Hello,
I've been stuck for two days trying to find a way to implement some C++ code that makes heavy usage of inheritance. To make things easier to understand, the piece of code I'm porting is part of a small entity-component-system of my own engine.
So far the flow is that an Entity owns a ComponentList and the ComponentList owns all the Component instances.
The real problem is that the Component struct has some common behavior functions and then, in C++, I just inherit from Component and override whatever function I need (usually it's just update() and eventually render(), but that's not 100% of the cases of course). I'm omitting the rest of the code (Scene that owns an EntityList that owns all the Entity instances) as it's pretty much the same problem, just a level higher.
The current Rust layout is pretty much the following:
pub struct Entity {
position: Vector2<f32>,
active: bool,
visibile: bool,
collidable: bool,
scene: Option<Rc<Scene>>,
components: ComponentList,
tags: Vec<u32>,
colliders: ColliderList,
actual_depth: f32,
depth: i32,
}
pub trait EntityTrait {
fn added(scene: &Scene);
fn removed(scene: &Scene);
fn awake(scene: &Scene);
fn scene_begin();
fn scene_end();
fn update();
fn render();
fn debug_render();
fn add(component: &Component);
fn remove(component: &Component);
fn get() -> Rc<Component>;
fn add_collider(collider: &Collider);
fn remove_collider(collider: &Collider);
fn tag(tag: u32);
fn untag(tag: u32);
fn collide_check(other: &Entity);
fn set_depth(depth: i32);
fn get_depth() -> i32;
}
pub struct ComponentList {
entity: Option<Rc<Entity>>,
components: Vec<Rc<Component>>,
to_add: Vec<Component>,
to_remove: Vec<Component>,
lock_mode: LockMode,
}
pub trait Component {
fn added(entity: Rc<Entity>);
fn removed(entity: Rc<Entity>);
fn entity_added();
fn entity_removed();
fn update();
fn render();
fn debug_render();
fn remove_self();
fn get_scene() -> Rc<Scene>;
}
I thought of implementing the Component as a BaseComponent + specializations, something like:
pub struct BaseComponent {
entity: Option<Rc<Entity>>,
visible: bool,
active: bool,
}
impl BaseComponent {
pub fn new() -> Self {
BaseComponent {
visible: true,
active: true,
}
}
}
pub struct Position {
base: BaseComponent,
x: f32,
y: f32,
}
impl Position {
pub fn new(x: f32, y: f32) -> Self {
Position {
base: BaseComponent::new(),
x: x,
y: y,
}
}
}
but then I'd have to implement all of the Component trait function for all the specialized Component and it doesn't really sound like a good option. I could split up the Component trait and keep just the update() and render() functions as they're the one I usually implement, but I'd still need to implement the other trait with all the other functions at least to call the embedded BaseComponent.
I've tried lots of different approaches to find a solution but nothing that really satisfies my needs. Eventually I might just be thinking the wrong way to be able to apply composition correctly.
I could really need a hand with this