"An automated input harness reads zero movement unless it runs first and injects on both steps"
▸ SYMPTOM
You write a component that injects movement input to drive an automated playtest. Camera and look phases pass. Every movement phase, walk, sprint, strafe, jump, and crouch, reads exactly zero. The character does not move, and nothing errors.
▸ CAUSE
Three separate facts combine into this split symptom.
Input.AnalogMove is computed once per frame from the movement actions, before components run. So setting the underlying Forward, Back, Left, and Right actions from inside a component moves nothing that frame: the value was already read.
Components run in scene (GameObject) order. A harness sitting on or under the controlled character runs after the stock mover's own component, so every write lands one frame late, then gets wiped when the next frame rebuilds input.
Movement is consumed on the fixed step, while looking is consumed on the per-frame update. All of a frame's fixed steps are already done by the time OnUpdate runs. A harness that injects only from OnUpdate therefore feeds the look phases correctly and feeds the movement phases nothing, which reads as exactly zero on every movement phase.
▸ FIX
- Put the harness on the first object in the scene, so it runs before the stock mover.
- For held movement, write
Input.AnalogMovedirectly rather than setting the Forward, Back, Left, and Right actions. - For
JumpandDuck, keep usingInput.SetAction. Those are real action reads and work as expected. - Inject from both
OnUpdateandOnFixedUpdate, so the movement phases on the fixed step get their input as well as the look phases on the per-frame update.
▸ WHY IT WORKS
The direct Input.AnalogMove write sidesteps the timing of the once-per-frame read. The engine computes AnalogMove from the actions before components run, so a component can only influence held movement by writing the resolved value, not the actions behind it. Jump and Duck are read as actions later, so Input.SetAction still reaches them.
Scene order and the two step types explain the rest. Running first means the write is in place before the mover reads it, instead of one frame behind. Writing on both OnUpdate and OnFixedUpdate covers both consumers: the fixed step that drives movement and the per-frame update that drives looking. Miss either half and the symptom is the clean split of passing look phases and zero movement.
- Published