mirror of
https://github.com/lisk77/comet.git
synced 2025-10-23 21:38:50 +00:00
feat(ecs): added a simple prefab system
This commit is contained in:
parent
fef128f8a7
commit
e1597e6fa4
10 changed files with 416 additions and 257 deletions
0
crates/comet_ecs/Cargo.toml
Normal file → Executable file
0
crates/comet_ecs/Cargo.toml
Normal file → Executable file
0
crates/comet_ecs/component_derive/Cargo.toml
Normal file → Executable file
0
crates/comet_ecs/component_derive/Cargo.toml
Normal file → Executable file
0
crates/comet_ecs/component_derive/src/lib.rs
Normal file → Executable file
0
crates/comet_ecs/component_derive/src/lib.rs
Normal file → Executable file
0
crates/comet_ecs/src/archetypes.rs
Normal file → Executable file
0
crates/comet_ecs/src/archetypes.rs
Normal file → Executable file
0
crates/comet_ecs/src/entity.rs
Normal file → Executable file
0
crates/comet_ecs/src/entity.rs
Normal file → Executable file
0
crates/comet_ecs/src/id.rs
Normal file → Executable file
0
crates/comet_ecs/src/id.rs
Normal file → Executable file
19
crates/comet_ecs/src/lib.rs
Normal file → Executable file
19
crates/comet_ecs/src/lib.rs
Normal file → Executable file
|
@ -1,12 +1,15 @@
|
||||||
pub use entity::*;
|
|
||||||
pub use component::*;
|
|
||||||
pub use scene::*;
|
|
||||||
pub use id::*;
|
|
||||||
pub use component_derive::*;
|
|
||||||
pub use comet_math as math;
|
pub use comet_math as math;
|
||||||
|
pub use component::*;
|
||||||
|
pub use component_derive::*;
|
||||||
|
pub use entity::*;
|
||||||
|
pub use id::*;
|
||||||
|
pub use prefabs::PrefabFactory;
|
||||||
|
pub use scene::*;
|
||||||
|
|
||||||
mod entity;
|
mod archetypes;
|
||||||
mod component;
|
mod component;
|
||||||
mod scene;
|
mod entity;
|
||||||
mod id;
|
mod id;
|
||||||
mod archetypes;
|
mod prefabs;
|
||||||
|
mod scene;
|
||||||
|
|
||||||
|
|
46
crates/comet_ecs/src/prefabs.rs
Normal file
46
crates/comet_ecs/src/prefabs.rs
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
use comet_structs::FlatMap;
|
||||||
|
|
||||||
|
pub type PrefabFactory = fn(&mut crate::Scene) -> usize;
|
||||||
|
|
||||||
|
pub(crate) struct PrefabManager {
|
||||||
|
pub(crate) prefabs: FlatMap<String, PrefabFactory>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PrefabManager {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
prefabs: FlatMap::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn register(&mut self, name: &str, factory: PrefabFactory) {
|
||||||
|
self.prefabs.insert(name.to_string(), factory);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn has_prefab(&self, name: &str) -> bool {
|
||||||
|
self.prefabs.contains(&name.to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! register_prefab {
|
||||||
|
($scene:expr, $name:expr, $($component:expr),* $(,)?) => {
|
||||||
|
{
|
||||||
|
fn prefab_factory(scene: &mut $crate::Scene) -> usize {
|
||||||
|
let entity = scene.new_entity() as usize;
|
||||||
|
$(
|
||||||
|
scene.add_component(entity, $component);
|
||||||
|
)*
|
||||||
|
entity
|
||||||
|
}
|
||||||
|
$scene.register_prefab($name, prefab_factory);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! spawn_prefab {
|
||||||
|
($scene:expr, $name:expr) => {
|
||||||
|
$scene.spawn_prefab($name)
|
||||||
|
};
|
||||||
|
}
|
|
@ -1,297 +1,355 @@
|
||||||
use std::any::TypeId;
|
use crate::archetypes::Archetypes;
|
||||||
use crate::{
|
use crate::prefabs::PrefabManager;
|
||||||
entity, Component, Entity, IdQueue
|
use crate::{Component, Entity, IdQueue};
|
||||||
};
|
|
||||||
use comet_log::*;
|
use comet_log::*;
|
||||||
use comet_structs::*;
|
use comet_structs::*;
|
||||||
use crate::archetypes::Archetypes;
|
use std::any::TypeId;
|
||||||
|
|
||||||
pub struct Scene {
|
pub struct Scene {
|
||||||
id_queue: IdQueue,
|
id_queue: IdQueue,
|
||||||
next_id: u32,
|
next_id: u32,
|
||||||
entities: Vec<Option<Entity>>,
|
entities: Vec<Option<Entity>>,
|
||||||
components: ComponentStorage,
|
components: ComponentStorage,
|
||||||
archetypes: Archetypes
|
archetypes: Archetypes,
|
||||||
|
prefabs: PrefabManager,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Scene {
|
impl Scene {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
id_queue: IdQueue::new(),
|
id_queue: IdQueue::new(),
|
||||||
next_id: 0,
|
next_id: 0,
|
||||||
entities: Vec::new(),
|
entities: Vec::new(),
|
||||||
components: ComponentStorage::new(),
|
components: ComponentStorage::new(),
|
||||||
archetypes: Archetypes::new()
|
archetypes: Archetypes::new(),
|
||||||
}
|
prefabs: PrefabManager::new(),
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns the number of how many entities exist in the current Scene.
|
/// Returns the number of how many entities exist in the current Scene.
|
||||||
pub fn active_entities(&self) -> u32 {
|
pub fn active_entities(&self) -> u32 {
|
||||||
self.entities.len() as u32 - self.id_queue.size()
|
self.entities.len() as u32 - self.id_queue.size()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_next_id(&mut self) {
|
fn get_next_id(&mut self) {
|
||||||
if self.id_queue.is_empty() {
|
if self.id_queue.is_empty() {
|
||||||
self.next_id = self.entities.len() as u32;
|
self.next_id = self.entities.len() as u32;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if self.next_id > self.id_queue.front().unwrap() || self.entities[self.next_id as usize] != None {
|
if self.next_id > self.id_queue.front().unwrap()
|
||||||
self.next_id = self.id_queue.dequeue().unwrap();
|
|| self.entities[self.next_id as usize] != None
|
||||||
}
|
{
|
||||||
}
|
self.next_id = self.id_queue.dequeue().unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// 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) -> u32 {
|
pub fn new_entity(&mut self) -> u32 {
|
||||||
let id = self.next_id;
|
let id = self.next_id;
|
||||||
if (self.next_id as usize) >= self.entities.len() {
|
if (self.next_id as usize) >= self.entities.len() {
|
||||||
self.entities.push(Some(Entity::new(self.next_id)));
|
self.entities.push(Some(Entity::new(self.next_id)));
|
||||||
self.get_next_id();
|
self.get_next_id();
|
||||||
info!("Created entity! ID: {}", id);
|
info!("Created entity! ID: {}", id);
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
self.entities[self.next_id as usize] = Some(Entity::new(self.next_id));
|
self.entities[self.next_id as usize] = Some(Entity::new(self.next_id));
|
||||||
self.get_next_id();
|
self.get_next_id();
|
||||||
info!("Created entity! ID: {}", id);
|
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: usize) -> Option<&Entity> {
|
pub fn get_entity(&self, entity_id: usize) -> Option<&Entity> {
|
||||||
self.entities.get(entity_id).unwrap().as_ref()
|
self.entities.get(entity_id).unwrap().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: usize) -> Option<&mut Entity> {
|
pub fn get_entity_mut(&mut self, entity_id: usize) -> Option<&mut Entity> {
|
||||||
self.entities.get_mut(entity_id).unwrap().as_mut()
|
self.entities.get_mut(entity_id).unwrap().as_mut()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Deletes an entity by its ID.
|
/// Deletes an entity by its ID.
|
||||||
pub fn delete_entity(&mut self, entity_id: usize) {
|
pub fn delete_entity(&mut self, entity_id: usize) {
|
||||||
self.remove_entity_from_archetype_subsets(entity_id as u32, self.get_component_set(entity_id));
|
self.remove_entity_from_archetype_subsets(
|
||||||
self.entities[entity_id] = None;
|
entity_id as u32,
|
||||||
info!("Deleted entity! ID: {}", entity_id);
|
self.get_component_set(entity_id),
|
||||||
for (_, value) in self.components.iter_mut() {
|
);
|
||||||
value.remove::<u8>(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);
|
||||||
|
self.get_next_id();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
fn create_archetype(&mut self, components: ComponentSet) {
|
||||||
self.id_queue.sorted_enqueue(entity_id as u32);
|
self.archetypes.create_archetype(components.clone());
|
||||||
self.get_next_id();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn create_archetype(&mut self, components: ComponentSet) {
|
let mut matching_entities = Vec::new();
|
||||||
self.archetypes.create_archetype(components.clone());
|
for (entity_id, entity_option) in self.entities.iter().enumerate() {
|
||||||
|
if let Some(_entity) = entity_option {
|
||||||
// Collect entities that match the component set first to avoid borrow checker issues
|
let entity_component_set = self.get_component_set(entity_id);
|
||||||
let mut matching_entities = Vec::new();
|
|
||||||
for (entity_id, entity_option) in self.entities.iter().enumerate() {
|
|
||||||
if let Some(_entity) = entity_option {
|
|
||||||
let entity_component_set = self.get_component_set(entity_id);
|
|
||||||
|
|
||||||
// If the entity has all the required components (components is subset of entity's components)
|
|
||||||
if components.is_subset(&entity_component_set) {
|
|
||||||
matching_entities.push(entity_id as u32);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add all matching entities to the archetype
|
|
||||||
for entity_id in matching_entities {
|
|
||||||
self.add_entity_to_archetype(entity_id, components.clone());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn remove_archetype(&mut self, components: ComponentSet) {
|
if components.is_subset(&entity_component_set) {
|
||||||
self.archetypes.remove_archetype(&components);
|
matching_entities.push(entity_id as u32);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn get_keys(&self, components: ComponentSet) -> Vec<ComponentSet> {
|
for entity_id in matching_entities {
|
||||||
let component_sets = self.archetypes.component_sets();
|
self.add_entity_to_archetype(entity_id, components.clone());
|
||||||
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 remove_archetype_subsets(&mut self, components: ComponentSet) {
|
fn get_keys(&self, components: ComponentSet) -> Vec<ComponentSet> {
|
||||||
let keys = self.get_keys(components);
|
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>>()
|
||||||
|
}
|
||||||
|
|
||||||
for key in keys {
|
fn add_entity_to_archetype(&mut self, entity_id: u32, components: ComponentSet) {
|
||||||
self.remove_archetype(key.clone());
|
self.archetypes
|
||||||
}
|
.add_entity_to_archetype(&components, entity_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_entity_to_archetype(&mut self, entity_id: u32, components: ComponentSet) {
|
fn remove_entity_from_archetype(&mut self, entity_id: u32, components: ComponentSet) {
|
||||||
self.archetypes.add_entity_to_archetype(&components, entity_id);
|
self.archetypes
|
||||||
}
|
.remove_entity_from_archetype(&components, entity_id);
|
||||||
|
}
|
||||||
|
|
||||||
fn remove_entity_from_archetype(&mut self, entity_id: u32, components: ComponentSet) {
|
fn remove_entity_from_archetype_subsets(&mut self, entity_id: u32, components: ComponentSet) {
|
||||||
self.archetypes.remove_entity_from_archetype(&components, entity_id);
|
let keys = self.get_keys(components);
|
||||||
}
|
|
||||||
|
|
||||||
fn remove_entity_from_archetype_subsets(&mut self, entity_id: u32, components: ComponentSet) {
|
for key in keys {
|
||||||
let keys = self.get_keys(components);
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
for key in keys {
|
fn get_component_set(&self, entity_id: usize) -> ComponentSet {
|
||||||
self.remove_entity_from_archetype(entity_id, key.clone());
|
let components = match self.entities.get(entity_id) {
|
||||||
if self.archetypes.get_archetype(&key).unwrap().len() == 0 {
|
Some(cmp) => match cmp.as_ref() {
|
||||||
self.archetypes.remove_archetype(&key);
|
Some(e) => e.get_components().iter().collect::<Vec<usize>>(),
|
||||||
}
|
None => {
|
||||||
}
|
error!("This entity ({}) does not have any components!", entity_id);
|
||||||
info!("Removed entity {} from all archetypes!", entity_id);
|
Vec::new()
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
_ => {
|
||||||
|
error!("This entity ({}) does not exist!", entity_id);
|
||||||
|
Vec::new()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
fn get_component_set(&self, entity_id: usize) -> ComponentSet {
|
let type_ids = components
|
||||||
let components = match self.entities.get(entity_id) {
|
.iter()
|
||||||
Some(cmp) => match cmp.as_ref() {
|
.map(|index| self.components.keys()[*index])
|
||||||
Some(e) => e.get_components().iter().collect::<Vec<usize>>(),
|
.collect::<Vec<TypeId>>();
|
||||||
None => {
|
ComponentSet::from_ids(type_ids)
|
||||||
error!("This entity ({}) does not have any components!", entity_id);
|
}
|
||||||
Vec::new()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
_ => {
|
|
||||||
error!("This entity ({}) does not exist!", entity_id);
|
|
||||||
Vec::new()
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let type_ids = components.iter().map(|index| self.components.keys()[*index]).collect::<Vec<TypeId>>();
|
/// Registers a new component in the scene.
|
||||||
ComponentSet::from_ids(type_ids)
|
pub fn register_component<C: Component + 'static>(&mut self) {
|
||||||
}
|
if !self.components.contains(&C::type_id()) {
|
||||||
|
self.components.register_component::<C>(self.entities.len());
|
||||||
|
self.create_archetype(ComponentSet::from_ids(vec![C::type_id()]));
|
||||||
|
info!("Registered component: {}", C::type_name());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
warn!("Component {} is already registered!", C::type_name());
|
||||||
|
}
|
||||||
|
|
||||||
/// Registers a new component in the scene.
|
/// Deregisters a component from the scene.
|
||||||
pub fn register_component<C: Component + 'static>(&mut self) {
|
pub fn deregister_component<C: Component + 'static>(&mut self) {
|
||||||
if !self.components.contains(&C::type_id()) {
|
if self.components.contains(&C::type_id()) {
|
||||||
self.components.register_component::<C>(self.entities.len());
|
self.components.deregister_component::<C>();
|
||||||
self.create_archetype(ComponentSet::from_ids(vec![C::type_id()]));
|
info!("Deregistered component: {}", C::type_name());
|
||||||
info!("Registered component: {}", C::type_name());
|
return;
|
||||||
return;
|
}
|
||||||
}
|
warn!("Component {} was not registered!", C::type_name());
|
||||||
warn!("Component {} is already registered!", C::type_name());
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// Deregisters a component from the scene.
|
/// Adds a component to an entity by its ID and an instance of the component.
|
||||||
pub fn deregister_component<C: Component + 'static>(&mut self) {
|
/// Overwrites the previous component if another component of the same type is added.
|
||||||
if self.components.contains(&C::type_id()) {
|
pub fn add_component<C: Component + 'static>(&mut self, entity_id: usize, component: C) {
|
||||||
self.components.deregister_component::<C>();
|
let old_component_set = self.get_component_set(entity_id);
|
||||||
info!("Deregistered component: {}", C::type_name());
|
if !old_component_set.to_vec().is_empty() {
|
||||||
return;
|
self.remove_entity_from_archetype_subsets(entity_id as u32, old_component_set);
|
||||||
}
|
}
|
||||||
warn!("Component {} was not registered!", C::type_name());
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Adds a component to an entity by its ID and an instance of the component.
|
self.components.set_component(entity_id, component);
|
||||||
/// Overwrites the previous component if another component of the same type is added.
|
let component_index = self
|
||||||
pub fn add_component<C: Component + 'static>(&mut self, entity_id: usize, component: C) {
|
.components
|
||||||
let old_component_set = self.get_component_set(entity_id);
|
.keys()
|
||||||
if !old_component_set.to_vec().is_empty() {
|
.iter_mut()
|
||||||
self.remove_entity_from_archetype_subsets(entity_id as u32, old_component_set);
|
.position(|x| *x == C::type_id())
|
||||||
}
|
.unwrap();
|
||||||
|
self.get_entity_mut(entity_id)
|
||||||
|
.unwrap()
|
||||||
|
.add_component(component_index);
|
||||||
|
|
||||||
self.components.set_component(entity_id, component);
|
let new_component_set = self.get_component_set(entity_id);
|
||||||
let component_index = self.components.keys().iter_mut().position(|x| *x == C::type_id()).unwrap();
|
|
||||||
self.get_entity_mut(entity_id).unwrap().add_component(component_index);
|
|
||||||
|
|
||||||
let new_component_set = self.get_component_set(entity_id);
|
if !self.archetypes.contains_archetype(&new_component_set) {
|
||||||
|
self.create_archetype(new_component_set.clone());
|
||||||
|
}
|
||||||
|
|
||||||
if !self.archetypes.contains_archetype(&new_component_set) {
|
let powerset = ComponentSet::powerset(new_component_set.to_vec());
|
||||||
self.create_archetype(new_component_set.clone());
|
|
||||||
}
|
|
||||||
|
|
||||||
let powerset = ComponentSet::powerset(new_component_set.to_vec());
|
for subset in powerset {
|
||||||
|
let component_set = ComponentSet::from_ids(subset.iter().cloned().collect());
|
||||||
for subset in powerset {
|
|
||||||
let component_set = ComponentSet::from_ids(subset.iter().cloned().collect());
|
|
||||||
|
|
||||||
if !self.archetypes.contains_archetype(&component_set) {
|
|
||||||
self.create_archetype(component_set.clone());
|
|
||||||
}
|
|
||||||
|
|
||||||
self.add_entity_to_archetype(entity_id as u32, component_set);
|
|
||||||
}
|
|
||||||
|
|
||||||
info!("Added component {} to entity {}!", C::type_name(), entity_id);
|
if !self.archetypes.contains_archetype(&component_set) {
|
||||||
}
|
self.create_archetype(component_set.clone());
|
||||||
|
}
|
||||||
|
|
||||||
pub fn remove_component<C: Component + 'static>(&mut self, entity_id: usize) {
|
self.add_entity_to_archetype(entity_id as u32, component_set);
|
||||||
let old_component_set = self.get_component_set(entity_id);
|
}
|
||||||
self.remove_entity_from_archetype_subsets(entity_id as u32, old_component_set);
|
|
||||||
|
|
||||||
self.components.remove_component::<C>(entity_id);
|
info!(
|
||||||
let component_index = self.components.keys().iter().position(|x| *x == C::type_id()).unwrap();
|
"Added component {} to entity {}!",
|
||||||
self.get_entity_mut(entity_id).unwrap().remove_component(component_index);
|
C::type_name(),
|
||||||
|
entity_id
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
let new_component_set = self.get_component_set(entity_id);
|
pub fn remove_component<C: Component + 'static>(&mut self, entity_id: usize) {
|
||||||
|
let old_component_set = self.get_component_set(entity_id);
|
||||||
|
self.remove_entity_from_archetype_subsets(entity_id as u32, old_component_set);
|
||||||
|
|
||||||
if !new_component_set.to_vec().is_empty() {
|
self.components.remove_component::<C>(entity_id);
|
||||||
if !self.archetypes.contains_archetype(&new_component_set) {
|
let component_index = self
|
||||||
self.create_archetype(new_component_set.clone());
|
.components
|
||||||
}
|
.keys()
|
||||||
|
.iter()
|
||||||
|
.position(|x| *x == C::type_id())
|
||||||
|
.unwrap();
|
||||||
|
self.get_entity_mut(entity_id)
|
||||||
|
.unwrap()
|
||||||
|
.remove_component(component_index);
|
||||||
|
|
||||||
let powerset = ComponentSet::powerset(new_component_set.to_vec());
|
let new_component_set = self.get_component_set(entity_id);
|
||||||
|
|
||||||
for subset in powerset {
|
|
||||||
let component_set = ComponentSet::from_ids(subset.iter().cloned().collect());
|
|
||||||
|
|
||||||
if !self.archetypes.contains_archetype(&component_set) {
|
|
||||||
self.create_archetype(component_set.clone());
|
|
||||||
}
|
|
||||||
|
|
||||||
self.add_entity_to_archetype(entity_id as u32, component_set);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
info!("Removed component {} from entity {}!", C::type_name(), entity_id);
|
if !new_component_set.to_vec().is_empty() {
|
||||||
}
|
if !self.archetypes.contains_archetype(&new_component_set) {
|
||||||
|
self.create_archetype(new_component_set.clone());
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns a reference to a component of an entity by its ID.
|
let powerset = ComponentSet::powerset(new_component_set.to_vec());
|
||||||
pub fn get_component<C: Component + 'static>(&self, entity_id: usize) -> Option<&C> {
|
|
||||||
self.components.get_component::<C>(entity_id)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_component_mut<C: Component + 'static>(&mut self, entity_id: usize) -> Option<&mut C> {
|
for subset in powerset {
|
||||||
self.components.get_component_mut::<C>(entity_id)
|
let component_set = ComponentSet::from_ids(subset.iter().cloned().collect());
|
||||||
}
|
|
||||||
|
|
||||||
pub fn has<C: Component + 'static>(&self, entity_id: usize) -> bool {
|
if !self.archetypes.contains_archetype(&component_set) {
|
||||||
self.components.get_component::<C>(entity_id).is_some()
|
self.create_archetype(component_set.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a list of entities that have the given components.
|
self.add_entity_to_archetype(entity_id as u32, component_set);
|
||||||
pub fn get_entities_with(&self, components: Vec<TypeId>) -> Vec<usize> {
|
}
|
||||||
let component_set = ComponentSet::from_ids(components);
|
}
|
||||||
if self.archetypes.contains_archetype(&component_set) {
|
|
||||||
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.
|
info!(
|
||||||
pub fn delete_entities_with(&mut self, components: Vec<TypeId>) {
|
"Removed component {} from entity {}!",
|
||||||
let entities = self.get_entities_with(components);
|
C::type_name(),
|
||||||
for entity in entities {
|
entity_id
|
||||||
self.delete_entity(entity);
|
);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// Iterates over all entities that have the given components and calls the given function.
|
/// Returns a reference to a component of an entity by its ID.
|
||||||
pub fn foreach<C: Component, K: Component>(&mut self, func: fn(&mut C,&mut K)) {
|
pub fn get_component<C: Component + 'static>(&self, entity_id: usize) -> Option<&C> {
|
||||||
let entities = self.get_entities_with(vec![C::type_id(), K::type_id()]);
|
self.components.get_component::<C>(entity_id)
|
||||||
for entity in entities {
|
}
|
||||||
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;
|
|
||||||
|
|
||||||
unsafe {
|
pub fn get_component_mut<C: Component + 'static>(
|
||||||
func(&mut *c_ptr, &mut *k_ptr);
|
&mut self,
|
||||||
}
|
entity_id: usize,
|
||||||
}
|
) -> Option<&mut C> {
|
||||||
}
|
self.components.get_component_mut::<C>(entity_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn has<C: Component + 'static>(&self, entity_id: usize) -> bool {
|
||||||
|
self.components.get_component::<C>(entity_id).is_some()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a list of entities that have the given components.
|
||||||
|
pub fn get_entities_with(&self, components: Vec<TypeId>) -> Vec<usize> {
|
||||||
|
let component_set = ComponentSet::from_ids(components);
|
||||||
|
if self.archetypes.contains_archetype(&component_set) {
|
||||||
|
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.
|
||||||
|
pub fn delete_entities_with(&mut self, components: Vec<TypeId>) {
|
||||||
|
let entities = self.get_entities_with(components);
|
||||||
|
for entity in entities {
|
||||||
|
self.delete_entity(entity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Iterates over all entities that have the given components and calls the given function.
|
||||||
|
pub fn foreach<C: Component, K: Component>(&mut self, func: fn(&mut C, &mut K)) {
|
||||||
|
let entities = self.get_entities_with(vec![C::type_id(), K::type_id()]);
|
||||||
|
for entity in entities {
|
||||||
|
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;
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
func(&mut *c_ptr, &mut *k_ptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Registers a prefab with the given name and factory function.
|
||||||
|
pub fn register_prefab(&mut self, name: &str, factory: crate::prefabs::PrefabFactory) {
|
||||||
|
self.prefabs.register(name, factory);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Spawns a prefab with the given name.
|
||||||
|
pub fn spawn_prefab(&mut self, name: &str) -> Option<usize> {
|
||||||
|
if self.prefabs.has_prefab(name) {
|
||||||
|
if let Some(factory) = self.prefabs.prefabs.get(&name.to_string()) {
|
||||||
|
let factory = *factory; // Copy the function pointer
|
||||||
|
Some(factory(self))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Checks if a prefab with the given name exists.
|
||||||
|
pub fn has_prefab(&self, name: &str) -> bool {
|
||||||
|
self.prefabs.has_prefab(name)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
52
examples/prefabs.rs
Normal file
52
examples/prefabs.rs
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
use comet::prelude::*;
|
||||||
|
|
||||||
|
fn setup(app: &mut App, renderer: &mut Renderer2D) {
|
||||||
|
// Initialize the texture atlas
|
||||||
|
renderer.initialize_atlas();
|
||||||
|
|
||||||
|
// Register components
|
||||||
|
app.register_component::<Position2D>();
|
||||||
|
app.register_component::<Color>();
|
||||||
|
|
||||||
|
// Register prefabs
|
||||||
|
register_prefab!(
|
||||||
|
app,
|
||||||
|
"player",
|
||||||
|
Position2D::from_vec(v2::new(0.0, 0.0)),
|
||||||
|
Color::new(0.0, 1.0, 0.0, 1.0) // Green player
|
||||||
|
);
|
||||||
|
|
||||||
|
register_prefab!(
|
||||||
|
app,
|
||||||
|
"enemy",
|
||||||
|
Position2D::from_vec(v2::new(5.0, 5.0)),
|
||||||
|
Color::new(1.0, 0.0, 0.0, 1.0) // Red enemy
|
||||||
|
);
|
||||||
|
|
||||||
|
register_prefab!(
|
||||||
|
app,
|
||||||
|
"pickup",
|
||||||
|
Position2D::from_vec(v2::new(-5.0, -5.0)),
|
||||||
|
Color::new(1.0, 1.0, 0.0, 1.0) // Yellow pickup
|
||||||
|
);
|
||||||
|
|
||||||
|
if let Some(player_id) = app.spawn_prefab("player") {
|
||||||
|
debug!("Spawned player with ID: {}", player_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(enemy_id) = app.spawn_prefab("enemy") {
|
||||||
|
debug!("Spawned enemy with ID: {}", enemy_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(pickup_id) = app.spawn_prefab("pickup") {
|
||||||
|
debug!("Spawned pickup with ID: {}", pickup_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update(app: &mut App, renderer: &mut Renderer2D, dt: f32) {}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
App::new()
|
||||||
|
.with_title("Prefabs Example")
|
||||||
|
.run::<Renderer2D>(setup, update);
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue