Compare commits

..

No commits in common. "053f1f48da46bd31afb73637719e359bc51776f2" and "a01a52766dfde65259c2cf7fac36fa71e733be79" have entirely different histories.

14 changed files with 196 additions and 448 deletions

View file

@ -1,7 +1,5 @@
use comet_colors::{Color as ColorTrait, LinearRgba}; use comet_colors::{Color as ColorTrait, LinearRgba};
use comet_ecs::{ use comet_ecs::{Camera2D, Component, Entity, Render2D, Scene, Text, Transform2D, Transform3D};
Camera2D, Component, Entity, EntityId, Render2D, Scene, Text, Transform2D, Transform3D,
};
use comet_input::keyboard::Key; use comet_input::keyboard::Key;
use comet_log::*; use comet_log::*;
use comet_renderer::renderer::Renderer; use comet_renderer::renderer::Renderer;
@ -165,22 +163,22 @@ impl App {
} }
/// Creates a new entity and returns its ID. /// Creates a new entity and returns its ID.
pub fn new_entity(&mut self) -> EntityId { pub fn new_entity(&mut self) -> usize {
self.scene.new_entity() self.scene.new_entity() as usize
} }
/// Deletes an entity by its ID. /// Deletes an entity by its ID.
pub fn delete_entity(&mut self, entity_id: EntityId) { pub fn delete_entity(&mut self, entity_id: usize) {
self.scene.delete_entity(entity_id) self.scene.delete_entity(entity_id)
} }
/// Gets an immutable reference to an entity by its ID. /// Gets an immutable reference to an entity by its ID.
pub fn get_entity(&self, entity_id: EntityId) -> Option<&Entity> { pub fn get_entity(&self, entity_id: usize) -> Option<&Entity> {
self.scene.get_entity(entity_id) self.scene.get_entity(entity_id)
} }
/// Gets a mutable reference to an entity by its ID. /// Gets a mutable reference to an entity by its ID.
pub fn get_entity_mut(&mut self, entity_id: EntityId) -> Option<&mut Entity> { pub fn get_entity_mut(&mut self, entity_id: usize) -> Option<&mut Entity> {
self.scene.get_entity_mut(entity_id) self.scene.get_entity_mut(entity_id)
} }
@ -196,29 +194,29 @@ impl App {
/// Adds a component to an entity by its ID and an instance of the component. /// Adds a component to an entity by its ID and an instance of the component.
/// Overwrites the previous component if another component of the same type is added. /// Overwrites the previous component if another component of the same type is added.
pub fn add_component<C: Component>(&mut self, entity_id: EntityId, component: C) { pub fn add_component<C: Component>(&mut self, entity_id: usize, component: C) {
self.scene.add_component(entity_id, component) self.scene.add_component(entity_id, component)
} }
/// Removes a component from an entity by its ID. /// Removes a component from an entity by its ID.
pub fn remove_component<C: Component>(&mut self, entity_id: EntityId) { pub fn remove_component<C: Component>(&mut self, entity_id: usize) {
self.scene.remove_component::<C>(entity_id) self.scene.remove_component::<C>(entity_id)
} }
/// Returns a reference to a component of an entity by its ID. /// Returns a reference to a component of an entity by its ID.
pub fn get_component<C: Component>(&self, entity_id: EntityId) -> Option<&C> { pub fn get_component<C: Component>(&self, entity_id: usize) -> Option<&C> {
self.scene.get_component::<C>(entity_id) self.scene.get_component::<C>(entity_id)
} }
/// Returns a mutable reference to a component of an entity by its ID. /// Returns a mutable reference to a component of an entity by its ID.
pub fn get_component_mut<C: Component>(&mut self, entity_id: EntityId) -> Option<&mut C> { pub fn get_component_mut<C: Component>(&mut self, entity_id: usize) -> Option<&mut C> {
self.scene.get_component_mut::<C>(entity_id) self.scene.get_component_mut::<C>(entity_id)
} }
/// Returns a list of entities that have the given components. /// Returns a list of entities that have the given components.
/// The amount of queriable components is limited to 3 such that the `Archetype` creation is more efficient. /// The amount of queriable components is limited to 3 such that the `Archetype` creation is more efficient.
/// Otherwise it would be a factorial complexity chaos. /// Otherwise it would be a factorial complexity chaos.
pub fn get_entities_with(&self, components: Vec<TypeId>) -> Vec<EntityId> { pub fn get_entities_with(&self, components: Vec<TypeId>) -> Vec<usize> {
self.scene.get_entities_with(components) self.scene.get_entities_with(components)
} }
@ -235,7 +233,7 @@ impl App {
} }
/// Returns whether an entity has the given component. /// Returns whether an entity has the given component.
pub fn has<C: Component>(&self, entity_id: EntityId) -> bool { pub fn has<C: Component>(&self, entity_id: usize) -> bool {
self.scene.has::<C>(entity_id) self.scene.has::<C>(entity_id)
} }
@ -245,7 +243,7 @@ impl App {
} }
/// Spawns a prefab with the given name. /// Spawns a prefab with the given name.
pub fn spawn_prefab(&mut self, name: &str) -> Option<EntityId> { pub fn spawn_prefab(&mut self, name: &str) -> Option<usize> {
self.scene.spawn_prefab(name) self.scene.spawn_prefab(name)
} }

