跳跃功能介绍


  总所周知,跳跃功能的逻辑是很容易的,但是也是很难写的,因为跳跃会引发很多的bug,例如连跳,跳比走还快,卡进了模型里面等等等等,我们常见的跳跃逻辑就是单纯的在按下跳跃键的时候,给予物体一个向上方向上的力,这样物体就跳了起来,但是,在跳的过程中,如果同时按下了方向键,那么物体是会移动的,而且移动的速度是和我们在平面上移动的速度相同,而且跳跃过程中多次按下跳跃键会发生连跳,最简单的解决方案就是加一个bool变量,在跳跃过程中锁定输入,但是这样我们就无法往前跳,那么跳跃的意义就不存在了,同样,在上述思路的基础上,我们可以在跳跃的时候修改移动的速度,使其没有在平面上移动的那么快,这也是一种解决方案,不过,这些逻辑都不用我们去写,UE4已经为我们定义好了一套跳跃的逻辑,我们可以直接使用,也可以在其基础上进行二次开发。不过,UE4的跳跃逻辑比我上述的远要复杂很多,涉及的源码也很多,有些逻辑本人水平有限,暂时还没看懂。

  首先,我们依然要设置输入,但是这次我们使用的是按键映射:


  我们在ThirdProjectCharacter.h中声明我们的跳跃函数:


    protected:
        // 按下跳跃键瞬间开始跳跃
        void TouchStarted(ETouchIndex::Type FingerIndex, FVector Location);
        // 弹起跳跃键瞬间停止跳跃
        void TouchStopped(ETouchIndex::Type FingerIndex, FVector Location);
						

  我们在ThirdProjectCharacter.cpp中写入以下定义:


    构造函数中先设置和跳跃相关的属性
    // 跳跃的高度
    GetCharacterMovement()->JumpZVelocity = 600.f;
    // 跳跃时可以进行横向移动控制,0为不能控制,1为以MaxWalkSpeed的最大速度进行完全控制
    GetCharacterMovement()->AirControl = 0.2f;
					
    绑定输入函数
    PlayerInputComponent->BindTouch(IE_Pressed, this, &AThirdProjectCharacter::TouchStarted);
    PlayerInputComponent->BindTouch(IE_Released, this, &AThirdProjectCharacter::TouchStopped);

    // 跳跃开始
    void AThirdProjectCharacter::TouchStarted(ETouchIndex::Type FingerIndex, FVector Location){
        // 没错,直接调用Jump函数,这个函数是为我们定义好的
        Jump();
    }
    // 跳跃停止
    void AThirdProjectCharacter::TouchStopped(ETouchIndex::Type FingerIndex, FVector Location){
        // 同理,这个函数也是定义好的
        StopJumping();
    }
						

  现在我们看看Jump函数的定义,在Character.cpp下


    void ACharacter::Jump(){
        // 设置跳跃属性为true
        bPressedJump = true;
        // 这个是跳跃键可以持续的时间,就是这个跳跃在这个时间内会持续触发
        JumpKeyHoldTime = 0.0f;
    }
						

  我们在Character.cpp查找bPressedJump这个属性,我们发现一断代码,这段代码很复杂,但是不难看出来,他调用了一个DoJump函数,而这个函数就是执行了我们的跳跃,于是我们查看DoJump函数源码,在CharacterMovementComponent下


    bool UCharacterMovementComponent::DoJump(bool bReplayingMoves){
        // 在这里调用了CanJump,用于判断是否可以跳跃
        if ( CharacterOwner && CharacterOwner->CanJump() ){
            // 如果我们无法上下移动,就不跳
            if (!bConstrainToPlane || FMath::Abs(PlaneConstraintNormal.Z) != 1.f){
                // 添加一个向上方向上的速度,JumpZVelocity为跳跃时的初始速度
                Velocity.Z = FMath::Max(Velocity.Z, JumpZVelocity);
                // 设置移动(数值方向上的位移,即为跳跃)
                SetMovementMode(MOVE_Falling);
                return true;
            }
        }
        return false;
    }
						

  对于停止跳跃的函数,在Character.cpp内的源码如下:


    void ACharacter::StopJumping(){
        bPressedJump = false;
        ResetJumpState();
    }
						

  我们继续追踪ResetJumpState函数:


    void ACharacter::ResetJumpState(){
        bPressedJump = false;
        bWasJumping = false;
        JumpKeyHoldTime = 0.0f;
        JumpForceTimeRemaining = 0.0f;

        if (CharacterMovement && !CharacterMovement->IsFalling()){
            JumpCurrentCount = 0;
        }
    }
						

  我们不难看出,它的作用就是将所有与跳跃相关的参数都进行了初始化。

  对于与跳跃相关的另外一个东西,是否在空中的判断,在不使用UE4自带的IsAir属性的情况下,本人能想到的制作逻辑如下:设置碰撞这个碰撞只有地面的物体和角色,如果没有接触,就将IsAir设为flase,如果有接触,也就触发了事件,将IsAir设为true。至于UE4中的IsAir,本人并不清楚他定义在哪个文件,也没有去看,如果使用Visual Studio搜索整个项目,搜索时间过长,而且电脑负担也大,所以也没有进行搜索,后面有时间会去了解的。