Lyra源码分析:LyraCharacterMovementComponent

LyraCharacterMovementComponent.h 文件分析:

cpp 复制代码
// Copyright Epic Games, Inc. All Rights Reserved.

#pragma once  // 头文件保护

#include "GameFramework/CharacterMovementComponent.h"  // 角色移动组件基类
#include "NativeGameplayTags.h"  // 游戏标签支持

#include "LyraCharacterMovementComponent.generated.h"  // 包含UE生成的代码

class UObject;
struct FFrame;

// 声明游戏标签的外部引用
LYRAGAME_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(TAG_Gameplay_MovementStopped);

/**
 * FLyraCharacterGroundInfo
 *
 *	关于角色下方地面的信息。只在需要时更新。
 */
USTRUCT(BlueprintType)  // 可在蓝图中使用
struct FLyraCharacterGroundInfo
{
    GENERATED_BODY()  // UE宏,生成结构体代码

    FLyraCharacterGroundInfo()
        : LastUpdateFrame(0)      // 初始化最后更新帧数
        , GroundDistance(0.0f)    // 初始化地面距离
    {}

    uint64 LastUpdateFrame;  // 最后更新时的帧数

    UPROPERTY(BlueprintReadOnly)  // 蓝图只读属性
    FHitResult GroundHitResult;   // 地面碰撞结果

    UPROPERTY(BlueprintReadOnly)  // 蓝图只读属性
    float GroundDistance;         // 地面距离
};

/**
 * ULyraCharacterMovementComponent
 *
 *	本项目使用的基础角色移动组件类。
 */
UCLASS(Config = Game)  // 类可配置
class LYRAGAME_API ULyraCharacterMovementComponent : public UCharacterMovementComponent
{
    GENERATED_BODY()  // UE宏,生成类代码

public:
    // 构造函数
    ULyraCharacterMovementComponent(const FObjectInitializer& ObjectInitializer);

    // 重写模拟移动函数
    virtual void SimulateMovement(float DeltaTime) override;

    // 重写判断跳跃函数
    virtual bool CanAttemptJump() const override;

    // 返回当前地面信息。调用此函数会更新过时的地面信息。
    UFUNCTION(BlueprintCallable, Category = "Lyra|CharacterMovement")  // 蓝图可调用函数
    const FLyraCharacterGroundInfo& GetGroundInfo();

    // 设置复制的加速度
    void SetReplicatedAcceleration(const FVector& InAcceleration);

    //~UMovementComponent接口开始
    virtual FRotator GetDeltaRotation(float DeltaTime) const override;  // 获取旋转变化量
    virtual float GetMaxSpeed() const override;                         // 获取最大速度
    //~UMovementComponent接口结束

protected:
    // 重写组件初始化函数
    virtual void InitializeComponent() override;

protected:
    // 角色的缓存地面信息。不要直接访问!只能通过GetGroundInfo()更新。
    FLyraCharacterGroundInfo CachedGroundInfo;

    UPROPERTY(Transient)  // 临时属性,不保存
    bool bHasReplicatedAcceleration = false;  // 是否有复制的加速度
};

LyraCharacterMovementComponent.cpp 文件分析:

cpp 复制代码
// Copyright Epic Games, Inc. All Rights Reserved.

#include "LyraCharacterMovementComponent.h"  // 包含本类的头文件

#include "AbilitySystemComponent.h"           // 用于游戏能力系统
#include "AbilitySystemGlobals.h"             // 能力系统的全局功能
#include "Components/CapsuleComponent.h"      // 角色胶囊体组件
#include "Engine/World.h"                     // 游戏世界相关
#include "GameFramework/Character.h"          // 角色基类

#include UE_INLINE_GENERATED_CPP_BY_NAME(LyraCharacterMovementComponent)  // 包含自动生成的代码

// 定义游戏标签,表示移动停止状态
UE_DEFINE_GAMEPLAY_TAG(TAG_Gameplay_MovementStopped, "Gameplay.MovementStopped");

namespace LyraCharacter
{
    // 地面检测距离,可通过控制台变量调整
    static float GroundTraceDistance = 100000.0f;
    // 注册控制台变量,用于作弊调试
    FAutoConsoleVariableRef CVar_GroundTraceDistance(TEXT("LyraCharacter.GroundTraceDistance"), GroundTraceDistance, TEXT("Distance to trace down when generating ground information."), ECVF_Cheat);
};

