Skip to main content

shadowengine2d/
entity.rs

1/*
2 * MIT License
3 * 
4 * Copyright (c) 2025 ShadowEngine2D
5 * 
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 * 
13 * The above copyright notice and this permission notice shall be included in all
14 * copies or substantial portions of the Software.
15 * 
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 * SOFTWARE.
23 */
24
25use crate::math::{Position, Size, Color};
26use std::collections::HashMap;
27
28pub type EntityId = u32;
29
30pub trait Component: std::fmt::Debug + 'static {}
31
32#[derive(Debug, Clone, Copy, PartialEq)]
33pub struct Transform {
34    pub position: Position,
35    pub rotation: f32,
36    pub scale: Size,
37}
38
39impl Transform {
40    pub fn new(position: Position) -> Self {
41        Self {
42            position,
43            rotation: 0.0,
44            scale: Size::new(1.0, 1.0),
45        }
46    }
47
48    pub fn with_scale(mut self, scale: Size) -> Self {
49        self.scale = scale;
50        self
51    }
52
53    pub fn with_rotation(mut self, rotation: f32) -> Self {
54        self.rotation = rotation;
55        self
56    }
57}
58
59impl Component for Transform {}
60
61#[derive(Debug, Clone, PartialEq)]
62pub struct Sprite {
63    pub color: Color,
64    pub size: Size,
65    pub visible: bool,
66}
67
68impl Sprite {
69    pub fn new(color: Color, size: Size) -> Self {
70        Self {
71            color,
72            size,
73            visible: true,
74        }
75    }
76
77    pub fn colored_square(color: Color, size: f32) -> Self {
78        Self::new(color, Size::new(size, size))
79    }
80
81    pub fn white_square(size: f32) -> Self {
82        Self::colored_square(Color::WHITE, size)
83    }
84}
85
86impl Component for Sprite {}
87
88#[derive(Debug, Clone, Copy, PartialEq)]
89pub struct Velocity {
90    pub velocity: Position,
91}
92
93impl Velocity {
94    pub fn new(x: f32, y: f32) -> Self {
95        Self {
96            velocity: Position::new(x, y),
97        }
98    }
99
100    pub fn zero() -> Self {
101        Self::new(0.0, 0.0)
102    }
103}
104
105impl Component for Velocity {}
106
107#[derive(Debug)]
108pub struct EntityManager {
109    next_id: EntityId,
110    entities: Vec<EntityId>,
111
112    transforms: HashMap<EntityId, Transform>,
113    sprites: HashMap<EntityId, Sprite>,
114    velocities: HashMap<EntityId, Velocity>,
115}
116
117impl EntityManager {
118    pub fn new() -> Self {
119        Self {
120            next_id: 1,
121            entities: Vec::new(),
122            transforms: HashMap::new(),
123            sprites: HashMap::new(),
124            velocities: HashMap::new(),
125        }
126    }
127
128    pub fn create_entity(&mut self) -> EntityId {
129        let id = self.next_id;
130        self.next_id += 1;
131        self.entities.push(id);
132        id
133    }
134
135    pub fn remove_entity(&mut self, id: EntityId) {
136        self.entities.retain(|&e| e != id);
137        self.transforms.remove(&id);
138        self.sprites.remove(&id);
139        self.velocities.remove(&id);
140    }
141
142    pub fn add_transform(&mut self, id: EntityId, transform: Transform) {
143        self.transforms.insert(id, transform);
144    }
145
146    pub fn add_sprite(&mut self, id: EntityId, sprite: Sprite) {
147        self.sprites.insert(id, sprite);
148    }
149
150    pub fn add_velocity(&mut self, id: EntityId, velocity: Velocity) {
151        self.velocities.insert(id, velocity);
152    }
153
154    pub fn get_transform_mut(&mut self, id: EntityId) -> Option<&mut Transform> {
155        self.transforms.get_mut(&id)
156    }
157
158    pub fn get_transform(&self, id: EntityId) -> Option<&Transform> {
159        self.transforms.get(&id)
160    }
161
162    pub fn get_sprite(&self, id: EntityId) -> Option<&Sprite> {
163        self.sprites.get(&id)
164    }
165
166    pub fn get_velocity_mut(&mut self, id: EntityId) -> Option<&mut Velocity> {
167        self.velocities.get_mut(&id)
168    }
169
170    pub fn get_velocity(&self, id: EntityId) -> Option<&Velocity> {
171        self.velocities.get(&id)
172    }
173
174    pub fn get_renderable_entities(&self) -> Vec<(EntityId, &Transform, &Sprite)> {
175        let mut result = Vec::new();
176        for &id in &self.entities {
177            if let (Some(transform), Some(sprite)) = (self.transforms.get(&id), self.sprites.get(&id)) {
178                if sprite.visible {
179                    result.push((id, transform, sprite));
180                }
181            }
182        }
183        result
184    }
185
186    pub fn update_physics(&mut self, delta_time: f32) {
187        let entity_ids: Vec<EntityId> = self.entities.clone();
188        
189        for id in entity_ids {
190            if let (Some(velocity), Some(transform)) = (
191                self.velocities.get(&id),
192                self.transforms.get_mut(&id)
193            ) {
194                transform.position += velocity.velocity * delta_time;
195            }
196        }
197    }
198
199    pub fn entities(&self) -> &[EntityId] {
200        &self.entities
201    }
202}
203
204impl Default for EntityManager {
205    fn default() -> Self {
206        Self::new()
207    }
208}