claude-code-arcane 2.3.0 → 2.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (103) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/README.md +54 -6
  3. package/agents/game/ue-blueprint-specialist.md +125 -0
  4. package/agents/game/ue-gas-specialist.md +133 -0
  5. package/agents/game/ue-umg-specialist.md +131 -0
  6. package/dist/cli.js +5 -0
  7. package/docs/SKILLS-CATALOG.md +42 -3
  8. package/docs/USER-GUIDE.md +2 -2
  9. package/hooks/detect-unreal.sh +90 -0
  10. package/package.json +1 -1
  11. package/profiles/unreal-dev.yaml +97 -0
  12. package/rules/gamedev/unreal-code.md +125 -0
  13. package/skills/install-mcp/SKILL.md +135 -46
  14. package/skills/install-mcp/references/unreal-operations.md +55 -0
  15. package/skills/ue-actor-component-architecture/SKILL.md +509 -0
  16. package/skills/ue-actor-component-architecture/references/actor-lifecycle.md +301 -0
  17. package/skills/ue-actor-component-architecture/references/component-types.md +592 -0
  18. package/skills/ue-ai-navigation/SKILL.md +526 -0
  19. package/skills/ue-ai-navigation/references/behavior-tree-patterns.md +392 -0
  20. package/skills/ue-ai-navigation/references/behavior-tree-workflow.md +107 -0
  21. package/skills/ue-ai-navigation/references/custom-bttask.md +104 -0
  22. package/skills/ue-ai-navigation/references/eqs-reference.md +423 -0
  23. package/skills/ue-animation-system/SKILL.md +521 -0
  24. package/skills/ue-animation-system/references/anim-notify-reference.md +486 -0
  25. package/skills/ue-animation-system/references/locomotion-setup.md +550 -0
  26. package/skills/ue-async-threading/SKILL.md +433 -0
  27. package/skills/ue-async-threading/references/thread-safety-guide.md +213 -0
  28. package/skills/ue-async-threading/references/threading-patterns.md +345 -0
  29. package/skills/ue-audio-system/SKILL.md +527 -0
  30. package/skills/ue-audio-system/references/audio-setup-patterns.md +700 -0
  31. package/skills/ue-blueprints/SKILL.md +134 -0
  32. package/skills/ue-blueprints/references/communication.md +82 -0
  33. package/skills/ue-character-movement/SKILL.md +475 -0
  34. package/skills/ue-character-movement/references/cmc-extension-patterns.md +335 -0
  35. package/skills/ue-character-movement/references/movement-pipeline.md +189 -0
  36. package/skills/ue-cpp-foundations/SKILL.md +533 -0
  37. package/skills/ue-cpp-foundations/references/components-and-gc.md +107 -0
  38. package/skills/ue-cpp-foundations/references/container-patterns.md +544 -0
  39. package/skills/ue-cpp-foundations/references/delegate-patterns.md +497 -0
  40. package/skills/ue-cpp-foundations/references/gameplay-classes-cpp.md +136 -0
  41. package/skills/ue-cpp-foundations/references/property-specifiers.md +306 -0
  42. package/skills/ue-data-assets-tables/SKILL.md +527 -0
  43. package/skills/ue-data-assets-tables/references/asset-loading-patterns.md +306 -0
  44. package/skills/ue-data-assets-tables/references/data-driven-design.md +378 -0
  45. package/skills/ue-editor-tools/SKILL.md +523 -0
  46. package/skills/ue-editor-tools/references/detail-customization-patterns.md +395 -0
  47. package/skills/ue-editor-tools/references/editor-module-setup.md +480 -0
  48. package/skills/ue-game-features/SKILL.md +477 -0
  49. package/skills/ue-game-features/references/experience-system.md +222 -0
  50. package/skills/ue-game-features/references/game-feature-patterns.md +308 -0
  51. package/skills/ue-gameplay-abilities/SKILL.md +518 -0
  52. package/skills/ue-gameplay-abilities/references/ability-task-reference.md +391 -0
  53. package/skills/ue-gameplay-abilities/references/gameplay-effect-reference.md +397 -0
  54. package/skills/ue-gameplay-abilities/references/gas-setup-patterns.md +369 -0
  55. package/skills/ue-gameplay-framework/SKILL.md +466 -0
  56. package/skills/ue-gameplay-framework/references/framework-class-map.md +243 -0
  57. package/skills/ue-input-system/SKILL.md +394 -0
  58. package/skills/ue-input-system/references/cpp-setup.md +131 -0
  59. package/skills/ue-input-system/references/enhanced-input-workflow.md +117 -0
  60. package/skills/ue-input-system/references/input-action-reference.md +731 -0
  61. package/skills/ue-mass-entity/SKILL.md +476 -0
  62. package/skills/ue-mass-entity/references/mass-entity-patterns.md +319 -0
  63. package/skills/ue-mass-entity/references/mass-fragment-reference.md +119 -0
  64. package/skills/ue-materials-rendering/SKILL.md +526 -0
  65. package/skills/ue-materials-rendering/references/material-parameter-reference.md +216 -0
  66. package/skills/ue-materials-rendering/references/post-process-settings.md +383 -0
  67. package/skills/ue-module-build-system/SKILL.md +487 -0
  68. package/skills/ue-module-build-system/references/build-cs-reference.md +418 -0
  69. package/skills/ue-module-build-system/references/common-build-errors.md +381 -0
  70. package/skills/ue-naming-conventions/SKILL.md +142 -0
  71. package/skills/ue-naming-conventions/references/asset-name-modifiers.md +233 -0
  72. package/skills/ue-naming-conventions/references/content-structure.md +83 -0
  73. package/skills/ue-networking-replication/SKILL.md +452 -0
  74. package/skills/ue-networking-replication/references/replication-patterns.md +526 -0
  75. package/skills/ue-networking-replication/references/rpc-decision-guide.md +393 -0
  76. package/skills/ue-niagara-effects/SKILL.md +531 -0
  77. package/skills/ue-niagara-effects/references/niagara-data-interfaces.md +491 -0
  78. package/skills/ue-niagara-effects/references/niagara-parameter-types.md +153 -0
  79. package/skills/ue-niagara-effects/references/niagara-workflow.md +115 -0
  80. package/skills/ue-packaging/SKILL.md +116 -0
  81. package/skills/ue-physics-collision/SKILL.md +423 -0
  82. package/skills/ue-physics-collision/references/collision-channel-setup.md +218 -0
  83. package/skills/ue-physics-collision/references/trace-patterns.md +499 -0
  84. package/skills/ue-procedural-generation/SKILL.md +505 -0
  85. package/skills/ue-procedural-generation/references/pcg-node-reference.md +381 -0
  86. package/skills/ue-procedural-generation/references/procedural-mesh-patterns.md +940 -0
  87. package/skills/ue-project-context/SKILL.md +305 -0
  88. package/skills/ue-sequencer-cinematics/SKILL.md +506 -0
  89. package/skills/ue-sequencer-cinematics/references/sequencer-patterns.md +629 -0
  90. package/skills/ue-serialization-savegames/SKILL.md +524 -0
  91. package/skills/ue-serialization-savegames/references/save-system-architecture.md +705 -0
  92. package/skills/ue-state-trees/SKILL.md +489 -0
  93. package/skills/ue-state-trees/references/state-tree-mass-integration.md +184 -0
  94. package/skills/ue-state-trees/references/state-tree-patterns.md +321 -0
  95. package/skills/ue-testing-debugging/SKILL.md +520 -0
  96. package/skills/ue-testing-debugging/references/automation-test-patterns.md +387 -0
  97. package/skills/ue-testing-debugging/references/profiling-commands.md +357 -0
  98. package/skills/ue-ui-umg-slate/SKILL.md +431 -0
  99. package/skills/ue-ui-umg-slate/references/common-ui-setup.md +484 -0
  100. package/skills/ue-ui-umg-slate/references/widget-types.md +487 -0
  101. package/skills/ue-world-level-streaming/SKILL.md +518 -0
  102. package/skills/ue-world-level-streaming/references/streaming-patterns.md +414 -0
  103. package/templates/gamedev/unreal-project-context.md +107 -0
