1. TransformCharacter (Light Flight)
Inherits ACharacter, not a component class; 3161-line .cpp; right-click Light Flight + SpaceBar flight + MPC dissolve transition.
TransformCharacter is the base class for character form transformation, not a Component attached to the character. Core structure:
// TransformCharacter.h(脱敏后)
UCLASS()
class TEST_API CharacterTransformBase : public ACharacter
{
GENERATED_BODY()
public:
// 形态系统
TArray> Forms; // 可用形态列表
int32 FormIndex = 0; // 当前形态索引
FOnFormChanged OnFormChanged; // 形态变化委托(蓝图绑定)
// 遁光/飞行
UFUNCTION(BlueprintCallable) TransformToNextForm();
UFUNCTION(BlueprintCallable) TransformToForm(int32 Index);
UFUNCTION(BlueprintPure) GetCurrentFormClass();
// 🆕 2026-09-29 新增:AI 专用遁光接口(CharacterTransformBase.h:419-432)
UFUNCTION(BlueprintCallable) ExecuteEnterTransformForAI();
UFUNCTION(BlueprintCallable) ExecuteExitTransformForAI();
};
Light Flight timing (right-click trigger / AI ForAI interface replica):
StartDissolveOut → Tick 每帧 Dissolve = 1-progress(0.2s 跑完) → 遁光状态切换:bIsInTransformedForm = true → MOVE_Flying,MaxWalkSpeed=4500,角色隐藏 → 退出反向:StartDissolveIn → Dissolve 拉回 1 → MOVE_Walking,MaxWalkSpeed=默认,角色恢复
Key point: the Light Flight state is switched by the bIsInTransformedForm bool atomic flag, and the C++ guard prevents repeated Enter/Exit within the transition window (SKIPPED in logs is hard proof).
2. ChangliCharacter (combat base class, inherits TransformCharacter)
7887-line .cpp; basic-attack five-hitter, three-shot homing volley, lightning chain, charged basic attack, E-key shield.
Combat C++ is not "one big function" but several independent skill-entry functions; each function owns only the execution timing and state management of that skill. Effects (VFX / montage / damage delivery) are triggered by Blueprint graphs calling the C++ interface:
| Function | Duty |
SpawnCombo3BulletVolley() | Entry point for the three-shot homing volley (C++ anchor for the basic-attack three-hitter) |
CollectEnemyPawns(From, Out) | Range enemy search (source of TargetActor for AI Light Flight pursuit) |
TriggerCombo4Lightning() | Lightning chain trigger (calls the Blueprint ChainLightning event) |
StartCombo5BulletRing() / SpawnOneCombo5Bullet() | Per-segment generation of the basic-attack five-hitter ring bullet pattern |
DevDash / DevAttack / DevAura / DevSwordQi | Developer quick-debug entry (press F in PIE to temporarily trigger a skill) |
OnMontageEnded | Montage-end callback → ResetAttackState → attack state machine reset (no state is lost no matter how complex the Blueprint gets) |
E-key shield: CharacterBase.cpp:7268 Tick polls the physical E key — when pressed, a temporary CollisionSphere is spawned Block on WorldDynamic.
3. TimeOfDayManager (day-night cycle)
1048-line .cpp; a singleton that uniformly drives DirectionalLight / SkyAtmosphere / PostProcess / character material MPC.
The day-night system is not a Timeline laid out in a Blueprint — TimeOfDayManager is an Actor: place one in the level, and all three subsystems hang on it:
// TimeOfDayManager.cpp 关键函数 float GetDaylightFactor(Hours) // 0.0(夜)→1.0(正午) 线性插值 void ApplySunMoonIntensity(Actor, Hours) // 驱动 DirectionalLight + SkyAtmosphere void SetTimeOfDay(TargetHour) // 手动跳时(调试/UI 面板) void ResumeDayCycle() // 恢复 1h/现实 2min 的真实时间流速 float GetCurrentTimeOfDay() // 对外暴露当前小时数
Three shared drives: 1. DirectionalLight angle (Transform Rotation.X maps the hour value) 2. SkyAtmosphere (sun intensity / atmospheric density) 3. PostProcess AutoExposureBias (night dimming + character material EffectBrightness scaling + skill VFX MPC EmissiveScale day-night curve). The same Hours value drives all three, so there is no "it is night but the character is as bright as daytime."
4. ASwordQOrbitManager (Six Swords orbit)
582-line .cpp; Tick updates the circular / helical orbits of the six swords every frame.
// SwordQOrbitManager.cpp 关键流程
Tick(DeltaTime)
├─ HandleQPressed() // Q 键按下 → StartWindup()
│ └─ 蓄力 0.8s 后 SpawnSwords() (生成 6 把飞剑 Actor)
└─ 每帧更新圆周位置
└─ SetActorLocation(Swords[i], Center + Offset[i])
Offset 由 sin/cos(θ+i*60°) 计算,θ 每帧 += 转速
5. Measured issues and fixes (all measured, confirmed outcomes, not speculation)
Light Flight silent-exit triple fix (V171, 2026-09-20). The path "press SpaceBar during Light Flight → exit Light Flight and chain into SpaceBar flight" was originally a silent exit (skipping the flash and dissolve), but it skipped too much:
- Missing exit sprite: the silent exit never calls
SpawnTransformSpriteVFX()(removed under the "don't turn into stars" rule). Fix: call it once, and it must be placed before ExecuteExitTransform — that function ends (cpp:1521) by setting bIsInTransformedForm false; placing it later would mis-fire the Enter VFX (SKIPPED in logs is hard proof). - Invisible character while flying: StartDissolveOut finishes with Dissolve=0 (character fully dissolved); the silent path skips StartDissolveIn → Dissolve stays at 0 forever. Fix: the silent exit writes the terminal value directly as Dissolve=1 / Opacity=1, no interpolation = no dissolve presentation.
- Entering/exiting Light Flight later fires the flight-stop VFX: The synthetic SpaceBar
IE_Pressedinjected by V163 has only the press edge, no paired release; and the injection timing is later than the player's key-up → the input side always reads SpaceBar as "pressed," so the release edge never arrives. Fix: 1. setbSpaceFlightLatched=true(the next frame takes the "seamless SpaceBar flight" branch); 2. wrap both flight-stop events with a pairedIE_Releasedadded after SetSprintEvent(false) to close the accounting.
CharacterMovement default MOVE_Flying (AI hovering invisible). TransformBase.cpp:1378-1380, CharacterBase.cpp:1068-1076 default to the hovering form MOVE_Flying. An AI spawns as Flying and never lands; after Launch there is no gravity brake → hovering at 44 m "invisible". Fix: the AI child Blueprint forces SetMovementMode(Walking) in BeginPlay (verified in PIE 105 s: C++ does not push it back).