mittens_engine/engine/ecs/component/
animation.rs1use super::{Component, ComponentRef};
2use crate::engine::ecs::ComponentId;
3
4#[derive(Debug, Clone, Copy, PartialEq, Eq)]
5pub enum AnimationState {
6 Playing,
7 Looping,
8 Paused,
9}
10
11#[derive(Debug, Clone, Copy, PartialEq, Eq)]
22pub enum ResolveTargetsMode {
23 OnAttach,
24 OnPlay,
25}
26
27impl Default for ResolveTargetsMode {
28 fn default() -> Self {
29 Self::OnAttach
30 }
31}
32
33#[derive(Debug, Clone)]
34pub struct AnimationComponent {
35 pub state: AnimationState,
36 pub resolve_targets: ResolveTargetsMode,
37 pub length_beats: Option<f64>,
41 pub scope_source: Option<ComponentRef>,
42 pub resolved_scope: Option<ComponentId>,
43
44 component: Option<ComponentId>,
45}
46
47impl AnimationComponent {
48 pub fn new() -> Self {
49 Self {
50 state: AnimationState::Looping,
51 resolve_targets: ResolveTargetsMode::default(),
52 length_beats: None,
53 scope_source: None,
54 resolved_scope: None,
55 component: None,
56 }
57 }
58
59 pub fn with_state(mut self, state: AnimationState) -> Self {
60 self.state = state;
61 self
62 }
63
64 pub fn with_resolve_targets(mut self, mode: ResolveTargetsMode) -> Self {
65 self.resolve_targets = mode;
66 self
67 }
68
69 pub fn with_length_beats(mut self, beats: f64) -> Self {
70 self.length_beats = Some(beats);
71 self
72 }
73
74 pub fn with_scope_source(mut self, source: ComponentRef) -> Self {
75 self.scope_source = Some(source);
76 self.resolved_scope = None;
77 self
78 }
79
80 pub fn with_playing(self, playing: bool) -> Self {
82 self.with_state(if playing {
83 AnimationState::Looping
84 } else {
85 AnimationState::Paused
86 })
87 }
88
89 pub fn id(&self) -> Option<ComponentId> {
90 self.component
91 }
92}
93
94impl Default for AnimationComponent {
95 fn default() -> Self {
96 Self::new()
97 }
98}
99
100impl Component for AnimationComponent {
101 fn set_id(&mut self, component: ComponentId) {
102 self.component = Some(component);
103 }
104
105 fn name(&self) -> &'static str {
106 "animation"
107 }
108
109 fn init(&mut self, emit: &mut dyn crate::engine::ecs::SignalEmitter, component: ComponentId) {
110 emit.push_intent_now(
111 component,
112 crate::engine::ecs::IntentValue::RegisterAnimation {
113 component_ids: vec![component],
114 },
115 );
116 }
117
118 fn as_any(&self) -> &dyn std::any::Any {
119 self
120 }
121
122 fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
123 self
124 }
125
126 fn to_mms_ast(
127 &self,
128 _world: &crate::engine::ecs::World,
129 ) -> crate::scripting::ast::ComponentExpression {
130 use crate::engine::ecs::component::ce_helpers::*;
131 use crate::scripting::ast::Expression;
132
133 fn target_expr(t: &ComponentRef) -> Expression {
134 match t {
135 ComponentRef::Guid(u) => Expression::String(format!("@uuid:{u}")),
136 ComponentRef::Query(s) => Expression::String(s.clone()),
137 }
138 }
139
140 let ctor = match self.state {
141 AnimationState::Playing => "playing",
142 AnimationState::Looping => "looping",
143 AnimationState::Paused => "paused",
144 };
145 let mut ce = ce_call("Animation", ctor, vec![]);
146 if self.resolve_targets != ResolveTargetsMode::default() {
149 let mode = match self.resolve_targets {
150 ResolveTargetsMode::OnAttach => "on_attach",
151 ResolveTargetsMode::OnPlay => "on_play",
152 };
153 ce = ce.with_call("resolve_targets", vec![s(mode)]);
154 }
155 if let Some(n) = self.length_beats {
156 ce = ce.with_call("length", vec![num(n)]);
157 }
158 if let Some(source) = &self.scope_source {
159 ce = ce.with_call("scope", vec![target_expr(source)]);
160 }
161 ce
162 }
163}