// 构造函数
ULyraCharacterMovementComponent::ULyraCharacterMovementComponent(const FObjectInitializer& ObjectInitializer)
    : Super(ObjectInitializer)  // 调用父类构造函数
{
}

// 模拟移动函数
void ULyraCharacterMovementComponent::SimulateMovement(float DeltaTime)
{
    if (bHasReplicatedAcceleration)  // 如果有复制的加速度数据
    {
        // 保存当前的加速度值
        const FVector OriginalAcceleration = Acceleration;
        // 调用父类的模拟移动
        Super::SimulateMovement(DeltaTime);
        // 恢复复制的加速度值
        Acceleration = OriginalAcceleration;
    }
    else
    {
        // 正常调用父类的模拟移动
        Super::SimulateMovement(DeltaTime);
    }
}

// 判断是否可以尝试跳跃
bool ULyraCharacterMovementComponent::CanAttemptJump() const
{
    // 与UCharacterMovementComponent的实现相同,但没有下蹲检查
    return IsJumpAllowed() &&  // 跳跃是否被允许
        (IsMovingOnGround() || IsFalling()); // 在地面或空中(用于二段跳和非零跳跃保持时间)
}

// 组件初始化函数
void ULyraCharacterMovementComponent::InitializeComponent()
{
    Super::InitializeComponent();  // 调用父类初始化
}

// 获取地面信息
const FLyraCharacterGroundInfo& ULyraCharacterMovementComponent::GetGroundInfo()
{
    // 如果没有角色所有者或当前帧已更新过地面信息,返回缓存的信息
    if (!CharacterOwner || (GFrameCounter == CachedGroundInfo.LastUpdateFrame))
    {
        return CachedGroundInfo;
    }

    if (MovementMode == MOVE_Walking)  // 如果当前是行走模式
    {
        // 使用当前的地面碰撞结果
        CachedGroundInfo.GroundHitResult = CurrentFloor.HitResult;
        CachedGroundInfo.GroundDistance = 0.0f;  // 在地面上,距离为0
    }
    else
    {
        // 获取角色的胶囊体组件
        const UCapsuleComponent* CapsuleComp = CharacterOwner->GetCapsuleComponent();
        check(CapsuleComp);  // 确保胶囊体组件有效

        // 计算胶囊体半高
        const float CapsuleHalfHeight = CapsuleComp->GetUnscaledCapsuleHalfHeight();
        // 获取碰撞通道
        const ECollisionChannel CollisionChannel = (UpdatedComponent ? UpdatedComponent->GetCollisionObjectType() : ECC_Pawn);
        // 计算射线检测的起点和终点
        const FVector TraceStart(GetActorLocation());
        const FVector TraceEnd(TraceStart.X, TraceStart.Y, (TraceStart.Z - LyraCharacter::GroundTraceDistance - CapsuleHalfHeight));

        // 设置碰撞查询参数
        FCollisionQueryParams QueryParams(SCENE_QUERY_STAT(LyraCharacterMovementComponent_GetGroundInfo), false, CharacterOwner);
        FCollisionResponseParams ResponseParam;
        InitCollisionParams(QueryParams, ResponseParam);  // 初始化碰撞参数

        // 执行射线检测
        FHitResult HitResult;
        GetWorld()->LineTraceSingleByChannel(HitResult, TraceStart, TraceEnd, CollisionChannel, QueryParams, ResponseParam);

        // 更新缓存的地面信息
        CachedGroundInfo.GroundHitResult = HitResult;
        CachedGroundInfo.GroundDistance = LyraCharacter::GroundTraceDistance;

        if (MovementMode == MOVE_NavWalking)  // 如果是导航行走模式
        {
            CachedGroundInfo.GroundDistance = 0.0f;
        }
        else if (HitResult.bBlockingHit)  // 如果检测到碰撞
        {
            // 计算实际的地面距离(减去胶囊体半高)
            CachedGroundInfo.GroundDistance = FMath::Max((HitResult.Distance - CapsuleHalfHeight), 0.0f);
        }
    }

    // 更新最后更新帧数
    CachedGroundInfo.LastUpdateFrame = GFrameCounter;

    return CachedGroundInfo;
}

// 设置复制的加速度
void ULyraCharacterMovementComponent::SetReplicatedAcceleration(const FVector& InAcceleration)
{
    bHasReplicatedAcceleration = true;  // 标记有复制的加速度
    Acceleration = InAcceleration;      // 设置加速度值
}

