I have created ECS framework from scratch using C++.
Everything works fine, but I think my code is not so cute (at #1):-
class RocketComponent{
Entity mainBodyGraphic;
Entity topGraphic ;
};
//inside some system (script-like)
void createRocket(){
Entity mainBodyGraphic = graphicFactory->createCylinder();
Entity topGraphic = graphicFactory->createCone();
//^ internally create entity (with graphic component and others),
// then attach together
Pointer<RocketComponent> rocket = create<RocketComponent>();
rocket->mainBodyGraphic = mainBodyGraphic;
rocket->topGraphic = topGraphic;
//.... other logics ....
}
void showDamage(Entity rocket){
Pointer<RocketComponent> rocket = rocket->get<RocketComponent>();
systemGraphic->setColor(rocket->mainBodyGraphic,RED); //#1
}
#1 is ugly.
In my dream (Object-oriented style), #1 could be :-
rocket->mainBodyGraphic->setColor(RED); //#1
The above line is far easier to read and code. It is also less error-prone.
The Change (super entity)
I plan to change my code to support it, but I don't want to lose any disadvantage of ECS.
Therefore, I will create super entity.
For example:-
- I create a new super Entity class named
GEntity(graphic entity). - I provide a converter (
operator=()) betweenEntityandGEntity. - Whenever a function just want
Entity, I can passGEntityinstead, and vice versa! graphicFactory->createCone()and similar functions will returnGEntityinstead ofEntity.- The field in
RocketComponentwill beGEntity mainBodyGraphic;. Entityhas no access to game logic like before, butGEntitycan access all game logic/system.
Here is my adoption (future plan / promise to myself):-
- In
GEntity, I can add all syntactic sugar functions e.g.setColor()as much as I want. - I will use
GEntityonly when logical type of entity is very obvious. - I will also create
PEntity= Physic body, because its type is also obvious. - I may also create other types of super entity if its type is very obvious && I want the syntactic-sugar.
Here is the result (change marked with $):-
class RocketComponent{
GEntity mainBodyGraphic; //$
GEntity topGraphic ; //$
};
void createRocket(){
GEntity mainBodyGraphic = graphicFactory->createCylinder(); //$
GEntity topGraphic = graphicFactory->createCone(); //$
Pointer<RocketComponent> rocket = create<RocketComponent>();
rocket->mainBodyGraphic = mainBodyGraphic;
rocket->topGraphic = topGraphic;
//.... other logics ....
}
void showDamage(Entity rocket){
Pointer<RocketComponent> rocket = rocket->get<RocketComponent>();
rocket->mainBodyGraphic->setColor(RED); //$
}
Concern (my fear)
I feel that I am violating some ECS rules.
I am probably destroying good ECS abstraction and design pattern in favor of my indolence.
I have already refactored some of my code to the new way.
It looks nice and neat. I think I am biased.
Question
- What are disadvantage of this approach?
- What are things (potential issue) that I should concern and prevent?
- What is the name of this technique/design-pattern (if any)?