nya-ecs 0.2.0

nya entity component system
Documentation
use indexmap::{IndexMap, IndexSet};

use crate::{
    Entity,
    component::{Bundle, Component, ComponentBox, ComponentKey},
};

/// The [World] contains all entities and components, it is queryable using [Queryable](crate::query::Queryable)
pub struct World {
    pub(crate) entities: IndexSet<Entity>,
    pub(crate) components: IndexMap<Entity, IndexMap<ComponentKey, ComponentBox>>,
    pub(crate) resources: IndexMap<ComponentKey, ComponentBox>,
}

impl World {
    /// Create a new [World]
    pub fn new() -> Self {
        let entities = 100;
        Self {
            entities: IndexSet::with_capacity(entities),
            components: IndexMap::with_capacity(entities),
            resources: IndexMap::with_capacity(5),
        }
    }

    /// Create an entity
    pub fn spawn(&mut self) -> Entity {
        let id = self.entities.len();
        self.entities.insert(id);
        self.components.insert(id, IndexMap::with_capacity(1000));
        id
    }

    /// Destroy an entity
    pub fn despawn(&mut self, entity: Entity) {
        self.entities.swap_remove(&entity);
        self.components.swap_remove(&entity);
    }

    /// Add a component to an entity
    pub fn add<B: Bundle>(&mut self, entity: Entity, bundle: B) {
        let boxes = bundle.into_boxes();

        for (key, boxed) in boxes {
            if !self.has_key(entity, &key) {
                self.components
                    .entry(entity)
                    .or_default()
                    .insert(key, boxed);
            }
        }
    }

    /// Check if `entity` has component `C`
    pub fn has<C: Component>(&self, entity: Entity) -> bool {
        self.has_key(entity, &ComponentKey::of::<C>())
    }

    /// Same as [Self::has] but uses a [ComponentKey]
    pub fn has_key(&self, entity: Entity, key: &ComponentKey) -> bool {
        let Some(components) = self.components.get(&entity) else {
            return false;
        };
        components.contains_key(key)
    }

    /// Get a reference to the component of an entity
    pub fn get<C: Component>(&self, entity: Entity) -> Option<&C> {
        let c = self
            .components
            .get(&entity)?
            .get(&ComponentKey::of::<C>())?;
        c.downcast_ref::<C>()
    }

    /// Get a mutable reference to the component of an entity
    pub fn get_mut<C: Component>(&mut self, entity: Entity) -> Option<&mut C> {
        let c = self
            .components
            .get_mut(&entity)?
            .get_mut(&ComponentKey::of::<C>())?;
        c.downcast_mut::<C>()
    }

    /// Remove a component from an entity
    pub fn del<C: Component>(&mut self, entity: Entity) -> Option<Box<C>> {
        let c = self
            .components
            .get_mut(&entity)?
            .swap_remove(&ComponentKey::of::<C>())?;
        c.downcast().ok()
    }

    /// Add a global resource
    ///
    /// A resource is like a component but it behaves like a singleton.
    /// There can only be one type of a resource at a time.
    ///
    /// Anything that implements [Component] can be used as a resource.
    ///
    /// You cannot overwrite a resource, if you must, delete one using [Self::delete_res]
    pub fn add_res<C: Component>(&mut self, resource: C) {
        if !self.has_res::<C>() {
            self.resources
                .insert(ComponentKey::of::<C>(), Box::new(resource));
        }
    }

    /// Similar to [Self::has] but for resources
    pub fn has_res<C: Component>(&self) -> bool {
        self.has_res_key(&ComponentKey::of::<C>())
    }

    /// Same as [Self::has_res] but uses a [ComponentKey]
    pub fn has_res_key(&self, key: &ComponentKey) -> bool {
        self.resources.contains_key(key)
    }

    /// Get a reference to a global resource
    ///
    /// For more on resources see [Self::add_res]
    pub fn get_res<C: Component>(&self) -> Option<&C> {
        self.resources.get(&ComponentKey::of::<C>())?.downcast_ref()
    }

    /// Get a mutable reference to a global resource
    ///
    /// For more on resources see [Self::add_res]
    pub fn get_res_mut<C: Component>(&mut self) -> Option<&mut C> {
        self.resources
            .get_mut(&ComponentKey::of::<C>())?
            .downcast_mut()
    }

    /// Remove a global resource
    pub fn del_res<C: Component>(&mut self) -> Option<Box<C>> {
        self.resources
            .swap_remove(&ComponentKey::of::<C>())
            .map(|c| c.downcast().ok())
            .flatten()
    }
}

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