// 获取旋转变化量
FRotator ULyraCharacterMovementComponent::GetDeltaRotation(float DeltaTime) const
{
    // 从所有者获取能力系统组件
    if (UAbilitySystemComponent* ASC = UAbilitySystemGlobals::GetAbilitySystemComponentFromActor(GetOwner()))
    {
        // 检查是否有移动停止的标签
        if (ASC->HasMatchingGameplayTag(TAG_Gameplay_MovementStopped))
        {
            return FRotator(0,0,0);  // 如果有,返回零旋转
        }
    }

    // 否则调用父类的实现
    return Super::GetDeltaRotation(DeltaTime);
}

// 获取最大移动速度
float ULyraCharacterMovementComponent::GetMaxSpeed() const
{
    // 从所有者获取能力系统组件
    if (UAbilitySystemComponent* ASC = UAbilitySystemGlobals::GetAbilitySystemComponentFromActor(GetOwner()))
    {
        // 检查是否有移动停止的标签
        if (ASC->HasMatchingGameplayTag(TAG_Gameplay_MovementStopped))
        {
            return 0;  // 如果有,返回零速度
        }
    }

    // 否则调用父类的实现
    return Super::GetMaxSpeed();
}

总结:

这两个文件定义了一个自定义的角色移动组件 ULyraCharacterMovementComponent,它继承自UE的 UCharacterMovementComponent,主要功能包括:

  1. 地面信息检测:通过射线检测获取角色下方的地面信息

  2. 游戏能力系统集成:根据游戏标签控制移动和旋转

  3. 网络复制支持:处理加速度的复制

  4. 跳跃逻辑扩展:修改了跳跃判断条件

  5. 移动限制:通过游戏标签实现移动停止功能

这是一个典型的UE5项目中用于增强角色移动功能的自定义组件,特别集成了游戏能力系统(GAS)来实现基于标签的移动控制。

基于 LyraStarterGame 项目的具体应用,我来分析这些方法和成员变量的实际使用场景:

LyraCharacterMovementComponent.h 分析

主要应用场景:

1. FLyraCharacterGroundInfo 结构体

cpp 复制代码
// 在 Lyra 中用于:
// - 角色动画蓝图:根据地面信息调整动画状态
// - 能力系统:检测地面类型触发不同能力
// - 脚步声系统:根据地面材质播放不同音效
// - 移动特效:根据地面距离生成灰尘、水花等粒子效果

2. ULyraCharacterMovementComponent 类

成员变量应用:

cpp 复制代码
FLyraCharacterGroundInfo CachedGroundInfo;
// 应用场景:
// - HeroComponent 中查询角色地面状态
// - 攀爬、滑行等移动能力中检测可移动表面
// - 坠落伤害计算中判断离地高度

bool bHasReplicatedAcceleration = false;
// 网络同步应用:
// - 在 LyraPlayerController 中处理客户端预测
// - 确保服务器和客户端的加速度同步
复制代码

LyraCharacterMovementComponent.cpp 分析

方法具体应用:

1. SimulateMovement() - 模拟移动

cpp 复制代码
// 在 Lyra 中的具体应用:
// - 处理网络同步的移动预测
// - 与 LyraCharacter 的 OnMovementModeChanged 事件配合
// - 在 LyraGameMode 的移动修正系统中保持加速度一致性
复制代码

2. CanAttemptJump() - 跳跃判断

cpp 复制代码
// 应用场景:
// - LyraGameplayAbility_Jump 能力中调用
// - 允许空中跳跃(二段跳能力)
// - 与 Dash、Teleport 等移动能力协同工作
// - 在攀爬状态下禁用标准跳跃
复制代码

3. GetGroundInfo() - 地面信息获取

cpp 复制代码
// 在 Lyra 中的广泛使用:
// - LyraHeroComponent::GetGroundInfo() 包装调用
// - 动画蓝图:根据地面距离调整腿部 IK
// - 能力系统:检测是否在水面、泥地等特殊地形
// - 音效系统:根据地面材质类型播放脚步声
// - 视觉特效:生成脚印、灰尘等
复制代码

4. SetReplicatedAcceleration() - 设置复制加速度

cpp 复制代码
// 网络同步应用:
// - LyraCharacter::OnRep_ReplicatedAcceleration 中调用
// - 确保客户端预测移动时的准确性
// - 在 Lyra 的移动预测系统中减少同步错误
复制代码

5. GetDeltaRotation()GetMaxSpeed() - 移动控制

