TransformCharacter 代码逐行解析
本文对 TransformCharacter.h 和 TransformCharacter.cpp 中的每一行代码进行解释,帮助理解角色形态变换与飞行遁速系统的实现。
一、TransformCharacter.h
1 // TransformCharacter.h - 角色形态变换系统
2 // 支持多形态切换、Niagara 特效、Enhanced Input 绑定
解释:文件头注释,说明本文件是角色形态变换系统的头文件,原设计支持多形态切换、Niagara 特效和 Enhanced Input(实际使用传统 BindKey)。
3
4 #pragma once
解释:预处理指令,确保头文件在单个编译单元中只被包含一次,避免重复定义。
5
6 #include "CoreMinimal.h"
解释:包含 UE 核心最小头文件,提供 UCLASS、UFUNCTION、UPROPERTY 等反射宏和基础类型。
7 #include "GameFramework/Character.h"
解释:包含 UE 的角色基类头文件,ATransformCharacter 继承自 ACharacter。
8 #include "TransformCharacter.generated.h"
解释:包含 UHT(Unreal Header Tool)生成的反射代码头文件,必须放在所有 include 的最后。
9
10 class UNiagaraSystem;
解释:前置声明 Niagara 系统类,避免在头文件中直接 include,减少编译依赖。
11 class UInputAction;
解释:前置声明 Enhanced Input 的输入动作类(保留属性,实际未在 C++ 中使用)。
12 class UInputMappingContext;
解释:前置声明 Enhanced Input 的输入映射上下文类(保留属性,实际未在 C++ 中使用)。
13 class UMaterialParameterCollection;
解释:前置声明材质参数集合类,用于溶解效果。
14
15 /** 形态变换事件委托 */
16 DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnFormChanged, int32, OldFormIndex, int32, NewFormIndex);
解释:声明一个动态多播委托。FOnFormChanged 有两个 int32 参数:OldFormIndex 和 NewFormIndex,用于在形态切换时广播事件给蓝图。
17
18 UCLASS()
解释:UE 反射宏,标记下面的类需要被 UHT 处理并生成反射代码。
19 class TEST_API ATransformCharacter : public ACharacter
解释:定义 ATransformCharacter 类,继承自 ACharacter,并导出模块 API(TEST_API 由模块名自动生成)。
20 {
21 GENERATED_BODY()
解释:GENERATED_BODY() 是 UHT 生成的反射代码插入点,替代旧的 GENERATED_UCLASS_BODY()。
22
23 public:
24 ATransformCharacter();
解释:声明默认构造函数,用于初始化组件和默认值。
25
26 protected:
27 virtual void BeginPlay() override;
解释:重写 AActor::BeginPlay(),在游戏开始时执行一些初始化逻辑(如速度兜底、资产引用修复)。
28 virtual void PossessedBy(AController* NewController) override;
解释:重写 APawn::PossessedBy(),当角色被控制器控制时调用。当前实现为空,保留扩展性。
29
30 /** 输入绑定:C++ 覆盖后也会调用蓝图中的 SetupPlayerInputComponent 实现 */
31 virtual void SetupPlayerInputComponent(UInputComponent* PlayerInputComponent) override;
解释:重写 ACharacter::SetupPlayerInputComponent(),用于绑定 T 键和鼠标右键。
32
33 public:
34 virtual void Tick(float DeltaTime) override;
解释:重写 AActor::Tick(),每帧调用一次,处理溶解动画、飞行移动、Niagara 速度传递等持续逻辑。
35
36 // ========== 形态系统 ==========
解释:注释分隔线,标记下面是形态系统相关属性。
37
38 /** 可用形态列表(Character 子类) */
39 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Transform|Forms")
40 TArray<TSubclassOf<ACharacter>> Forms;
解释:声明一个可在编辑器中编辑、可在蓝图中读写的数组,存储多个角色形态类。TSubclassOf 保证数组元素必须是 ACharacter 的子类。
41
42 /** 当前形态索引 */
43 UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Transform|Forms")
44 int32 FormIndex = 0;
解释:当前形态的数组索引,默认值为 0。VisibleAnywhere 表示在属性面板中可见但不可编辑,只读。
45
46 /** 切换到下一个形态 */
47 UFUNCTION(BlueprintCallable, Category = "Transform")
48 void TransformToNextForm();
解释:声明一个蓝图可调用的函数,用于切换到下一个形态。当前实现直接调用 OnTransformInput()。
49
50 /** 切换到指定形态 */
51 UFUNCTION(BlueprintCallable, Category = "Transform")
52 void TransformToForm(int32 Index);
解释:声明一个蓝图可调用的函数,按指定索引切换形态。当前实现也直接调用 OnTransformInput()。
53
54 /** 获取当前形态类 */
55 UFUNCTION(BlueprintPure, Category = "Transform")
56 TSubclassOf<ACharacter> GetCurrentFormClass() const;
解释:声明一个纯函数(无副作用),返回当前形态对应的 Character 子类。当前未实际使用。
57
58 /** 形态变化事件 */
59 UPROPERTY(BlueprintAssignable, Category = "Transform")
60 FOnFormChanged OnFormChanged;
解释:声明形态变化委托变量,蓝图可以绑定这个事件来响应形态切换。
61
62 // ========== 特效 ==========
解释:注释分隔线,标记下面是特效相关属性。
63
64 /** 变身爆发 Niagara 系统 */
65 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Transform|VFX")
66 TObjectPtr<UNiagaraSystem> TransformEffect;
解释:声明 Niagara 系统引用,用于变身爆发特效。当前未在 C++ 中使用,保留给蓝图配置。
67
68 /** 变身特效持续时间 */
69 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Transform|VFX")
70 float TransformEffectDuration = 1.5f;
解释:变身特效持续时间,默认 1.5 秒。当前未在 C++ 中使用。
71
72 // ========== 输入 ==========
解释:注释分隔线,标记下面是输入相关属性。
73
74 /** 变身输入动作 */
75 UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Input")
76 TObjectPtr<UInputAction> IA_Transform;
解释:Enhanced Input 的输入动作引用。当前未在 C++ 中使用,保留属性以便未来迁移。
77
78 /** 默认输入映射上下文 */
79 UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Input")
80 TObjectPtr<UInputMappingContext> DefaultMappingContext;
解释:Enhanced Input 的输入映射上下文引用。当前未在 C++ 中使用。
81
82 /** 输入映射上下文优先级 */
83 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Input")
84 int32 MappingContextPriority = 0;
解释:输入映射上下文优先级。当前未在 C++ 中使用。
85
86 // ========== 相机 ==========
解释:注释分隔线,标记下面是相机相关属性。
87
88 /** 变身时相机过渡时间 */
89 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Transform|Camera")
90 float CameraBlendTime = 0.3f;
解释:相机混合过渡时间,默认 0.3 秒。当前未在 C++ 中使用。
91
92 protected:
93 /** 变身输入处理 */
94 void OnTransformInput();
解释:声明变身输入处理函数,按 T 键时调用。
95
96 /** 鼠标右键加速输入处理 */
97 void OnBoostInput();
解释:声明鼠标右键加速输入处理函数。
98
99 /** 服务端执行变身(RPC) */
100 UFUNCTION(Server, Reliable)
101 void Server_ExecuteTransform(int32 NewFormIndex);
解释:声明一个可靠的服务端 RPC 函数,用于多玩家环境下的变身同步。当前实现为空。
102
103 /** 执行变身逻辑(C++ 实现) */
104 void ExecuteTransform(int32 NewFormIndex);
解释:声明执行变身逻辑的函数。当前实现为空。
105
106 /** 多播播放变身特效 */
107 UFUNCTION(NetMulticast, Reliable)
108 void Multicast_PlayTransformEffect();
解释:声明一个可靠的多播 RPC 函数,用于多玩家环境下同步播放变身特效。当前调用 PlayTransformEffect()。
109
110 /** 播放特效 */
111 void PlayTransformEffect();
112
113 /** 变身冷却计时器 */
114 FTimerHandle TransformCooldownTimer;
解释:声明变身冷却计时器句柄,用于防止连续触发变身。
115
116 /** 是否正在变身中 */
117 bool bIsTransforming = false;
解释:标记是否正在执行变身流程,防止在冷却期间重复触发。
118
119 /** 变身冷却时间 */
120 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Transform")
121 float TransformCooldown = 0.5f;
解释:变身冷却时间,默认 0.5 秒。
122
123 /** 变身形态显示网格(Sphere 等,已废弃改用 FormNiagaraComponent) */
124 UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Transform|Components")
125 TObjectPtr<class UStaticMeshComponent> FormMeshComponent;
解释:声明静态网格组件,用于早期变身形态的球体显示。当前已废弃,但保留兼容。
126
127 /** 加速 Niagara 特效(按鼠标右键进入加速时播放一次) */
128 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Transform|VFX")
129 TObjectPtr<UNiagaraSystem> BoostEffect;
解释:声明加速特效 Niagara 系统引用,按鼠标右键进入加速时播放一次。
130
131 /** 变身闪光过渡特效(按 T 瞬间播放,0.4s 后才正式变身) */
132 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Transform|VFX")
133 TObjectPtr<UNiagaraSystem> TransformFlashEffect;
解释:声明变身闪光过渡特效,按 T 瞬间播放,延迟后才正式变身。
134
135 /** 变身闪光过渡延迟(秒),闪光播放多久后才正式变身 */
136 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Transform|VFX")
137 float TransformFlashDelay = 0.4f;
解释:闪光过渡延迟时间,默认 0.4 秒。
138
139 /** 溶解效果 MPC 资源(Material Parameter Collection,驱动角色材质从四周→中间溶解) */
140 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Transform|VFX")
141 TObjectPtr<UMaterialParameterCollection> DissolveMPC;
解释:声明材质参数集合引用,用于驱动角色溶解效果。
142
143 /** MPC 中的溶解进度参数名 */
144 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Transform|VFX")
145 FName DissolveParamName = "DissolveProgress";
解释:声明 MPC 中控制溶解进度的参数名,默认 "DissolveProgress"。
146
147 /** 变身特效蓝图 Actor 类(包含所有 Niagara 组件) */
148 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Transform|VFX")
149 TSubclassOf<AActor> TransformVFXBlueprint;
解释:声明变身特效蓝图 Actor 类,变身后会生成该 Actor。
150
151 /** 已生成的变身特效 Actor 实例 */
152 UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Transform|VFX")
153 AActor* SpawnedTransformVFX = nullptr;
解释:声明已生成的变身特效 Actor 实例指针,用于后续销毁。
154
155 /** 是否处于变身形态 */
156 UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Transform")
157 bool bIsInTransformedForm = false;
解释:标记当前是否处于变身形态。
158
159 /** 是否处于加速状态 */
160 UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Transform")
161 bool bIsBoosting = false;
解释:标记当前是否处于加速状态。
162
163 /** 普通飞行速度 */
164 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Transform|Flight")
165 float NormalFlySpeed = 1200.0f;
解释:普通飞行状态下的自动前进速度,默认 1200 cm/s。
166
167 /** 普通操控速度 */
168 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Transform|Flight")
169 float NormalSteerSpeed = 800.0f;
170 ```
**解释**:普通飞行状态下的 WASD 操控速度,默认 800 cm/s。
```cpp
171
172 /** 加速飞行速度 */
173 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Transform|Flight")
174 float BoostFlySpeed = 3000.0f;
解释:加速状态下的自动前进速度,默认 3000 cm/s(运行时被 BeginPlay() 覆盖为 5000)。
175
176 /** 加速操控速度 */
177 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Transform|Flight")
178 float BoostSteerSpeed = 2000.0f;
解释:加速状态下的 WASD 操控速度,默认 2000 cm/s(运行时被 BeginPlay() 覆盖为 4000)。
179
180 private:
181 /** 闪光过渡计时器 */
182 FTimerHandle TransformFlashTimer;
解释:声明闪光过渡计时器句柄,用于延迟执行正式变身/退出。
183
184 /** 正式执行进入变身逻辑(闪光结束后调用) */
185 void ExecuteEnterTransform();
解释:声明闪光结束后执行的进入变身函数。
186
187 /** 正式执行退出变身逻辑(瞬间) */
188 void ExecuteExitTransform();
解释:声明闪光结束后执行的退出变身函数。
189
190 /** 溶解动画是否激活 */
191 bool bDissolveActive = false;
解释:标记溶解动画是否正在进行。
192
193 /** 溶解消失的起始值(0=可见,1=溶解消失) */
194 float DissolveStart = 0.0f;
解释:溶解起始值,0 表示完全可见,1 表示完全溶解消失。
195
196 /** 溶解消失的目标值 */
197 float DissolveTarget = 0.0f;
解释:溶解目标值。
198
199 /** 溶解已用时间 */
200 float DissolveElapsed = 0.0f;
解释:溶解动画已经过的时间。
201
202 /** 开始溶解(进入变身,0→1) */
203 void StartDissolveOut();
204
205 /** 开始反溶解(退出变身,1→0) */
206 void StartDissolveIn();
207 };
解释:声明开始溶解和反溶解的辅助函数。最后的 }; 结束类定义。
二、TransformCharacter.cpp
1 // TransformCharacter.cpp - 角色形态变换系统实现
解释:文件头注释,说明本文件是 TransformCharacter.h 的实现文件。
2
3 #include "TransformCharacter.h"
解释:包含对应的头文件。
4 #include "Components/StaticMeshComponent.h"
解释:包含静态网格组件头文件,用于创建 FormMeshComponent。
5 #include "GameFramework/CharacterMovementComponent.h"
解释:包含角色移动组件头文件,用于控制移动模式和速度。
6 #include "NiagaraFunctionLibrary.h"
解释:包含 Niagara 函数库头文件,用于生成 Niagara 特效。
7 #include "NiagaraComponent.h"
解释:包含 Niagara 组件头文件,用于获取和操作 Niagara 组件。
8 #include "NiagaraSystem.h"
解释:包含 Niagara 系统头文件,用于声明 Niagara 系统引用。
9 #include "Engine/World.h"
解释:包含世界头文件,用于生成 Actor、射线检测等。
10 #include "TimerManager.h"
解释:包含计时器管理器头文件,用于设置延迟调用。
11 #include "Components/CapsuleComponent.h"
解释:包含胶囊体组件头文件,用于获取角色胶囊体做地面检测。
12 #include "Camera/CameraComponent.h"
13 #include "GameFramework/PlayerController.h"
解释:包含相机组件和玩家控制器头文件(相机组件 include 保留,实际 FOV 通过 PlayerCameraManager 设置)。
14 #include "Kismet/GameplayStatics.h"
解释:包含 Gameplay 静态工具头文件,当前未使用,保留。
15 #include "Engine/Blueprint.h"
解释:包含蓝图头文件,用于加载 UBlueprint 资产。
16 #include "GameFramework/ProjectileMovementComponent.h"
解释:包含投射物移动组件头文件,用于禁用变身特效 Actor 上的投射物移动。
17 #include "Materials/MaterialParameterCollectionInstance.h"
解释:包含材质参数集合实例头文件,用于写入 MPC 参数值。
18
19 ATransformCharacter::ATransformCharacter()
解释:定义默认构造函数。
20 {
21 PrimaryActorTick.bCanEverTick = true;
解释:启用每帧 Tick 调用。
22
23 // 创建变身形态显示网格组件(保留兼容,实际使用蓝图 Actor 中的 Niagara 组件)
24 FormMeshComponent = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("FormMesh"));
解释:在构造函数中创建静态网格子对象,命名为 FormMesh。
25 FormMeshComponent->SetupAttachment(RootComponent);
解释:将网格组件附加到根组件(胶囊体)上。
26 FormMeshComponent->SetVisibility(false);
解释:默认隐藏该网格组件。
27 FormMeshComponent->SetCollisionEnabled(ECollisionEnabled::NoCollision);
解释:关闭该网格组件的碰撞。
28
29 // 加载引擎内置 Sphere 网格(已废弃,保留兼容)
30 static ConstructorHelpers::FObjectFinder<UStaticMesh> SphereMesh(TEXT("/Engine/BasicShapes/Sphere"));
解释:使用 ConstructorHelpers::FObjectFinder 在构造函数中加载引擎内置球体网格。
31 if (SphereMesh.Succeeded())
解释:如果加载成功。
32 {
33 FormMeshComponent->SetStaticMesh(SphereMesh.Object);
解释:将球体网格设置到组件上。
34 FormMeshComponent->SetRelativeLocation(FVector(0, 0, -40));
解释:设置网格相对位置,向下偏移 40 单位。
35 FormMeshComponent->SetRelativeScale3D(FVector(1.2f));
解释:设置网格相对缩放为 1.2 倍。
36 }
37
38 // 加载默认变身特效蓝图:BP_Projectile_Ice(Niagara 结合而成的变身特效 Actor)
39 static ConstructorHelpers::FObjectFinder<UBlueprint> DefaultVFXBlueprint(TEXT("/Game/Test_02/VFX/VFXBP/BP_Projectile_Ice"));
解释:加载变身特效蓝图 Actor 类。
40 if (DefaultVFXBlueprint.Succeeded() && DefaultVFXBlueprint.Object->GeneratedClass)
解释:如果加载成功且已生成类存在。
41 {
42 TransformVFXBlueprint = DefaultVFXBlueprint.Object->GeneratedClass;
43 }
解释:将生成的 UClass 赋值给 TransformVFXBlueprint。
44
45 // 加载默认变身闪光过渡特效:NS_SpriteSpawn(闪光后 0.4s 才正式变身)
46 static ConstructorHelpers::FObjectFinder<UNiagaraSystem> DefaultFlashEffect(TEXT("/Game/Test_02/VFX/FlashVFX/NS_SpriteSpawn"));
解释:加载变身闪光过渡特效 Niagara 系统。
47 if (DefaultFlashEffect.Succeeded())
48 {
49 TransformFlashEffect = DefaultFlashEffect.Object;
50 }
解释:加载成功则赋值给 TransformFlashEffect。
51
52 // 加载默认加速特效:NS_JiaSu(变身后按右键加速时播放一次)
53 static ConstructorHelpers::FObjectFinder<UNiagaraSystem> DefaultBoostEffect(TEXT("/Game/Test_02/VFX/FeiDunLight/NS/NS_JiaSu"));
解释:加载加速特效 Niagara 系统。
54 if (DefaultBoostEffect.Succeeded())
55 {
56 BoostEffect = DefaultBoostEffect.Object;
57 }
解释:加载成功则赋值给 BoostEffect。
58
59 // 配置移动组件
60 UCharacterMovementComponent* Movement = GetCharacterMovement();
解释:获取角色的移动组件。
61 if (Movement)
62 {
63 Movement->bOrientRotationToMovement = true;
解释:设置角色朝向移动方向。
64 Movement->RotationRate = FRotator(0.0f, 540.0f, 0.0f);
解释:设置旋转速率为每秒 540 度(只在 Yaw 轴)。
65 }
66
67 bUseControllerRotationPitch = false;
68 bUseControllerRotationYaw = false;
69 bUseControllerRotationRoll = false;
解释:关闭角色使用控制器旋转,避免与自定义飞行控制冲突。
70 }
71
72 void ATransformCharacter::BeginPlay()
73 {
74 Super::BeginPlay();
解释:调用父类的 BeginPlay()。
75
76 // 兜底:若蓝图 CDO 把 TransformVFXBlueprint 序列化为空,则用 BP_Projectile_Ice 覆盖
77 if (!TransformVFXBlueprint)
78 {
79 UBlueprint* IceBP = LoadObject<UBlueprint>(nullptr, TEXT("/Game/Test_02/VFX/VFXBP/BP_Projectile_Ice"));
解释:如果蓝图 CDO 导致 TransformVFXBlueprint 为空,则运行时重新加载。
80 if (IceBP && IceBP->GeneratedClass)
81 {
82 TransformVFXBlueprint = IceBP->GeneratedClass;
83 }
84 }
85
86 // 兜底:强制设置飞行速度(防止蓝图 CDO 序列化覆盖为 0)
87 NormalFlySpeed = 1200.0f;
88 NormalSteerSpeed = 800.0f;
89 BoostFlySpeed = 5000.0f;
90 BoostSteerSpeed = 4000.0f;
91 }
解释:在 BeginPlay() 中强制设置速度值,覆盖可能因蓝图 CDO 序列化导致的 0 值。
92
93 void ATransformCharacter::PossessedBy(AController* NewController)
94 {
95 Super::PossessedBy(NewController);
96 }
解释:重写 PossessedBy,当前为空实现。
97
98 void ATransformCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
99 {
100 Super::SetupPlayerInputComponent(PlayerInputComponent);
解释:调用父类的输入绑定。
101
102 if (PlayerInputComponent)
103 {
104 PlayerInputComponent->BindKey(EKeys::T, IE_Pressed, this, &ATransformCharacter::OnTransformInput);
解释:绑定 T 键按下事件到 OnTransformInput。
105 PlayerInputComponent->BindKey(EKeys::RightMouseButton, IE_Pressed, this, &ATransformCharacter::OnBoostInput);
解释:绑定鼠标右键按下事件到 OnBoostInput。
106 GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Green, TEXT("[Transform] T / RMB bound"));
107 }
108 }
解释:在屏幕上打印输入绑定成功的调试信息。
109
110 void ATransformCharacter::Tick(float DeltaTime)
111 {
112 Super::Tick(DeltaTime);
解释:调用父类 Tick,然后执行自定义逻辑。
113
114 // ========== 溶解动画(进入变身/退出变身的过渡效果)==========
115 if (bDissolveActive)
116 {
117 DissolveElapsed += DeltaTime;
解释:如果溶解动画激活,累加经过的时间。
118 float Progress = FMath::Clamp(DissolveElapsed / TransformFlashDelay, 0.0f, 1.0f);
解释:计算溶解进度,限制在 0~1 之间。
119 float DissolveValue = FMath::Lerp(DissolveStart, DissolveTarget, Progress);
解释:在起始值和目标值之间插值,得到当前溶解值。
120
121 // 写入 MPC,驱动材质溶解
122 if (DissolveMPC)
123 {
124 UMaterialParameterCollectionInstance* MPCInstance = GetWorld()->GetParameterCollectionInstance(DissolveMPC);
解释:如果配置了 MPC,获取其世界实例。
125 if (MPCInstance)
126 {
127 MPCInstance->SetScalarParameterValue(DissolveParamName, DissolveValue);
128 }
129 }
解释:将溶解值写入 MPC 的标量参数。
130
131 if (Progress >= 1.0f)
132 {
133 bDissolveActive = false;
134 }
135 }
解释:溶解完成,关闭标记。
136
137 // ========== 变身飞行系统 ==========
138 if (!bIsInTransformedForm)
139 {
140 return;
141 }
解释:如果不在变身形态,跳过飞行逻辑。
142
143 // 获取移动组件
144 UCharacterMovementComponent* MoveComp = GetCharacterMovement();
145 if (!MoveComp)
146 {
147 return;
148 }
149
150 // 清除蓝图 WASD 移动输入(否则按 S 会同时触发"后退",与飞行方向控制冲突)
151 MoveComp->ConsumeInputVector();
解释:获取移动组件,并清空已有的输入向量,避免与蓝图输入冲突。
152
153 // 获取玩家视角方向
154 APlayerController* PC = Cast<APlayerController>(GetController());
155 if (!PC)
156 {
157 return;
158 }
解释:获取玩家控制器并转换为 APlayerController,用于读取视角方向和按键状态。
159 const FRotator ControlRot = PC->GetControlRotation();
160 const FVector ViewForward = FRotationMatrix(ControlRot).GetUnitAxis(EAxis::X);
161 const FVector ViewRight = FRotationMatrix(ControlRot).GetUnitAxis(EAxis::Y);
解释:获取控制器旋转,并计算视角的前向量和右向量。
162
163 const float AutoFlySpeed = bIsBoosting ? BoostFlySpeed : NormalFlySpeed;
164 const float SteerSpeed = bIsBoosting ? BoostSteerSpeed : NormalSteerSpeed;
解释:根据是否加速,选择对应的速度值。
165
166 // 调试:显示当前速度和加速状态
167 FString DebugMsg = FString::Printf(TEXT("[Transform] Speed=%.0f | Boost=%s"),
168 AutoFlySpeed, bIsBoosting ? TEXT("ON") : TEXT("OFF"));
169 GEngine->AddOnScreenDebugMessage(-1, 0.05f, FColor::Cyan, DebugMsg);
170 }
解释:在屏幕上打印当前速度和加速状态。
171
172 // ========== 直接计算目标速度并设置 Velocity(绕过 MaxAcceleration 限制)==========
173 FVector DesiredVelocity = ViewForward * AutoFlySpeed;
解释:根据视角前向量和自动飞行速度计算基础目标速度。
174
175 // W → 向上飞(世界 Z+)
176 if (PC->IsInputKeyDown(EKeys::W))
177 {
178 DesiredVelocity += FVector::UpVector * SteerSpeed;
179 }
180
181 // S → 向下飞(世界 Z-,地面限制)
182 if (PC->IsInputKeyDown(EKeys::S))
183 {
184 UCapsuleComponent* Capsule = GetCapsuleComponent();
解释:如果按下 W,给目标速度加上向上的分量;如果按下 S,准备做地面检测。
185 if (Capsule)
186 {
187 const float HalfHeight = Capsule->GetScaledCapsuleHalfHeight();
188 const FVector FeetPos = GetActorLocation() - FVector(0, 0, HalfHeight);
189 const FVector TraceEnd = FeetPos - FVector(0, 0, HalfHeight * 2.0f);
解释:获取胶囊体半高,计算脚底位置和射线终点。
190
191 FHitResult Hit;
192 FCollisionQueryParams Params;
193 Params.AddIgnoredActor(this);
194
195 bool bNearGround = GetWorld()->LineTraceSingleByChannel(Hit, FeetPos, TraceEnd, ECC_Visibility, Params);
解释:从脚底向下做射线检测,判断角色是否接近地面。
196 if (!bNearGround)
197 {
198 DesiredVelocity += FVector::DownVector * SteerSpeed;
199 }
200 }
201 }
202
203 // A → 向左飞(视角左方)
204 if (PC->IsInputKeyDown(EKeys::A))
205 {
206 DesiredVelocity += -ViewRight * SteerSpeed;
207 }
208
209 // D → 向右飞(视角右方)
210 if (PC->IsInputKeyDown(EKeys::D))
211 {
212 DesiredVelocity += ViewRight * SteerSpeed;
213 }
解释:根据 A/D 按键给目标速度加上左右分量。
214
215 // 平滑过渡到目标速度(避免瞬间突变,加速/减速都有手感)
216 const float SpeedLerpRate = 8.0f;
217 FVector NewVelocity = FMath::VInterpTo(MoveComp->Velocity, DesiredVelocity, DeltaTime, SpeedLerpRate);
218 MoveComp->Velocity = NewVelocity;
解释:使用 VInterpTo 在 8.0 的速率下平滑过渡当前速度到目标速度,然后赋值给移动组件。
219
220 // 提高上限,防止 CharacterMovement 把速度压回去
221 MoveComp->MaxFlySpeed = FMath::Max(MoveComp->MaxFlySpeed, AutoFlySpeed * 1.2f);
222 MoveComp->MaxAcceleration = FMath::Max(MoveComp->MaxAcceleration, 10000.0f);
223 }
解释:确保 MaxFlySpeed 和 MaxAcceleration 足够大,防止 CharacterMovement 限制速度。
224
225 // ========== 将角色世界速度传给 Niagara User 参数 ==========
226 if (SpawnedTransformVFX)
227 {
228 TArray<UNiagaraComponent*> NiagaraComps;
229 SpawnedTransformVFX->GetComponents<UNiagaraComponent>(NiagaraComps);
解释:如果变身特效 Actor 存在,获取其下所有 Niagara 组件。
230
231 const FVector FlyVel = GetVelocity();
232
233 for (UNiagaraComponent* NiagaraComp : NiagaraComps)
234 {
235 // 传飞行速度给 Niagara(拖尾惯性甩尾 + Projectile 朝向)
236 NiagaraComp->SetVariableVec3(FName("User.FlyVelocity"), FlyVel);
237 }
238 }
239 }
解释:遍历 Niagara 组件,将角色世界速度传递给名为 User.FlyVelocity 的用户参数。
240
241 // ========== 形态切换 ==========
242
243 void ATransformCharacter::OnTransformInput()
244 {
245 GEngine->AddOnScreenDebugMessage(-1, 2.f, FColor::Cyan, TEXT("[Transform] FIRED!"));
解释:定义变身输入处理函数,先在屏幕上打印触发信息。
246
247 if (bIsTransforming)
248 {
249 return;
250 }
解释:如果正在变身流程中(冷却中),直接返回。
251
252 bIsTransforming = true;
253
254 if (bIsInTransformedForm)
255 {
256 // 退出变身:立刻标记为非变身状态,停止 Tick 中的飞行逻辑
257 bIsInTransformedForm = false;
解释:如果当前处于变身形态,执行退出变身逻辑。先立即标记为非变身,停止飞行 Tick。
258
259 // 立刻停止飞行移动,避免延迟期间继续往前飞
260 UCharacterMovementComponent* PreMoveComp = GetCharacterMovement();
261 if (PreMoveComp)
262 {
263 PreMoveComp->Velocity = FVector::ZeroVector;
264 PreMoveComp->ConsumeInputVector();
265 PreMoveComp->StopMovementImmediately();
266 PreMoveComp->SetMovementMode(MOVE_Walking);
267 }
解释:立即停止移动:清零速度、清空输入、停止移动、切换为行走模式。
268
269 // 退出变身:先播闪光 + 销毁特效 + 显示角色网格 + 溶解出现
270 if (SpawnedTransformVFX)
271 {
272 SpawnedTransformVFX->Destroy();
273 SpawnedTransformVFX = nullptr;
274 }
解释:销毁变身特效 Actor。
275
276 // 显示网格(溶解会从 1→0 让角色逐渐出现)
277 USkeletalMeshComponent* BodyMesh = GetMesh();
278 if (BodyMesh)
279 {
280 BodyMesh->SetVisibility(true);
281 }
解释:显示角色身体网格。
282
283 StartDissolveIn();
解释:开始从 1→0 的反溶解动画。
284
285 // 播放闪光
286 if (TransformFlashEffect)
287 {
288 UNiagaraFunctionLibrary::SpawnSystemAtLocation(
289 GetWorld(),
290 TransformFlashEffect,
291 GetActorLocation(),
292 GetActorRotation(),
293 FVector(1.0f),
294 true,
295 true
296 );
297 }
解释:如果配置了闪光特效,在角色位置生成一次性闪光特效。
298
299 // 延迟 0.4s 后正式退出变身
300 GetWorldTimerManager().SetTimer(
301 TransformFlashTimer,
302 this,
303 &ATransformCharacter::ExecuteExitTransform,
304 TransformFlashDelay,
305 false
306 );
307 }
解释:设置 0.4 秒延迟计时器,时间到后调用 ExecuteExitTransform()。
308 else
309 {
310 // 进入变身:先播闪光透特 + 溶解消失,延迟后才正式变身
311 GEngine->AddOnScreenDebugMessage(-1, 3.f, FColor::Orange, TEXT("[Transform] Playing flash VFX..."));
解释:如果当前不是变身形态,执行进入变身逻辑。
312
313 StartDissolveOut();
解释:开始从 0→1 的溶解动画。
314
315 // 播放一次性闪光特效(不附着、不跟随移动)
316 if (TransformFlashEffect)
317 {
318 UNiagaraFunctionLibrary::SpawnSystemAtLocation(
319 GetWorld(),
320 TransformFlashEffect,
321 GetActorLocation(),
322 GetActorRotation(),
323 FVector(1.0f),
324 true, // bAutoDestroy
325 true // bAutoActivate
326 );
327 }
解释:在角色位置生成闪光特效,true, true 表示自动销毁和自动激活。
328
329 // 延迟 0.4s 后正式变身
330 GetWorldTimerManager().SetTimer(
331 TransformFlashTimer,
332 this,
333 &ATransformCharacter::ExecuteEnterTransform,
334 TransformFlashDelay,
335 false
336 );
337 }
338 }
解释:设置 0.4 秒延迟计时器,时间到后调用 ExecuteEnterTransform()。
339
340 void ATransformCharacter::OnBoostInput()
341 {
342 GEngine->AddOnScreenDebugMessage(-1, 3.f, FColor::Yellow,
343 FString::Printf(TEXT("[Transform] RMB pressed | bIsInTransformedForm=%s"),
344 bIsInTransformedForm ? TEXT("true") : TEXT("false")));
解释:定义鼠标右键加速输入处理函数,打印当前是否处于变身形态。
345
346 // 只有变身状态下才能切换加速
347 if (!bIsInTransformedForm)
348 {
349 return;
350 }
解释:如果不在变身形态,不处理右键加速。
351
352 bIsBoosting = !bIsBoosting;
解释:切换加速状态。
353
354 // 同步修改 CharacterMovementComponent 的最大飞行速度上限
355 if (UCharacterMovementComponent* MoveComp = GetCharacterMovement())
356 {
357 MoveComp->MaxFlySpeed = bIsBoosting ? BoostFlySpeed : NormalFlySpeed;
358 }
解释:根据加速状态同步修改 MaxFlySpeed。
359
360 // 只在进入加速时播放一次特效,退出加速不播放
361 if (bIsBoosting)
362 {
363 if (BoostEffect)
364 {
365 FVector SpawnLoc = GetActorLocation() + FVector(0, 0, 50);
解释:如果进入加速状态且配置了加速特效,计算生成位置(角色位置上方 50 单位)。
366 UNiagaraFunctionLibrary::SpawnSystemAtLocation(
367 GetWorld(),
368 BoostEffect,
369 SpawnLoc,
370 GetActorRotation(),
371 FVector(2.0f),
372 true, // bAutoDestroy
373 true // bAutoActivate
374 );
375 GEngine->AddOnScreenDebugMessage(-1, 3.f, FColor::Green, TEXT("[Transform] Boost VFX spawned"));
376 }
377 else
378 {
379 GEngine->AddOnScreenDebugMessage(-1, 3.f, FColor::Red, TEXT("[Transform] BoostEffect is NULL!"));
380 }
381 }
解释:生成加速特效并打印调试信息;如果特效为空则打印错误。
382
383 GEngine->AddOnScreenDebugMessage(-1, 2.f, FColor::Yellow,
384 bIsBoosting ? TEXT("[Transform] Boost ON") : TEXT("[Transform] Boost OFF"));
385 }
解释:打印当前加速状态。
386
387 void ATransformCharacter::ExecuteEnterTransform()
388 {
389 bIsInTransformedForm = true;
解释:定义闪光结束后的正式进入变身函数,标记为变身形态。
390
391 // 隐藏角色网格
392 USkeletalMeshComponent* BodyMesh = GetMesh();
393 if (BodyMesh)
394 {
395 BodyMesh->SetVisibility(false);
396 }
解释:隐藏角色身体网格。
397
398 // 生成变身特效蓝图 Actor
399 if (TransformVFXBlueprint && !SpawnedTransformVFX)
400 {
401 FActorSpawnParameters SpawnParams;
402 SpawnParams.Owner = this;
解释:如果配置了变身特效蓝图且尚未生成,准备生成参数并设置 Owner 为当前角色。
403 SpawnedTransformVFX = GetWorld()->SpawnActor<AActor>(TransformVFXBlueprint, FVector::ZeroVector, FRotator::ZeroRotator, SpawnParams);
404 if (SpawnedTransformVFX)
405 {
406 SpawnedTransformVFX->AttachToActor(this, FAttachmentTransformRules::KeepRelativeTransform);
解释:在世界原点生成特效 Actor,并附加到角色上,保持相对变换。
407 SpawnedTransformVFX->SetActorRelativeLocation(FVector(0.0f, 0.0f, 0.0f));
408
409 // 禁用投射物移动组件
410 UProjectileMovementComponent* ProjMove = SpawnedTransformVFX->FindComponentByClass<UProjectileMovementComponent>();
411 if (ProjMove)
412 {
413 ProjMove->Deactivate();
414 }
解释:设置相对位置为原点,并禁用特效 Actor 上的投射物移动组件。
415
416 // 强制激活所有 Niagara 组件
417 TArray<UNiagaraComponent*> NiagaraComps;
418 SpawnedTransformVFX->GetComponents<UNiagaraComponent>(NiagaraComps);
419 for (UNiagaraComponent* NiagaraComp : NiagaraComps)
420 {
421 NiagaraComp->Activate(true);
422 }
423 }
424 }
解释:获取特效 Actor 下所有 Niagara 组件并强制激活。
425
426 // 切换飞行模式
427 UCharacterMovementComponent* MoveComp = GetCharacterMovement();
428 if (MoveComp)
429 {
430 MoveComp->SetMovementMode(MOVE_Flying);
431 MoveComp->MaxFlySpeed = NormalFlySpeed;
432 }
解释:切换移动模式为飞行,并初始化最大飞行速度为普通速度。
433
434 // FOV 放大
435 APlayerController* PC_FOV = Cast<APlayerController>(GetController());
436 if (PC_FOV && PC_FOV->PlayerCameraManager)
437 {
438 PC_FOV->PlayerCameraManager->SetFOV(120.0f);
439 }
解释:通过玩家相机管理器将 FOV 设置为 120。
440
441 // 广播事件
442 OnFormChanged.Broadcast(FormIndex, 1);
解释:广播形态变化事件,参数为旧形态索引和新形态索引。
443
444 // 冷却
445 GetWorldTimerManager().SetTimer(
446 TransformCooldownTimer,
447 [this]() { bIsTransforming = false; },
448 TransformCooldown,
449 false
450 );
451 }
解释:设置冷却计时器,时间到后重置 bIsTransforming。
452
453 void ATransformCharacter::ExecuteExitTransform()
454 {
455 bIsInTransformedForm = false;
解释:定义闪光结束后的正式退出变身函数,标记为非变身形态。
456
457 // 切换行走模式并立即停止移动
458 UCharacterMovementComponent* MoveComp = GetCharacterMovement();
459 if (MoveComp)
460 {
461 MoveComp->SetMovementMode(MOVE_Walking);
462 MoveComp->Velocity = FVector::ZeroVector;
463 MoveComp->ConsumeInputVector();
464 MoveComp->StopMovementImmediately();
465 }
解释:切换为行走模式并立即停止移动。
466
467 // 退出变身时重置加速状态
468 bIsBoosting = false;
解释:退出变身时重置加速状态。
469
470 // FOV 恢复
471 APlayerController* PC_FOV = Cast<APlayerController>(GetController());
472 if (PC_FOV && PC_FOV->PlayerCameraManager)
473 {
474 PC_FOV->PlayerCameraManager->SetFOV(80.0f);
475 }
解释:恢复 FOV 为 80。
476
477 // 广播事件
478 OnFormChanged.Broadcast(FormIndex, 0);
解释:广播形态变化事件。
479
480 // 冷却
481 GetWorldTimerManager().SetTimer(
482 TransformCooldownTimer,
483 [this]() { bIsTransforming = false; },
484 TransformCooldown,
485 false
486 );
487 }
解释:设置冷却计时器。
488
489 void ATransformCharacter::StartDissolveOut()
490 {
491 DissolveStart = 0.0f;
492 DissolveTarget = 1.0f;
493 DissolveElapsed = 0.0f;
494 bDissolveActive = true;
495 }
解释:开始溶解消失:从 0 过渡到 1,并重置经过时间,激活溶解标记。
496
497 void ATransformCharacter::StartDissolveIn()
498 {
499 DissolveStart = 1.0f;
500 DissolveTarget = 0.0f;
501 DissolveElapsed = 0.0f;
502 bDissolveActive = true;
503 }
解释:开始反溶解出现:从 1 过渡到 0。
504
505 void ATransformCharacter::Server_ExecuteTransform_Implementation(int32 NewFormIndex)
506 {
507 }
解释:服务端 RPC 实现,当前为空。
508
509 void ATransformCharacter::TransformToNextForm()
510 {
511 OnTransformInput();
512 }
513
514 void ATransformCharacter::TransformToForm(int32 Index)
515 {
516 OnTransformInput();
517 }
解释:形态切换函数实现,当前都直接调用 OnTransformInput()。
518
519 TSubclassOf<ACharacter> ATransformCharacter::GetCurrentFormClass() const
520 {
521 if (Forms.IsValidIndex(FormIndex))
522 {
523 return Forms[FormIndex];
524 }
525 return nullptr;
526 }
解释:返回当前形态类,如果索引无效则返回空。
527
528 void ATransformCharacter::ExecuteTransform(int32 NewFormIndex)
529 {
530 }
解释:变身逻辑执行函数,当前为空。
531
532 void ATransformCharacter::Multicast_PlayTransformEffect_Implementation()
533 {
534 PlayTransformEffect();
535 }
536
537 void ATransformCharacter::PlayTransformEffect()
538 {
539 // 不再动态生成,使用常驻组件 TransformNiagaraComponent
540 // 激活/停用逻辑已在 OnTransformInput() 中处理
541 }
解释:多播 RPC 实现调用 PlayTransformEffect(),后者已废弃,特效生成逻辑已移到 OnTransformInput() 中。
三、废弃代码清单与迁移注意事项
A 类:安全可删除(无任何引用,删除零风险)
| 代码位置 | 废弃说明 |
|---|---|
TransformEffect / TransformEffectDuration(.h 特效区) |
变身爆发特效属性,C++ 从未读写,纯死属性 |
CameraBlendTime(.h 相机区) |
相机过渡时间,从未使用 |
PossessedBy() 空实现(.cpp) |
无逻辑的空重写,删掉不影响 |
#include "Camera/CameraComponent.h"(.cpp) |
FOV 实际通过 PlayerCameraManager 设置,未用到该头文件 |
#include "Kismet/GameplayStatics.h"(.cpp) |
未使用的 include |
Server_ExecuteTransform 空实现(.cpp) |
多玩家 RPC,单人项目未启用 |
ExecuteTransform(int32) 空实现(.cpp) |
未使用的空函数 |
Multicast_PlayTransformEffect / PlayTransformEffect(.cpp) |
已废弃,特效逻辑已迁至 OnTransformInput() |
B 类:谨慎删除(需连带处理蓝图引用)
| 代码位置 | 废弃说明 | 删除前检查 |
|---|---|---|
FormMeshComponent(Sphere 网格,.h + 构造函数) |
已废弃,实际用 Niagara。但蓝图 BP_ThirdPersonCharacter 组件列表里有 FormMesh 实例 |
删除 C++ 成员后必须重新编译蓝图,否则蓝图残留该组件引用 |
Forms / FormIndex / TransformToNextForm() / TransformToForm() / GetCurrentFormClass() |
多形态系统,当前只用单形态 | 检查蓝图是否调用过这些 BlueprintCallable 函数 |
OnFormChanged 事件委托 |
ExecuteEnter/ExitTransform 中 Broadcast |
检查蓝图是否绑定了该事件,绑定则需同步处理 |
IA_Transform / DefaultMappingContext / MappingContextPriority |
Enhanced Input 属性,实际用传统 BindKey |
检查蓝图属性面板是否设置了引用,删前需清空 |
C 类:不可删除(当前功能正在依赖)
bIsTransforming/TransformCooldownTimer/TransformCooldown:防连点冷却bIsInTransformedForm/bIsBoosting:形态与加速状态标记- 四个飞行速度属性 +
BeginPlay()中的强制赋值(防蓝图 CDO 覆盖) TransformFlashEffect/TransformFlashDelay:闪光过渡DissolveMPC/DissolveParamName及溶解相关私有成员:溶解效果TransformVFXBlueprint/SpawnedTransformVFX:变身特效 ActorOnBoostInput()与右键绑定:加速功能
迁移到正式项目(CultivatingImmortality_RPG)注意事项
-
模块 API 宏:
TEST_API需替换为正式项目的模块名宏(如CULTIVATINGIMMORTALITY_RPG_API),类名建议一并改为正式项目风格。 -
资产路径硬编码:构造函数中的
FObjectFinder路径(/Game/Test_02/...)是测试项目路径,迁移时要么改成正式项目路径,要么保留 UPROPERTY 由蓝图配置(推荐后者,更灵活)。 -
模块依赖:
.Build.cs中需包含 Niagara 相关模块(Niagara、NiagaraCore、NiagaraShader等),迁移时在正式项目.Build.cs补上。 -
变身特效 Actor:
BP_Projectile_Ice及其内部引用的 Niagara 资产(NS_StarSkill002、NS_Dash、NS_JiaSu、NS_SpriteSpawn 等)需要一并复制到正式项目,并保持相对路径一致。 -
输入绑定冲突:测试项目用传统
BindKey。正式项目若用 Enhanced Input 且已占用T键 / 鼠标右键,需要调整键位或改用 Enhanced Input 方式绑定。 -
角色材质:溶解效果需要在正式项目的角色材质中自行添加
CollectionParameter→OneMinus→OpacityMask节点链,并创建对应的 MPC 资产。 -
蓝图 CDO 覆盖陷阱:正式项目中若在蓝图属性面板修改过飞行速度等参数,会覆盖 C++ 默认值(本项目就踩过坑:速度被序列化为 0)。保持
BeginPlay()兜底赋值即可规避。 -
FOV 与速度是测试值:120/80 FOV、1200/800/5000/4000 速度均为测试项目调参结果,正式项目按手感重新调整。
-
编译方式:修改
.h(新增/删除 UPROPERTY、UFUNCTION)必须关闭编辑器完整重编译;只改.cpp函数体可用 Live Coding。