Blitz3D+ Command Reference

SetAnimRootMotion entity,node_name$[,apply][,vertical][,yaw]

Parameters

entity - handle of an animated entity
node_name$ - name of the animated node to take the motion from, or a slash-separated path
apply (optional) - True to let the engine move the entity itself; False (default)
vertical (optional) - True to extract up-and-down movement as well; False (default)
yaw (optional) - True to extract turning about the up axis; True (default)

Description

Turns on root motion for an entity: the movement baked into one animated node is taken out of the displayed pose and handed to you as a per-update delta.

Animators often build a walk cycle that genuinely travels forward, so the feet plant properly instead of skating. Played back as-is, the character wanders away from its own entity origin. Root motion fixes that: the travel is stripped out of the skeleton, the character animates on the spot, and you get the distance it would have covered so the entity can be moved by exactly that much.

Sideways and forward translation is always extracted. vertical adds Y, which you want for jumps and vaults and not much else. yaw, on by default, extracts turning so an animated turn-in-place actually rotates the entity. Scale, pitch and roll are left on the node.

With apply False - the default - nothing moves by itself: read AnimRootMotionX, AnimRootMotionY, AnimRootMotionZ and AnimRootMotionYaw after each UpdateWorld and feed them into whatever moves your character, whether that is MoveEntity, a character controller or a physics body. With apply True the engine moves and turns the entity for you before the normal collision pass, so classic Blitz collisions still push back on the animated movement. A character driven by a Box3D dynamic body should always use apply False and pass the deltas to the body itself, rather than letting two systems fight over the same transform.

The node is looked up like FindBone: exact name first, then case-insensitively, with a slash-separated path when names repeat. It does not have to be a skin joint - glTF files often animate an armature or model root that sits above the real joints, and that node is usually the right source. A name that matches no animated node raises an error.

Root motion is deliberately opt-in, because plenty of models carry accidental drift on their hip node and plenty of games would rather drive movement entirely from code. Switching it on, changing the source node or restarting a clip resets the reference pose and reports a zero delta for that update instead of teleporting the character.

See also: ClearAnimRootMotion, AnimRootMotionX, AnimRootMotionZ, AnimRootMotionYaw, FindBone.

Example

; SetAnimRootMotion Example
; -------------------------

Graphics3D 640,480,0,2
SetBuffer BackBuffer()

camera=CreateCamera()
PositionEntity camera,0,3,-8
RotateEntity camera,15,0,0

light=CreateLight()
RotateEntity light,45,45,0

ground=CreatePlane()
EntityTexture ground,LoadTexture("media/MossyGround.BMP")

; A courier robot: a named pivot with a cube body
courier=CreatePivot()
NameEntity courier,"CourierRoot"
body=CreateCube(courier)
ScaleEntity body,0.4,0.4,0.6
PositionEntity body,0,0.4,0
EntityColor body,60,220,255

; Author a patrol animation whose keys carry the robot 8 units along X
PositionEntity courier,-4,0,0
SetAnimKey courier,0
PositionEntity courier,4,0,0
SetAnimKey courier,60
patrol=AddAnimSeq(courier,60)
PositionEntity courier,-4,0,0

; SetAnimRootMotion strips that movement out of the displayed pose and,
; with apply=True, moves the entity itself instead
apply=True
SetAnimRootMotion courier,"CourierRoot",apply,False,False

; Play the patrol ping-pong so the robot shuttles back and forth
CrossFadeAnim courier,patrol,0,2

While Not KeyDown(1)

    ; Space re-calls SetAnimRootMotion with apply flipped: with apply=False
    ; the extracted movement is discarded and the robot marches on the spot
    If KeyHit(57)
        apply=1-apply
        SetAnimRootMotion courier,"CourierRoot",apply,False,False
    EndIf

    UpdateWorld

    ; Arrow keys move the camera
    If KeyDown(200) Then MoveEntity camera,0,0,0.1
    If KeyDown(208) Then MoveEntity camera,0,0,-0.1
    If KeyDown(203) Then TurnEntity camera,0,1,0
    If KeyDown(205) Then TurnEntity camera,0,-1,0

    RenderWorld

    Text 0,0,"Space: toggle apply   Arrows: camera   Esc: exit"
    Text 0,20,"SetAnimRootMotion courier,"+Chr$(34)+"CourierRoot"+Chr$(34)+","+apply+",False,False"
    Text 0,40,"Root delta X: "+AnimRootMotionX(courier)+"   EntityX: "+EntityX(courier)

    Flip

Wend

End

Index