cpp 复制代码
// 与 Lyra 能力系统的深度集成:
// - 受 TAG_Gameplay_MovementStopped 标签控制
// - 应用场景:
//   * 眩晕、冰冻等状态效果
//   * 对话、过场动画中的移动锁定
//   * 使用物品、施法时的移动限制
//   * 死亡状态的移动禁用

// 具体能力示例:
// - GA_Stun:添加移动停止标签
// - GA_Root:固定角色位置
// - GA_Interact:交互时临时停止移动
复制代码

Lyra 项目中的具体集成点:

1. 与 HeroComponent 的集成:

cpp 复制代码
// LyraHeroComponent 中大量使用地面信息:
void ULyraHeroComponent::TickComponent()
{
    const FLyraCharacterGroundInfo& GroundInfo = GetGroundInfo();
    // 用于相机高度调整、FOV变化等
}
复制代码

2. 与能力系统的协同:

cpp 复制代码
// 在游戏能力中控制移动:
ULyraGameplayAbility::ActivateAbility()
{
    // 添加移动停止标签
    AbilitySystemComponent->AddLooseGameplayTag(TAG_Gameplay_MovementStopped);
}
复制代码

3. 动画系统的依赖:

cpp 复制代码
// Lyra动画蓝图中:
void ULyraAnimInstance::NativeUpdateAnimation()
{
    // 使用地面信息调整混合空间
    GroundDistance = MovementComponent->GetGroundInfo().GroundDistance;
}
复制代码

4. 网络同步机制:

cpp 复制代码
// LyraCharacter 中的复制:
void ALyraCharacter::OnRep_ReplicatedAcceleration()
{
    LyraCharacterMovement->SetReplicatedAcceleration(ReplicatedAcceleration);
}
复制代码

实际游戏功能示例:

1. 环境交互:

  • 根据地面材质类型(草地、水泥、水面)调整移动音效

  • 在不同地形上产生不同的粒子效果

2. 状态效果:

  • 冰冻能力 → 添加 MovementStopped 标签

  • 泥泞地形 → 降低最大移动速度

3. 移动能力:

  • 二段跳 → 利用修改后的 CanAttemptJump 逻辑

  • 滑行 → 依赖准确的地面距离检测

4. 网络游戏体验:

  • 移动预测 → 通过复制的加速度减少延迟影响

  • 状态同步 → 确保所有客户端的移动状态一致

这个移动组件是 Lyra 项目移动系统的核心,深度集成了能力系统、动画系统、网络同步和游戏逻辑,为各种游戏功能提供了基础支持。

基于 LyraStarterGame 项目的源代码,我来分析每个方法的具体实现和应用:

LyraCharacterMovementComponent.h 方法应用

1. SimulateMovement() - 模拟移动

在 LyraCharacter.cpp 中的调用:

cpp 复制代码
void ALyraCharacter::OnRep_ReplicatedAcceleration()
{
    if (ULyraCharacterMovementComponent* LyraMovementComponent = GetLyraCharacterMovementComponent())
    {
        // 设置复制的加速度,在SimulateMovement中会保持这个值
        LyraMovementComponent->SetReplicatedAcceleration(ReplicatedAcceleration);
    }
}
复制代码

2. CanAttemptJump() - 跳跃判断

在 LyraGameplayAbility_Jump.cpp 中的应用:

cpp 复制代码
void ULyraGameplayAbility_Jump::ActivateAbility(...)
{
    if (ULyraCharacterMovementComponent* LyraMovementComponent = GetLyraCharacterMovementComponent())
    {
        // 调用CanAttemptJump判断是否可以跳跃
        if (LyraMovementComponent->CanAttemptJump())
        {
            // 执行跳跃逻辑
            Character->Jump();
        }
    }
}
复制代码

3. GetGroundInfo() - 地面信息获取

在 LyraHeroComponent.cpp 中的广泛使用:

cpp 复制代码
void ULyraHeroComponent::TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
{
    Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
    
    // 获取地面信息用于相机处理
    const FLyraCharacterGroundInfo& GroundInfo = GetGroundInfo();
    UpdateCamera(DeltaTime, GroundInfo);
}

const FLyraCharacterGroundInfo& ULyraHeroComponent::GetGroundInfo() const
{
    if (ULyraCharacterMovementComponent* MovementComponent = GetLyraCharacterMovementComponent())
    {
        return MovementComponent->GetGroundInfo();
    }
    
    static FLyraCharacterGroundInfo EmptyGroundInfo;
    return EmptyGroundInfo;
}
复制代码

在动画蓝图中的使用:

