Skip to content

Instantly share code, notes, and snippets.

@matthewjberger
Created September 29, 2024 15:11
Show Gist options
  • Save matthewjberger/b4c7741cc0abea8ee755eeb75804ec56 to your computer and use it in GitHub Desktop.
Save matthewjberger/b4c7741cc0abea8ee755eeb75804ec56 to your computer and use it in GitHub Desktop.
more ecs ideas in rust
use std::any::Any;
use std::collections::HashMap;
use std::marker::PhantomData;
// Generic handle type
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct Handle<T> {
id: usize,
_phantom: PhantomData<T>,
}
// Trait for components
pub trait Component: 'static {}
// Generic storage for components
pub struct ComponentStorage<T: Component> {
data: Vec<T>,
}
impl<T: Component> ComponentStorage<T> {
fn new() -> Self {
ComponentStorage { data: Vec::new() }
}
fn insert(&mut self, component: T) -> Handle<T> {
let id = self.data.len();
self.data.push(component);
Handle { id, _phantom: PhantomData }
}
fn get(&self, handle: Handle<T>) -> Option<&T> {
self.data.get(handle.id)
}
fn get_mut(&mut self, handle: Handle<T>) -> Option<&mut T> {
self.data.get_mut(handle.id)
}
}
// World struct to manage all component storages
pub struct World {
storages: HashMap<std::any::TypeId, Box<dyn Any>>,
}
impl World {
pub fn new() -> Self {
World { storages: HashMap::new() }
}
pub fn register_component<T: Component>(&mut self) {
let type_id = std::any::TypeId::of::<T>();
if !self.storages.contains_key(&type_id) {
self.storages.insert(type_id, Box::new(ComponentStorage::<T>::new()));
}
}
pub fn add_component<T: Component>(&mut self, component: T) -> Handle<T> {
let type_id = std::any::TypeId::of::<T>();
let storage = self.storages.get_mut(&type_id)
.and_then(|boxed| boxed.downcast_mut::<ComponentStorage<T>>())
.expect("Component type not registered");
storage.insert(component)
}
pub fn get_component<T: Component>(&self, handle: Handle<T>) -> Option<&T> {
let type_id = std::any::TypeId::of::<T>();
self.storages.get(&type_id)
.and_then(|boxed| boxed.downcast_ref::<ComponentStorage<T>>())
.and_then(|storage| storage.get(handle))
}
pub fn get_component_mut<T: Component>(&mut self, handle: Handle<T>) -> Option<&mut T> {
let type_id = std::any::TypeId::of::<T>();
self.storages.get_mut(&type_id)
.and_then(|boxed| boxed.downcast_mut::<ComponentStorage<T>>())
.and_then(|storage| storage.get_mut(handle))
}
}
// Example usage
impl Component for Camera {}
impl Component for Transform {}
impl Component for Node {}
#[derive(Default, Debug)]
struct Camera;
#[derive(Default, Debug)]
struct Transform;
#[derive(Default, Debug)]
struct Node;
fn main() {
let mut world = World::new();
world.register_component::<Camera>();
world.register_component::<Transform>();
world.register_component::<Node>();
let camera_handle = world.add_component(Camera);
let transform_handle = world.add_component(Transform);
let node_handle = world.add_component(Node);
// Use the handles to access the components
if let Some(camera) = world.get_component(camera_handle) {
println!("Got camera: {:?}", camera);
}
if let Some(transform) = world.get_component_mut(transform_handle) {
println!("Got mutable transform: {:?}", transform);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment