JustMakeGame 16. 飞行系统

打折的时候买了这个资产,纯蓝图项目,里面的飞行动画不错。逻辑也可以做一定的参考,直接接入进来。

image.png

初步实现

我希望在空中按shift进入飞行状态。

void ACwlBasePlayer::InputBeginSprint(const FInputActionValue& InputValue)
{
    if (GetMovementState() == ECwlMovementState::InAir)
    {
        FlyComponent->Server_StartFly();
        FlyComponent->StartFly();
        return ;
    }
    DesiredGait = ECwlGait::Sprinting;
    Server_SetDesiredGait(DesiredGait);
}

飞行状态按空格跳一下退出飞行状态。

void ACwlBasePlayer::InputBeginJump(const FInputActionValue& InputValue)
{
    // ...

    if (GetMovementState() == ECwlMovementState::Fly)
    {
        FlyComponent->Server_StopFly();
        FlyComponent->StopFly();
        return;
    }

    // ...

进入退出飞行状态。核心是设置移动组件状态 OwnerCharacter->GetMyMovementComponent()->SetMovementMode(MOVE_Flying);

void UCwlFlyComponent::StartFly()
{
    if (!IsComponentReady())
    {
        UE_LOG(LogTemp, Error, TEXT("UCwlFlyComponent::StartFly Component Init Fail"));
        return ;
    }

    OwnerCharacter->SetMovementState(ECwlMovementState::Fly);
    OwnerCharacter->GetMyMovementComponent()->SetMovementMode(MOVE_Flying);
}

void UCwlFlyComponent::StopFly()
{
    if (!IsComponentReady())
    {
        UE_LOG(LogTemp, Error, TEXT("UCwlFlyComponent::StopFly Component Init Fail"));
        return ;
    }

    OwnerCharacter->SetMovementState(ECwlMovementState::InAir);
    OwnerCharacter->GetMyMovementComponent()->SetMovementMode(MOVE_Falling);
}

如果是飞行状态输入直接接到飞行组件里面处理。

FlyComponent->Move(OutForwardAxis, OutRightAxis);

这里直接按摄像机的前,右方向加就好了。

void UCwlFlyComponent::Move(float ForwardAxis, float RightAxis)
{
    if (!IsComponentReady())
    {
        UE_LOG(LogTemp, Error, TEXT("UCwlFlyComponent::StopFly Component Init Fail"));
        return ;
    }

    APlayerController* PlayerController = Cast<APlayerController>(OwnerCharacter->GetController());
    if (PlayerController == nullptr)
    {
        UE_LOG(LogTemp, Error, TEXT("UCwlFlyComponent::Move PlayerController is nullptr"));
        return ;
    }

    APlayerCameraManager* PlayerCameraManager = PlayerController->PlayerCameraManager;
    if (PlayerCameraManager == nullptr)
    {
        UE_LOG(LogTemp, Error, TEXT("UCwlFlyComponent::Move PlayerCameraManager is nullptr"));
        return ;
    }

    OwnerCharacter->AddMovementInput(PlayerCameraManager->GetActorForwardVector(), ForwardAxis);
    OwnerCharacter->AddMovementInput(PlayerCameraManager->GetActorRightVector(), RightAxis);
}

在tick中把角色的Rotation往摄像机的Rotation插值。

    FRotator CameraRotator = PlayerCameraManager->GetCameraRotation();
    CameraRotator.Pitch = 0.f;
    FRotator NewRot = FMath::RInterpTo(OwnerCharacter->GetActorRotation(), CameraRotator, DeltaTime, 8.f);
    OwnerCharacter->SetActorRotation(NewRot);

然后在动画蓝图里面计算一下各个方向的速度。

void UFlyAnimIns::NativeUpdateAnimation(float DeltaSeconds)
{
    Super::NativeUpdateAnimation(DeltaSeconds);

    if (ACwlCharacter* InCharacterBase = Cast<ACwlCharacter>(TryGetPawnOwner()))
    {
        FVector SpeedVector = InCharacterBase->GetVelocity();
        FRotator CharacterRot =  InCharacterBase->GetActorRotation();
        SpeedVector = CharacterRot.UnrotateVector(SpeedVector);

        if (UCharacterMovementComponent* InCharacterMovementComponent = Cast<UCharacterMovementComponent>(InCharacterBase->GetMovementComponent()))
        {
            float MaxFlySpeed = InCharacterMovementComponent->MaxFlySpeed;
            FlySpeed.X = FMath::GetMappedRangeValueClamped(FVector2D(-MaxFlySpeed, MaxFlySpeed), FVector2D(-1.f, 1.f), SpeedVector.X);
            FlySpeed.Y = FMath::GetMappedRangeValueClamped(FVector2D(-MaxFlySpeed, MaxFlySpeed), FVector2D(-1.f, 1.f), SpeedVector.Y);
            FlySpeed.Z = FMath::GetMappedRangeValueClamped(FVector2D(-MaxFlySpeed, MaxFlySpeed), FVector2D(-1.f, 1.f), SpeedVector.Z);
        }
    }
}

image.png

然后准备一个根据速度方向倾斜的混合空间。
把飞行状态丢到这里
image.png

然后收工

image.png

更多的细节

上一篇
下一篇