shadowengine2d 2.0.0

A comprehensive 2D game engine built in Rust with ECS, rendering, audio, assets, animations, and scene management
Documentation
/*
 * MIT License
 * 
 * Copyright (c) 2025 ShadowEngine2D
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

use crate::{
    window::{Window, WindowConfig, AppHandler, run_window},
    renderer::Renderer,
    entity::EntityManager,
    input::Input,
    time::Time,
    EngineResult
};
use winit::event::WindowEvent;

pub struct Engine {
    pub entities: EntityManager,
    pub input: Input,
    pub time: Time,
    pub renderer: Option<Renderer>,
}

impl Engine {
    pub fn new() -> Self {
        Self {
            entities: EntityManager::new(),
            input: Input::new(),
            time: Time::new(),
            renderer: None,
        }
    }

    pub async fn init_renderer(&mut self, window: &Window) -> EngineResult<()> {
        self.renderer = Some(Renderer::new(window).await?);
        Ok(())
    }

    pub fn update(&mut self, delta_time: f32) {
        self.time.tick();
        self.input.new_frame();
        self.entities.update_physics(delta_time);
    }

    pub fn handle_event(&mut self, event: &WindowEvent) {
        self.input.handle_event(event);
    }

    pub fn render(&mut self) -> EngineResult<()> {
        if let Some(renderer) = &mut self.renderer {
            renderer.begin_frame();
            
            let renderable = self.entities.get_renderable_entities();
            renderer.draw_entities(renderable);
            
            renderer.end_frame()?;
        }
        Ok(())
    }

    pub fn renderer(&self) -> Option<&Renderer> {
        self.renderer.as_ref()
    }

    pub fn renderer_mut(&mut self) -> Option<&mut Renderer> {
        self.renderer.as_mut()
    }
}

pub trait Game {
    fn init(&mut self, engine: &mut Engine) -> EngineResult<()> {
        Ok(())
    }

    fn update(&mut self, engine: &mut Engine, delta_time: f32) -> EngineResult<()>;

    fn render(&mut self, engine: &mut Engine) -> EngineResult<()> {
        engine.render()
    }

    fn on_event(&mut self, engine: &mut Engine, event: &WindowEvent) -> EngineResult<()> {
        Ok(())
    }

    fn cleanup(&mut self, engine: &mut Engine) {}
}

struct GameAppHandler {
    engine: Engine,
    game: Box<dyn Game>,
    initialized: bool,
}

impl GameAppHandler {
    fn new(game: Box<dyn Game>) -> Self {
        Self {
            engine: Engine::new(),
            game,
            initialized: false,
        }
    }
}

impl AppHandler for GameAppHandler {
    fn on_init(&mut self, window: &Window) -> EngineResult<()> {
        pollster::block_on(self.engine.init_renderer(window))?;
        
        self.game.init(&mut self.engine)?;
        self.initialized = true;
        
        Ok(())
    }

    fn on_update(&mut self, _window: &Window, delta_time: f32) -> EngineResult<()> {
        if self.initialized {
            self.engine.update(delta_time);
            self.game.update(&mut self.engine, delta_time)?;
        }
        Ok(())
    }

    fn on_render(&mut self, _window: &Window) -> EngineResult<()> {
        if self.initialized {
            self.game.render(&mut self.engine)?;
        }
        Ok(())
    }

    fn on_window_event(&mut self, _window: &Window, event: &WindowEvent) -> EngineResult<()> {
        if self.initialized {
            self.engine.handle_event(event);
            self.game.on_event(&mut self.engine, event)?;
        }
        Ok(())
    }

    fn on_exit(&mut self) {
        if self.initialized {
            self.game.cleanup(&mut self.engine);
        }
    }
}

pub fn run_game(config: WindowConfig, game: Box<dyn Game>) -> EngineResult<()> {
    let handler = GameAppHandler::new(game);
    run_window(config, Box::new(handler))
}

impl Default for Engine {
    fn default() -> Self {
        Self::new()
    }
}