实体组件系统(ECS)是一种常用的游戏架构模式,它将游戏对象拆分为实体、组件和系统三个核心部分。实体只是一个唯一标识,组件是附加在实体上的数据,系统则负责处理具备某些组件的实体集合。下面我们用C++实现一个最基础的ECS框架。

基础结构设计
首先定义实体类型和组件基类。实体使用整数ID表示,所有组件都继承自一个空基类以便统一存储。
#include <iostream>
#include <vector>
#include <unordered_map>
#include <memory>
// 实体类型:使用整数作为唯一ID
using Entity = int;
// 组件基类
struct Component {
virtual ~Component() = default;
};
// 具体组件:位置组件
struct PositionComponent : Component {
float x = 0.0f;
float y = 0.0f;
};
// 具体组件:速度组件
struct VelocityComponent : Component {
float vx = 0.0f;
float vy = 0.0f;
};
实体与组件管理
我们需要一个世界类来管理所有实体以及它们绑定的组件。这里使用映射表按组件类型存储。
class World {
public:
// 创建新实体
Entity createEntity() {
Entity e = nextEntityId++;
entities.push_back(e);
return e;
}
// 为实体添加组件
template<typename T>
void addComponent(Entity e, T* comp) {
components[typeid(T).hash_code()][e] = std::shared_ptr<Component>(comp);
}
// 获取实体组件
template<typename T>
T* getComponent(Entity e) {
auto& map = components[typeid(T).hash_code()];
auto it = map.find(e);
if (it != map.end()) {
return static_cast<T*>(it->second.get());
}
return nullptr;
}
// 判断实体是否拥有某组件
template<typename T>
bool hasComponent(Entity e) {
return getComponent<T>(e) != nullptr;
}
std::vector<Entity> entities;
private:
Entity nextEntityId = 0;
std::unordered_map<size_t, std::unordered_map<Entity, std::shared_ptr<Component>>> components;
};
系统实现
系统遍历拥有相关组件的实体并执行逻辑。下面实现一个移动系统,它更新带位置和速度组件的实体。
class MovementSystem {
public:
void update(World& world, float dt) {
for (Entity e : world.entities) {
if (world.hasComponent<PositionComponent>(e) &&
world.hasComponent<VelocityComponent>(e)) {
PositionComponent* pos = world.getComponent<PositionComponent>(e);
VelocityComponent* vel = world.getComponent<VelocityComponent>(e);
pos->x += vel->vx * dt;
pos->y += vel->vy * dt;
}
}
}
};
使用示例
把上面的代码组合起来,就可以创建一个世界、生成实体并运行系统。
int main() {
World world;
MovementSystem moveSys;
Entity player = world.createEntity();
world.addComponent<PositionComponent>(player, new PositionComponent());
world.addComponent<VelocityComponent>(player, new VelocityComponent());
world.getComponent<VelocityComponent>(player)->vx = 1.0f;
world.getComponent<VelocityComponent>(player)->vy = 2.0f;
moveSys.update(world, 0.1f);
PositionComponent* p = world.getComponent<PositionComponent>(player);
std::cout << "Player position: " << p->x << ", " << p->y << std::endl;
return 0;
}
小结
以上代码展示了一个极简的C++实体组件系统。实际项目中通常会使用更复杂的组件存储方式(如按类型分组的连续数组)来提升缓存命中率,也会引入事件机制和系统调度器。理解这个基础模型后,你可以更容易地阅读Unity DOTS或Entt等成熟ECS库的设计思路。