• 看Ue4角色代码——跳跃与实现二段跳


    看了一下终于发现了跳跃的关键代码

    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); }
  • 相关阅读:
    一次摸鱼
    scenes
    mysql日志
    十万个为什么
    ss
    mysql之explain
    mysql之索引
    mysql1
    分页
    ajax分页
  • 原文地址:https://www.cnblogs.com/blueroses/p/5307609.html
Copyright © 2020-2023  润新知