claude-code-arcane 2.2.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.
- package/CHANGELOG.md +37 -0
- package/README.md +104 -55
- package/agents/career/career-strategist.md +88 -0
- package/agents/career/cv-reviewer.md +81 -0
- package/agents/career/hiring-manager.md +68 -0
- package/agents/career/mock-interviewer.md +76 -0
- package/agents/freelance/client-screener.md +84 -0
- package/agents/freelance/discovery-call.md +65 -0
- package/agents/freelance/pipeline-strategist.md +99 -0
- package/agents/freelance/proposal-reviewer.md +82 -0
- package/agents/game/ue-blueprint-specialist.md +125 -0
- package/agents/game/ue-gas-specialist.md +133 -0
- package/agents/game/ue-umg-specialist.md +131 -0
- package/dist/cli.js +57 -13
- package/docs/RELEASE-SETUP.md +1 -1
- package/docs/SKILLS-CATALOG.md +67 -4
- package/docs/USER-GUIDE.md +77 -72
- package/docs/agent-hierarchy.md +21 -1
- package/docs/presentations/build_arcane_deck.py +2 -2
- package/docs/presentations/build_arcane_deck_12.py +2 -2
- package/hooks/detect-unreal.sh +90 -0
- package/package.json +2 -2
- package/profiles/freelance.yaml +43 -0
- package/profiles/job-hunt.yaml +5 -2
- package/profiles/unreal-dev.yaml +97 -0
- package/rules/drafter-reviewer.md +16 -3
- package/rules/freelance-guardrails.md +53 -0
- package/rules/gamedev/unreal-code.md +125 -0
- package/skills/career-registry/SKILL.md +95 -0
- package/skills/career-registry/scripts/career_registry.py +488 -0
- package/skills/client-screen/SKILL.md +83 -0
- package/skills/client-screen/references/red-flags.md +95 -0
- package/skills/cover-letter/SKILL.md +4 -3
- package/skills/cv-tailor/SKILL.md +11 -2
- package/skills/freelance-deliver/SKILL.md +90 -0
- package/skills/freelance-hunt/SKILL.md +126 -0
- package/skills/freelance-hunt/references/templates/Connects.md +39 -0
- package/skills/freelance-hunt/references/templates/Contrato.md +60 -0
- package/skills/freelance-hunt/references/templates/Propuesta.md +66 -0
- package/skills/freelance-kickoff/SKILL.md +94 -0
- package/skills/freelance-pipeline/SKILL.md +109 -0
- package/skills/freelance-pipeline/scripts/import_history.py +425 -0
- package/skills/freelance-profile/SKILL.md +93 -0
- package/skills/freelance-proposal/SKILL.md +112 -0
- package/skills/freelance-scan/SKILL.md +196 -0
- package/skills/freelance-scan/references/dedup.md +35 -0
- package/skills/freelance-scan/references/platforms.md +167 -0
- package/skills/freelance-scan/scripts/freelance_search.py +1077 -0
- package/skills/install-mcp/SKILL.md +135 -46
- package/skills/install-mcp/references/unreal-operations.md +55 -0
- package/skills/interview-prep/SKILL.md +11 -3
- package/skills/job-aplicar/SKILL.md +5 -1
- package/skills/job-hunt/SKILL.md +17 -0
- package/skills/job-outcome/SKILL.md +15 -1
- package/skills/job-upskill/SKILL.md +10 -2
- package/skills/ue-actor-component-architecture/SKILL.md +509 -0
- package/skills/ue-actor-component-architecture/references/actor-lifecycle.md +301 -0
- package/skills/ue-actor-component-architecture/references/component-types.md +592 -0
- package/skills/ue-ai-navigation/SKILL.md +526 -0
- package/skills/ue-ai-navigation/references/behavior-tree-patterns.md +392 -0
- package/skills/ue-ai-navigation/references/behavior-tree-workflow.md +107 -0
- package/skills/ue-ai-navigation/references/custom-bttask.md +104 -0
- package/skills/ue-ai-navigation/references/eqs-reference.md +423 -0
- package/skills/ue-animation-system/SKILL.md +521 -0
- package/skills/ue-animation-system/references/anim-notify-reference.md +486 -0
- package/skills/ue-animation-system/references/locomotion-setup.md +550 -0
- package/skills/ue-async-threading/SKILL.md +433 -0
- package/skills/ue-async-threading/references/thread-safety-guide.md +213 -0
- package/skills/ue-async-threading/references/threading-patterns.md +345 -0
- package/skills/ue-audio-system/SKILL.md +527 -0
- package/skills/ue-audio-system/references/audio-setup-patterns.md +700 -0
- package/skills/ue-blueprints/SKILL.md +134 -0
- package/skills/ue-blueprints/references/communication.md +82 -0
- package/skills/ue-character-movement/SKILL.md +475 -0
- package/skills/ue-character-movement/references/cmc-extension-patterns.md +335 -0
- package/skills/ue-character-movement/references/movement-pipeline.md +189 -0
- package/skills/ue-cpp-foundations/SKILL.md +533 -0
- package/skills/ue-cpp-foundations/references/components-and-gc.md +107 -0
- package/skills/ue-cpp-foundations/references/container-patterns.md +544 -0
- package/skills/ue-cpp-foundations/references/delegate-patterns.md +497 -0
- package/skills/ue-cpp-foundations/references/gameplay-classes-cpp.md +136 -0
- package/skills/ue-cpp-foundations/references/property-specifiers.md +306 -0
- package/skills/ue-data-assets-tables/SKILL.md +527 -0
- package/skills/ue-data-assets-tables/references/asset-loading-patterns.md +306 -0
- package/skills/ue-data-assets-tables/references/data-driven-design.md +378 -0
- package/skills/ue-editor-tools/SKILL.md +523 -0
- package/skills/ue-editor-tools/references/detail-customization-patterns.md +395 -0
- package/skills/ue-editor-tools/references/editor-module-setup.md +480 -0
- package/skills/ue-game-features/SKILL.md +477 -0
- package/skills/ue-game-features/references/experience-system.md +222 -0
- package/skills/ue-game-features/references/game-feature-patterns.md +308 -0
- package/skills/ue-gameplay-abilities/SKILL.md +518 -0
- package/skills/ue-gameplay-abilities/references/ability-task-reference.md +391 -0
- package/skills/ue-gameplay-abilities/references/gameplay-effect-reference.md +397 -0
- package/skills/ue-gameplay-abilities/references/gas-setup-patterns.md +369 -0
- package/skills/ue-gameplay-framework/SKILL.md +466 -0
- package/skills/ue-gameplay-framework/references/framework-class-map.md +243 -0
- package/skills/ue-input-system/SKILL.md +394 -0
- package/skills/ue-input-system/references/cpp-setup.md +131 -0
- package/skills/ue-input-system/references/enhanced-input-workflow.md +117 -0
- package/skills/ue-input-system/references/input-action-reference.md +731 -0
- package/skills/ue-mass-entity/SKILL.md +476 -0
- package/skills/ue-mass-entity/references/mass-entity-patterns.md +319 -0
- package/skills/ue-mass-entity/references/mass-fragment-reference.md +119 -0
- package/skills/ue-materials-rendering/SKILL.md +526 -0
- package/skills/ue-materials-rendering/references/material-parameter-reference.md +216 -0
- package/skills/ue-materials-rendering/references/post-process-settings.md +383 -0
- package/skills/ue-module-build-system/SKILL.md +487 -0
- package/skills/ue-module-build-system/references/build-cs-reference.md +418 -0
- package/skills/ue-module-build-system/references/common-build-errors.md +381 -0
- package/skills/ue-naming-conventions/SKILL.md +142 -0
- package/skills/ue-naming-conventions/references/asset-name-modifiers.md +233 -0
- package/skills/ue-naming-conventions/references/content-structure.md +83 -0
- package/skills/ue-networking-replication/SKILL.md +452 -0
- package/skills/ue-networking-replication/references/replication-patterns.md +526 -0
- package/skills/ue-networking-replication/references/rpc-decision-guide.md +393 -0
- package/skills/ue-niagara-effects/SKILL.md +531 -0
- package/skills/ue-niagara-effects/references/niagara-data-interfaces.md +491 -0
- package/skills/ue-niagara-effects/references/niagara-parameter-types.md +153 -0
- package/skills/ue-niagara-effects/references/niagara-workflow.md +115 -0
- package/skills/ue-packaging/SKILL.md +116 -0
- package/skills/ue-physics-collision/SKILL.md +423 -0
- package/skills/ue-physics-collision/references/collision-channel-setup.md +218 -0
- package/skills/ue-physics-collision/references/trace-patterns.md +499 -0
- package/skills/ue-procedural-generation/SKILL.md +505 -0
- package/skills/ue-procedural-generation/references/pcg-node-reference.md +381 -0
- package/skills/ue-procedural-generation/references/procedural-mesh-patterns.md +940 -0
- package/skills/ue-project-context/SKILL.md +305 -0
- package/skills/ue-sequencer-cinematics/SKILL.md +506 -0
- package/skills/ue-sequencer-cinematics/references/sequencer-patterns.md +629 -0
- package/skills/ue-serialization-savegames/SKILL.md +524 -0
- package/skills/ue-serialization-savegames/references/save-system-architecture.md +705 -0
- package/skills/ue-state-trees/SKILL.md +489 -0
- package/skills/ue-state-trees/references/state-tree-mass-integration.md +184 -0
- package/skills/ue-state-trees/references/state-tree-patterns.md +321 -0
- package/skills/ue-testing-debugging/SKILL.md +520 -0
- package/skills/ue-testing-debugging/references/automation-test-patterns.md +387 -0
- package/skills/ue-testing-debugging/references/profiling-commands.md +357 -0
- package/skills/ue-ui-umg-slate/SKILL.md +431 -0
- package/skills/ue-ui-umg-slate/references/common-ui-setup.md +484 -0
- package/skills/ue-ui-umg-slate/references/widget-types.md +487 -0
- package/skills/ue-world-level-streaming/SKILL.md +518 -0
- package/skills/ue-world-level-streaming/references/streaming-patterns.md +414 -0
- package/templates/gamedev/unreal-project-context.md +107 -0
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
# Gameplay Framework Class Map
|
|
2
|
+
|
|
3
|
+
Reference table showing where each class lives, who owns it, what it stores, and
|
|
4
|
+
the exact lifecycle hook order. Cross-reference with SKILL.md for code examples.
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Authority and Presence Matrix
|
|
9
|
+
|
|
10
|
+
| Class | Dedicated Server | Listen Server (Host) | Listen Server (Remote Client) | Standalone |
|
|
11
|
+
|---|---|---|---|---|
|
|
12
|
+
| AGameModeBase / AGameMode | YES (authority) | YES (authority) | NO — null | YES (authority) |
|
|
13
|
+
| AGameStateBase / AGameState | YES | YES | YES (replicated) | YES |
|
|
14
|
+
| APlayerController (local player) | N/A | YES (server+client role) | YES (own only) | YES |
|
|
15
|
+
| APlayerController (remote player) | YES (all players) | YES (all players) | NO — not present | N/A |
|
|
16
|
+
| APlayerState (all players) | YES (all) | YES (all) | YES (all, replicated) | YES |
|
|
17
|
+
| APawn / ACharacter (possessed by local) | YES (auth) | YES (auth+local) | YES (local proxy) | YES |
|
|
18
|
+
| APawn / ACharacter (possessed by remote) | YES (auth) | YES (auth) | YES (simulated proxy) | N/A |
|
|
19
|
+
| UGameInstance | YES | YES | YES | YES |
|
|
20
|
+
| AHUD | NO | YES (host player only) | YES (own only) | YES |
|
|
21
|
+
| APlayerCameraManager | NO | YES (host player only) | YES (own only) | YES |
|
|
22
|
+
|
|
23
|
+
**Key:** "YES (auth)" = exists with `ROLE_Authority`. "YES (simulated proxy)" = exists with `ROLE_SimulatedProxy`, position interpolated from server updates.
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## Class Ownership Chain
|
|
28
|
+
|
|
29
|
+
```
|
|
30
|
+
UGameInstance [persists across all level loads]
|
|
31
|
+
|
|
|
32
|
+
+-- UWorld
|
|
33
|
+
|
|
|
34
|
+
+-- AGameMode [server only]
|
|
35
|
+
| |
|
|
36
|
+
| +-- AGameState [server + all clients]
|
|
37
|
+
| |
|
|
38
|
+
| +-- PlayerArray[] --> APlayerState per player
|
|
39
|
+
|
|
|
40
|
+
+-- APlayerController [server: all; client: own only]
|
|
41
|
+
|
|
|
42
|
+
+-- APlayerState [server + all clients]
|
|
43
|
+
|
|
|
44
|
+
+-- AHUD [local client only]
|
|
45
|
+
|
|
|
46
|
+
+-- APlayerCameraManager [local client only]
|
|
47
|
+
|
|
|
48
|
+
+-- (possesses) --> APawn / ACharacter
|
|
49
|
+
|
|
|
50
|
+
+-- UCharacterMovementComponent
|
|
51
|
+
+-- UCapsuleComponent (root)
|
|
52
|
+
+-- USkeletalMeshComponent
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
## Responsibility Summary
|
|
58
|
+
|
|
59
|
+
| Class | Primary Responsibility | Do NOT put here |
|
|
60
|
+
|---|---|---|
|
|
61
|
+
| AGameModeBase | Game rules, join approval, player spawn points, match initialization | Any data clients need to read |
|
|
62
|
+
| AGameMode | AGameModeBase + match state machine (WaitingToStart, InProgress, etc.) | Per-player data |
|
|
63
|
+
| AGameStateBase | Global replicated state: server clock, player array, has match started | Server-only logic |
|
|
64
|
+
| AGameState | AGameStateBase + match elapsed time | Client-only UI state |
|
|
65
|
+
| APlayerController | Input, camera, HUD management, possess/unpossess, client↔server RPC bridge | Cross-session data (may be replaced during seamless travel if PC class changes) |
|
|
66
|
+
| APlayerState | Replicated per-player data: name, score, team, ping | Input processing, UI |
|
|
67
|
+
| APawn | Minimal possessable actor, custom movement | Anything requiring capsule/mesh/built-in movement |
|
|
68
|
+
| ACharacter | Humanoid movement with capsule, skeletal mesh, and CMC prediction | Game rules, scoring |
|
|
69
|
+
| UGameInstance | Cross-level persistence: sessions, save game refs, analytics | Per-match state |
|
|
70
|
+
| AHUD | Local-only 2D overlay rendering | Any replicated data |
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
## Player Join Sequence (Server Side)
|
|
75
|
+
|
|
76
|
+
```
|
|
77
|
+
1. PreLogin(Options, Address, UniqueId, ErrorMessage)
|
|
78
|
+
Set ErrorMessage != "" to reject.
|
|
79
|
+
|
|
80
|
+
2. Login(NewPlayer, RemoteRole, Portal, Options, UniqueId, ErrorMessage)
|
|
81
|
+
Creates APlayerController via SpawnPlayerController().
|
|
82
|
+
Creates APlayerState, assigns UniqueId and name.
|
|
83
|
+
Returns new PC (or null on failure).
|
|
84
|
+
|
|
85
|
+
3. PostLogin(NewPlayer)
|
|
86
|
+
First point where server-to-client RPCs are safe.
|
|
87
|
+
GameState->PlayerArray is populated.
|
|
88
|
+
Override to assign teams, send initial data.
|
|
89
|
+
|
|
90
|
+
4. HandleStartingNewPlayer(NewPlayer)
|
|
91
|
+
Calls RestartPlayer() if not spectator.
|
|
92
|
+
|
|
93
|
+
5. RestartPlayer(NewPlayer)
|
|
94
|
+
Calls FindPlayerStart() -> ChoosePlayerStart()
|
|
95
|
+
Calls SpawnDefaultPawnFor()
|
|
96
|
+
Calls NewPlayer->Possess(Pawn)
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
## Player Logout Sequence
|
|
102
|
+
|
|
103
|
+
```
|
|
104
|
+
1. Logout(Exiting) -- GameMode notified (server only)
|
|
105
|
+
2. GameState->RemovePlayerState(PS) -- PlayerArray updated
|
|
106
|
+
3. PlayerController destroyed
|
|
107
|
+
4. PlayerState destroyed (after ReplicationTimeout or immediately if non-seamless)
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
---
|
|
111
|
+
|
|
112
|
+
## Seamless Travel Actor Survival
|
|
113
|
+
|
|
114
|
+
When `bUseSeamlessTravel = true`, the travel happens in two legs:
|
|
115
|
+
- **Leg 1:** Current map → Transition map
|
|
116
|
+
- **Leg 2:** Transition map → Destination map
|
|
117
|
+
|
|
118
|
+
`GetSeamlessTravelActorList` is called for BOTH legs.
|
|
119
|
+
|
|
120
|
+
| Object | Survives Seamless Travel | Notes |
|
|
121
|
+
|---|---|---|
|
|
122
|
+
| UGameInstance | YES | Never dies |
|
|
123
|
+
| APlayerController | YES (transferred) | Engine handles this automatically |
|
|
124
|
+
| APlayerState | YES (transferred with PC) | Engine handles this automatically |
|
|
125
|
+
| AGameMode | NO | New one spawned in destination map |
|
|
126
|
+
| AGameState | NO | New one spawned in destination map |
|
|
127
|
+
| APawn / ACharacter | NO (by default) | Destroyed; new one spawned by RestartPlayer |
|
|
128
|
+
| Custom actors | Optional | Add in GetSeamlessTravelActorList() |
|
|
129
|
+
|
|
130
|
+
---
|
|
131
|
+
|
|
132
|
+
## Movement Mode Reference (UCharacterMovementComponent)
|
|
133
|
+
|
|
134
|
+
| EMovementMode | Description | Typical Use |
|
|
135
|
+
|---|---|---|
|
|
136
|
+
| MOVE_None | No movement processed | Ragdoll, dead state |
|
|
137
|
+
| MOVE_Walking | On ground, uses NavMesh | Default walking/running |
|
|
138
|
+
| MOVE_NavWalking | On NavMesh surface (AI) | AI characters on nav mesh |
|
|
139
|
+
| MOVE_Falling | In air, gravity applied | After jump, falling off ledge |
|
|
140
|
+
| MOVE_Swimming | In fluid volume | Water traversal |
|
|
141
|
+
| MOVE_Flying | No gravity, full air control | Spectator, flying character |
|
|
142
|
+
| MOVE_Custom | User-defined (CustomMovementMode byte) | Wall running, zero-G, grapple |
|
|
143
|
+
|
|
144
|
+
---
|
|
145
|
+
|
|
146
|
+
## Key Properties Quick Reference
|
|
147
|
+
|
|
148
|
+
### AGameModeBase Classes
|
|
149
|
+
|
|
150
|
+
```cpp
|
|
151
|
+
TSubclassOf<APawn> DefaultPawnClass;
|
|
152
|
+
TSubclassOf<AGameStateBase> GameStateClass;
|
|
153
|
+
TSubclassOf<APlayerController> PlayerControllerClass;
|
|
154
|
+
TSubclassOf<APlayerState> PlayerStateClass;
|
|
155
|
+
TSubclassOf<AHUD> HUDClass;
|
|
156
|
+
TSubclassOf<ASpectatorPawn> SpectatorClass;
|
|
157
|
+
TSubclassOf<AGameSession> GameSessionClass;
|
|
158
|
+
uint32 bUseSeamlessTravel : 1;
|
|
159
|
+
uint32 bStartPlayersAsSpectators : 1;
|
|
160
|
+
uint32 bPauseable : 1;
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
### AGameStateBase Replicated Properties
|
|
164
|
+
|
|
165
|
+
```cpp
|
|
166
|
+
TSubclassOf<AGameModeBase> GameModeClass; // ReplicatedUsing=OnRep_GameModeClass
|
|
167
|
+
TSubclassOf<ASpectatorPawn> SpectatorClass; // ReplicatedUsing=OnRep_SpectatorClass
|
|
168
|
+
TArray<APlayerState*> PlayerArray; // Always relevant
|
|
169
|
+
bool bReplicatedHasBegunPlay; // ReplicatedUsing=OnRep_ReplicatedHasBegunPlay
|
|
170
|
+
double ReplicatedWorldTimeSecondsDouble; // server clock sync
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
### APlayerController Notable Members
|
|
174
|
+
|
|
175
|
+
```cpp
|
|
176
|
+
TObjectPtr<APawn> AcknowledgedPawn; // server-confirmed possession
|
|
177
|
+
TObjectPtr<APlayerCameraManager> PlayerCameraManager;
|
|
178
|
+
TObjectPtr<AHUD> MyHUD;
|
|
179
|
+
TObjectPtr<UPlayerInput> PlayerInput; // only valid locally
|
|
180
|
+
uint32 bShowMouseCursor : 1;
|
|
181
|
+
uint32 bEnableClickEvents : 1;
|
|
182
|
+
uint32 bEnableStreamingSource : 1;
|
|
183
|
+
uint16 SeamlessTravelCount;
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
### ACharacter Notable Members
|
|
187
|
+
|
|
188
|
+
```cpp
|
|
189
|
+
// Components (access via getters)
|
|
190
|
+
USkeletalMeshComponent* GetMesh()
|
|
191
|
+
UCharacterMovementComponent* GetCharacterMovement()
|
|
192
|
+
UCapsuleComponent* GetCapsuleComponent()
|
|
193
|
+
|
|
194
|
+
// Replicated state
|
|
195
|
+
uint8 bIsCrouched : 1; // ReplicatedUsing=OnRep_IsCrouched
|
|
196
|
+
uint8 bProxyIsJumpForceApplied : 1;
|
|
197
|
+
float JumpMaxHoldTime; // Replicated — variable jump height
|
|
198
|
+
int32 JumpMaxCount; // Replicated — multi-jump count
|
|
199
|
+
int32 JumpCurrentCount; // current jump count this airtime
|
|
200
|
+
uint8 ReplicatedMovementMode; // Replicated — movement mode for simulated proxies
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
---
|
|
204
|
+
|
|
205
|
+
## NetMode Cheat Sheet
|
|
206
|
+
|
|
207
|
+
```cpp
|
|
208
|
+
GetNetMode() == NM_Standalone // single player, no network
|
|
209
|
+
GetNetMode() == NM_DedicatedServer // server process, no local player
|
|
210
|
+
GetNetMode() == NM_ListenServer // server + local player (host)
|
|
211
|
+
GetNetMode() == NM_Client // remote client
|
|
212
|
+
|
|
213
|
+
HasAuthority() // true on server (NM_Standalone, NM_DedicatedServer, NM_ListenServer)
|
|
214
|
+
IsLocalController() // true if this PlayerController belongs to the local machine's player
|
|
215
|
+
IsLocallyControlled() // true on Pawn if its controller is a local player
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
---
|
|
219
|
+
|
|
220
|
+
## Class Selection Decision Tree
|
|
221
|
+
|
|
222
|
+
```
|
|
223
|
+
Need to store game-wide rules or control who can join?
|
|
224
|
+
--> AGameMode (server-only, authoritative)
|
|
225
|
+
|
|
226
|
+
Need global data visible to ALL clients (scores, match timer)?
|
|
227
|
+
--> AGameState (replicated everywhere)
|
|
228
|
+
|
|
229
|
+
Need per-player data visible to ALL clients (kills, team, name)?
|
|
230
|
+
--> APlayerState (always relevant, replicated everywhere)
|
|
231
|
+
|
|
232
|
+
Need to handle input, camera, or UI for ONE player?
|
|
233
|
+
--> APlayerController (exists on server + owning client only)
|
|
234
|
+
|
|
235
|
+
Need a player body that walks/jumps/crouches with built-in prediction?
|
|
236
|
+
--> ACharacter (with UCharacterMovementComponent)
|
|
237
|
+
|
|
238
|
+
Need a custom vehicle, drone, or non-humanoid body?
|
|
239
|
+
--> APawn (with a custom UPawnMovementComponent or manual physics)
|
|
240
|
+
|
|
241
|
+
Need data that survives level transitions?
|
|
242
|
+
--> UGameInstance (singleton per process, never destroyed)
|
|
243
|
+
```
|
|
@@ -0,0 +1,394 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: ue-input-system
|
|
3
|
+
description: "Enhanced Input system — Input Actions, Input Mapping Contexts, modifiers, triggers"
|
|
4
|
+
category: "gamedev"
|
|
5
|
+
argument-hint: "[action o input scheme]"
|
|
6
|
+
user-invocable: true
|
|
7
|
+
allowed-tools: Read, Glob, Grep, Bash, Write, Edit
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# UE Enhanced Input System
|
|
11
|
+
|
|
12
|
+
You are an expert in Unreal Engine's Enhanced Input system.
|
|
13
|
+
|
|
14
|
+
Ask before writing: this skill edits Input Action and Mapping Context assets plus binding code. Propose the change and get approval before using Write or Edit.
|
|
15
|
+
|
|
16
|
+
## Context Check
|
|
17
|
+
|
|
18
|
+
Read `docs/unreal/project-context.md` before proceeding. Confirm:
|
|
19
|
+
|
|
20
|
+
- `EnhancedInput` plugin is listed as enabled
|
|
21
|
+
- Target platforms (affects which modifiers are needed per platform)
|
|
22
|
+
- Whether CommonUI is in use (it manages input mode switching automatically)
|
|
23
|
+
- Whether the project still uses legacy input (migration may be needed)
|
|
24
|
+
|
|
25
|
+
## Information Gathering
|
|
26
|
+
|
|
27
|
+
Ask the developer: what actions are needed and their value types (Bool/Axis1D/Axis2D/Axis3D), which platforms, any complex input requirements (hold-to-charge, double-tap, combos, chord shortcuts), and whether multiple input modes are required (gameplay vs UI vs vehicle).
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## Enhanced Input Setup
|
|
32
|
+
|
|
33
|
+
### Plugin and Module
|
|
34
|
+
|
|
35
|
+
`.uproject`: add `{ "Name": "EnhancedInput", "Enabled": true }` to Plugins.
|
|
36
|
+
|
|
37
|
+
`Build.cs`: add `"EnhancedInput"` to `PublicDependencyModuleNames`.
|
|
38
|
+
|
|
39
|
+
`DefaultInput.ini`:
|
|
40
|
+
```ini
|
|
41
|
+
[/Script/Engine.InputSettings]
|
|
42
|
+
DefaultPlayerInputClass=/Script/EnhancedInput.EnhancedPlayerInput
|
|
43
|
+
DefaultInputComponentClass=/Script/EnhancedInput.EnhancedInputComponent
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### UInputAction Asset
|
|
47
|
+
|
|
48
|
+
`UInputAction : UDataAsset`. Create one per logical player action. Key properties (from `InputAction.h`):
|
|
49
|
+
|
|
50
|
+
```cpp
|
|
51
|
+
EInputActionValueType ValueType = EInputActionValueType::Boolean;
|
|
52
|
+
// Boolean | Axis1D (float) | Axis2D (FVector2D) | Axis3D (FVector)
|
|
53
|
+
|
|
54
|
+
EInputActionAccumulationBehavior AccumulationBehavior
|
|
55
|
+
= EInputActionAccumulationBehavior::TakeHighestAbsoluteValue;
|
|
56
|
+
// TakeHighestAbsoluteValue — highest magnitude wins across all mappings to this action
|
|
57
|
+
// Cumulative — all mapping values sum (W + S cancel each other for WASD)
|
|
58
|
+
|
|
59
|
+
bool bConsumeInput = true; // blocks lower-priority Enhanced Input mappings to same keys
|
|
60
|
+
|
|
61
|
+
TArray<TObjectPtr<UInputTrigger>> Triggers; // applied AFTER per-mapping triggers
|
|
62
|
+
TArray<TObjectPtr<UInputModifier>> Modifiers; // applied AFTER per-mapping modifiers
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### UInputMappingContext Asset
|
|
66
|
+
|
|
67
|
+
`UInputMappingContext : UDataAsset`. Maps physical keys to actions.
|
|
68
|
+
|
|
69
|
+
- `DefaultKeyMappings.Mappings` — `TArray<FEnhancedActionKeyMapping>` of key-to-action entries
|
|
70
|
+
- `MappingProfileOverrides` — per-profile key overrides for player remapping support
|
|
71
|
+
- `RegistrationTrackingMode`: `Untracked` (default, first Remove wins) or `CountRegistrations` (IMC stays until Remove called N times, safe when multiple systems share it)
|
|
72
|
+
|
|
73
|
+
---
|
|
74
|
+
|
|
75
|
+
## Binding Actions in C++
|
|
76
|
+
|
|
77
|
+
### SetupPlayerInputComponent
|
|
78
|
+
|
|
79
|
+
```cpp
|
|
80
|
+
// MyCharacter.h — declare assets and handlers
|
|
81
|
+
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Input")
|
|
82
|
+
TObjectPtr<UInputMappingContext> DefaultMappingContext;
|
|
83
|
+
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Input")
|
|
84
|
+
TObjectPtr<UInputAction> MoveAction;
|
|
85
|
+
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Input")
|
|
86
|
+
TObjectPtr<UInputAction> JumpAction;
|
|
87
|
+
|
|
88
|
+
void Move(const FInputActionValue& Value);
|
|
89
|
+
void StartJump();
|
|
90
|
+
void StopJump();
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
```cpp
|
|
94
|
+
// MyCharacter.cpp
|
|
95
|
+
#include "EnhancedInputComponent.h"
|
|
96
|
+
#include "EnhancedInputSubsystems.h"
|
|
97
|
+
|
|
98
|
+
void AMyCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
|
|
99
|
+
{
|
|
100
|
+
Super::SetupPlayerInputComponent(PlayerInputComponent);
|
|
101
|
+
UEnhancedInputComponent* EIC = Cast<UEnhancedInputComponent>(PlayerInputComponent);
|
|
102
|
+
if (!EIC) { return; }
|
|
103
|
+
|
|
104
|
+
EIC->BindAction(MoveAction, ETriggerEvent::Triggered, this, &AMyCharacter::Move);
|
|
105
|
+
EIC->BindAction(JumpAction, ETriggerEvent::Started, this, &AMyCharacter::StartJump);
|
|
106
|
+
EIC->BindAction(JumpAction, ETriggerEvent::Completed, this, &AMyCharacter::StopJump);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
void AMyCharacter::BeginPlay()
|
|
110
|
+
{
|
|
111
|
+
Super::BeginPlay();
|
|
112
|
+
if (APlayerController* PC = Cast<APlayerController>(GetController()))
|
|
113
|
+
{
|
|
114
|
+
if (auto* Sub = ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(
|
|
115
|
+
PC->GetLocalPlayer()))
|
|
116
|
+
{
|
|
117
|
+
Sub->AddMappingContext(DefaultMappingContext, 0); // priority 0 = lowest
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### Callback Signatures
|
|
124
|
+
|
|
125
|
+
`BindAction` accepts four delegate signatures:
|
|
126
|
+
|
|
127
|
+
```cpp
|
|
128
|
+
// No params — press/release without value needed
|
|
129
|
+
void AMyCharacter::StartJump() { Jump(); }
|
|
130
|
+
|
|
131
|
+
// FInputActionValue — for axis values
|
|
132
|
+
void AMyCharacter::Move(const FInputActionValue& Value)
|
|
133
|
+
{
|
|
134
|
+
const FVector2D Input = Value.Get<FVector2D>();
|
|
135
|
+
AddMovementInput(GetActorForwardVector(), Input.Y);
|
|
136
|
+
AddMovementInput(GetActorRightVector(), Input.X);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// FInputActionInstance — when elapsed/triggered time is needed
|
|
140
|
+
void AMyCharacter::OnChargeAttack(const FInputActionInstance& Instance)
|
|
141
|
+
{
|
|
142
|
+
const float HeldFor = Instance.GetElapsedTime(); // Started + Ongoing + Triggered
|
|
143
|
+
const float ActiveFor = Instance.GetTriggeredTime(); // Triggered only
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// Lambda variant
|
|
147
|
+
EIC->BindActionValueLambda(InteractAction, ETriggerEvent::Triggered,
|
|
148
|
+
[this](const FInputActionValue& Value) { TryInteract(); });
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
Storing and removing a binding:
|
|
152
|
+
```cpp
|
|
153
|
+
FEnhancedInputActionEventBinding& B =
|
|
154
|
+
EIC->BindAction(DebugAction, ETriggerEvent::Started, this, &AMyCharacter::DebugToggle);
|
|
155
|
+
uint32 Handle = B.GetHandle();
|
|
156
|
+
// ...
|
|
157
|
+
EIC->RemoveBindingByHandle(Handle); // remove one binding
|
|
158
|
+
EIC->ClearBindingsForObject(this); // remove all bindings for an object
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
---
|
|
162
|
+
|
|
163
|
+
## Trigger Events (ETriggerEvent)
|
|
164
|
+
|
|
165
|
+
Bitmask enum from `InputTriggers.h`:
|
|
166
|
+
|
|
167
|
+
| Event | State Transition | Use for |
|
|
168
|
+
|---|---|---|
|
|
169
|
+
| `Started` | None -> Ongoing/Triggered | First frame of input; press-once actions |
|
|
170
|
+
| `Triggered` | *->Triggered, Triggered->Triggered | Every active frame; continuous movement |
|
|
171
|
+
| `Ongoing` | Ongoing->Ongoing | Held but not yet triggered (charge build-up) |
|
|
172
|
+
| `Canceled` | Ongoing->None | Released before trigger threshold |
|
|
173
|
+
| `Completed` | Triggered->None | Input released after triggering; stop continuous actions |
|
|
174
|
+
|
|
175
|
+
Note: `Completed` does not fire if any trigger on the same action reports `Ongoing` that frame.
|
|
176
|
+
|
|
177
|
+
---
|
|
178
|
+
|
|
179
|
+
## Built-in Triggers
|
|
180
|
+
|
|
181
|
+
Full parameter listings in `references/input-action-reference.md`.
|
|
182
|
+
|
|
183
|
+
| Class | Name | Behavior |
|
|
184
|
+
|---|---|---|
|
|
185
|
+
| `UInputTriggerDown` | Down | Every frame input exceeds threshold (implicit default) |
|
|
186
|
+
| `UInputTriggerPressed` | Pressed | Once on first actuation; holding does not repeat |
|
|
187
|
+
| `UInputTriggerReleased` | Released | Once when input drops below threshold after actuation |
|
|
188
|
+
| `UInputTriggerHold` | Hold | After `HoldTimeThreshold` s; `bIsOneShot=false` repeats every frame |
|
|
189
|
+
| `UInputTriggerHoldAndRelease` | Hold And Release | On release after holding `HoldTimeThreshold` s |
|
|
190
|
+
| `UInputTriggerTap` | Tap | Released within `TapReleaseTimeThreshold` s |
|
|
191
|
+
| `UInputTriggerRepeatedTap` | Repeated Tap | N taps within `RepeatDelay` (`NumberOfTapsWhichTriggerRepeat=2` for double-tap) |
|
|
192
|
+
| `UInputTriggerPulse` | Pulse | Repeatedly at `Interval` s while held; optional `TriggerLimit` |
|
|
193
|
+
| `UInputTriggerChordAction` | Chorded Action | Only fires while `ChordAction` is active (Implicit type; auto-blocks solo key) |
|
|
194
|
+
| `UInputTriggerCombo` | Combo (Beta) | All `ComboActions` completed in order within `TimeToPressKey` windows |
|
|
195
|
+
|
|
196
|
+
Trigger type rules for multi-trigger evaluation: `Explicit` (default, at least one must fire), `Implicit` (all must fire), `Blocker` (blocks everything if active).
|
|
197
|
+
|
|
198
|
+
---
|
|
199
|
+
|
|
200
|
+
## Built-in Modifiers
|
|
201
|
+
|
|
202
|
+
Applied in array order. Mapping-level modifiers run before action-level modifiers.
|
|
203
|
+
|
|
204
|
+
| Class | Name | Effect |
|
|
205
|
+
|---|---|---|
|
|
206
|
+
| `UInputModifierDeadZone` | Dead Zone | Zero input below `LowerThreshold`; remap to 1 at `UpperThreshold`. Types: Axial, Radial, UnscaledRadial |
|
|
207
|
+
| `UInputModifierScalar` | Scalar | Multiply per axis by `FVector Scalar` |
|
|
208
|
+
| `UInputModifierScaleByDeltaTime` | Scale By Delta Time | Multiply by frame DeltaTime |
|
|
209
|
+
| `UInputModifierNegate` | Negate | Invert selected axes (`bX`, `bY`, `bZ`) |
|
|
210
|
+
| `UInputModifierSwizzleAxis` | Swizzle Input Axis Values | Reorder axes; `YXZ` (default) swaps X/Y — maps 1D key onto Y of Axis2D action |
|
|
211
|
+
| `UInputModifierSmooth` | Smooth | Rolling average over recent samples |
|
|
212
|
+
| `UInputModifierSmoothDelta` | Smooth Delta | Smoothed normalized delta; configurable interpolation (`Lerp`, `Interp_To`, ease curves) |
|
|
213
|
+
| `UInputModifierResponseCurveExponential` | Response Curve - Exponential | `sign(x)*|x|^CurveExponent` per axis |
|
|
214
|
+
| `UInputModifierResponseCurveUser` | Response Curve - User Defined | Separate `UCurveFloat` per axis |
|
|
215
|
+
| `UInputModifierFOVScaling` | FOV Scaling | Scale by camera FOV for consistent angular speed across zoom levels |
|
|
216
|
+
| `UInputModifierToWorldSpace` | To World Space | 2D axis -> world space (up/down = world X, left/right = world Y) |
|
|
217
|
+
|
|
218
|
+
**WASD -> Axis2D recipe** (`AccumulationBehavior = Cumulative`):
|
|
219
|
+
- `W`: `SwizzleAxis(YXZ)` → Y=+1
|
|
220
|
+
- `S`: `SwizzleAxis(YXZ)` + `Negate(bY)` → Y=-1
|
|
221
|
+
- `D`: none → X=+1
|
|
222
|
+
- `A`: `Negate(bX)` → X=-1
|
|
223
|
+
|
|
224
|
+
**Gamepad stick**: `DeadZone(Radial, LowerThreshold=0.2)` per stick mapping.
|
|
225
|
+
|
|
226
|
+
**Mouse look**: `[Scalar(0.4,0.4,1), Smooth, FOVScaling]` per mapping.
|
|
227
|
+
|
|
228
|
+
---
|
|
229
|
+
|
|
230
|
+
## Mapping Context Priority
|
|
231
|
+
|
|
232
|
+
```cpp
|
|
233
|
+
// Higher integer = higher priority; wins key conflicts
|
|
234
|
+
Subsystem->AddMappingContext(GameplayIMC, 0);
|
|
235
|
+
Subsystem->AddMappingContext(VehicleIMC, 1);
|
|
236
|
+
|
|
237
|
+
// FModifyContextOptions — prevent ghost inputs on switch
|
|
238
|
+
FModifyContextOptions Opts;
|
|
239
|
+
Opts.bIgnoreAllPressedKeysUntilRelease = true;
|
|
240
|
+
Subsystem->AddMappingContext(UIIMC, 2, Opts);
|
|
241
|
+
|
|
242
|
+
// Remove on mode exit
|
|
243
|
+
Subsystem->RemoveMappingContext(VehicleIMC);
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
When `bConsumeInput = true` on a `UInputAction` (the default), a higher-priority context that maps the same physical key will consume it, blocking all lower-priority bindings to that key from firing. This is intentional: use priority layering and `bConsumeInput` together to prevent input conflicts between modes (e.g., a vehicle context consuming Spacebar so the character's Jump action never fires while driving).
|
|
247
|
+
|
|
248
|
+
### Split-Screen / Multiple Local Players
|
|
249
|
+
|
|
250
|
+
In split-screen, each local player has their own `UEnhancedInputLocalPlayerSubsystem`. Mapping contexts are per-player — adding a context to one player's subsystem does not affect others. To target a specific player, retrieve their subsystem directly from their `ULocalPlayer`:
|
|
251
|
+
|
|
252
|
+
```cpp
|
|
253
|
+
// Access subsystem for a specific local player (e.g., player 2)
|
|
254
|
+
if (ULocalPlayer* LP = PlayerController->GetLocalPlayer())
|
|
255
|
+
{
|
|
256
|
+
if (auto* Sub = ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(LP))
|
|
257
|
+
{
|
|
258
|
+
Sub->AddMappingContext(PlayerTwoIMC, 0);
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
---
|
|
264
|
+
|
|
265
|
+
## Custom Triggers
|
|
266
|
+
|
|
267
|
+
Subclass `UInputTrigger`; override `UpdateState_Implementation` returning `ETriggerState::None / Ongoing / Triggered`:
|
|
268
|
+
|
|
269
|
+
```cpp
|
|
270
|
+
UCLASS(EditInlineNew, meta=(DisplayName="Double Click"))
|
|
271
|
+
class MYGAME_API UDoubleClickTrigger : public UInputTrigger
|
|
272
|
+
{
|
|
273
|
+
GENERATED_BODY()
|
|
274
|
+
public:
|
|
275
|
+
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Trigger Settings")
|
|
276
|
+
float DoubleClickThreshold = 0.3f;
|
|
277
|
+
protected:
|
|
278
|
+
virtual ETriggerType GetTriggerType_Implementation() const override
|
|
279
|
+
{ return ETriggerType::Explicit; }
|
|
280
|
+
virtual ETriggerState UpdateState_Implementation(
|
|
281
|
+
const UEnhancedPlayerInput* PlayerInput, FInputActionValue ModifiedValue, float DeltaTime) override;
|
|
282
|
+
private:
|
|
283
|
+
float LastPressTime = 0.f;
|
|
284
|
+
bool bWasActuated = false;
|
|
285
|
+
};
|
|
286
|
+
|
|
287
|
+
ETriggerState UDoubleClickTrigger::UpdateState_Implementation(
|
|
288
|
+
const UEnhancedPlayerInput* PlayerInput, FInputActionValue ModifiedValue, float DeltaTime)
|
|
289
|
+
{
|
|
290
|
+
const bool bActuated = IsActuated(ModifiedValue); // helper: magnitude >= ActuationThreshold
|
|
291
|
+
const float Now = PlayerInput->GetWorld()->GetTimeSeconds();
|
|
292
|
+
if (bActuated && !bWasActuated)
|
|
293
|
+
{
|
|
294
|
+
if ((Now - LastPressTime) <= DoubleClickThreshold)
|
|
295
|
+
{ LastPressTime = 0.f; bWasActuated = bActuated; return ETriggerState::Triggered; }
|
|
296
|
+
LastPressTime = Now;
|
|
297
|
+
}
|
|
298
|
+
bWasActuated = bActuated;
|
|
299
|
+
return ETriggerState::None;
|
|
300
|
+
}
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
`UInputTriggerTimedBase` provides `HeldDuration` and `CalculateHeldDuration` for time-based triggers.
|
|
304
|
+
|
|
305
|
+
---
|
|
306
|
+
|
|
307
|
+
## Custom Modifiers
|
|
308
|
+
|
|
309
|
+
Subclass `UInputModifier`; override `ModifyRaw_Implementation`:
|
|
310
|
+
|
|
311
|
+
```cpp
|
|
312
|
+
UCLASS(EditInlineNew, meta=(DisplayName="Clamp Magnitude"))
|
|
313
|
+
class MYGAME_API UClampMagnitudeModifier : public UInputModifier
|
|
314
|
+
{
|
|
315
|
+
GENERATED_BODY()
|
|
316
|
+
public:
|
|
317
|
+
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Settings)
|
|
318
|
+
float MaxMagnitude = 1.0f;
|
|
319
|
+
protected:
|
|
320
|
+
virtual FInputActionValue ModifyRaw_Implementation(
|
|
321
|
+
const UEnhancedPlayerInput* PlayerInput, FInputActionValue CurrentValue, float DeltaTime) override
|
|
322
|
+
{
|
|
323
|
+
FVector V = CurrentValue.Get<FVector>();
|
|
324
|
+
if (V.SizeSquared() > MaxMagnitude * MaxMagnitude)
|
|
325
|
+
V = V.GetSafeNormal() * MaxMagnitude;
|
|
326
|
+
return FInputActionValue(CurrentValue.GetValueType(), V);
|
|
327
|
+
}
|
|
328
|
+
};
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
---
|
|
332
|
+
|
|
333
|
+
## Common Mistakes
|
|
334
|
+
|
|
335
|
+
- **Mapping context not added**: Add via subsystem in `BeginPlay`/after `Possess`, not in `SetupPlayerInputComponent` (called earlier on some paths).
|
|
336
|
+
- **Legacy binding on UEnhancedInputComponent**: `BindAction(FName,...)` and `BindAxis` are `= delete`. Compile error. Set `DefaultInputComponentClass` in `DefaultInput.ini`.
|
|
337
|
+
- **Triggered for a button press**: `Triggered` fires every active frame. Use `Started` for press-once, `Completed` for release.
|
|
338
|
+
- **Completed not firing with Ongoing**: If any trigger reports `Ongoing` that frame, `Completed` is suppressed. Use separate actions for clean press/release events.
|
|
339
|
+
- **No dead zone on gamepad sticks**: Sticks produce non-zero resting values. Always add `DeadZone(Radial)` per stick mapping.
|
|
340
|
+
- **Missing SwizzleAxis for WASD-to-2D**: Keyboard produces 1D. Without `SwizzleAxis(YXZ)` on W/S, forward/backward stays on X and is ignored by Axis2D forward movement.
|
|
341
|
+
- **Replicating input actions**: Input is client-local. Replicate results (movement, ability activation), not trigger events.
|
|
342
|
+
- **MapKey/UnmapKey at runtime for rebinding**: These are editor/config-screen helpers. Use subsystem player mappable key APIs or swap contexts instead.
|
|
343
|
+
- **Wrong trigger type for intent**: Using `Down` when `Hold` is needed, or `Triggered` when `Started` is needed. Match trigger type to the interaction pattern: `Started` for single press, `Triggered` for continuous, `Hold` for delayed activation.
|
|
344
|
+
|
|
345
|
+
---
|
|
346
|
+
|
|
347
|
+
## Legacy Input Migration
|
|
348
|
+
|
|
349
|
+
To migrate from the legacy input system to Enhanced Input: search for `InputComponent->BindAction` and `InputComponent->BindAxis` calls and replace each with `UEnhancedInputComponent::BindAction`. Create a `UInputAction` data asset for every old action name, choosing the appropriate `ValueType` (Boolean for buttons, Axis1D for single-axis, Axis2D for stick/WASD). Create a `UInputMappingContext` asset and add key mappings corresponding to the old `DefaultInput.ini` `ActionMappings`/`AxisMappings` entries. Set `DefaultInputComponentClass` in `DefaultInput.ini` and enable the EnhancedInput plugin.
|
|
350
|
+
|
|
351
|
+
## UI Input Mode
|
|
352
|
+
|
|
353
|
+
Without CommonUI, manage input modes manually via `APlayerController::SetInputMode()`:
|
|
354
|
+
```cpp
|
|
355
|
+
PC->SetInputMode(FInputModeUIOnly()); // cursor captured by UI, no game input
|
|
356
|
+
PC->SetInputMode(FInputModeGameAndUI()); // both UI and game receive input
|
|
357
|
+
PC->SetInputMode(FInputModeGameOnly()); // full game input, UI events suppressed
|
|
358
|
+
```
|
|
359
|
+
CommonUI automates input routing through `UCommonActivatableWidget` stacks and eliminates most manual `SetInputMode` calls — see `/ue-ui-umg-slate`.
|
|
360
|
+
|
|
361
|
+
---
|
|
362
|
+
|
|
363
|
+
## Related Skills
|
|
364
|
+
|
|
365
|
+
- `/ue-gameplay-framework` — PlayerController input lifecycle, `Possess`/`UnPossess`, `SetupPlayerInputComponent`
|
|
366
|
+
- `/ue-ui-umg-slate` — `SetInputMode(FInputModeUIOnly())`/`FInputModeGameAndUI()`, cursor visibility, CommonUI `UCommonActivatableWidget` stacks
|
|
367
|
+
- `/ue-gameplay-abilities` — binding Enhanced Input actions to GAS ability activation via input ID tags
|
|
368
|
+
- `/ue-naming-conventions` — asset prefixes and Content folder layout for these assets
|
|
369
|
+
|
|
370
|
+
## Reference Files
|
|
371
|
+
|
|
372
|
+
- `references/input-action-reference.md` — full trigger and modifier catalogue with parameters
|
|
373
|
+
- `references/enhanced-input-workflow.md` — editor-side authoring flow for actions and mapping contexts
|
|
374
|
+
- `references/cpp-setup.md` — C++ setup: subsystem access, context priorities, binding callbacks
|
|
375
|
+
|
|
376
|
+
---
|
|
377
|
+
|
|
378
|
+
## Checklist
|
|
379
|
+
|
|
380
|
+
Validate before considering the work done:
|
|
381
|
+
|
|
382
|
+
- [ ] Mapping contexts are added and removed with explicit priorities per game state
|
|
383
|
+
- [ ] Input Action value types match how the action is consumed
|
|
384
|
+
- [ ] No legacy `BindAction`/`BindAxis` or direct key polling remains
|
|
385
|
+
- [ ] Conventions in `docs/unreal/project-context.md` were read and followed
|
|
386
|
+
- [ ] The Common Mistakes section of this skill was reviewed against the change
|
|
387
|
+
|
|
388
|
+
**PASS** — every item holds. **CONCERNS** — the work stands but at least one item is unresolved and worth flagging to the user. **FAIL** — an item is violated in a way that breaks correctness, replication or the frame budget; fix it before handing the work over.
|
|
389
|
+
|
|
390
|
+
## Next Steps
|
|
391
|
+
|
|
392
|
+
- `/ue-ui-umg-slate` — verify input mode switching between game and UI
|
|
393
|
+
- `/code-review` — architectural and quality review of the change
|
|
394
|
+
- `/commit` — conventional commit once the change is verified
|