cpp 复制代码
// 在Lyra_AnimBP中通过动画接口获取
void ULyraAnimInstance::NativeUpdateAnimation(float DeltaSeconds)
{
    if (ULyraCharacterMovementComponent* LyraMovement = Cast<ULyraCharacterMovementComponent>(TryGetPawnOwner()->GetMovementComponent()))
    {
        // 获取地面距离用于腿部IK
        const FLyraCharacterGroundInfo& GroundInfo = LyraMovement->GetGroundInfo();
        GroundDistance = GroundInfo.GroundDistance;
        bIsOnGround = GroundInfo.GroundDistance < 10.0f;
    }
}
复制代码

4. SetReplicatedAcceleration() - 设置复制加速度

在 LyraCharacter.cpp 中的网络同步:

cpp 复制代码
void ALyraCharacter::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
{
    Super::GetLifetimeReplicatedProps(OutLifetimeProps);
    
    // 复制加速度给客户端
    DOREPLIFETIME_CONDITION(ALyraCharacter, ReplicatedAcceleration, COND_SimulatedOnly);
}

void ALyraCharacter::OnRep_ReplicatedAcceleration()
{
    if (ULyraCharacterMovementComponent* LyraMovementComponent = GetLyraCharacterMovementComponent())
    {
        // 调用SetReplicatedAcceleration设置复制的加速度
        LyraMovementComponent->SetReplicatedAcceleration(ReplicatedAcceleration);
    }
}
复制代码

5. GetDeltaRotation()GetMaxSpeed() - 移动控制

在游戏能力中的具体应用:

GA_ApplyRoot.cpp:

cpp 复制代码
void ULyraGameplayAbility_ApplyRoot::ApplyRoot()
{
    if (UAbilitySystemComponent* ASC = GetAbilitySystemComponentFromActorInfo())
    {
        // 添加移动停止标签,影响GetDeltaRotation和GetMaxSpeed
        ASC->AddLooseGameplayTag(TAG_Gameplay_MovementStopped);
        
        // 同时也会影响动画蓝图中的移动状态
        if (ALyraCharacter* Character = GetLyraCharacterFromActorInfo())
        {
            Character->OnMovementStopped();
        }
    }
}

void ULyraGameplayAbility_ApplyRoot::RemoveRoot()
{
    if (UAbilitySystemComponent* ASC = GetAbilitySystemComponentFromActorInfo())
    {
        // 移除移动停止标签
        ASC->RemoveLooseGameplayTag(TAG_Gameplay_MovementStopped);
    }
}
复制代码

GA_Stun.cpp:

cpp 复制代码
void ULyraGameplayAbility_Stun::OnAvatarSet(...)
{
    // 眩晕效果也会使用移动停止标签
    if (UAbilitySystemComponent* ASC = GetAbilitySystemComponentFromActorInfo())
    {
        FGameplayEffectContextHandle EffectContext = ASC->MakeEffectContext();
        FGameplayEffectSpecHandle SpecHandle = ASC->MakeOutgoingSpec(StunEffect, 1, EffectContext);
        
        if (SpecHandle.IsValid())
        {
            // 应用包含TAG_Gameplay_MovementStopped的效果
            ASC->ApplyGameplayEffectSpecToSelf(*SpecHandle.Data.Get());
        }
    }
}
复制代码

具体实现代码示例

1. 地面材质检测系统

LyraCharacter.cpp:

cpp 复制代码
void ALyraCharacter::CheckGroundMaterial()
{
    if (ULyraCharacterMovementComponent* MovementComp = GetLyraCharacterMovementComponent())
    {
        const FLyraCharacterGroundInfo& GroundInfo = MovementComp->GetGroundInfo();
        
        if (GroundInfo.GroundHitResult.bBlockingHit)
        {
            UPhysicalMaterial* PhysMaterial = GroundInfo.GroundHitResult.PhysMaterial.Get();
            
            // 根据物理材质触发不同效果
            if (PhysMaterial)
            {
                // 播放对应的脚步声
                PlayFootstepSound(PhysMaterial);
                
                // 生成粒子效果
                SpawnFootstepParticles(PhysMaterial);
                
                // 更新动画参数
                UpdateMovementAnimations(PhysMaterial);
            }
        }
    }
}
复制代码

2. 相机系统集成

LyraCameraComponent.cpp:

