看了一下終於發現了跳躍的關鍵代碼
bool UCharacterMovementComponent::DoJump(bool bReplayingMoves) { if ( CharacterOwner && CharacterOwner->CanJump() ) { // Don't jump if we can't move up/down. if (!bConstrainToPlane || FMath::Abs(PlaneConstraintNormal.Z) != 1.f) { Velocity.Z = JumpZVelocity; SetMovementMode(MOVE_Falling); return true; } } return false; }
這里跳躍就和JumpZVelocity聯系在一起了,同時運動狀態改成了Falling(我認為這里設置Falling是不對的,因為在空中有上升還有下落兩個狀態),不過MovementComponent有判斷停止下落的函數,可以在狀態機里直接用。
當然判斷是否可以跳躍就是另一回事了,你也可以自己寫一個跳躍函數。
首先是CharactorMovementComponent中的DoJump(),里面檢測一下能不能跳躍,(即是否允許角色Z方向的移動,因為要兼容別的類型的游戲。
),之后在ACharacter中DoJump()中與CanJump()進行與運算,CanJump返回CanJumpInternal(),CanJumpInternal()是個事件,所以我們需要
去看CanJumpInternal_Implementation(),果然CanJumpInternal_Implementation是個虛函數,所以修改跳躍邏輯就修改這個函數就好了。
看一下CanJumpInternal_Implementation的邏輯
bool ACharacter::CanJumpInternal_Implementation() const { const bool bCanHoldToJumpHigher = (GetJumpMaxHoldTime() > 0.0f) && IsJumpProvidingForce(); return !bIsCrouched && CharacterMovement && (CharacterMovement->IsMovingOnGround() || bCanHoldToJumpHigher) && CharacterMovement->IsJumpAllowed() && !CharacterMovement->bWantsToCrouch; }
!bIsCrouched角色的運行模式不能為蹲
CharacterMovement->IsMovingOnGround() 確定角色是否還處於走路狀態
bCanHoldToJumpHigher的是判斷當按下跳躍鍵的時候,是否還能到達最高點
CharacterMovement->IsJumpAllowed() 角色運動組件是否可以跳
!CharacterMovement->bWantsToCrouch不能正在做下蹲動作
另外補充一下相關代碼
float UCharacterMovementComponent::GetMaxJumpHeight() const { const float Gravity = GetGravityZ(); if (FMath::Abs(Gravity) > KINDA_SMALL_NUMBER) { return FMath::Square(JumpZVelocity) / (-2.f * Gravity); } else { return 0.f; } }
一個重力下落公式
void UCharacterMovementComponent::JumpOff(AActor* MovementBaseActor) { if ( !bPerformingJumpOff ) { bPerformingJumpOff = true; if ( CharacterOwner ) { const float MaxSpeed = GetMaxSpeed() * 0.85f; Velocity += MaxSpeed * GetBestDirectionOffActor(MovementBaseActor); if ( Velocity.Size2D() > MaxSpeed ) { Velocity = MaxSpeed * Velocity.GetSafeNormal(); } Velocity.Z = JumpOffJumpZFactor * JumpZVelocity; SetMovementMode(MOVE_Falling); } bPerformingJumpOff = false; } }
----------------------------------------------------------------------------------------------
如何實現:
首先在你的角色類的頭文件中加入
virtual bool CanJumpInternal_Implementation() const override;
覆蓋CanJumpInternal事件。
之后在Cpp文件中加入
bool AThirdPersonCharacter::CanJumpInternal_Implementation() const { const bool bCanHoldToJumpHigher = (GetJumpMaxHoldTime() > 0.0f) && IsJumpProvidingForce(); //return !bIsCrouched && CharacterMovement && (CharacterMovement->IsMovingOnGround() || bCanHoldToJumpHigher) && CharacterMovement->IsJumpAllowed() && !CharacterMovement->bWantsToCrouch; return !bIsCrouched && CharacterMovement && CharacterMovement->IsJumpAllowed() && !CharacterMovement->bWantsToCrouch; }
我把(CharacterMovement->IsMovingOnGround() || bCanHoldToJumpHigher)刪掉了,這里就替換上你的二段跳邏輯即可
在頭文件中加入2個用於判斷二段跳的變量
//最大跳躍次數 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Jump") int32 MaxJumpNum = 2; //當前跳躍次數 int32 JumpNum=2;
當然把JumNum在構造函數中賦值才是正確選擇
覆蓋事件
//virtual void OnMovementModeChanged(EMovementMode PrevMovementMode, uint8 PreviousCustomMode = 0) override; virtual void Landed(const FHitResult& Hit) override;
2個都可以用,第一個功能更加強大
然后在Cpp文件里:
void AThirdPersonCharacter::Jump() { if (JumpNum>0) { bPressedJump = true; JumpKeyHoldTime = 0.0f; JumpNum = JumpNum - 1; } } void AThirdPersonCharacter::Landed(const FHitResult& Hit) { Super::Landed(Hit); JumpNum = MaxJumpNum; }
當然之前的按鍵事件綁定也需要修改一下
void AThirdPersonCharacter::SetupPlayerInputComponent(class UInputComponent* InputComponent) { // Set up gameplay key bindings check(InputComponent);
//把這個Jump改為你自己剛才定義的Jump InputComponent->BindAction("Jump", IE_Pressed, this, &AThirdPersonCharacter::Jump); InputComponent->BindAction("Jump", IE_Released, this, &ACharacter::StopJumping); InputComponent->BindAxis("MoveForward", this, &AThirdPersonCharacter::MoveForward); InputComponent->BindAxis("MoveRight", this, &AThirdPersonCharacter::MoveRight); // We have 2 versions of the rotation bindings to handle different kinds of devices differently // "turn" handles devices that provide an absolute delta, such as a mouse. // "turnrate" is for devices that we choose to treat as a rate of change, such as an analog joystick InputComponent->BindAxis("Turn", this, &APawn::AddControllerYawInput); InputComponent->BindAxis("TurnRate", this, &AThirdPersonCharacter::TurnAtRate); InputComponent->BindAxis("LookUp", this, &APawn::AddControllerPitchInput); InputComponent->BindAxis("LookUpRate", this, &AThirdPersonCharacter::LookUpAtRate); // handle touch devices InputComponent->BindTouch(IE_Pressed, this, &AThirdPersonCharacter::TouchStarted); InputComponent->BindTouch(IE_Released, this, &AThirdPersonCharacter::TouchStopped); }