我正在尝试构建一个优化的实体组件系统。我知道为了做到这一点,我应该尽量避免不必要的(小)虚函数,其中vtable查找将导致比实际函数本身更多的开销。我也知道一个流行的策略是让实体只有一个指向其组件的指针,让管理系统包含实际的组件本身,以增加数据的位置。
问题1: 我希望能够做的是建立一个事件监听系统。因此,对于大量实体的一般维护和操作,我将在EntityManagers组件数组中执行操作。当要处理事件时,它们将传递给实体,然后实体将其委托给其组件。然后,组件将处理事件,并可能将更多内容传递回实体以再次处理它们。
我的第一个问题是我应该这样做吗?我应该“向下”传递事件,还是应该让EntityManager解析整个数组,寻找与特定实体相关的组件?
问题2: 我应该使用这么多虚拟功能吗?其中一些看起来很像我的GetType()函数,它是返回静态值的一行代码。我知道像这样的函数的大部分开销都来自vtable查找。
问题3: 我对组件系统的想法已经变得非常复杂了。我想拥有一个武器组件,有3种类型的武器,每种都有自己的类,这样它们每个都有自己的火法。如果我循环遍历所有组件的数组是他们可以在没有虚函数的情况下处理这个问题的方法吗?我是否必须将每种武器类型分成不同的阵列才能正确处理?我是否必须对Body和其他所有类型的组件做同样的事情?我是否必须遍历每个武器类型的数组才能找到特定的实体武器,即使它们只能有一个呢?
提前感谢您的帮助。
Entity.h
#include <string>
#include "Transform.h"
#include "../Components/Component.h"
#include <vector>
class EntityManager;
class Event;
class Entity {
friend class EntityManager;
public:
Entity(size_t);
~Entity();
Transform transform;
void HandleEvent(Event *event);
size_t GetId() const;
std::string GetTag() const;
bool HasTag(std::string _tag) const;
private:
Entity(size_t _id);
void AddComponent(Component component);
void RemoveComponent(Component *component);
void SetTag(std::string _tag);
Component* GetComponent(ComponentType type);
size_t id;
std::string tag;
std::vector<Component> components; //Entities only have references to their components
std::vector<Listener> listeners;
};
Component.h
class Event;
class Entity;
enum ComponentType {
ComponentType_Mesh,
ComponentType_Camera,
ComponentType_PointLight,
ComponentType_DirectionLight,
ComponentType_SpotLight,
ComponentType_Body,
ComponentType_Input,
ComponentType_Weapon
};
class Component {
public:
Component();
bool enabled;
virtual ComponentType GetType() = 0;
virtual void HandleEvent(Event *event) = 0;
void Invoke(Event *event);
virtual void SetEntity(Entity *_entity);
Entity* GetEntity() const;
protected:
Entity *entity;
};
class Weapon : Component {
public:
ComponentType GetType() override { return ComponentType_Weapon; }
virtual void Fire();
};
class MachineGun : Weapon {
public:
void Fire() override;
};
class Railgun : Weapon {
public:
void Fire() override;
};
class Launcher : Weapon {
public:
void Fire() override;
};
class Body : Component {
ComponentType GetType() override { return ComponentType_Body; }
int health;
};
Event.h
enum EventType {
EventType_Null = -1,
EventType_PhysCol = 0,
EventType_WheelRayCol = 1,
EventType_Accelerate = 2,
EventType_Turn = 3,
EventType_Fire = 4,
EventType_Damage = 5
};
struct Listener {
Component* comp;
EventType type;
};
class Event {
public:
int affectedID;
const static EventType type;
//vector<int> entityIDs;
Event(int);
inline int GetAffectedID();
};
class InteractEvent : Event {
public:
int sourceID;
InteractEvent(int, int);
inline int GetSourceID();
};
class AccelerateEvent : Event {
public:
using Event::Event;
const static EventType type;
};
class FireEvent : Event {
public:
using Event::Event;
const static EventType type;
};