Skip to content

Latest commit

Β 

History

History
302 lines (223 loc) Β· 7.65 KB

File metadata and controls

302 lines (223 loc) Β· 7.65 KB

Animation

Page Map

Header Link
Purpose Purpose
Use Cases Use Cases
Example Example
Reference Reference

Purpose

Perro animation has two resource files and two scene nodes that together let you play authored motion instead of scripting transforms by hand. Use a single .panim clip through an AnimationPlayer for one-off motion (a door, a chest, a taunt), or mix many clips through a .panimtree graph and an AnimationTree node when a character needs speed blends and aim layers. This page is the map that tells you which of the four pieces to reach for.

Use Cases

  • One-shot prop or UI motion: AnimationPlayer with a single .panim and playback = once for a door swing or reward popup.
  • Looping ambient motion: AnimationPlayer with playback = loop for a spinning fan or bobbing pickup.
  • Full character locomotion: AnimationTree + .panimtree blending Idle/Run/Aim slots, driven live with anim_tree_set_weight!.
  • Rebinding one clip to different rigs: reuse the same .panim object name (@Hero) but point bindings at a different scene node per slot entry.
  • Scripted playback control: anim_player_play!, anim_player_seek_frame!, and anim_tree_play_slot! start, scrub, and retime clips from gameplay code.

Choice Guide

Use AnimationPlayer for one clip timeline on known targets. Use AnimationTree when gameplay continuously blends slots/layers. Keep gameplay truth in script state: animation events may notify contact frames, but a visual timeline should not become the sole owner of health, inventory, or win state.

Example

A single looping clip driven by an AnimationPlayer:

[PlayerRoot]
    [Node3D/]
[/PlayerRoot]

[IdlePlayer]
    [AnimationPlayer]
        animation = "res://animations/idle.panim"
        bindings = { Hero = @PlayerRoot }
        playback = loop
    [/AnimationPlayer]
[/IdlePlayer]
let clip = animation_load!(res, "res://animations/idle.panim");
let _ = anim_player_set_clip!(ctx, player, clip);
let _ = anim_player_bind!(ctx, player, "Hero", hero);
let _ = anim_player_seek_frame!(ctx, player, 0);
let _ = anim_player_play!(ctx, player);

For the multi-clip blend path, see the AnimationTree section below and .panimtree Format.

Reference

Animation

Perro animation has two resource files and two scene nodes.

Sigils:

  • $ => value var define/use.

  • scenes: @NodeKey => scene node ref.

  • .panim: [Objects] declares bare names (Hero = Node3D), frame blocks ref them as @Hero.

  • .panimtree: graph blocks declare bare names ([MoveBlend]), graph inputs ref graph nodes or slots as @MoveBlend, @Idle.

  • scene AnimationPlayer / AnimationTree bindings map object names to scene node refs with @NodeKey.

  • .panim: one animation clip.

  • .panimtree: one animation graph.

  • AnimationPlayer: plays one .panim.

  • AnimationTree: mixes many .panim clips through one .panimtree.

.panim

Use .panim for raw clip data.

It declares animation object names in [Objects].

Those names are clip-local track keys.

They are not scene node names.

[Animation]
name = "Idle"
fps = 30
[/Animation]

[Objects]
Hero = Node3D
[/Objects]

[Frame0]
@Hero {
    position = (0, 0, 0)
}
[/Frame0]

@Hero is the animation object.

Scene binding maps Hero to a real scene node.

Full format: .panim Format.

AnimationPlayer

Use AnimationPlayer when one clip drives one set of bindings.

[PlayerRoot]
    [Node3D/]
[/PlayerRoot]

[IdlePlayer]
    [AnimationPlayer]
        animation = "res://animations/idle.panim"
        bindings = { Hero = @PlayerRoot }
        speed = 1.0
        paused = false
        playback = loop
    [/AnimationPlayer]
[/IdlePlayer]

animation loads one .panim.

bindings maps .panim [Objects] names to scene nodes.

Binding values must use @NodeKey (or a var such as $root that resolves to one).

Runtime API:

