The Arisen now has a full set of placeholder animations: idle, walk, run, a hunched sprint, a tired run when stamina is low, and a hands on knees pose when you run dry. Getting there took one decoding bug, one sign bug, and a blend tree written entirely in C++.
Measure Before You Name
The placeholder set has 173 motions, and the first render looked promising from the waist up: arms swinging on the walk, the hunch on the tired run. The legs were a different story. In every single frame they were folded up behind the body, even on the plain standing idle.
Rather than guess which clip was which, I measured every one of them: how far the character travels per loop, how long the loop is, how high the hips sit. Then I rendered side view frames of each candidate. The walk turned out to cover about 2 meters per loop, the run about 3, the sprint about 3.4, and the tired run about 2.9 per second long loop. Numbers first, eyes second, names last.
The Knee Bug
Knees and elbows are hinge joints, so the animation format stores them compactly: one rotation axis plus a scalar, 14 bits each. Every other joint stores a small range block next to its data, and the decoder scales values into that range. Hinge tracks have no range block at all. The importer scaled them anyway, by a range of zero, and every knee and elbow key came out as an all zero rotation. Zero is not a valid rotation, so the legs collapsed.
I wrote a small decoder for just those tracks, working from an open source format library. To trust it, I first decoded all the tracks the importer already handles correctly and compared them key by key. They matched. Then I rebuilt the hinge channels frame by frame and patched them back in.
The Elbow Bug
In game, one arm still looked wrong: the left forearm folded up toward the shoulder. The knees and the right elbow were fine because their values happen to be positive. The left elbow bends the other way, and those components are signed, two's complement, spanning minus two to plus two. Reading them as unsigned turned a small bend into a huge one.
The fix is two lines, and it came with a free self check: once decoded as signed, every single key comes out as an exact unit rotation.
v = int(round(raw * 16383.0))
if v >= 8192: # negative in 14 bit two's complement
v -= 16384
value = v * 4.0 / 16383.0A Blend Tree Without An Animation Blueprint
Instead of an Animation Blueprint, the locomotion lives in a C++ anim instance and its worker thread proxy. The game thread decides what to play and how much each clip counts. The proxy samples the clips, blends the poses, and layers attack montages on top.
- Speed blends idle into walk into run.
- Low stamina swaps in the tired run, sprinting swaps in the hunched sprint, and exhaustion fades to catching breath over everything.
- Raising your fists switches to the fighting stance set.
- Every moving clip shares one stride phase that advances by distance travelled, so feet stay planted at any speed and a half walk, half run blend never goes out of step.
// Stride phase: advance by distance travelled over the blended stride length
const float Stride = (W_Walk * WalkStride + W_Run * RunStride + W_Tired * TiredRunStride +
W_Sprint * SprintStride) / MovingTotal;
StridePhase = FMath::Fmod(StridePhase + SmoothedSpeed * DeltaSeconds / Stride, 1.0f);Without an Animation Blueprint there is no Slot node to play attack montages through, so the proxy registers its own slot, reads the montage weights each update, and calls the engine's slot evaluation itself.
Unarmed First
While testing, the attack set I had filed as sword and shield turned out to be unarmed moves: fist stance, punches and a leaping blow. That settled a design question. The Arisen fights unarmed until vocations and weapons exist, so the placeholder sword and shield are hidden and "draw weapon" now raises your fists.
What I Learned
- Identify animations by measuring and rendering them, never by an index or a guess.
- When a decoder is suspect, validate it against the cases that already work before trusting it on the ones that do not.
- If a fix is right, it often gives you a free check. Every decoded key being exactly unit length was that check here.
- Playtesting finds what renders miss. The left elbow only looked wrong from the front.
What Is Next
- Enemy health bars above their heads.
- Lock on with the middle mouse button.
- Guard on Left Alt, unarmed for now.
- Sort out the remaining clips, including proper Blink Strike and Burst Strike moves.
- Replace the placeholder body and animations with my own, starting with a character model made in MakeHuman.