View file

@ -27,13 +27,6 @@ pub fn component_derive(input: TokenStream) -> TokenStream {
} }
}); });
let clone_fields = fields.iter().map(|field| {
let field_name = &field.ident;
quote! {
#field_name: self.#field_name.clone()
}
});
let default_fields = if let Data::Struct(data) = &input.data { let default_fields = if let Data::Struct(data) = &input.data {
match &data.fields { match &data.fields {
Fields::Named(fields) => fields Fields::Named(fields) => fields
@ -90,11 +83,13 @@ pub fn component_derive(input: TokenStream) -> TokenStream {
impl Clone for #name { impl Clone for #name {
fn clone(&self) -> Self { fn clone(&self) -> Self {
Self { Self {
#(#clone_fields),* ..*self
} }
} }
} }
impl Copy for #name {}
impl std::fmt::Debug for #name { impl std::fmt::Debug for #name {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct(stringify!(#name)) f.debug_struct(stringify!(#name))

View file

@ -1,9 +1,9 @@
use comet_structs::ComponentSet; use comet_structs::ComponentSet;
use std::collections::HashMap; use std::collections::{HashMap, HashSet};
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Archetypes { pub struct Archetypes {
archetypes: HashMap<ComponentSet, Vec<u32>>, archetypes: HashMap<ComponentSet, HashSet<u32>>,
} }
impl Archetypes { impl Archetypes {
@ -13,31 +13,27 @@ impl Archetypes {
} }
} }
pub fn component_sets(&self) -> impl Iterator<Item = &ComponentSet> { pub fn component_sets(&self) -> Vec<ComponentSet> {
self.archetypes.keys() self.archetypes.keys().cloned().collect()
} }
pub fn create_archetype(&mut self, components: ComponentSet) { pub fn create_archetype(&mut self, components: ComponentSet) {
self.archetypes.entry(components).or_insert_with(Vec::new); self.archetypes.insert(components, HashSet::new());
} }
pub fn get_archetype(&self, components: &ComponentSet) -> Option<&Vec<u32>> { pub fn get_archetype(&self, components: &ComponentSet) -> Option<&HashSet<u32>> {
self.archetypes.get(components) self.archetypes.get(components)
} }
pub fn add_entity_to_archetype(&mut self, components: &ComponentSet, entity: u32) { pub fn add_entity_to_archetype(&mut self, components: &ComponentSet, entity: u32) {
if let Some(archetype) = self.archetypes.get_mut(components) { if let Some(archetype) = self.archetypes.get_mut(components) {
if !archetype.iter().any(|&e| e == entity) { archetype.insert(entity);
archetype.push(entity);
}
} }
} }
pub fn remove_entity_from_archetype(&mut self, components: &ComponentSet, entity: u32) { pub fn remove_entity_from_archetype(&mut self, components: &ComponentSet, entity: u32) {
if let Some(archetype) = self.archetypes.get_mut(components) { if let Some(archetype) = self.archetypes.get_mut(components) {
if let Some(pos) = archetype.iter().position(|&id| id == entity) { archetype.retain(|&id| id != entity);
archetype.swap_remove(pos);
}
} }
} }

View file

@ -5,7 +5,6 @@
// They are intended to work with the base suite of systems provided by the engine. // They are intended to work with the base suite of systems provided by the engine.
use crate::math::{v2, v3}; use crate::math::{v2, v3};
use crate::{Entity, Scene}; use crate::{Entity, Scene};
use comet_log::*;
use comet_colors::Color as ColorTrait; use comet_colors::Color as ColorTrait;
use comet_math::m4; use comet_math::m4;
use component_derive::Component; use component_derive::Component;
@ -111,13 +110,10 @@ pub struct Transform3D {
// # TRAITS # // # TRAITS #
// ################################################## // ##################################################
pub trait Component: Send + Sync + 'static { pub trait Component: Send + Sync + PartialEq + Default + 'static {
fn new() -> Self fn new() -> Self
where where
Self: Sized + Default, Self: Sized;
{
Default::default()
}
fn type_id() -> std::any::TypeId { fn type_id() -> std::any::TypeId {
std::any::TypeId::of::<Self>() std::any::TypeId::of::<Self>()
@ -140,7 +136,7 @@ pub trait Render {
} }
pub trait Camera { pub trait Camera {
fn get_visible_entities(&self, camera_position: &Position2D, scene: &Scene) -> Vec<Entity>; fn get_visible_entities(&self, camera_position: Position2D, scene: Scene) -> Vec<Entity>;
fn get_projection_matrix(&self) -> m4; fn get_projection_matrix(&self) -> m4;
} }
@ -250,8 +246,8 @@ impl Rectangle2D {
} }
} }
pub fn position(&self) -> &Position2D { pub fn position(&self) -> Position2D {
&self.position self.position
} }
pub fn set_position(&mut self, position: Position2D) { pub fn set_position(&mut self, position: Position2D) {
@ -421,7 +417,7 @@ impl Camera2D {
self.priority = priority; self.priority = priority;
} }
pub fn in_view_frustum(&self, camera_pos: &Position2D, entity: &Position2D) -> bool { pub fn in_view_frustum(&self, camera_pos: Position2D, entity: Position2D) -> bool {
let left = camera_pos.x() - self.zoom; let left = camera_pos.x() - self.zoom;
let right = camera_pos.x() + self.zoom; let right = camera_pos.x() + self.zoom;
let bottom = camera_pos.y() - self.zoom; let bottom = camera_pos.y() - self.zoom;
@ -432,19 +428,18 @@ impl Camera2D {
} }
impl Camera for Camera2D { impl Camera for Camera2D {
fn get_visible_entities(&self, camera_position: &Position2D, scene: &Scene) -> Vec<Entity> { fn get_visible_entities(&self, camera_position: Position2D, scene: Scene) -> Vec<Entity> {
let entities = scene.entities(); let entities = scene.entities();
let mut visible_entities = Vec::new(); let mut visible_entities = Vec::new();
for entity in entities { for entity in entities {
if let Some(ent) = entity.clone() { if self.in_view_frustum(
let id = ent.id(); camera_position,
if let Some(transform) = scene.get_component::<Transform2D>(id) { *scene
if self.in_view_frustum(camera_position, transform.position()) { .get_component::<Transform2D>(*entity.clone().unwrap().id() as usize)
visible_entities.push(ent); .unwrap()
} .position(),
} else { ) {
error!("Entity {} missing Transform2D", id.index); visible_entities.push(entity.clone().unwrap());
}
} }
} }
visible_entities visible_entities
@ -503,7 +498,7 @@ impl Text {
} }
pub fn color(&self) -> Color { pub fn color(&self) -> Color {
self.color.clone() self.color
} }
pub fn set_visibility(&mut self, visibility: bool) { pub fn set_visibility(&mut self, visibility: bool) {

View file

@ -1,46 +1,32 @@
use bit_set::BitSet; use bit_set::BitSet;
/// Handle used to reference entities safely. Contains an index into the entity
/// storage and a generation counter to detect stale handles.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct EntityId {
pub index: u32,
pub gen: u32,
}
impl Default for EntityId {
fn default() -> Self {
Self { index: 0, gen: 0 }
}
}
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub struct Entity { pub struct Entity {
id: EntityId, id: u32,
components: BitSet, components: BitSet
} }
impl Entity { impl Entity {
pub(crate) fn new(index: u32, gen: u32) -> Self { pub(crate) fn new(id: u32) -> Self {
Self { Self {
id: EntityId { index, gen }, id,
components: BitSet::new(), components: BitSet::new()
} }
} }
pub fn id(&self) -> EntityId { pub fn id(&self) -> &u32 {
self.id &self.id
} }
pub(crate) fn add_component(&mut self, component_index: usize) { pub(crate) fn add_component(&mut self, component_index: usize) {
self.components.insert(component_index); self.components.insert(component_index);
} }
pub(crate) fn remove_component(&mut self, component_index: usize) { pub(crate) fn remove_component(&mut self, component_index: usize) {
self.components.remove(component_index); self.components.remove(component_index);
} }
pub(crate) fn get_components(&self) -> &BitSet { pub(crate) fn get_components(&self) -> &BitSet {
&self.components &self.components
} }
} }

View file

@ -1,6 +1,6 @@
use comet_structs::FlatMap; use comet_structs::FlatMap;
pub type PrefabFactory = fn(&mut crate::Scene) -> crate::EntityId; pub type PrefabFactory = fn(&mut crate::Scene) -> usize;
pub(crate) struct PrefabManager { pub(crate) struct PrefabManager {
pub(crate) prefabs: FlatMap<String, PrefabFactory>, pub(crate) prefabs: FlatMap<String, PrefabFactory>,
@ -26,8 +26,8 @@ impl PrefabManager {
macro_rules! register_prefab { macro_rules! register_prefab {
($scene:expr, $name:expr, $($component:expr),* $(,)?) => { ($scene:expr, $name:expr, $($component:expr),* $(,)?) => {
{ {
fn prefab_factory(scene: &mut $crate::Scene) -> $crate::EntityId { fn prefab_factory(scene: &mut $crate::Scene) -> usize {
let entity = scene.new_entity(); let entity = scene.new_entity() as usize;
$( $(
scene.add_component(entity, $component); scene.add_component(entity, $component);
)* )*

View file

@ -1,6 +1,6 @@
use crate::archetypes::Archetypes; use crate::archetypes::Archetypes;
use crate::prefabs::PrefabManager; use crate::prefabs::PrefabManager;
use crate::{Component, Entity, EntityId, IdQueue}; use crate::{Component, Entity, IdQueue};
use comet_log::*; use comet_log::*;
use comet_structs::*; use comet_structs::*;
use std::any::TypeId; use std::any::TypeId;
@ -8,7 +8,6 @@ use std::any::TypeId;
pub struct Scene { pub struct Scene {
id_queue: IdQueue, id_queue: IdQueue,
next_id: u32, next_id: u32,
generations: Vec<u32>,
entities: Vec<Option<Entity>>, entities: Vec<Option<Entity>>,
components: ComponentStorage, components: ComponentStorage,
archetypes: Archetypes, archetypes: Archetypes,
@ -20,7 +19,6 @@ impl Scene {
Self { Self {
id_queue: IdQueue::new(), id_queue: IdQueue::new(),
next_id: 0, next_id: 0,
generations: Vec::new(),
entities: Vec::new(), entities: Vec::new(),
components: ComponentStorage::new(), components: ComponentStorage::new(),
archetypes: Archetypes::new(), archetypes: Archetypes::new(),
@ -45,78 +43,48 @@ impl Scene {
} }
} }
fn is_alive(&self, id: EntityId) -> bool {
self.generations
.get(id.index as usize)
.is_some_and(|g| *g == id.gen)
&& self
.entities
.get(id.index as usize)
.is_some_and(|e| e.is_some())
}
/// Retuns the `Vec` of `Option<Entity>` which contains all the entities in the current Scene. /// Retuns the `Vec` of `Option<Entity>` which contains all the entities in the current Scene.
pub fn entities(&self) -> &Vec<Option<Entity>> { pub fn entities(&self) -> &Vec<Option<Entity>> {
&self.entities &self.entities
} }
/// Creates a new entity and returns its ID. /// Creates a new entity and returns its ID.
pub fn new_entity(&mut self) -> EntityId { pub fn new_entity(&mut self) -> u32 {
let index = self.next_id; let id = self.next_id;
let gen = if (index as usize) >= self.generations.len() { if (self.next_id as usize) >= self.entities.len() {
self.generations.push(0); self.entities.push(Some(Entity::new(self.next_id)));
0 self.get_next_id();
} else { info!("Created entity! ID: {}", id);
self.generations[index as usize] return id;
};
if (index as usize) >= self.entities.len() {
self.entities.push(Some(Entity::new(index, gen)));
} else {
self.entities[index as usize] = Some(Entity::new(index, gen));
} }
self.entities[self.next_id as usize] = Some(Entity::new(self.next_id));
let id = EntityId { index, gen };
self.get_next_id(); self.get_next_id();
info!("Created entity! ID: {} (gen {})", id.index, id.gen); info!("Created entity! ID: {}", id);
id id
} }
/// Gets an immutable reference to an entity by its ID. /// Gets an immutable reference to an entity by its ID.
pub fn get_entity(&self, entity_id: EntityId) -> Option<&Entity> { pub fn get_entity(&self, entity_id: usize) -> Option<&Entity> {
if !self.is_alive(entity_id) { self.entities.get(entity_id).unwrap().as_ref()
return None;
}
self.entities
.get(entity_id.index as usize)
.and_then(|e| e.as_ref())
} }
/// Gets a mutable reference to an entity by its ID. /// Gets a mutable reference to an entity by its ID.
pub fn get_entity_mut(&mut self, entity_id: EntityId) -> Option<&mut Entity> { pub fn get_entity_mut(&mut self, entity_id: usize) -> Option<&mut Entity> {
if !self.is_alive(entity_id) { self.entities.get_mut(entity_id).unwrap().as_mut()
return None;
}
self.entities
.get_mut(entity_id.index as usize)
.and_then(|e| e.as_mut())
} }
/// Deletes an entity by its ID. /// Deletes an entity by its ID.
pub fn delete_entity(&mut self, entity_id: EntityId) { pub fn delete_entity(&mut self, entity_id: usize) {
if !self.is_alive(entity_id) { self.remove_entity_from_archetype_subsets(
return; entity_id as u32,
self.get_component_set(entity_id),
);
self.entities[entity_id] = None;
info!("Deleted entity! ID: {}", entity_id);
for (_, value) in self.components.iter_mut() {
value.remove::<u8>(entity_id);
} }
self.id_queue.sorted_enqueue(entity_id as u32);
let idx = entity_id.index as usize;
self.remove_entity_from_archetype(entity_id.index, self.get_component_set(idx));
self.entities[idx] = None;
info!("Deleted entity! ID: {}", entity_id.index);
self.components.remove_entity(idx);
if let Some(gen) = self.generations.get_mut(idx) {
*gen = gen.wrapping_add(1);
}
self.id_queue.sorted_enqueue(entity_id.index);
self.get_next_id(); self.get_next_id();
} }
@ -139,6 +107,24 @@ impl Scene {
} }
} }
fn get_keys(&self, components: ComponentSet) -> Vec<ComponentSet> {
let component_sets = self.archetypes.component_sets();
component_sets
.iter()
.enumerate()
.filter_map(|(i, &ref elem)| {
if elem.is_subset(&components) {
Some(i)
} else {
None
}
})
.collect::<Vec<usize>>()
.iter()
.map(|index| component_sets[*index].clone())
.collect::<Vec<ComponentSet>>()
}
fn add_entity_to_archetype(&mut self, entity_id: u32, components: ComponentSet) { fn add_entity_to_archetype(&mut self, entity_id: u32, components: ComponentSet) {
self.archetypes self.archetypes
.add_entity_to_archetype(&components, entity_id); .add_entity_to_archetype(&components, entity_id);
@ -149,6 +135,18 @@ impl Scene {
.remove_entity_from_archetype(&components, entity_id); .remove_entity_from_archetype(&components, entity_id);
} }
fn remove_entity_from_archetype_subsets(&mut self, entity_id: u32, components: ComponentSet) {
let keys = self.get_keys(components);
for key in keys {
self.remove_entity_from_archetype(entity_id, key.clone());
if self.archetypes.get_archetype(&key).unwrap().len() == 0 {
self.archetypes.remove_archetype(&key);
}
}
info!("Removed entity {} from all archetypes!", entity_id);
}
fn get_component_set(&self, entity_id: usize) -> ComponentSet { fn get_component_set(&self, entity_id: usize) -> ComponentSet {
let components = match self.entities.get(entity_id) { let components = match self.entities.get(entity_id) {
Some(cmp) => match cmp.as_ref() { Some(cmp) => match cmp.as_ref() {
@ -194,152 +192,120 @@ impl Scene {
/// Adds a component to an entity by its ID and an instance of the component. /// Adds a component to an entity by its ID and an instance of the component.
/// Overwrites the previous component if another component of the same type is added. /// Overwrites the previous component if another component of the same type is added.
pub fn add_component<C: Component + 'static>(&mut self, entity_id: EntityId, component: C) { pub fn add_component<C: Component + 'static>(&mut self, entity_id: usize, component: C) {
if !self.is_alive(entity_id) { let old_component_set = self.get_component_set(entity_id);
error!(
"Attempted to add component {} to dead entity {}",
C::type_name(),
entity_id.index
);
return;
}
let old_component_set = self.get_component_set(entity_id.index as usize);
if !old_component_set.to_vec().is_empty() { if !old_component_set.to_vec().is_empty() {
self.remove_entity_from_archetype(entity_id.index, old_component_set); self.remove_entity_from_archetype_subsets(entity_id as u32, old_component_set);
} }
self.components self.components.set_component(entity_id, component);
.set_component(entity_id.index as usize, component); let component_index = self
if let Some(component_index) = self
.components .components
.keys() .keys()
.iter() .iter_mut()
.position(|x| *x == C::type_id()) .position(|x| *x == C::type_id())
{ .unwrap();
if let Some(entity) = self.get_entity_mut(entity_id) { self.get_entity_mut(entity_id)
entity.add_component(component_index); .unwrap()
} else { .add_component(component_index);
error!(
"Attempted to add component to non-existent entity {}",
entity_id.index
);
}
} else {
error!(
"Component {} not registered, cannot add to entity {}",
C::type_name(),
entity_id.index
);
}
let new_component_set = self.get_component_set(entity_id.index as usize); let new_component_set = self.get_component_set(entity_id);
if !self.archetypes.contains_archetype(&new_component_set) { if !self.archetypes.contains_archetype(&new_component_set) {
self.create_archetype(new_component_set.clone()); self.create_archetype(new_component_set.clone());
} }
self.add_entity_to_archetype(entity_id.index, new_component_set); let subsets = ComponentSet::compute_subsets_up_to_size_3(new_component_set.to_vec());
for subset in subsets {
if !self.archetypes.contains_archetype(&subset) {
self.create_archetype(subset.clone());
}
self.add_entity_to_archetype(entity_id as u32, subset);
}
info!( info!(
"Added component {} to entity {}!", "Added component {} to entity {}!",
C::type_name(), C::type_name(),
entity_id.index entity_id
); );
} }
pub fn remove_component<C: Component + 'static>(&mut self, entity_id: EntityId) { pub fn remove_component<C: Component + 'static>(&mut self, entity_id: usize) {
if !self.is_alive(entity_id) { let old_component_set = self.get_component_set(entity_id);
return; self.remove_entity_from_archetype_subsets(entity_id as u32, old_component_set);
}
let old_component_set = self.get_component_set(entity_id.index as usize);
self.remove_entity_from_archetype(entity_id.index, old_component_set);
self.components self.components.remove_component::<C>(entity_id);
.remove_component::<C>(entity_id.index as usize); let component_index = self
if let Some(component_index) = self
.components .components
.keys() .keys()
.iter() .iter()
.position(|x| *x == C::type_id()) .position(|x| *x == C::type_id())
{ .unwrap();
if let Some(entity) = self.get_entity_mut(entity_id) { self.get_entity_mut(entity_id)
entity.remove_component(component_index); .unwrap()
} .remove_component(component_index);
}
let new_component_set = self.get_component_set(entity_id.index as usize); let new_component_set = self.get_component_set(entity_id);
if !new_component_set.to_vec().is_empty() { if !new_component_set.to_vec().is_empty() {
if !self.archetypes.contains_archetype(&new_component_set) { if !self.archetypes.contains_archetype(&new_component_set) {
self.create_archetype(new_component_set.clone()); self.create_archetype(new_component_set.clone());
} }
self.add_entity_to_archetype(entity_id.index, new_component_set); let subsets = ComponentSet::compute_subsets_up_to_size_3(new_component_set.to_vec());
for subset in subsets {
if !self.archetypes.contains_archetype(&subset) {
self.create_archetype(subset.clone());
}
self.add_entity_to_archetype(entity_id as u32, subset);
}
} }
info!( info!(
"Removed component {} from entity {}!", "Removed component {} from entity {}!",
C::type_name(), C::type_name(),
entity_id.index entity_id
); );
} }
/// Returns a reference to a component of an entity by its ID. /// Returns a reference to a component of an entity by its ID.
pub fn get_component<C: Component + 'static>(&self, entity_id: EntityId) -> Option<&C> { pub fn get_component<C: Component + 'static>(&self, entity_id: usize) -> Option<&C> {
if !self.is_alive(entity_id) { self.components.get_component::<C>(entity_id)
return None;
}
self.components
.get_component::<C>(entity_id.index as usize)
} }
pub fn get_component_mut<C: Component + 'static>( pub fn get_component_mut<C: Component + 'static>(
&mut self, &mut self,
entity_id: EntityId, entity_id: usize,
) -> Option<&mut C> { ) -> Option<&mut C> {
if !self.is_alive(entity_id) { self.components.get_component_mut::<C>(entity_id)
return None;
}
self.components
.get_component_mut::<C>(entity_id.index as usize)
} }
pub fn has<C: Component + 'static>(&self, entity_id: EntityId) -> bool { pub fn has<C: Component + 'static>(&self, entity_id: usize) -> bool {
self.is_alive(entity_id) self.components.get_component::<C>(entity_id).is_some()
&& self
.components
.get_component::<C>(entity_id.index as usize)
.is_some()
} }
/// Returns a list of entities that have the given components. /// Returns a list of entities that have the given components.
pub fn get_entities_with(&self, components: Vec<TypeId>) -> Vec<EntityId> { pub fn get_entities_with(&self, components: Vec<TypeId>) -> Vec<usize> {
let component_set = ComponentSet::from_ids(components); let component_set = ComponentSet::from_ids(components);
let mut result = Vec::new(); if component_set.size() > 3 {
error!("An entity query should only contain at most 3 different components!");
for archetype_set in self.archetypes.component_sets() { return Vec::new();
if component_set.is_subset(archetype_set) {
if let Some(entities) = self.archetypes.get_archetype(archetype_set) {
for index in entities.iter() {
if let Some(gen) = self.generations.get(*index as usize) {
if self
.entities
.get(*index as usize)
.is_some_and(|e| e.is_some())
{
result.push(EntityId {
index: *index,
gen: *gen,
});
}
}
}
}
}
} }
if self.archetypes.contains_archetype(&component_set) {
result return self
.archetypes
.get_archetype(&component_set)
.unwrap()
.clone()
.iter()
.map(|x| *x as usize)
.collect();
}
Vec::new()
} }
/// Deletes all entities that have the given components. /// Deletes all entities that have the given components.
@ -351,31 +317,14 @@ impl Scene {
} }
/// Iterates over all entities that have the two given components and calls the given function. /// Iterates over all entities that have the two given components and calls the given function.
pub fn foreach<C: Component, K: Component>(&mut self, mut func: impl FnMut(&mut C, &mut K)) { pub fn foreach<C: Component, K: Component>(&mut self, func: fn(&mut C, &mut K)) {
if std::any::TypeId::of::<C>() == std::any::TypeId::of::<K>() { let entities = self.get_entities_with(vec![C::type_id(), K::type_id()]);
error!("foreach called with identical component types"); for entity in entities {
return; let c_ptr = self.get_component_mut::<C>(entity).unwrap() as *mut C;
} let k_ptr = self.get_component_mut::<K>(entity).unwrap() as *mut K;
let required = ComponentSet::from_ids(vec![C::type_id(), K::type_id()]); unsafe {
let (c_set, k_set) = self func(&mut *c_ptr, &mut *k_ptr);
.components
.get_two_mut(&C::type_id(), &K::type_id());
if let (Some(c_store), Some(k_store)) = (c_set, k_set) {
for archetype_set in self.archetypes.component_sets() {
if required.is_subset(archetype_set) {
if let Some(entities) = self.archetypes.get_archetype(archetype_set) {
for &idx in entities {
let idx = idx as usize;
if let (Some(c), Some(k)) =
(c_store.get_mut::<C>(idx), k_store.get_mut::<K>(idx))
{
func(c, k);
}
}
}
}
} }
} }
} }
@ -386,7 +335,7 @@ impl Scene {
} }
/// Spawns a prefab with the given name. /// Spawns a prefab with the given name.
pub fn spawn_prefab(&mut self, name: &str) -> Option<EntityId> { pub fn spawn_prefab(&mut self, name: &str) -> Option<usize> {
if self.prefabs.has_prefab(name) { if self.prefabs.has_prefab(name) {
if let Some(factory) = self.prefabs.prefabs.get(&name.to_string()) { if let Some(factory) = self.prefabs.prefabs.get(&name.to_string()) {
let factory = *factory; // Copy the function pointer let factory = *factory; // Copy the function pointer

View file

@ -18,11 +18,7 @@ impl CameraManager {
self.cameras.get(self.active_camera).unwrap() self.cameras.get(self.active_camera).unwrap()
} }
pub fn update_from_scene( pub fn update_from_scene(&mut self, scene: &comet_ecs::Scene, camera_entities: Vec<usize>) {
&mut self,
scene: &comet_ecs::Scene,
camera_entities: Vec<comet_ecs::EntityId>,
) {
self.cameras.clear(); self.cameras.clear();
let mut cameras_with_priority: Vec<(RenderCamera, u8)> = Vec::new(); let mut cameras_with_priority: Vec<(RenderCamera, u8)> = Vec::new();

View file

@ -11,7 +11,6 @@ use comet_math::{m4, v2};
use comet_resources::{ use comet_resources::{
font::Font, graphic_resource_manager::GraphicResourceManager, texture_atlas::*, Texture, Vertex, font::Font, graphic_resource_manager::GraphicResourceManager, texture_atlas::*, Texture, Vertex,
}; };
use std::collections::HashSet;
use std::sync::Arc; use std::sync::Arc;
use wgpu::util::DeviceExt; use wgpu::util::DeviceExt;
use winit::{dpi::PhysicalSize, window::Window}; use winit::{dpi::PhysicalSize, window::Window};
@ -62,7 +61,6 @@ pub struct Renderer2D<'a> {
resource_manager: GraphicResourceManager, resource_manager: GraphicResourceManager,
camera_manager: CameraManager, camera_manager: CameraManager,
render_passes: Vec<RenderPass>, render_passes: Vec<RenderPass>,
cached_render_entities: Vec<comet_ecs::EntityId>,
last_frame_time: std::time::Instant, last_frame_time: std::time::Instant,
delta_time: f32, delta_time: f32,
} }
@ -746,45 +744,16 @@ impl<'a> Renderer2D<'a> {
return; return;
} }
let unsorted_entities = scene.get_entities_with(vec![ let mut entities = scene.get_entities_with(vec![
comet_ecs::Transform2D::type_id(), comet_ecs::Transform2D::type_id(),
comet_ecs::Render2D::type_id(), comet_ecs::Render2D::type_id(),
]); ]);
let mut dirty_sort = self.cached_render_entities.len() != unsorted_entities.len(); entities.sort_by(|&a, &b| {
let ra = scene.get_component::<comet_ecs::Render2D>(a).unwrap();
if !dirty_sort { let rb = scene.get_component::<comet_ecs::Render2D>(b).unwrap();
let unsorted_set: HashSet<comet_ecs::EntityId> = ra.draw_index().cmp(&rb.draw_index())
unsorted_entities.iter().copied().collect(); });
dirty_sort = self
.cached_render_entities
.iter()
.any(|e| !unsorted_set.contains(e));
}
if !dirty_sort {
dirty_sort = !self.cached_render_entities.windows(2).all(|w| {
let a = scene
.get_component::<comet_ecs::Render2D>(w[0])
.map(|r| r.draw_index());
let b = scene
.get_component::<comet_ecs::Render2D>(w[1])
.map(|r| r.draw_index());
matches!((a, b), (Some(da), Some(db)) if da <= db)
});
}
if dirty_sort {
let mut entities = unsorted_entities;
entities.sort_by(|&a, &b| {
let ra = scene.get_component::<comet_ecs::Render2D>(a).unwrap();
let rb = scene.get_component::<comet_ecs::Render2D>(b).unwrap();
ra.draw_index().cmp(&rb.draw_index())
});
self.cached_render_entities = entities;
}
let entities = self.cached_render_entities.clone();
let texts = scene.get_entities_with(vec![ let texts = scene.get_entities_with(vec![
comet_ecs::Transform2D::type_id(), comet_ecs::Transform2D::type_id(),
@ -953,7 +922,7 @@ impl<'a> Renderer2D<'a> {
} }
} }
fn setup_camera(&mut self, scene: &comet_ecs::Scene, cameras: Vec<comet_ecs::EntityId>) { fn setup_camera(&mut self, scene: &comet_ecs::Scene, cameras: Vec<usize>) {
if cameras.is_empty() { if cameras.is_empty() {
return; return;
} }
@ -1043,7 +1012,6 @@ impl<'a> Renderer for Renderer2D<'a> {
resource_manager: GraphicResourceManager::new(), resource_manager: GraphicResourceManager::new(),
camera_manager: CameraManager::new(), camera_manager: CameraManager::new(),
render_passes: Vec::new(), render_passes: Vec::new(),
cached_render_entities: Vec::new(),
last_frame_time: std::time::Instant::now(), last_frame_time: std::time::Instant::now(),
delta_time: 0.0, delta_time: 0.0,
} }

View file

@ -272,33 +272,6 @@ impl Column {
} }
} }
/// Remove an element without knowing its concrete type. Drops in place.
pub fn remove_any(&mut self, index: usize) {
if index >= self.data.len() {
return;
}
unsafe {
let ptr = self.data.swap_remove_and_forget_unchecked(index);
(self.data.drop)(ptr);
}
}
/// Overwrites an existing element in place, dropping the previous value.
pub fn set<T: 'static>(&mut self, index: usize, item: T) -> Option<()> {
assert_eq!(TypeId::of::<T>(), TypeId::of::<T>(), "Type mismatch");
if index >= self.data.len() {
return None;
}
unsafe {
let ptr = self.data.get_unchecked_mut(index) as *mut T;
ptr::drop_in_place(ptr);
ptr::write(ptr, item);
}
Some(())
}
pub fn swap(&mut self, index1: usize, index2: usize) { pub fn swap(&mut self, index1: usize, index2: usize) {
assert!( assert!(
index1 < self.data.len() && index2 < self.data.len(), index1 < self.data.len() && index2 < self.data.len(),

View file

@ -55,11 +55,4 @@ impl ComponentStorage {
None None
} }
} }
/// Removes all components belonging to the given entity index.
pub fn remove_entity(&mut self, index: usize) {
for (_, value) in self.iter_mut() {
value.remove_any(index);
}
}
} }

View file

@ -67,10 +67,6 @@ impl ComponentSet {
self.set.is_subset(&other.set) self.set.is_subset(&other.set)
} }
pub fn is_superset(&self, other: &ComponentSet) -> bool {
self.set.is_superset(&other.set)
}
pub fn to_vec(&self) -> Vec<TypeId> { pub fn to_vec(&self) -> Vec<TypeId> {
self.set.iter().cloned().collect() self.set.iter().cloned().collect()
} }

View file

@ -44,39 +44,6 @@ impl<K: PartialEq + Clone, V: Clone> FlatMap<K, V> {
} }
} }
pub fn get_two_mut(&mut self, a: &K, b: &K) -> (Option<&mut V>, Option<&mut V>) {
if a == b {
let first = self.get_mut(a);
return (first, None);
}
let mut first_index = None;
let mut second_index = None;
for (idx, (key, _)) in self.map.iter().enumerate() {
if key == a {
first_index = Some(idx);
} else if key == b {
second_index = Some(idx);
}
}
match (first_index, second_index) {
(Some(i), Some(j)) => {
if i < j {
let (left, right) = self.map.split_at_mut(j);
(Some(&mut left[i].1), Some(&mut right[0].1))
} else {
let (left, right) = self.map.split_at_mut(i);
(Some(&mut right[0].1), Some(&mut left[j].1))
}
}
(Some(i), None) => (self.map.get_mut(i).map(|pair| &mut pair.1), None),
(None, Some(j)) => (None, self.map.get_mut(j).map(|pair| &mut pair.1)),
_ => (None, None),
}
}
pub fn contains(&self, key: &K) -> bool { pub fn contains(&self, key: &K) -> bool {
self.map.iter().any(|node| node.0 == *key) self.map.iter().any(|node| node.0 == *key)
} }
@ -84,4 +51,4 @@ impl<K: PartialEq + Clone, V: Clone> FlatMap<K, V> {
pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut (K, V)> { pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut (K, V)> {
self.map.iter_mut() self.map.iter_mut()
} }
} }

View file

@ -28,12 +28,6 @@ impl SparseSet {
} }
if let Some(page_vec) = &mut self.sparse[page] { if let Some(page_vec) = &mut self.sparse[page] {
// If there is already a mapping, overwrite the existing dense value instead of pushing.
if let Some(sparse_index) = page_vec[index % self.page_size] {
let _ = self.dense.set::<T>(sparse_index, value);
return;
}
page_vec[index % self.page_size] = Some(self.dense.data.len()); page_vec[index % self.page_size] = Some(self.dense.data.len());
} }
@ -75,64 +69,6 @@ impl SparseSet {
None None
} }
/// Removes an element by external index without knowing its type. Returns true if something was removed.
pub fn remove_any(&mut self, index: usize) -> bool {
if let Some(page_vec) = self
.sparse
.get(index / self.page_size)
.and_then(|x| x.as_ref())
{
if let Some(sparse_index) = page_vec
.get(index % self.page_size)
.and_then(|x| x.as_ref())
{
let dense_index = *sparse_index;
let last_dense_index = self.dense.data.len() - 1;
if dense_index != last_dense_index {
if let Some(ext_index) = self.find_external_index(last_dense_index) {
if let Some(page_vec) = self
.sparse
.get_mut(ext_index / self.page_size)
.and_then(|x| x.as_mut())
{
page_vec[ext_index % self.page_size] = Some(dense_index);
}
}
self.dense.swap(dense_index, last_dense_index);
}
if let Some(page_vec) = self
.sparse
.get_mut(index / self.page_size)
.and_then(|x| x.as_mut())
{
page_vec[index % self.page_size] = None;
}
self.dense.remove_any(dense_index);
return true;
}
}
false
}
/// Finds the external index that maps to a given dense index.
fn find_external_index(&self, dense_index: usize) -> Option<usize> {
for (page_idx, page_opt) in self.sparse.iter().enumerate() {
if let Some(page) = page_opt {
for (offset, entry) in page.iter().enumerate() {
if let Some(idx) = entry {
if *idx == dense_index {
return Some(page_idx * self.page_size + offset);
}
}
}
}
}
None
}
pub fn get<T: 'static>(&self, index: usize) -> Option<&T> { pub fn get<T: 'static>(&self, index: usize) -> Option<&T> {
if let Some(page_vec) = self if let Some(page_vec) = self
.sparse .sparse