У меня есть система на основе сущностей.
GameObject
(сущность) сохраняет все указатели на все связанные GameComponent
s.
Все GameComponent
держать указатель на GameObject
,
Если я знаю, что мне нужно часто запрашивать один компонент из другого компонента (Physics
<->Graphics
), Я буду кешировать указатель другого компонента.
class Physics : public GameComponent {
Graphics* graphic; //different GameObject
};
class Graphics: public GameComponent {
Physics * physic ; //different GameObject
};
Стоимость запроса указателя друг от друга (Physics->Graphics
а также Graphics->Physics
) очень маленький.
хранения Graphics
указатель в Physics
и наоборот становится менее чувствительным и вызывает проблему ремонтопригодности.
Например, если я хочу добавить новое отношение, например, Physics-Player
Мне нужно будет добавить поле в оба класса:
Player*
в class Physics
Physic*
в class Player
Если я продолжу, совершенно простые компоненты будут забиты множеством полей отношение это трудно отслеживать и поддерживать.
class Physic: public GameComponent {
Graphic* graphicsMain;
Graphic* graphicsSecondary;
Player* playerPtr;
Enemy* enemyPtr;
//10+ as project grow
}
Код для запроса объекта из другого объекта разбросаны во многих местах.
Вопрос: Как решить проблему ремонтопригодности без снижения производительности?
Я создал новый GameComponent
названный RelationNode
,
Затем создайте новую систему с именем Relation
управлять каждым типом отношений в одно место.
Плюсы: Я могу закодировать все утилиты, которые я хочу, и это будет работать для каждого типа отношений.
class Physics : public GameComponent {
//no keep Graphics pointer anymore ... clean :)
};
class Graphics: public GameComponent {
//no keep Physics pointer anymore ... clean :)
};
public RelationNode : public GameComponent {
//... some code ... cache other component ...
RelationNode* slot01; //shared Physics->Graphics and Graphics->Physics
RelationNode* slot02; //Physic->graphicsSecondary
.......
RelationNode* slot20;
//^ I can reuse same slot of variable if I am sure.
//instead of "RelationNode*" , it can also be "GameObject*"};
class Relation{
Graphics* getGraphicsFromPhysics(Physics* gameComponent){
RelationNode* a = toNode(gameComponent); //waste 1-2 indirection
RelationNode* b = queryGraphicFromPhysics(gameComponent);
Graphics* bCom= fromNode(b); //waste 1-2 indirection
return bCom;
}
//the real code is more elegant than this, but suffer the same issue
};
Теперь мой код настолько чистый, но страдает от снижения производительности косвенность.
Это стоит около 1-30% (профилировано), зависит от тестового примера.
у меня есть другой сумасшедшая идея о добавлении поля в компонент с помощью макроса, но я не люблю макрос — он вызывает другие проблемы.
Моя старая идея заключается в использовании hashMap
например HashMap<Graphics*,Physics*>
, но это намного медленнее, чем мой обходной путь (проверено).
Задача ещё не решена.
Других решений пока нет …