Skip to main content

euv_engine/entity/
impl.rs

1use super::*;
2
3/// Implements static factory and ID generation methods for `Entity`.
4impl Entity {
5    /// Generates the next unique entity ID using a global atomic counter.
6    ///
7    /// # Returns
8    ///
9    /// - `u64` - The next unique ID.
10    pub fn generate_id() -> u64 {
11        NEXT_ENTITY_ID.fetch_add(1, Ordering::Relaxed)
12    }
13
14    /// Creates a new entity with the given name and a default identity transform.
15    ///
16    /// Creates a new entity with the given name and a default identity transform.
17    ///
18    /// # Arguments
19    ///
20    /// - `N` - The name of the entity.
21    ///
22    /// # Returns
23    ///
24    /// - `Entity` - The newly created entity.
25    pub fn create<N>(name: N) -> Entity
26    where
27        N: AsRef<str>,
28    {
29        Entity::new(
30            Self::generate_id(),
31            name.as_ref().to_string(),
32            Transform2D::identity(),
33            true,
34            Vec::new(),
35            Vec::new(),
36        )
37    }
38
39    /// Creates a new entity at the specified position with a default name.
40    ///
41    /// # Arguments
42    ///
43    /// - `Vector2D` - The initial position.
44    ///
45    /// # Returns
46    ///
47    /// - `Entity` - The newly created entity.
48    pub fn create_at(position: Vector2D) -> Entity {
49        let mut entity: Entity = Self::create(DEFAULT_ENTITY_NAME);
50        entity.get_mut_transform().set_position(position);
51        entity
52    }
53}
54
55/// Implements pooled entity lifecycle methods for `Entity`.
56///
57/// These pair [`ObjectPool`] with `Entity` so a spawn/despawn cycle reuses
58/// the same allocation instead of dropping the entity and building a new one.
59/// A recycled entity is reset to a clean state and given a **fresh** id, so a
60/// stale reference held elsewhere can never alias a live entity.
61impl Entity {
62    /// Checks an entity out of the pool, creating one if the pool is empty.
63    ///
64    /// # Arguments
65    ///
66    /// - `N` - The name given to the entity, anything that converts into a
67    ///   `String`.
68    /// - `&mut ObjectPool<Entity>` - The pool the entity is checked out from.
69    ///
70    /// # Returns
71    ///
72    /// - `Entity` - A ready-to-use entity carrying the requested name.
73    pub fn create_pooled<N>(name: N, pool: &mut ObjectPool<Entity>) -> Self
74    where
75        N: Into<String>,
76    {
77        Self::take_from(pool, name.into(), Transform2D::identity())
78    }
79
80    /// Checks an entity out of the pool and places it at `position`.
81    ///
82    /// The position is applied after the recycle reset, so a recycled entity
83    /// never keeps the position it was last drawn at.
84    ///
85    /// # Arguments
86    ///
87    /// - `Vector2D` - Where the entity should sit.
88    /// - `&mut ObjectPool<Entity>` - The pool the entity is checked out from.
89    ///
90    /// # Returns
91    ///
92    /// - `Entity` - A ready-to-use entity at the requested position.
93    pub fn create_pooled_at(position: Vector2D, pool: &mut ObjectPool<Entity>) -> Self {
94        let mut transform: Transform2D = Transform2D::identity();
95        transform.set_position(position);
96        Self::take_from(pool, String::from(DEFAULT_ENTITY_NAME), transform)
97    }
98
99    /// Builds `count` entities into the pool's free list.
100    ///
101    /// Only the shortfall is built, so prewarming an already-warm pool costs
102    /// nothing and a spawn burst does not grow the pool mid-frame.
103    ///
104    /// # Arguments
105    ///
106    /// - `usize` - How many free entities the pool should hold.
107    /// - `&mut ObjectPool<Entity>` - The pool to prewarm.
108    ///
109    /// # Returns
110    ///
111    /// - `usize` - The number of entities that were built.
112    pub fn prewarm_pool(count: usize, pool: &mut ObjectPool<Entity>) -> usize {
113        pool.prewarm(count, || Self::create(DEFAULT_ENTITY_NAME))
114    }
115
116    /// Resets an entity and hands it back to the pool.
117    ///
118    /// Components, tags and transform are cleared before the entity is
119    /// released so a recycled entity never inherits stale state. A fresh id
120    /// is assigned on the next checkout, so the released entity's id is not
121    /// reused.
122    ///
123    /// # Arguments
124    ///
125    /// - `&mut Entity` - The entity to recycle.
126    /// - `&mut ObjectPool<Entity>` - The pool to return it to.
127    pub fn release_to_pool(entity: &mut Entity, pool: &mut ObjectPool<Entity>) {
128        // The caller's slot is handed a fresh entity so the reference it keeps
129        // is never left aliasing a pooled one, then the released entity is
130        // scrubbed before it goes back: a recycled entity must not inherit the
131        // components, tags or transform it happened to hold on the way out.
132        let mut released: Entity = std::mem::replace(entity, Self::create(DEFAULT_ENTITY_NAME));
133        released.get_mut_components().clear();
134        released.get_mut_tags().clear();
135        *released.get_mut_transform() = Transform2D::identity();
136        pool.release(released);
137    }
138
139    /// Checks out an entity and applies the caller's name and transform.
140    ///
141    /// # Arguments
142    ///
143    /// - `&mut ObjectPool<Entity>` - The pool to check out from.
144    /// - `String` - The name to apply.
145    /// - `Transform2D` - The transform to apply.
146    ///
147    /// # Returns
148    ///
149    /// - `Entity` - The reset, freshly-identified entity.
150    fn take_from(pool: &mut ObjectPool<Entity>, name: String, transform: Transform2D) -> Self {
151        let mut entity: Entity = match pool.acquire() {
152            // `acquire` counted the checkout itself, so a recycled entity only
153            // needs its identity and state refreshed.
154            Some(recycled) => recycled,
155            None => {
156                // Nothing was checked out, so the checkout `acquire` skipped has
157                // to be counted here or `len` under-reports the new entity.
158                pool.set_active(pool.get_active() + 1);
159                Self::create(DEFAULT_ENTITY_NAME)
160            }
161        };
162        entity.set_id(Self::generate_id());
163        entity.set_name(name);
164        *entity.get_mut_transform() = transform;
165        entity.set_active(true);
166        entity
167    }
168}
169
170/// Implements lifecycle and component management methods for `Entity`.
171impl Entity {
172    /// Adds a component to this entity and calls its `on_start` lifecycle method.
173    ///
174    /// # Arguments
175    ///
176    /// - `ComponentRc` - The component to add.
177    pub fn add_component(&mut self, component: ComponentRc) {
178        component.get_mut().on_start();
179        self.get_mut_components().push(component);
180    }
181
182    /// Removes the first component matching the given name.
183    ///
184    /// # Arguments
185    ///
186    /// - `N` - The component name to match.
187    ///
188    /// # Returns
189    ///
190    /// - `Option<ComponentRc>` - The removed component, if found.
191    pub fn remove_component_by_name<N>(&mut self, name: N) -> Option<ComponentRc>
192    where
193        N: AsRef<str>,
194    {
195        let target: &str = name.as_ref();
196        let position: Option<usize> = self
197            .get_components()
198            .iter()
199            .position(|component: &ComponentRc| component.get().name() == target);
200        let index: usize = position?;
201        let removed: ComponentRc = self.get_mut_components().remove(index);
202        removed.get_mut().on_destroy();
203        Some(removed)
204    }
205
206    /// Returns the first component matching the given name.
207    ///
208    /// # Arguments
209    ///
210    /// - `N` - The component name to match.
211    ///
212    /// # Returns
213    ///
214    /// - `Option<ComponentRc>` - The matching component, if found.
215    pub fn get_component_by_name<N>(&self, name: N) -> Option<ComponentRc>
216    where
217        N: AsRef<str>,
218    {
219        let target: &str = name.as_ref();
220        self.get_components()
221            .iter()
222            .find(|component: &&ComponentRc| component.get().name() == target)
223            .cloned()
224    }
225
226    /// Calls `on_update` on all active components.
227    ///
228    /// # Arguments
229    ///
230    /// - `f64` - The delta time in seconds.
231    pub fn update(&mut self, delta_time: f64) {
232        if !self.get_active() {
233            return;
234        }
235        for component in self.get_components() {
236            component.get_mut().on_update(delta_time);
237        }
238    }
239
240    /// Calls `on_render` on all active components, recording into the draw list.
241    ///
242    /// # Arguments
243    ///
244    /// - `&mut DrawList` - The draw list to record commands into.
245    pub fn render(&self, draw_list: &mut DrawList) {
246        if !self.get_active() {
247            return;
248        }
249        let transform: Transform2D = self.get_transform();
250        for component in self.get_components() {
251            component.get_mut().on_render(draw_list, &transform);
252        }
253    }
254
255    /// Calls `on_destroy` on all components and clears the component list.
256    pub fn destroy(&mut self) {
257        for component in self.get_components() {
258            component.get_mut().on_destroy();
259        }
260        self.get_mut_components().clear();
261    }
262
263    /// Adds a tag string to this entity.
264    ///
265    /// # Arguments
266    ///
267    /// - `String` - The tag to add.
268    pub fn add_tag(&mut self, tag: String) {
269        if !self.get_tags().contains(&tag) {
270            self.get_mut_tags().push(tag);
271        }
272    }
273
274    /// Tests whether this entity has the given tag.
275    ///
276    /// # Arguments
277    ///
278    /// - `T` - The tag to check.
279    ///
280    /// # Returns
281    ///
282    /// - `bool` - True if the tag is present.
283    pub fn has_tag<T>(&self, tag: T) -> bool
284    where
285        T: AsRef<str>,
286    {
287        let target: &str = tag.as_ref();
288        self.get_tags().iter().any(|t: &String| t == target)
289    }
290}
291
292/// Forwards `Entity::update` through the [`Updatable`] trait so that collections
293/// of heterogeneous updateable objects can be driven by the scheduler.
294///
295/// The inherent [`Entity::update`] method is the canonical implementation;
296/// this impl exists purely for trait dispatch. The inherent call resolves
297/// first when both are in scope, so there is no recursion.
298impl Updatable for Entity {
299    /// Advances the simulation by `delta_time` seconds.
300    ///
301    /// # Arguments
302    ///
303    /// - `f64` - Seconds elapsed since the previous update.
304    fn update(&mut self, delta_time: f64) {
305        Entity::update(self, delta_time);
306    }
307}
308
309/// Implements event subscription, emission, and management for `EventBus`.
310impl EventBus {
311    /// Creates a new empty event bus.
312    ///
313    /// # Returns
314    ///
315    /// - `EventBus` - The new event bus.
316    pub fn create() -> EventBus {
317        EventBus::new()
318    }
319
320    /// Subscribes a handler to the named event channel.
321    ///
322    /// # Arguments
323    ///
324    /// - `String` - The event name to subscribe to.
325    /// - `EventHandler` - The handler closure to call when the event is emitted.
326    pub fn subscribe(&mut self, event_name: String, handler: EventHandler) {
327        self.get_mut_handlers()
328            .entry(event_name)
329            .or_default()
330            .push(handler);
331    }
332
333    /// Emits an event to all handlers subscribed to the matching channel.
334    ///
335    /// The event name is derived from the `EntityEvent` variant.
336    ///
337    /// # Arguments
338    ///
339    /// - `&EntityEvent` - The event to emit.
340    pub fn emit(&self, event: &EntityEvent) {
341        let event_name: &str = Self::event_name(event);
342        if let Some(handlers) = self.get_handlers().get(event_name) {
343            for handler in handlers {
344                handler(event);
345            }
346        }
347    }
348
349    /// Removes all handlers for the named event channel.
350    ///
351    /// # Arguments
352    ///
353    /// - `E` - The event name to clear.
354    pub fn unsubscribe_all<E>(&mut self, event_name: E)
355    where
356        E: AsRef<str>,
357    {
358        self.get_mut_handlers().remove(event_name.as_ref());
359    }
360
361    /// Returns the number of handlers registered for the named event.
362    ///
363    /// # Arguments
364    ///
365    /// - `E` - The event name.
366    ///
367    /// # Returns
368    ///
369    /// - `usize` - The handler count.
370    pub fn handler_count<E>(&self, event_name: E) -> usize
371    where
372        E: AsRef<str>,
373    {
374        self.get_handlers()
375            .get(event_name.as_ref())
376            .map(|handlers: &Vec<EventHandler>| handlers.len())
377            .unwrap_or_default()
378    }
379
380    /// Derives the event channel name from an `EntityEvent` variant.
381    ///
382    /// # Arguments
383    ///
384    /// - `&EntityEvent` - The event.
385    ///
386    /// # Returns
387    ///
388    /// - `&str` - The channel name (borrowed — no allocation per emit;
389    ///   the `Custom` variant borrows its `name` field).
390    fn event_name(event: &EntityEvent) -> &str {
391        match event {
392            EntityEvent::Collision { .. } => ENTITY_EVENT_NAME_COLLISION,
393            EntityEvent::TriggerEnter { .. } => ENTITY_EVENT_NAME_TRIGGER_ENTER,
394            EntityEvent::TriggerExit { .. } => ENTITY_EVENT_NAME_TRIGGER_EXIT,
395            EntityEvent::Spawn => ENTITY_EVENT_NAME_SPAWN,
396            EntityEvent::Destroy => ENTITY_EVENT_NAME_DESTROY,
397            EntityEvent::Custom { name, .. } => name.as_str(),
398        }
399    }
400}
401
402/// Implements `Default` for `EventBus` as a new empty bus.
403impl Default for EventBus {
404    /// Constructs a default [`EventBus`] value.
405    ///
406    /// # Returns
407    ///
408    /// - `EventBus` - A default-constructed instance with the documented initial state.
409    fn default() -> EventBus {
410        EventBus::create()
411    }
412}