Skip to content

AnimBP Cookbook

Common recipes and patterns for AnimBP authoring with PyUnreal.


Basic Locomotion (Idle / Walk / Run)

The most common AnimBP pattern -- three states with bidirectional transitions.

from pyunreal import load
from pyunreal.anim import AnimBlueprint

skeleton = load('/Game/Characters/Meshes/SK_Mannequin')
abp = AnimBlueprint.create('/Game/AnimBP', 'ABP_Locomotion', skeleton)

loco = abp.add_state_machine('Locomotion')

idle = loco.add_state('Idle', animation=load('/Game/Anims/Idle'), default=True)
walk = loco.add_state('Walk', animation=load('/Game/Anims/Walk'))
run  = loco.add_state('Run',  animation=load('/Game/Anims/Run'))

# Idle <-> Walk
idle.transition_to(walk, crossfade=0.2)
walk.transition_to(idle, crossfade=0.2)

# Walk <-> Run
walk.transition_to(run,  crossfade=0.15)
run.transition_to(walk,  crossfade=0.15)

abp.compile()

Jump with Auto-Return

A jump state that automatically transitions back to idle when the animation finishes.

idle = loco.add_state('Idle', animation=idle_anim, default=True)
jump = loco.add_state('Jump', animation=jump_anim)

idle.transition_to(jump, crossfade=0.1)

# Auto-return: when Jump has < 0.1s remaining, blend back to Idle
jump.auto_transition_to(idle, trigger_time=0.1, crossfade=0.25)

Batch Create from Data

Build state machines from a dictionary of state definitions.

from pyunreal import load
from pyunreal.anim import AnimBlueprint

# Define states as data
STATES = {
    'Idle':  {'anim': '/Game/Anims/Idle',  'default': True},
    'Walk':  {'anim': '/Game/Anims/Walk',  'default': False},
    'Run':   {'anim': '/Game/Anims/Run',   'default': False},
    'Jump':  {'anim': '/Game/Anims/Jump',  'default': False},
}

# Define transitions as (from, to, crossfade) tuples
TRANSITIONS = [
    ('Idle', 'Walk', 0.2),
    ('Walk', 'Idle', 0.2),
    ('Walk', 'Run',  0.15),
    ('Run',  'Walk', 0.15),
    ('Idle', 'Jump', 0.1),
]

# Auto-transitions as (from, to, trigger_time) tuples
AUTO_TRANSITIONS = [
    ('Jump', 'Idle', 0.1),
]

# Build it
skeleton = load('/Game/Characters/Meshes/SK_Mannequin')
abp = AnimBlueprint.create('/Game/AnimBP', 'ABP_DataDriven', skeleton)
loco = abp.add_state_machine('Locomotion')

# Create all states
state_map = {}
for name, config in STATES.items():
    state_map[name] = loco.add_state(
        name,
        animation=load(config['anim']),
        default=config['default']
    )

# Wire transitions
for from_name, to_name, crossfade in TRANSITIONS:
    state_map[from_name].transition_to(state_map[to_name], crossfade=crossfade)

# Wire auto-transitions
for from_name, to_name, trigger_time in AUTO_TRANSITIONS:
    state_map[from_name].auto_transition_to(state_map[to_name], trigger_time=trigger_time)

abp.compile()
print("Created {} states, {} transitions".format(len(STATES), len(TRANSITIONS)))

Inspect an Existing AnimBP

Read the structure of an AnimBP without modifying it.

from pyunreal.anim import AnimBlueprint

abp = AnimBlueprint.load('/Game/AnimBP/ABP_Character')

print("AnimBP: {}".format(abp.name))
print("Skeleton: {}".format(abp.skeleton.get_name()))
print()

for sm in abp.state_machines:
    print("State Machine: {}".format(sm.name))
    for state in sm.states:
        print("  State: {}".format(state.name))

Multiple State Machines

An AnimBP can have multiple state machines for layered animation.

abp = AnimBlueprint.create('/Game/AnimBP', 'ABP_Layered', skeleton)

# Primary locomotion (wired to output)
loco = abp.add_state_machine('Locomotion', connect_to_root=True)
idle = loco.add_state('Idle', animation=idle_anim, default=True)
walk = loco.add_state('Walk', animation=walk_anim)
idle.transition_to(walk, crossfade=0.2)
walk.transition_to(idle, crossfade=0.2)

# Upper body overlay (NOT wired to output -- for manual blending)
upper = abp.add_state_machine('UpperBody', connect_to_root=False)
relaxed = upper.add_state('Relaxed', animation=relaxed_anim, default=True)
aiming  = upper.add_state('Aiming',  animation=aim_anim)
relaxed.transition_to(aiming, crossfade=0.15)
aiming.transition_to(relaxed, crossfade=0.15)

abp.compile()

Tips

Always compile last. Make all your state and transition changes first, then call compile() once at the end. Compiling after each change is wasteful.

Use default=True on exactly one state per state machine. This is the state the machine starts in. If you forget, the state machine will have no entry point and compilation may warn.

Crossfade values are in seconds. 0.2 = 200ms blend. Use shorter values (0.1-0.15) for snappy transitions (walk->run) and longer values (0.25-0.5) for smooth ones (idle->walk).

String names work for targets. idle.transition_to('Walk') works, but using the State object (idle.transition_to(walk)) is safer because it validates that both states are in the same state machine.