假设我正在用 C++ 创建一个 OpenGL 游戏,它将创建许多对象(敌人、玩家角色、元素等)。我想知道组织这些的最佳方法,因为它们将根据时间、玩家位置/ Action 等实时创建和销毁。
这是我到目前为止想到的: 我可以有一个全局数组来存储指向这些对象的指针。这些对象的纹理/上下文加载在它们的构造函数中。这些对象将具有不同的类型,因此我可以转换指针以将它们放入数组中,但我希望稍后有一个 renderObjects() 函数,该函数将使用循环为每个现有对象调用 ObjectN.render() 函数。
我想我以前试过这个,但我不知道用什么类型来初始化数组,所以我选择了一个任意的对象类型,然后转换任何不是那种类型的东西。如果我记得,这不起作用,因为编译器不希望我取消引用指针,如果它不再知道它们的类型,即使给定的成员函数具有相同的名称: (*Object5).render() <-doesn不行吗?
有没有更好的办法?像HL2这样的商业游戏如何处理?我想一定有一些模块等可以跟踪所有对象。
Best Answer-推荐答案
对于我即将成为的个人游戏项目,我使用了基于组件的实体系统。
您可以通过搜索“基于组件的游戏开发”了解更多相关信息。一篇著名的文章是Evolve Your Hierarchy来自牛仔编程博客。
在我的系统中,实体只是 ids - unsigned long,有点像在关系数据库中。 与我的实体关联的所有数据和逻辑都写入到组件中。我有将实体 ID 与其各自组件链接的系统。类似的东西:
typedef unsigned long EntityId;
class Component {
Component(EntityId id) : owner(id) {}
EntityId owner;
};
template <typename C> class System {
std::map<EntityId, C * > components;
};
然后对于每种功能,我编写了一个特殊的组件。所有实体都没有相同的组件。 例如,您可以拥有一个包含 WorldPositionComponent 和 ShapeComponent 的静态岩石对象,以及一个具有相同组件和 VelocityComponent 的移动敌人。 下面是一个例子:
class WorldPositionComponent : public Component {
float x, y, z;
WorldPositionComponent(EntityId id) : Component(id) {}
};
class RenderComponent : public Component {
WorldPositionComponent * position;
3DModel * model;
RenderComponent(EntityId id, System<WorldPositionComponent> & wpSys)
: Component(id), position(wpSys.components[owner]) {}
void render() {
model->draw(position);
}
};
class Game {
System<WorldPositionComponent> wpSys;
System<RenderComponent> rSys;
void init() {
EntityId visibleObject = 1;
// Watch out for memory leaks.
wpSys.components[visibleObject] = new WorldPositionComponent(visibleObject);
rSys.components[visibleObject] = new RenderComponent(visibleObject, wpSys);
EntityId invisibleObject = 2;
wpSys.components[invisibleObject] = new WorldPositionComponent(invisibleObject);
// No RenderComponent for invisibleObject.
}
void gameLoop() {
std::map<EntityId, RenderComponent *>::iterator it;
for (it = rSys.components.iterator(); it != rSys.components.end(); ++it) {
(*it).second->render();
}
}
};
这里有 2 个组件,WorldPosition 和 Render。 Game 类包含 2 个系统。 Render 组件可以访问对象的位置。如果实体没有 WorldPosition 组件,您可以选择默认值,或忽略该实体。 Game::gameLoop() 方法只会渲染可见对象。对于不可渲染的组件没有处理浪费。
您还可以将我的 Game 类拆分为两个或三个,以将显示和输入系统与逻辑分开。诸如模型、 View 和 Controller 之类的东西。
我发现根据组件定义我的游戏逻辑很巧妙,并且拥有只具有它们需要的功能的实体——不再有空的 render() 或无用的碰撞检测检查。
关于c++ - 在游戏中组织实体的最佳方式?,我们在Stack Overflow上找到一个类似的问题:
https://stackoverflow.com/questions/764824/
|