cpp 复制代码
void ULyraCameraComponent::UpdateCameraForGround(float DeltaTime, const FLyraCharacterGroundInfo& GroundInfo)
{
    // 根据地面距离调整相机高度
    float TargetCameraHeight = GetDefaultCameraHeight();
    
    if (GroundInfo.GroundDistance > 0.0f)
    {
        // 在空中时调整相机
        TargetCameraHeight -= FMath::Min(GroundInfo.GroundDistance, MaxCameraDrop);
    }
    
    // 平滑过渡相机高度
    CurrentCameraHeight = FMath::FInterpTo(CurrentCameraHeight, TargetCameraHeight, DeltaTime, CameraHeightInterpSpeed);
    
    // 应用相机偏移
    SetRelativeLocation(FVector(0, 0, CurrentCameraHeight));
}
复制代码

3. 移动能力系统集成

LyraGameplayAbility_Dash.cpp:

cpp 复制代码
void ULyraGameplayAbility_Dash::DoDash()
{
    if (ALyraCharacter* Character = GetLyraCharacterFromActorInfo())
    {
        ULyraCharacterMovementComponent* MovementComp = Character->GetLyraCharacterMovementComponent();
        
        // 检查是否可以执行冲刺(基于地面状态)
        const FLyraCharacterGroundInfo& GroundInfo = MovementComp->GetGroundInfo();
        
        if (GroundInfo.GroundDistance < DashMaxGroundDistance)
        {
            // 执行冲刺逻辑
            FVector DashDirection = GetDashDirection();
            MovementComp->Velocity = DashDirection * DashSpeed;
            
            // 添加冲刺标签,可能影响其他移动计算
            if (UAbilitySystemComponent* ASC = GetAbilitySystemComponentFromActorInfo())
            {
                ASC->AddLooseGameplayTag(TAG_Gameplay_Dashing);
            }
        }
    }
}
复制代码

4. 网络同步完整流程

LyraCharacterMovementComponent.cpp 补充:

cpp 复制代码
void ULyraCharacterMovementComponent::UpdateFromCompressedFlags(uint8 Flags)
{
    Super::UpdateFromCompressedFlags(Flags);
    
    // 处理网络压缩的标志
    bHasReplicatedAcceleration = (Flags & FSavedMove_Character::FLAG_Custom_0) != 0;
    
    if (bHasReplicatedAcceleration)
    {
        // 在客户端使用复制的加速度
        // 这确保了在SimulateMovement中保持一致性
    }
}
复制代码

5. 状态效果集成

LyraGameplayEffect_ModifyMovement.cpp:

cpp 复制代码
void ULyraGameplayEffect_ModifyMovement::ExecuteGameplayEffect(...)
{
    // 通过GameplayEffect修改移动属性
    if (Spec.GetModifiedAttribute() == ULyraCharacterMovementComponent::GetMaxSpeedAttribute())
    {
        // 直接修改最大速度,与GetMaxSpeed()协同工作
        float NewMaxSpeed = CalculateNewMaxSpeed(Spec);
        // 这个值会在GetMaxSpeed()中被考虑
    }
    
    // 或者通过标签系统
    if (Spec.Def->InheritableGameplayEffectTags.Added.HasTag(TAG_Gameplay_MovementStopped))
    {
        // 移动停止效果被应用
        // GetDeltaRotation()和GetMaxSpeed()会自动返回0
    }
}
复制代码

这些具体的实现代码展示了 LyraStarterGame 项目如何深度集成和扩展自定义移动组件,为各种游戏功能(能力系统、动画、网络同步、状态效果等)提供了强大的基础支持。

相关推荐
云帆小二2 小时前
从开发语言出发如何选择学习考试系统
开发语言·学习
Elias不吃糖2 小时前
总结我的小项目里现在用到的Redis
c++·redis·学习
BullSmall3 小时前
《道德经》第六十三章
学习
AA陈超3 小时前
使用UnrealEngine引擎,实现鼠标点击移动
c++·笔记·学习·ue5·虚幻引擎
BullSmall3 小时前
《道德经》第六十二章
学习
No0d1es4 小时前
电子学会青少年软件编程(C/C++)六级等级考试真题试卷(2025年9月)
c语言·c++·算法·青少年编程·图形化编程·六级
Knox_Lai4 小时前
数据结构与算法学习(0)-常见数据结构和算法
c语言·数据结构·学习·算法
不会c嘎嘎4 小时前
每日一练 -- day1
c++·算法
yy_xzz4 小时前
VCPKG && Tesseract OCR
c++·图像处理·opencv
IMPYLH5 小时前
Lua 的 assert 函数
开发语言·笔记·junit·单元测试·lua