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::math::{Position, Size, Color};
use std::collections::HashMap;

pub type EntityId = u32;

pub trait Component: std::fmt::Debug + 'static {}

#[derive(Debug, Clone, Copy, PartialEq)]
pub struct Transform {
    pub position: Position,
    pub rotation: f32,
    pub scale: Size,
}

impl Transform {
    pub fn new(position: Position) -> Self {
        Self {
            position,
            rotation: 0.0,
            scale: Size::new(1.0, 1.0),
        }
    }

    pub fn with_scale(mut self, scale: Size) -> Self {
        self.scale = scale;
        self
    }

    pub fn with_rotation(mut self, rotation: f32) -> Self {
        self.rotation = rotation;
        self
    }
}

impl Component for Transform {}

#[derive(Debug, Clone, PartialEq)]
pub struct Sprite {
    pub color: Color,
    pub size: Size,
    pub visible: bool,
}

impl Sprite {
    pub fn new(color: Color, size: Size) -> Self {
        Self {
            color,
            size,
            visible: true,
        }
    }

    pub fn colored_square(color: Color, size: f32) -> Self {
        Self::new(color, Size::new(size, size))
    }

    pub fn white_square(size: f32) -> Self {
        Self::colored_square(Color::WHITE, size)
    }
}

impl Component for Sprite {}

#[derive(Debug, Clone, Copy, PartialEq)]
pub struct Velocity {
    pub velocity: Position,
}

impl Velocity {
    pub fn new(x: f32, y: f32) -> Self {
        Self {
            velocity: Position::new(x, y),
        }
    }

    pub fn zero() -> Self {
        Self::new(0.0, 0.0)
    }
}

impl Component for Velocity {}

#[derive(Debug)]
pub struct EntityManager {
    next_id: EntityId,
    entities: Vec<EntityId>,

    transforms: HashMap<EntityId, Transform>,
    sprites: HashMap<EntityId, Sprite>,
    velocities: HashMap<EntityId, Velocity>,
}

impl EntityManager {
    pub fn new() -> Self {
        Self {
            next_id: 1,
            entities: Vec::new(),
            transforms: HashMap::new(),
            sprites: HashMap::new(),
            velocities: HashMap::new(),
        }
    }

    pub fn create_entity(&mut self) -> EntityId {
        let id = self.next_id;
        self.next_id += 1;
        self.entities.push(id);
        id
    }

    pub fn remove_entity(&mut self, id: EntityId) {
        self.entities.retain(|&e| e != id);
        self.transforms.remove(&id);
        self.sprites.remove(&id);
        self.velocities.remove(&id);
    }

    pub fn add_transform(&mut self, id: EntityId, transform: Transform) {
        self.transforms.insert(id, transform);
    }

    pub fn add_sprite(&mut self, id: EntityId, sprite: Sprite) {
        self.sprites.insert(id, sprite);
    }

    pub fn add_velocity(&mut self, id: EntityId, velocity: Velocity) {
        self.velocities.insert(id, velocity);
    }

    pub fn get_transform_mut(&mut self, id: EntityId) -> Option<&mut Transform> {
        self.transforms.get_mut(&id)
    }

    pub fn get_transform(&self, id: EntityId) -> Option<&Transform> {
        self.transforms.get(&id)
    }

    pub fn get_sprite(&self, id: EntityId) -> Option<&Sprite> {
        self.sprites.get(&id)
    }

    pub fn get_velocity_mut(&mut self, id: EntityId) -> Option<&mut Velocity> {
        self.velocities.get_mut(&id)
    }

    pub fn get_velocity(&self, id: EntityId) -> Option<&Velocity> {
        self.velocities.get(&id)
    }

    pub fn get_renderable_entities(&self) -> Vec<(EntityId, &Transform, &Sprite)> {
        let mut result = Vec::new();
        for &id in &self.entities {
            if let (Some(transform), Some(sprite)) = (self.transforms.get(&id), self.sprites.get(&id)) {
                if sprite.visible {
                    result.push((id, transform, sprite));
                }
            }
        }
        result
    }

    pub fn update_physics(&mut self, delta_time: f32) {
        let entity_ids: Vec<EntityId> = self.entities.clone();
        
        for id in entity_ids {
            if let (Some(velocity), Some(transform)) = (
                self.velocities.get(&id),
                self.transforms.get_mut(&id)
            ) {
                transform.position += velocity.velocity * delta_time;
            }
        }
    }

    pub fn entities(&self) -> &[EntityId] {
        &self.entities
    }
}

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