let clip = animation_load!(res, "res://animations/idle.panim");
let _ = anim_player_set_clip!(ctx, player, clip);
let _ = anim_player_bind!(ctx, player, "Hero", hero);
let _ = anim_player_seek_frame!(ctx, player, 0);
let _ = anim_player_play!(ctx, player);

Runtime docs: Animations Module.

.panimtree

Use .panimtree for static graph shape.

It owns:

  • slot names
  • graph node keys
  • Blend, Add, Invert
  • default weights
  • masks
  • required Output

It does not own actual scene node bindings.

It does not own runtime playback state.

[AnimationTree]
name = "PlayerLocomotion"
[/AnimationTree]

[AnimationSlots]
Idle
Run
Aim
[/AnimationSlots]

[MoveBlend]
    [Blend]
        inputs = [@Idle, @Run]
        weights = [1.0, 0.0]
        mask = { objects=[Hero], fields=[position, rotation, scale] }
    [/Blend]
[/MoveBlend]

[AimAdd]
    [Add]
        base = @MoveBlend
        inputs = [@Aim]
        weights = [0.75]
        mask = { objects=[Hero], bones=[Spine, Chest] }
    [/Add]
[/AimAdd]

[Output]
    input = @AimAdd
[/Output]

Blend mixes any number of inputs.

[MoveBlend]
    [Blend]
        inputs = [@Idle, @Walk, @Run]
        weights = [0.0, 0.35, 0.65]
    [/Blend]
[/MoveBlend]

Add applies additive deltas to a base.

[UpperBodyAdd]
    [Add]
        base = @MoveBlend
        inputs = [@Aim, @Recoil, @Breath]
        weights = [1.0, 0.45, 0.2]
    [/Add]
[/UpperBodyAdd]

Invert flips a delta for subtractive layers.

[AimSubtract]
    [Invert]
        input = @Aim
    [/Invert]
[/AimSubtract]

Output is required.

Full format: .panimtree Format.

AnimationTree

Use AnimationTree when many clips combine into one final pose.

The scene node supplies:

  • tree: loaded .panimtree
  • animations: clips bound by slot order
  • per-slot clip object bindings
  • speed
  • paused
[Hero]
    [Node3D/]
[/Hero]

[HeroAnimTree]
    [AnimationTree]
        tree = "res://animations/player.panimtree"
        animations = [
            { animation = "res://animations/idle.panim", bindings = { Hero = @PlayerRoot }, playback = loop, speed = 1.0, paused = false },
            { animation = "res://animations/run.panim", bindings = { Hero = @PlayerRoot }, playback = loop, speed = 1.0, paused = false },
            { animation = "res://animations/aim.panim", bindings = { Hero = @PlayerRoot }, playback = boomerang, speed = 1.0, paused = false },
        ]
        speed = 1.0
        paused = false
    [/AnimationTree]
[/HeroAnimTree]

Slot mapping comes from .panimtree [AnimationSlots].

If [AnimationSlots] is Idle, Run, Aim, then:

  • animations[0] feeds Idle
  • animations[1] feeds Run
  • animations[2] feeds Aim

Each slot entry can bind the same .panim object name to a different scene node.

Each slot entry can set playback, speed, and paused.

playback accepts once, loop, or boomerang.

Slot speed multiplies tree speed.

Runtime API:

let run = animation_load!(res, "res://animations/run.panim");
let _ = anim_tree_set_clip!(ctx, tree, "Run", run);
let _ = anim_tree_play_slot!(ctx, tree, "Run");
let _ = anim_tree_seek_slot_frame!(ctx, tree, "Run", 0);
let _ = anim_tree_set_slot_speed!(ctx, tree, "Run", 1.25);
let _ = anim_tree_set_slot_playback!(ctx, tree, "Run", AnimationPlaybackType::Loop);
let _ = anim_tree_set_weight!(ctx, tree, "MoveBlend", "Run", 1.0);
let _ = anim_tree_pause!(ctx, tree, false);

Slots accept name or index.

Node and input names omit @ in Rust API, that's just for .panim and .panimtree files

Bad refs return false.

Runtime node trees: Node Collections.