Architecture 什么';游戏对象绘制和更新自身的架构有什么问题?

Architecture 什么';游戏对象绘制和更新自身的架构有什么问题?,architecture,oop,Architecture,Oop,游戏对象绘制和更新自身的原因是什么?例如,如果您有一个玩家在屏幕上有位置的游戏,为什么不设置一个包罗万象的类: public class Player { private int x, y, xVelocity, yVelocity; private Sprite s; //... public Player() { // load the sprite here, somehow? } public void draw(Cus

游戏对象绘制和更新自身的原因是什么?例如,如果您有一个玩家在屏幕上有位置的游戏,为什么不设置一个包罗万象的类:

public class Player {
    private int x, y, xVelocity, yVelocity;
    private Sprite s;
    //...

    public Player() {
        // load the sprite here, somehow?
    }

    public void draw(CustomGraphicsClass g) {
        g.draw(s, x, y);
    }

    public void update(long timeElapsed) {
        x += (xVelocity * timeElapsed);
        y += (yVelocity * timeElapsed);
    }
}
这个设计有什么问题?下跌或担忧是什么?你怎样才能更好地写这样的东西,或者更好地在游戏中设计这样的东西

另外,有些关联,您将如何实现加载该精灵图像

此外,您将如何实现两个
Player
s之间的冲突


(我可能应该把这两个额外的问题分成新的问题,嗯?)

没关系,但是如果你有很多不同的对象,都有需要更新的精灵、位置和天鹅绒,那么会有很多复制。你可以将位置,速度推到一个基类中,但是这会硬连接运动的类型。更好的方法是将运动与对象本身分开


例如,考虑一个球上下跳动。仅以速度来建模并不容易。相反,创建一个运动类,使用ConstantMotion(用于速度)和BounceMotion(用于反弹)。然后,motion类负责从一帧到另一帧更新对象的位置状态。

一个可能的缺点可能是违反了关注点的分离。我认为,理想情况下,对象不应该知道它们是如何渲染的,这样渲染引擎就可以与游戏对象分开调整……不过,在实践中,可能是这些东西往往相互依赖,无法以这种方式分开。

假设每次更新对象(即玩家)时都应该这样做

1) 重画自己

2) 通知其他单位它已更新

3) 将“更新动作”写入历史记录/日志/其他任何内容(也许你想在游戏结束后重现整个游戏,就像电影一样)

n) 玩家对象与其环境之间的任何其他交互

在所有这些情况下,您必须更改更新方法,如:

public void update(long timeElapsed) {
   dosmth();

   redraw();
   notifyUnits();
   updateHistory();
}

这很烦人。这就是为什么在这种情况下应该使用观察者模式。对象应通知所有侦听器它已更新。监听器(GraphicsContext、History、units)将以适当的方式做出反应,并且您的程序将保持易于维护,因为它的所有部分将只负责一个具体任务

了解系统中的大多数对象只应修改特定于引擎的描述符(速度、活动动画)并允许引擎处理实际效果的可能性非常有用。有一些例外(通常是子弹和其他单勾效应),但总的来说,这些系统依靠一个通用的勾来更新游戏。这主要是因为,正如mdma在评论Roman的答案时所指出的,实际引擎所做的远远不止是简单的单个渲染操作。类似地,物理引擎将更新整个世界,计算碰撞体积,同时考虑子刻度移动

加载精灵通常是加载整个地图的资源,然后在地图的资源库中按名称对该精灵进行寻址


冲突通常由单独的物理引擎处理,请参见上文。

它将所有渲染和逻辑代码耦合在一起,而它们除了概念上绑定到同一个“实体”之外几乎没有什么共同之处。随着你的类越来越大,你会发现自己有一个巨大的单片
播放器
,这是一个需要维护的噩梦。沿着域边界(渲染、人工智能)拆分使其更易于管理,而不必放弃太多,因为这些域没有太多重叠

除了可维护性之外,还有一些其他考虑因素:

  • 如果您想在不同的线程上处理渲染和AI,那么将它们的状态混合到同一个类中只会导致严重的多线程问题

  • >P>如果使用像C++这样的语言,这样的高度耦合类会杀死编译时间。

  • 根据代码和对象在内存中的布局,将对象拆分为每个域的单独组件可以提供更好的缓存一致性和更好的性能


  • 如果你好奇的话,这里是我的答案。

    在我输入之前就已经爱上了这个模式:

    对于一个游戏来说,性能将是最大的缺点。您可能希望将所有图形上下文、对象等保留在一个位置,并优化一个较大的代码块


    如果出于某种原因希望在不同的平台上进行渲染,那么这种方法由于缺乏分离而失败,同样,插件渲染器是一种更好的方法

    请注意,redraw()不应直接重新绘制,而只是指示需要绘制对象。外部渲染器负责在需要重画的对象之间进行迭代,并以正确的顺序绘制它们,应用适当的剪辑等。我喜欢你链接到的带有“更多信息”的页面!!仍然在考虑这一切,但这肯定是有益的,不仅是被告知要做什么,但给出一个体面的例子,并讨论的陷阱和其他考虑因素。谢谢!这是我正在写的一本书,但它现在或多或少处于停顿期。如果本章中有任何不清楚的地方,请告诉我。+1仅针对第3点,这是关键原因,尤其是在控制台上。封装可能会导致缓存性能差,特别是在存储每个对象的IsVisible等标志,然后加载该对象的整个缓存线以检查是否应该绘制它的etcGood点时。甚至比执行
    isVisible
    检查更好的是只对可渲染组件进行单独的集合,这样就根本不需要遍历不可见的组件。最快的代码是永远不会被调用的代码:)用于