// Pre-made animation clips: a store seeds a clip from an `.anim` asset in the project. // // cargo run --bin aac-dump -- rust/examples/animation_store.rhai // // A store clip is a starting point. Requesting `Assets/.../.anim` produces a clip that is // usable anywhere a generated clip is; anything written in the script (looping, keyframes, toggles, // blend shapes) is applied to a clone, so the pre-made asset itself is never modified. A clip the // script does not touch keeps the asset's own settings. // // Combine conditions with `when_all([...])`: Rhai's `&&` cannot be overloaded. let aac = AnimatorAsCode(); aac.system_name("AnimationStore"); aac.asset_key("AAC_STORE_"); let speed = aac.float_param("Speed", 0.0); let vertical = aac.float_param("Vertical", 0.0); let grip = aac.float_param("Grip", 0.0); let crouching = aac.bool_param("Crouching", false); let gesture = aac.int_param("Gesture", 0); let ctrl = aac.new_controller(); let locomotion_layer = ctrl.layer("Locomotion"); let props_layer = ctrl.layer("Props"); // A store per folder. The name is joined as written, so it may contain subfolders, and the `.anim` // extension is optional. let locomotion = aac.AnimationStore("Assets/Doloro/Clips/Locomotion"); let props = aac.AnimationStore("Assets/Doloro/Clips/Props/"); let directions = aac.AnimationStore("Assets/Doloro/Clips/Directions"); let idle_clip = locomotion.clip("Idle"); let walk_clip = locomotion.clip("Walk"); let run_clip = locomotion.clip("Run"); // Requesting the same asset again -- with the extension this time -- returns the same clip, so it is // only declared once and only one clone is generated. let walk_again = locomotion.clip("Walk.anim"); // Untouched: `Idle` is used as authored, with no looping override and no curves added here. let idle = locomotion_layer.state("Idle", 0, 0); idle.set_clip(idle_clip); // Edited: `Walk` loops and toggles a prop on top of whatever the asset already animates. walk_clip.looping(true); walk_clip.toggle("Body/Props/Umbrella", true); let walk = locomotion_layer.state("Walk", 1, 0); walk.set_clip(walk_clip); // Edited: `Run` forces non-looping and blends a smile in over one second. run_clip.looping(false); run_clip.blend_shape("Body", "Smile", 0.0, 0.0); run_clip.blend_shape("Body", "Smile", 1.0, 1.0); let run = locomotion_layer.state("Run", 2, 0); run.set_clip(run_clip); // --- Blend trees over store clips // A 1D tree over three store clips. `idle_clip` is shared with the `Idle` state above. let movement = aac.blend_tree("movement"); movement.simple_1d(speed); movement.add_motion(idle_clip, 0.0); movement.add_motion(walk_clip, 2.0); movement.add_motion(run_clip, 5.0); // A 2D tree over four directional assets. let forward = directions.clip("Forward"); let back = directions.clip("Back"); let left = directions.clip("Left"); let right = directions.clip("Right"); let strafe = aac.blend_tree("strafe"); strafe.freeform_directional_2d(speed, vertical); strafe.add_motion(forward, 0.0, 1.0); strafe.add_motion(back, 0.0, -1.0); strafe.add_motion(left, -1.0, 0.0); strafe.add_motion(right, 1.0, 0.0); // A tree may nest trees declared before it, so the two above blend into one full-body motion. let full_body = aac.blend_tree("full_body"); full_body.simple_1d(speed); full_body.add_motion(movement, 0.0); full_body.add_motion(strafe, 5.0); let move = locomotion_layer.state("Move", 3, 0); move.set_motion(full_body); // A direct tree addresses a store clip by parameter, here a clip nested in a store subfolder. let umbrella = props.clip("Weapons/Umbrella"); umbrella.looping(true); let hold = aac.blend_tree("hold"); hold.direct(); hold.add_motion_direct(umbrella, grip); let holding = props_layer.state("Hold", 0, 0); holding.set_motion(hold); // --- Transitions, any-state, and a sub-state machine idle.transition_to(walk).when(speed > 0.1).no_exit_time().duration(0.2); walk.transition_to(run).when(speed > 4.0).no_exit_time().duration(0.2); run.transition_to(walk).when(speed < 4.0).no_exit_time().duration(0.2); walk.transition_to(idle).when_all([speed < 0.05, crouching == false]).duration(0.2); let sit_clip = locomotion.clip("Sit"); let sit = locomotion_layer.state("Sit", 4, 0); sit.set_clip(sit_clip); locomotion_layer.any_state().transition_to(sit).when(crouching == true).no_exit_time().duration(0.15); let gestures = locomotion_layer.sub_machine("Gestures", 5, 0); let wave = gestures.state("Wave", 0, 0); let point = gestures.state("Point", 1, 0); wave.set_clip(props.clip("Gestures/Wave")); point.set_clip(props.clip("Gestures/Point")); wave.transition_to(point).when(gesture == 1).duration(0.1); point.transition_to(wave).when(gesture == 0).duration(0.1);