@@ -0,0 +1,550 @@
1
+ # Locomotion Setup Reference
2
+
3
+ This guide covers the end-to-end setup for character locomotion using UE5's
4
+ animation system: AnimInstance properties, blend spaces, state machines, and
5
+ layered blending.
6
+
7
+ Source headers referenced:
8
+ - `Engine/Source/Runtime/Engine/Classes/Animation/AnimInstance.h`
9
+ - `Engine/Source/Runtime/Engine/Classes/Animation/BlendSpace.h`
10
+ - `Engine/Source/Runtime/Engine/Classes/Animation/BlendSpace1D.h`
11
+ - `Engine/Source/Runtime/Engine/Classes/Animation/AimOffsetBlendSpace.h`
12
+
13
+ ---
14
+
15
+ ## AnimInstance: Locomotion Properties
16
+
17
+ ```cpp
18
+ // LocomotionAnimInstance.h
19
+ #pragma once
20
+ #include "Animation/AnimInstance.h"
21
+ #include "LocomotionAnimInstance.generated.h"
22
+
23
+ UCLASS()
24
+ class MYGAME_API ULocomotionAnimInstance : public UAnimInstance
25
+ {
26
+ GENERATED_BODY()
27
+
28
+ public:
29
+ virtual void NativeInitializeAnimation() override;
30
+ virtual void NativeUpdateAnimation(float DeltaSeconds) override;
31
+
32
+ protected:
33
+ // Cached references (game thread only)
34
+ UPROPERTY(Transient)
35
+ TObjectPtr<ACharacter> OwningCharacter;
36
+
37
+ UPROPERTY(Transient)
38
+ TObjectPtr<UCharacterMovementComponent> MovementComp;
39
+
40
+ // --- Properties read by the AnimGraph ---
41
+
42
+ // Ground speed (XY plane), drives blend space Y axis
43
+ UPROPERTY(Transient, BlueprintReadOnly, Category="Locomotion")
44
+ float GroundSpeed = 0.f;
45
+
46
+ // Movement direction relative to actor facing (-180 to 180), drives X axis
47
+ UPROPERTY(Transient, BlueprintReadOnly, Category="Locomotion")
48
+ float Direction = 0.f;
49
+
50
+ // True when CharacterMovement reports IsFalling()
51
+ UPROPERTY(Transient, BlueprintReadOnly, Category="Locomotion")
52
+ bool bIsInAir = false;
53
+
54
+ // True when velocity is near zero
55
+ UPROPERTY(Transient, BlueprintReadOnly, Category="Locomotion")
56
+ bool bIsIdle = true;
57
+
58
+ // True when crouching
59
+ UPROPERTY(Transient, BlueprintReadOnly, Category="Locomotion")
60
+ bool bIsCrouching = false;
61
+
62
+ // Acceleration magnitude, for start/stop transitions
63
+ UPROPERTY(Transient, BlueprintReadOnly, Category="Locomotion")
64
+ float Acceleration = 0.f;
65
+
66
+ // For aim offset
67
+ UPROPERTY(Transient, BlueprintReadOnly, Category="AimOffset")
68
+ float AimYaw = 0.f;
69
+
70
+ UPROPERTY(Transient, BlueprintReadOnly, Category="AimOffset")
71
+ float AimPitch = 0.f;
72
+
73
+ // Lean amount for banking in turns
74
+ UPROPERTY(Transient, BlueprintReadOnly, Category="Locomotion")
75
+ float LeanAmount = 0.f;
76
+
77
+ private:
78
+ // Previous yaw for lean calculation
79
+ float PreviousActorYaw = 0.f;
80
+ float LeanVelocity = 0.f;
81
+ };
82
+ ```
83
+
84
+ ```cpp
85
+ // LocomotionAnimInstance.cpp
86
+ #include "LocomotionAnimInstance.h"
87
+ #include "GameFramework/Character.h"
88
+ #include "GameFramework/CharacterMovementComponent.h"
89
+ #include "Kismet/KismetMathLibrary.h"
90
+
91
+ static constexpr float IdleSpeedThreshold = 10.f;
92
+ static constexpr float LeanInterpSpeed = 4.f;
93
+ static constexpr float LeanMaxAngle = 30.f;
94
+
95
+ void ULocomotionAnimInstance::NativeInitializeAnimation()
96
+ {
97
+ Super::NativeInitializeAnimation();
98
+
99
+ OwningCharacter = Cast<ACharacter>(TryGetPawnOwner());
100
+ if (OwningCharacter)
101
+ {
102
+ MovementComp = OwningCharacter->GetCharacterMovement();
103
+ PreviousActorYaw = OwningCharacter->GetActorRotation().Yaw;
104
+ }
105
+ }
106
+
107
+ void ULocomotionAnimInstance::NativeUpdateAnimation(float DeltaSeconds)
108
+ {
109
+ Super::NativeUpdateAnimation(DeltaSeconds);
110
+
111
+ if (!OwningCharacter || !MovementComp || DeltaSeconds <= 0.f) return;
112
+
113
+ const FVector Velocity = MovementComp->Velocity;
114
+ GroundSpeed = Velocity.Size2D();
115
+ bIsInAir = MovementComp->IsFalling();
116
+ bIsCrouching = MovementComp->IsCrouching();
117
+ bIsIdle = GroundSpeed < IdleSpeedThreshold && !bIsInAir;
118
+ Acceleration = MovementComp->GetCurrentAcceleration().Size2D();
119
+
120
+ // Direction: angle between velocity and actor facing
121
+ if (GroundSpeed > IdleSpeedThreshold)
122
+ {
123
+ const FRotator ActorRot = OwningCharacter->GetActorRotation();
124
+ const FRotator VelocityRot = Velocity.ToOrientationRotator();
125
+ Direction = UKismetMathLibrary::NormalizedDeltaRotator(
126
+ VelocityRot, ActorRot).Yaw;
127
+ }
128
+
129
+ // Aim offset (yaw/pitch delta from actor to control rotation)
130
+ const FRotator AimRot = OwningCharacter->GetBaseAimRotation();
131
+ const FRotator ActorRot = OwningCharacter->GetActorRotation();
132
+ const FRotator AimDelta = UKismetMathLibrary::NormalizedDeltaRotator(
133
+ AimRot, ActorRot);
134
+ AimYaw = FMath::Clamp(AimDelta.Yaw, -90.f, 90.f);
135
+ AimPitch = FMath::Clamp(AimDelta.Pitch, -90.f, 90.f);
136
+
137
+ // Lean: angular velocity of actor yaw, smoothed with interp
138
+ const float CurrentYaw = OwningCharacter->GetActorRotation().Yaw;
139
+ const float YawDeltaRate = UKismetMathLibrary::NormalizedDeltaRotator(
140
+ FRotator(0.f, CurrentYaw, 0.f),
141
+ FRotator(0.f, PreviousActorYaw, 0.f)).Yaw / DeltaSeconds;
142
+ PreviousActorYaw = CurrentYaw;
143
+
144
+ const float TargetLean = FMath::Clamp(YawDeltaRate / LeanMaxAngle, -1.f, 1.f);
145
+ LeanAmount = FMath::FInterpTo(LeanAmount, TargetLean,
146
+ DeltaSeconds, LeanInterpSpeed);
147
+ }
148
+ ```
149
+
150
+ ---
151
+
152
+ ## Blend Space Setup
153
+
154
+ ### 1D Blend Space — Walk/Run
155
+
156
+ **Asset**: `BS_GroundLocomotion1D` (type: `BlendSpace1D`)
157
+
158
+ | Axis | Name | Min | Max | Grid Points |
159
+ |-------|---------|-----|-----|-------------|
160
+ | X | Speed | 0 | 600 | 3 |
161
+
162
+ Samples:
163
+ | Speed | Animation |
164
+ |-------|-----------------|
165
+ | 0 | Idle |
166
+ | 200 | Walk_Fwd |
167
+ | 600 | Run_Fwd |
168
+
169
+ Interpolation (from `FInterpolationParameter`):
170
+ ```
171
+ InterpolationTime = 0.15
172
+ InterpolationType = SpringDamper
173
+ DampingRatio = 1.0
174
+ MaxSpeed = 0.0 (unclamped)
175
+ ```
176
+
177
+ In the AnimGraph, a **Blend Space 1D Player** node:
178
+ - Asset: `BS_GroundLocomotion1D`
179
+ - X pin: bound to `GroundSpeed` from the AnimInstance
180
+
181
+ ---
182
+
183
+ ### 2D Blend Space — Directional Locomotion
184
+
185
+ **Asset**: `BS_GroundLocomotion2D` (type: `BlendSpace`)
186
+
187
+ | Axis | Name | Min | Max | Grid Points |
188
+ |------|-----------|------|-----|-------------|
189
+ | X | Direction | -180 | 180 | 5 |
190
+ | Y | Speed | 0 | 600 | 3 |
191
+
192
+ Sample layout (Direction x Speed):
193
+
194
+ ```
195
+ Direction\Speed | 0 (Idle) | 200 (Walk) | 600 (Run)
196
+ ----------------+-----------+------------+-----------
197
+ 0 (Fwd) | Idle | Walk_Fwd | Run_Fwd
198
+ 90 (Right) | Idle | Walk_Right | Run_Right
199
+ -90 (Left) | Idle | Walk_Left | Run_Left
200
+ 180 (Bwd) | Idle | Walk_Bwd | Run_Bwd
201
+ ```
202
+
203
+ Idle is the same animation at all direction values and Speed=0; it is defined
204
+ at four direction points so the blend falls back to it cleanly.
205
+
206
+ Interpolation per axis:
207
+ ```
208
+ X (Direction): InterpolationTime=0.10, InterpolationType=SpringDamper
209
+ Y (Speed): InterpolationTime=0.15, InterpolationType=SpringDamper
210
+ ```
211
+
212
+ In the AnimGraph, a **Blend Space Player** node:
213
+ - Asset: `BS_GroundLocomotion2D`
214
+ - X pin: `Direction`
215
+ - Y pin: `GroundSpeed`
216
+
217
+ ---
218
+
219
+ ### Aim Offset — Upper Body Aiming
220
+
221
+ **Asset**: `AO_Rifle` (type: `AimOffset`)
222
+
223
+ | Axis | Name | Min | Max |
224
+ |-------|-------|-----|-----|
225
+ | X | Yaw | -90 | 90 |
226
+ | Y | Pitch | -90 | 90 |
227
+
228
+ Samples (5 poses, all additive relative to reference pose):
229
+
230
+ | Yaw | Pitch | Animation |
231
+ |-----|-------|-----------------------|
232
+ | 0 | 0 | AO_Rifle_Center |
233
+ | 90 | 0 | AO_Rifle_Right |
234
+ | -90 | 0 | AO_Rifle_Left |
235
+ | 0 | 90 | AO_Rifle_Up |
236
+ | 0 | -90 | AO_Rifle_Down |
237
+
238
+ In the AnimGraph:
239
+ - Place **Aim Offset** node after the base locomotion result
240
+ - X pin: `AimYaw`, Y pin: `AimPitch`
241
+ - This node applies an additive pose on top of the base pose
242
+
243
+ ---
244
+
245
+ ## State Machine Setup — Locomotion State Machine
246
+
247
+ **State Machine Name**: `LocomotionSM`
248
+
249
+ ### States
250
+
251
+ ```
252
+ [Entry] --> [Idle] --> [Walk/Run] --> [Idle]
253
+ \--> [Jump Start] --> [In Air] --> [Land] --> [Idle]
254
+ \--> [Crouch Idle] --> [Crouch Walk] --> [Crouch Idle]
255
+ ```
256
+
257
+ ### State Definitions
258
+
259
+ **Idle**
260
+ - Animation: Idle loop sequence or the 1D/2D blend space at Speed=0
261
+ - Transition to Walk/Run: `GroundSpeed > 10 && !bIsInAir`
262
+ - Transition to Jump Start: `bIsInAir`
263
+ - Transition to Crouch Idle: `bIsCrouching`
264
+
265
+ **Walk/Run**
266
+ - Animation: `BS_GroundLocomotion1D` or `BS_GroundLocomotion2D`
267
+ - Transition to Idle: `GroundSpeed <= 10 && !bIsInAir`
268
+ - Transition to Jump Start: `bIsInAir`
269
+
270
+ **Jump Start**
271
+ - Animation: `JumpStart` (plays once)
272
+ - Automatic transition to In Air when animation finishes:
273
+ `TimeRemaining(ratio) < 0.1`
274
+
275
+ **In Air**
276
+ - Animation: `InAir` loop (often a blend between apex and falling poses)
277
+ - Transition to Land: `!bIsInAir`
278
+
279
+ **Land**
280
+ - Animation: `Land` (plays once)
281
+ - Automatic transition to Idle or Walk/Run when complete
282
+
283
+ **Crouch Idle**
284
+ - Animation: `CrouchIdle` loop
285
+ - Transition to Crouch Walk: `GroundSpeed > 3`
286
+ - Transition to Idle (stand): `!bIsCrouching`
287
+
288
+ **Crouch Walk**
289
+ - Animation: `BS_CrouchLocomotion1D` (separate blend space for crouch walk)
290
+ - Transition to Crouch Idle: `GroundSpeed <= 3`
291
+ - Transition to Idle: `!bIsCrouching`
292
+
293
+ ### Transition Cross-Fade Settings
294
+
295
+ | From | To | Duration | Blend Curve |
296
+ |-------------|-------------|----------|--------------|
297
+ | Idle | Walk/Run | 0.15s | Cubic In-Out |
298
+ | Walk/Run | Idle | 0.20s | Cubic In-Out |
299
+ | Walk/Run | Jump Start | 0.10s | Linear |
300
+ | In Air | Land | 0.05s | Linear |
301
+ | Land | Idle | 0.20s | Cubic In-Out |
302
+ | Idle | Crouch Idle | 0.15s | Linear |
303
+ | Crouch Idle | Idle | 0.15s | Linear |
304
+
305
+ Use **Automatic Rule Based on Sequence Player** for states with a single
306
+ play-once animation (Jump Start, Land) to auto-transition when the animation
307
+ nears completion.
308
+
309
+ ---
310
+
311
+ ## AnimGraph Structure
312
+
313
+ ```
314
+ [Output Pose]
315
+ |
316
+ [Layered Blend Per Bone] <-- upper body slot for montages
317
+ | |
318
+ [LocomotionSM] [Slot 'UpperBody']
319
+ |
320
+ [Aim Offset] <-- aim yaw/pitch additive
321
+ |
322
+ [Locomotion Blend Space Player]
323
+ ```
324
+
325
+ ### Full AnimGraph Node Order (Bottom to Top)
326
+
327
+ 1. **Blend Space Player** (`BS_GroundLocomotion2D`) — base movement pose
328
+ 2. **Aim Offset** (`AO_Rifle`) — additive aim layer on top of base
329
+ 3. **State Machine** (`LocomotionSM`) — wraps steps 1 & 2 inside states
330
+ 4. **Slot 'UpperBody'** — montage poses blend into upper body here
331
+ 5. **Layered Blend Per Bone** — blends upper body slot over the state machine
332
+ - Blend Poses 0: State Machine output (lower body + full)
333
+ - Blend Poses 1: UpperBody slot
334
+ - Layer Setup: `spine_01`, Depth=0, BlendDepth=1, MeshPoseBlendFactor=1
335
+ 6. **Output Pose**
336
+
337
+ ---
338
+
339
+ ## Layered Blend Per Bone — Upper/Lower Split
340
+
341
+ To play attack montages on the upper body while keeping lower body locomotion:
342
+
343
+ In the AnimGraph:
344
+ 1. Add a **Slot** node named `UpperBody` (create the slot in Skeleton settings).
345
+ 2. Add a **Layered Blend Per Bone** node.
346
+ 3. Connect the State Machine output to **Base Pose**.
347
+ 4. Connect the `UpperBody` slot output to **Blend Poses 0**.
348
+ 5. In the **Layer Setup** array, add entry:
349
+ - Bone Name: `spine_01`
350
+ - Blend Depth: `-1` (blend from the specified bone downward to root is
351
+ unaffected; upward is fully blended)
352
+ - Mesh Pose Blend Factor: 1.0
353
+ - Inverse: unchecked (positive bones = upper body = get slot blend)
354
+
355
+ The montage must target the `UpperBody` slot. In C++:
356
+
357
+ ```cpp
358
+ // Play on UpperBody slot only
359
+ AnimInst->Montage_Play(AttackMontage);
360
+ // AttackMontage must have its anim tracks assigned to the 'UpperBody' slot
361
+ // in the montage editor (SlotAnimTracks[0].SlotName = "UpperBody")
362
+ ```
363
+
364
+ ---
365
+
366
+ ## Native State Machine Bindings
367
+
368
+ Bind C++ logic to state transitions without Blueprint:
369
+
370
+ ```cpp
371
+ // In ULocomotionAnimInstance::NativeInitializeAnimation()
372
+
373
+ // Transition rule
374
+ AddNativeTransitionBinding(
375
+ FName("LocomotionSM"),
376
+ FName("Idle"),
377
+ FName("Walk/Run"),
378
+ FCanTakeTransition::CreateUObject(
379
+ this, &ULocomotionAnimInstance::CanStartMoving),
380
+ FName("IdleToMoving")
381
+ );
382
+
383
+ // State entry notification
384
+ AddNativeStateEntryBinding(
385
+ FName("LocomotionSM"),
386
+ FName("Land"),
387
+ FOnGraphStateChanged::CreateUObject(
388
+ this, &ULocomotionAnimInstance::OnLandStateEntered)
389
+ );
390
+ ```
391
+
392
+ ```cpp
393
+ bool ULocomotionAnimInstance::CanStartMoving() const
394
+ {
395
+ return GroundSpeed > IdleSpeedThreshold && !bIsInAir;
396
+ }
397
+
398
+ void ULocomotionAnimInstance::OnLandStateEntered(
399
+ const FAnimNode_StateMachine& SM,
400
+ int32 PrevState,
401
+ int32 NextState)
402
+ {
403
+ // Play landing camera shake, rumble, etc.
404
+ if (OwningCharacter)
405
+ {
406
+ // UGameplayStatics::PlayWorldCameraShake(...);
407
+ }
408
+ }
409
+ ```
410
+
411
+ ---
412
+
413
+ ## Modular Locomotion via Linked Anim Layers
414
+
415
+ For projects with multiple locomotion modes (ground, swimming, climbing,
416
+ zero-gravity), use the linked anim layer pattern instead of a monolithic state
417
+ machine.
418
+
419
+ ### Interface Definition
420
+
421
+ Create `ULocomotionLayerInterface` (AnimLayerInterface Blueprint asset)
422
+ with a single layer function: `LocomotionLayer`.
423
+
424
+ ### Main AnimInstance
425
+
426
+ The main `ABP_Character` has a **Linked Anim Layer** node targeting
427
+ `ULocomotionLayerInterface::LocomotionLayer`. Its output feeds directly into
428
+ the **Output Pose** (after any additive overlays).
429
+
430
+ ### Layer Implementations
431
+
432
+ ```cpp
433
+ // GroundLocomotionLayer.h — implements LocomotionLayerInterface
434
+ UCLASS()
435
+ class MYGAME_API UGroundLocomotionLayer : public UAnimInstance
436
+ {
437
+ GENERATED_BODY()
438
+ // ...same locomotion properties as above...
439
+ };
440
+
441
+ // ClimbingLocomotionLayer.h
442
+ UCLASS()
443
+ class MYGAME_API UClimbingLocomotionLayer : public UAnimInstance
444
+ {
445
+ GENERATED_BODY()
446
+ // Separate state machine / sequences for climbing
447
+ };
448
+ ```
449
+
450
+ ### Swapping at Runtime
451
+
452
+ ```cpp
453
+ void AMyCharacter::EnterClimbing()
454
+ {
455
+ if (UAnimInstance* AnimInst = GetMesh()->GetAnimInstance())
456
+ {
457
+ AnimInst->LinkAnimClassLayers(UClimbingLocomotionLayer::StaticClass());
458
+ }
459
+ }
460
+
461
+ void AMyCharacter::ExitClimbing()
462
+ {
463
+ if (UAnimInstance* AnimInst = GetMesh()->GetAnimInstance())
464
+ {
465
+ AnimInst->LinkAnimClassLayers(UGroundLocomotionLayer::StaticClass());
466
+ // Or pass nullptr to reset all layers to defaults:
467
+ // AnimInst->LinkAnimClassLayers(nullptr);
468
+ }
469
+ }
470
+ ```
471
+
472
+ The transition is automatically inertially blended when an **Inertialization**
473
+ node is placed in the main AnimGraph.
474
+
475
+ ---
476
+
477
+ ## Inertial Blending for Smooth Layer Transitions
478
+
479
+ Add an **Inertialization** node in the main AnimGraph between the linked layer
480
+ output and the Output Pose. When `LinkAnimClassLayers` is called, the system
481
+ will inertialize the transition using the blend duration configured on the
482
+ `FAnimNode_LinkedAnimGraph` node (`PendingBlendInDuration` /
483
+ `PendingBlendOutDuration`).
484
+
485
+ To request inertialization from C++:
486
+
487
+ ```cpp
488
+ // Request a 0.2s inertialized blend for all slots in the "DefaultGroup"
489
+ AnimInst->RequestSlotGroupInertialization(FName("DefaultGroup"), 0.2f);
490
+ ```
491
+
492
+ ---
493
+
494
+ ## Root Motion Configuration
495
+
496
+ | Mode | Description |
497
+ |-----------------------------|----------------------------------------------------------|
498
+ | `NoRootMotionExtraction` | Root bone moves normally; no extraction to component |
499
+ | `IgnoreRootMotion` | Root motion is extracted and discarded (root stays put) |
500
+ | `RootMotionFromMontagesOnly`| Only montage root motion drives component movement |
501
+ | `RootMotionFromEverything` | All animations contribute root motion to component |
502
+
503
+ For typical third-person games with CharacterMovementComponent:
504
+ ```cpp
505
+ // In Character BP defaults or constructor:
506
+ GetMesh()->GetAnimInstance()->RootMotionMode =
507
+ ERootMotionMode::RootMotionFromMontagesOnly;
508
+ ```
509
+
510
+ In the `AnimInstance` class default:
511
+ ```cpp
512
+ // Set in class constructor or CDO:
513
+ RootMotionMode = ERootMotionMode::RootMotionFromMontagesOnly;
514
+ ```
515
+
516
+ For multiplayer, pair `RootMotionFromMontagesOnly` with GAS montage replication
517
+ so the server's `CharacterMovementComponent` processes root motion authoritatively.
518
+
519
+ ---
520
+
521
+ ## Common Locomotion Pitfalls
522
+
523
+ **Direction flips when speed is near zero**
524
+ - Only update `Direction` when `GroundSpeed > threshold`. Keep the last valid
525
+ direction when the character is decelerating to idle, preventing the blend
526
+ space from snapping.
527
+
528
+ **Blend space snapping on direction change**
529
+ - Use `SpringDamper` interpolation on the Direction axis with
530
+ `InterpolationTime = 0.08–0.12`. Too low = snappy, too high = sluggish turns.
531
+
532
+ **Aim offset fighting the state machine**
533
+ - Ensure the Aim Offset node is placed inside the locomotion state (not outside
534
+ the state machine), or apply it as an additive overlay after the state machine
535
+ output, so it blends correctly during transitions.
536
+
537
+ **Crouch/stand transition pops**
538
+ - Ensure crouch and stand blend spaces share samples at Speed=0. The blend space
539
+ sampler interpolates between them; if the idle samples differ significantly,
540
+ use a short cross-fade on the Idle->Crouch Idle transition (0.15s+).
541
+
542
+ **Upper body slot not blending**
543
+ - Verify the montage's slot track is named exactly `UpperBody` (case-sensitive)
544
+ and the Layered Blend Per Bone node references the same slot name. Mismatches
545
+ result in the montage playing on the wrong slot or not blending at all.
546
+
547
+ **State machine transition not firing from C++**
548
+ - `AddNativeTransitionBinding` must be called in `NativeInitializeAnimation`,
549
+ not in `BeginPlay` or later. The binding is registered against the compiled
550
+ state machine before the AnimGraph evaluates.