mirror of
https://github.com/lisk77/comet.git
synced 2025-12-12 09:08:49 +00:00
fix(ecs): some replacement issues
This commit is contained in:
parent
a01a52766d
commit
eced6ddf3f
8 changed files with 176 additions and 112 deletions
|
|
@ -27,6 +27,13 @@ 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 {
|
||||
match &data.fields {
|
||||
Fields::Named(fields) => fields
|
||||
|
|
@ -83,13 +90,11 @@ pub fn component_derive(input: TokenStream) -> TokenStream {
|
|||
impl Clone for #name {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
..*self
|
||||
#(#clone_fields),*
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Copy for #name {}
|
||||
|
||||
impl std::fmt::Debug for #name {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct(stringify!(#name))
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
// They are intended to work with the base suite of systems provided by the engine.
|
||||
use crate::math::{v2, v3};
|
||||
use crate::{Entity, Scene};
|
||||
use comet_log::*;
|
||||
use comet_colors::Color as ColorTrait;
|
||||
use comet_math::m4;
|
||||
use component_derive::Component;
|
||||
|
|
@ -110,10 +111,13 @@ pub struct Transform3D {
|
|||
// # TRAITS #
|
||||
// ##################################################
|
||||
|
||||
pub trait Component: Send + Sync + PartialEq + Default + 'static {
|
||||
pub trait Component: Send + Sync + 'static {
|
||||
fn new() -> Self
|
||||
where
|
||||
Self: Sized;
|
||||
Self: Sized + Default,
|
||||
{
|
||||
Default::default()
|
||||
}
|
||||
|
||||
fn type_id() -> std::any::TypeId {
|
||||
std::any::TypeId::of::<Self>()
|
||||
|
|
@ -136,7 +140,7 @@ pub trait Render {
|
|||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
@ -246,8 +250,8 @@ impl Rectangle2D {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn position(&self) -> Position2D {
|
||||
self.position
|
||||
pub fn position(&self) -> &Position2D {
|
||||
&self.position
|
||||
}
|
||||
|
||||
pub fn set_position(&mut self, position: Position2D) {
|
||||
|
|
@ -417,7 +421,7 @@ impl Camera2D {
|
|||
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 right = camera_pos.x() + self.zoom;
|
||||
let bottom = camera_pos.y() - self.zoom;
|
||||
|
|
@ -428,19 +432,18 @@ impl 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 mut visible_entities = Vec::new();
|
||||
for entity in entities {
|
||||
if self.in_view_frustum(
|
||||
camera_position,
|
||||
*scene
|
||||
.get_component::<Transform2D>(*entity.clone().unwrap().id() as usize)
|
||||
.unwrap()
|
||||
.position(),
|
||||
) {
|
||||
let id = *entity.clone().unwrap().id() as usize;
|
||||
if let Some(transform) = scene.get_component::<Transform2D>(id) {
|
||||
if self.in_view_frustum(camera_position, transform.position()) {
|
||||
visible_entities.push(entity.clone().unwrap());
|
||||
}
|
||||
} else {
|
||||
error!("Entity {} missing Transform2D", id);
|
||||
}
|
||||
}
|
||||
visible_entities
|
||||
}
|
||||
|
|
@ -498,7 +501,7 @@ impl Text {
|
|||
}
|
||||
|
||||
pub fn color(&self) -> Color {
|
||||
self.color
|
||||
self.color.clone()
|
||||
}
|
||||
|
||||
pub fn set_visibility(&mut self, visibility: bool) {
|
||||
|
|
|
|||
|
|
@ -65,20 +65,17 @@ impl Scene {
|
|||
|
||||
/// Gets an immutable reference to an entity by its ID.
|
||||
pub fn get_entity(&self, entity_id: usize) -> Option<&Entity> {
|
||||
self.entities.get(entity_id).unwrap().as_ref()
|
||||
self.entities.get(entity_id).and_then(|e| e.as_ref())
|
||||
}
|
||||
|
||||
/// Gets a mutable reference to an entity by its ID.
|
||||
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).and_then(|e| e.as_mut())
|
||||
}
|
||||
|
||||
/// Deletes an entity by its ID.
|
||||
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(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() {
|
||||
|
|
@ -107,24 +104,6 @@ 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) {
|
||||
self.archetypes
|
||||
.add_entity_to_archetype(&components, entity_id);
|
||||
|
|
@ -135,18 +114,6 @@ impl Scene {
|
|||
.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 {
|
||||
let components = match self.entities.get(entity_id) {
|
||||
Some(cmp) => match cmp.as_ref() {
|
||||
|
|
@ -195,19 +162,28 @@ impl Scene {
|
|||
pub fn add_component<C: Component + 'static>(&mut self, entity_id: usize, component: C) {
|
||||
let old_component_set = self.get_component_set(entity_id);
|
||||
if !old_component_set.to_vec().is_empty() {
|
||||
self.remove_entity_from_archetype_subsets(entity_id as u32, old_component_set);
|
||||
self.remove_entity_from_archetype(entity_id as u32, old_component_set);
|
||||
}
|
||||
|
||||
self.components.set_component(entity_id, component);
|
||||
let component_index = self
|
||||
if let Some(component_index) = self
|
||||
.components
|
||||
.keys()
|
||||
.iter_mut()
|
||||
.iter()
|
||||
.position(|x| *x == C::type_id())
|
||||
.unwrap();
|
||||
self.get_entity_mut(entity_id)
|
||||
.unwrap()
|
||||
.add_component(component_index);
|
||||
{
|
||||
if let Some(entity) = self.get_entity_mut(entity_id) {
|
||||
entity.add_component(component_index);
|
||||
} else {
|
||||
error!("Attempted to add component to non-existent entity {}", entity_id);
|
||||
}
|
||||
} else {
|
||||
error!(
|
||||
"Component {} not registered, cannot add to entity {}",
|
||||
C::type_name(),
|
||||
entity_id
|
||||
);
|
||||
}
|
||||
|
||||
let new_component_set = self.get_component_set(entity_id);
|
||||
|
||||
|
|
@ -215,15 +191,7 @@ impl Scene {
|
|||
self.create_archetype(new_component_set.clone());
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
self.add_entity_to_archetype(entity_id as u32, new_component_set);
|
||||
|
||||
info!(
|
||||
"Added component {} to entity {}!",
|
||||
|
|
@ -234,18 +202,19 @@ impl Scene {
|
|||
|
||||
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);
|
||||
self.remove_entity_from_archetype(entity_id as u32, old_component_set);
|
||||
|
||||
self.components.remove_component::<C>(entity_id);
|
||||
let component_index = self
|
||||
if let Some(component_index) = self
|
||||
.components
|
||||
.keys()
|
||||
.iter()
|
||||
.position(|x| *x == C::type_id())
|
||||
.unwrap();
|
||||
self.get_entity_mut(entity_id)
|
||||
.unwrap()
|
||||
.remove_component(component_index);
|
||||
{
|
||||
if let Some(entity) = self.get_entity_mut(entity_id) {
|
||||
entity.remove_component(component_index);
|
||||
}
|
||||
}
|
||||
|
||||
let new_component_set = self.get_component_set(entity_id);
|
||||
|
||||
|
|
@ -254,15 +223,7 @@ impl Scene {
|
|||
self.create_archetype(new_component_set.clone());
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
self.add_entity_to_archetype(entity_id as u32, new_component_set);
|
||||
}
|
||||
|
||||
info!(
|
||||
|
|
@ -291,21 +252,17 @@ impl Scene {
|
|||
/// 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 component_set.size() > 3 {
|
||||
error!("An entity query should only contain at most 3 different components!");
|
||||
return Vec::new();
|
||||
let mut result = Vec::new();
|
||||
|
||||
for archetype_set in self.archetypes.component_sets() {
|
||||
if component_set.is_subset(&archetype_set) {
|
||||
if let Some(entities) = self.archetypes.get_archetype(&archetype_set) {
|
||||
result.extend(entities.iter().map(|x| *x as usize));
|
||||
}
|
||||
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()
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
/// Deletes all entities that have the given components.
|
||||
|
|
@ -317,14 +274,23 @@ impl Scene {
|
|||
}
|
||||
|
||||
/// Iterates over all entities that have the two given components and calls the given function.
|
||||
pub fn foreach<C: Component, K: Component>(&mut self, func: fn(&mut C, &mut K)) {
|
||||
pub fn foreach<C: Component, K: Component>(&mut self, mut func: impl FnMut(&mut C, &mut K)) {
|
||||
if std::any::TypeId::of::<C>() == std::any::TypeId::of::<K>() {
|
||||
error!("foreach called with identical component types");
|
||||
return;
|
||||
}
|
||||
|
||||
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;
|
||||
let (c_set, k_set) = self
|
||||
.components
|
||||
.get_two_mut(&C::type_id(), &K::type_id());
|
||||
|
||||
unsafe {
|
||||
func(&mut *c_ptr, &mut *k_ptr);
|
||||
let c_opt = c_set.and_then(|set| set.get_mut::<C>(entity));
|
||||
let k_opt = k_set.and_then(|set| set.get_mut::<K>(entity));
|
||||
|
||||
if let (Some(c), Some(k)) = (c_opt, k_opt) {
|
||||
func(c, k);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ use comet_math::{m4, v2};
|
|||
use comet_resources::{
|
||||
font::Font, graphic_resource_manager::GraphicResourceManager, texture_atlas::*, Texture, Vertex,
|
||||
};
|
||||
use std::collections::HashSet;
|
||||
use std::sync::Arc;
|
||||
use wgpu::util::DeviceExt;
|
||||
use winit::{dpi::PhysicalSize, window::Window};
|
||||
|
|
@ -61,6 +62,7 @@ pub struct Renderer2D<'a> {
|
|||
resource_manager: GraphicResourceManager,
|
||||
camera_manager: CameraManager,
|
||||
render_passes: Vec<RenderPass>,
|
||||
cached_render_entities: Vec<usize>,
|
||||
last_frame_time: std::time::Instant,
|
||||
delta_time: f32,
|
||||
}
|
||||
|
|
@ -744,16 +746,44 @@ impl<'a> Renderer2D<'a> {
|
|||
return;
|
||||
}
|
||||
|
||||
let mut entities = scene.get_entities_with(vec![
|
||||
let unsorted_entities = scene.get_entities_with(vec![
|
||||
comet_ecs::Transform2D::type_id(),
|
||||
comet_ecs::Render2D::type_id(),
|
||||
]);
|
||||
|
||||
let mut dirty_sort = self.cached_render_entities.len() != unsorted_entities.len();
|
||||
|
||||
if !dirty_sort {
|
||||
let unsorted_set: HashSet<usize> = 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![
|
||||
comet_ecs::Transform2D::type_id(),
|
||||
|
|
@ -1012,6 +1042,7 @@ impl<'a> Renderer for Renderer2D<'a> {
|
|||
resource_manager: GraphicResourceManager::new(),
|
||||
camera_manager: CameraManager::new(),
|
||||
render_passes: Vec::new(),
|
||||
cached_render_entities: Vec::new(),
|
||||
last_frame_time: std::time::Instant::now(),
|
||||
delta_time: 0.0,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -272,6 +272,22 @@ impl Column {
|
|||
}
|
||||
}
|
||||
|
||||
/// 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) {
|
||||
assert!(
|
||||
index1 < self.data.len() && index2 < self.data.len(),
|
||||
|
|
|
|||
|
|
@ -67,6 +67,10 @@ impl ComponentSet {
|
|||
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> {
|
||||
self.set.iter().cloned().collect()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -44,6 +44,39 @@ 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 {
|
||||
self.map.iter().any(|node| node.0 == *key)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,6 +28,12 @@ impl SparseSet {
|
|||
}
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue