shadowengine2d/
app.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::{
26    engine::{Engine, Game, run_game},
27    window::WindowConfig,
28    entity::{EntityManager, Transform, Sprite, Velocity},
29    math::{Position, Size, Color},
30    resources::Resources,
31    systems::{System, SystemSet},
32    EngineResult,
33};
34use std::any::Any;
35use winit::event::WindowEvent;
36
37pub struct App {
38    resources: Resources,
39    startup_systems: Vec<Box<dyn System>>,
40    update_systems: Vec<Box<dyn System>>,
41    render_systems: Vec<Box<dyn System>>,
42    window_config: WindowConfig,
43}
44
45impl App {
46    pub fn new() -> AppBuilder {
47        AppBuilder::new()
48    }
49
50    pub fn run(self) -> EngineResult<()> {
51        let game = ShadowGame {
52            app: self,
53            initialized: false,
54        };
55        run_game(game.app.window_config.clone(), Box::new(game))
56    }
57}
58
59pub struct AppBuilder {
60    resources: Resources,
61    startup_systems: Vec<Box<dyn System>>,
62    update_systems: Vec<Box<dyn System>>,
63    render_systems: Vec<Box<dyn System>>,
64    window_config: WindowConfig,
65}
66
67impl AppBuilder {
68    pub fn new() -> Self {
69        Self {
70            resources: Resources::new(),
71            startup_systems: Vec::new(),
72            update_systems: Vec::new(),
73            render_systems: Vec::new(),
74            window_config: WindowConfig::default(),
75        }
76    }
77
78    pub fn set_window(mut self, config: WindowConfig) -> Self {
79        self.window_config = config;
80        self
81    }
82
83    pub fn insert_resource<T: 'static>(mut self, resource: T) -> Self {
84        self.resources.insert(resource);
85        self
86    }
87
88    pub fn add_startup_system<T: System + 'static>(mut self, system: T) -> Self {
89        self.startup_systems.push(Box::new(system));
90        self
91    }
92
93    pub fn add_system<T: System + 'static>(mut self, system: T) -> Self {
94        self.update_systems.push(Box::new(system));
95        self
96    }
97
98    pub fn add_system_set(mut self, system_set: SystemSet) -> Self {
99        match system_set {
100            SystemSet::Startup(systems) => {
101                self.startup_systems.extend(systems);
102            }
103            SystemSet::Update(systems) => {
104                self.update_systems.extend(systems);
105            }
106            SystemSet::Render(systems) => {
107                self.render_systems.extend(systems);
108            }
109        }
110        self
111    }
112
113    pub fn build(self) -> App {
114        App {
115            resources: self.resources,
116            startup_systems: self.startup_systems,
117            update_systems: self.update_systems,
118            render_systems: self.render_systems,
119            window_config: self.window_config,
120        }
121    }
122}
123
124struct ShadowGame {
125    app: App,
126    initialized: bool,
127}
128
129impl Game for ShadowGame {
130    fn init(&mut self, engine: &mut Engine) -> EngineResult<()> {
131
132        for system in &mut self.app.startup_systems {
133            system.run(engine, &mut self.app.resources)?;
134        }
135        self.initialized = true;
136        Ok(())
137    }
138
139    fn update(&mut self, engine: &mut Engine, delta_time: f32) -> EngineResult<()> {
140        if !self.initialized {
141            return Ok(());
142        }
143
144        if let Some(time) = self.app.resources.get_mut::<TimeResource>() {
145            time.update(delta_time);
146        }
147
148        for system in &mut self.app.update_systems {
149            system.run(engine, &mut self.app.resources)?;
150        }
151
152        Ok(())
153    }
154
155    fn render(&mut self, engine: &mut Engine) -> EngineResult<()> {
156        if !self.initialized {
157            return Ok(());
158        }
159
160        for system in &mut self.app.render_systems {
161            system.run(engine, &mut self.app.resources)?;
162        }
163
164        engine.render()?;
165        Ok(())
166    }
167
168    fn on_event(&mut self, engine: &mut Engine, event: &WindowEvent) -> EngineResult<()> {
169
170        if let Some(input) = self.app.resources.get_mut::<InputResource>() {
171            input.handle_event(event);
172        }
173        Ok(())
174    }
175}
176
177#[derive(Debug)]
178pub struct TimeResource {
179    pub delta_time: f32,
180    pub total_time: f32,
181}
182
183impl TimeResource {
184    pub fn new() -> Self {
185        Self {
186            delta_time: 0.0,
187            total_time: 0.0,
188        }
189    }
190
191    pub fn update(&mut self, delta_time: f32) {
192        self.delta_time = delta_time;
193        self.total_time += delta_time;
194    }
195}
196
197#[derive(Debug)]
198pub struct InputResource {
199
200}
201
202impl InputResource {
203    pub fn new() -> Self {
204        Self {}
205    }
206
207    pub fn handle_event(&mut self, _event: &WindowEvent) {
208
209    }
210}
211
212impl Default for AppBuilder {
213    fn default() -> Self {
214        Self::new()
215    }
216}