1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
// src/components/animation_params.rs
use alloc::vec::Vec;
use crate::ecs::SkinnedMeshHandle;
/// Runtime-only parameter block for one animation graph target.
///
/// `AnimationSystem` publishes one `AnimationParams` per `AnimationGraph` at init,
/// seeded to the graph's declared parameter defaults. Gameplay systems write
/// values into it each frame (matching on `target`); `AnimationSystem` reads
/// it back during its step and evaluates the graph's transitions against the
/// values. Entries are indexed by the graph's parameter declaration order --
/// parameter names are compiled away at build time, so nothing resolves them
/// at runtime.
///
/// Not authored in world files: it has no `args`.
#[derive(Debug, Clone)]
pub struct AnimationParams {
/// The `SkinnedMesh` resource whose graph these parameters drive.
pub target: SkinnedMeshHandle,
/// One value per graph parameter, in declaration order.
pub values: Vec<f32>,
}
impl AnimationParams {
/// A parameter block for `target`, seeded with the graph's defaults.
pub fn new(target: SkinnedMeshHandle, values: Vec<f32>) -> Self {
Self { target, values }
}
/// Set one parameter by index; out-of-range writes are ignored so a
/// stale writer cannot grow the block.
pub fn set(&mut self, index: usize, value: f32) {
if let Some(slot) = self.values.get_mut(index) {
*slot = value;
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use alloc::vec;
#[test]
fn set_writes_in_range_and_ignores_out_of_range() {
let mut p = AnimationParams::new(SkinnedMeshHandle(1), vec![0.0, 1.0]);
p.set(0, 3.5);
assert_eq!(p.values, vec![3.5, 1.0]);
p.set(5, 9.0);
assert_eq!(p.values.len(), 2, "out-of-range write must not grow");
}
}