【问题标题】:my c++ game architecture我的 C++ 游戏架构
【发布时间】:2012-12-12 09:35:49
【问题描述】:

我是一个相当有经验的程序员,但我对 OOP 架构和 C++ 设计还是比较陌生。 我的大部分经验是使用 C# 和 Java。我最近尝试用 C++ 编写一个简单的游戏引擎。 我将 SDL 用于图形。在这篇文章中,我想讨论我的架构并获得一些反馈 在上面。特别是,我遇到了一个需要帮助的设计问题。所以,这里是:

  • 在我的主函数中,我初始化了所有用于绘制到屏幕等的 SDL 内容。
  • 然后我实例化我打算使用的所有对象:地板、墙壁、播放器等。
  • 接下来我开始主循环。此循环执行每个对象的移动、碰撞检测和碰撞处理功能,并重新绘制它们。
  • 主循环一直运行直到应用程序退出,每次迭代绘制一帧。

我的问题是: 我尝试做一种界面风格的设计。它涉及一系列 允许每个对象实现行为的抽象基类。例如,如果我希望一个对象是可移动的, 它必须继承自可移动基类,该基类包含一个名为move() 的虚函数和某个位置 坐标。如果我希望它是可碰撞的,则该对象将从可碰撞抽象类继承,它 包含虚函数checkCollision()handleCollision() 以及一个hitbox 成员变量。一个东西 就像玩家从这两个基类以及其他几个基类继承的一样。

只要我在主循环中手动完成所有操作,这就足够了。我只能说:

player.move();
player.checkCollision();
player.handleCollision();
player.draw(). 

没关系。但我想 能够在主循环中拥有一个向量或通用对象数组并执行以下操作:

for each object in vector
    if object is of type movable
        object.move();
    if object is of type collidable
        object.checkCollision();

我认为我可以通过动态投射来实现这一点,但我真的什么都想不出来。 我已经尝试将它们存储为 void 指针,但这并不像我想要的那样工作。我一直在读这个 我可能会尝试的视频游戏的游戏对象组件架构,但我真的很想挽救我已经拥有的东西 书面。我认为这是一个很好的学习机会。如果有人有任何想法,我将不胜感激。我的架构与其他简单的游戏引擎设计相比如何?我的界面架构有意义还是完全靠不住?

【问题讨论】:

  • 您可以为每个界面保留一份列表吗?在你的例子中;一份可移动对象列表和一份可碰撞对象列表?但是,如果同一对象具有多个属性,则需要将其保留在多个列表中。
  • Jonathan 所说的是动态转换的合理替代方案。您可以通过为每个对象提供一个 enroll 方法(或您想要的任何名称)来使其“更好”,您可以将包含这些单独列表的对象注册表传递给该方法。例如,如果您有一个FlyingSaucer 类,那么它的.enroll(Registry r) 方法将调用r.add((Movable) this)r.add((Collidable) this),将FlyingSaucer 添加到可移动对象列表和可碰撞对象列表中。然后可以将确保对象永远不会部分删除的业务逻辑隐藏到Registry::add
  • 你可以使用typeid操作符,en.wikipedia.org/wiki/Typeid
  • @Dims:这是可能的,但是您依赖于编译器附带的(可能效率低下和/或功能过于强大)RTTI。
  • 我认为RTTI在你已经拥有的虚拟功能的情况下是不可避免的。

标签: c++ oop architecture interface game-engine


【解决方案1】:

如果你使用 C++,试试 SFML,它比 SDL 更快,如果你知道 OpenGL,你也可以使用它。
对于您的问题:

class Entity {
     //constructor and other stuff
     void virtual exec() =0; ///<= pure virtual method
};

class Movable : Entity {
    void move(); //do somthing
    void exec() {move();};
};

class Collidable : Entity {
   void col(); //do your job
   void exec(){col();};
};

std::vector<Entity*> e_v;
///push some instance
for (Entity* e : e_v)
   e->exec();

【讨论】:

  • std::vector&lt;Entity&gt; 不会在 C++ 中完成这项工作,因为无论您输入什么类型,它都会被分割为 Entity
  • 抱歉,我忘记了“*”。矢量
  • 对于 C++11 甚至 TR1 或 boost 的智能指针,原始指针的使用在许多情况下都被贬低了。我更愿意使用std::vector&lt;std::unique_ptr&lt;Entity&gt;&gt;
【解决方案2】:

在基类中使用模板方法模式和非抽象空虚函数怎么样?

class Entity
{
    void update()
    {
        move();
        checkCollision();
    }

    virtual void move() {}
    virtual void checkCollision() {}
};

class Movable : public virtual Entity
{
    virtual void move() {}   // Stuff
};

class Collidable : public virtual Entity
{
    virtual void checkCollision() {}   // Stuff
};

【讨论】:

  • 我喜欢虚拟继承解决方案。我什至没有意识到有这样的事情。我一直在尝试类似的方法,但遇到了钻石问题。
  • 死亡钻石已在游戏中通过不在游戏中使用 OOP 来解决。尝试搜索“以属性为中心”或“基于组件”的架构。
猜你喜欢
  • 1970-01-01
  • 2011-07-24
  • 2013-02-01
  • 2017-08-22
  • 1970-01-01
  • 1970-01-01
  • 2010-12-01
  • 2011-08-31
  • 1970-01-01
相关资源
最近更新 更多