Files
doloro 2c3b670ab9 Add animation store for pre-made clips
aac.AnimationStore(folder) seeds a clip from an existing .anim asset and
returns a normal ClipBuilder, so pre-made clips work anywhere generated
clips do and can still be edited (looping, keyframes, toggles, blend
shapes). The Unity side clones the asset into the container and applies
the script's changes to the clone, leaving the original untouched.

- ClipData gains optional source; looping becomes Option<bool> so an
  untouched store clip keeps the asset's own looping setting.
- Add rust/examples/animation_store.rhai, a worked store example.
2026-09-18 14:52:02 +01:00

67 lines
2.3 KiB
Plaintext

// An Animator Controller described as Rhai.
//
// cargo run --bin aac-dump -- rust/examples/avatar.rhai
//
// Combine conditions with `when_all([...])`: Rhai's `&&` cannot be overloaded, so
// `when(a > 0.1 && b)` is not valid.
let aac = AnimatorAsCode();
aac.system_name("MyAvatar");
aac.asset_key("AAC_");
let speed = aac.float_param("Speed", 0.0);
let is_sitting = aac.bool_param("IsSitting", false);
let gesture = aac.int_param("Gesture", 0);
let ctrl = aac.new_controller();
let base = ctrl.layer("Base");
let idle = base.state("Idle", 0, 0);
let walk = base.state("Walk", 1, 0);
let run = base.state("Run", 2, 0);
let sit = base.state("Sit", 0, 1);
let idle_clip = aac.clip("idle_anim");
idle_clip.looping(true);
idle_clip.keyframe("Body/Hand", "m_IsActive", 0.0, 1.0);
idle_clip.blend_shape("Body", "Smile", 0.0, 0.0);
idle_clip.blend_shape("Body", "Smile", 1.0, 0.8);
let walk_clip = aac.clip("walk_anim");
walk_clip.looping(true);
walk_clip.toggle("Body/Props", true);
let run_clip = aac.clip("run_anim");
run_clip.looping(true);
run_clip.toggle("Body/Props", false);
// A pre-made clip: it is cloned into the container at generation time, so it can be edited here
// without touching the asset stored in Assets/Doloro/Clips.
let store = aac.AnimationStore("Assets/Doloro/Clips");
let crouch_clip = store.clip("Crouch");
crouch_clip.looping(true);
crouch_clip.toggle("Body/Props", true);
sit.set_clip(crouch_clip);
idle.set_clip(idle_clip);
walk.set_clip(walk_clip);
let locomotion = aac.blend_tree("locomotion");
locomotion.simple_1d(speed);
locomotion.add_motion(walk_clip, 0.0);
locomotion.add_motion(run_clip, 5.0);
run.set_motion(locomotion);
idle.transition_to(walk).when(speed > 0.1).no_exit_time().duration(0.25);
walk.transition_to(run).when(speed > 4.0).no_exit_time().duration(0.25);
run.transition_to(walk).when(speed < 4.0).no_exit_time().duration(0.25);
walk.transition_to(idle).when_all([speed < 0.05, is_sitting == false]).duration(0.25);
base.any_state().transition_to(sit).when(is_sitting == true).no_exit_time().duration(0.2);
let gestures = base.sub_machine("Gestures", 2, 0);
let peace = gestures.state("Peace", 0, 0);
let point = gestures.state("Point", 1, 0);
peace.transition_to(point).when(gesture == 1).duration(0.1);
point.transition_to(peace).when(gesture == 0).duration(0.1);