以 OO 方式进行游戏设计

2022-09-02 03:55:49

我正在设计一个简单的游戏,它使用Java 2D和牛顿物理学。目前,我的主要“游戏循环”看起来像这样:

do {
  for (GameEntity entity : entities) {
    entity.update(gameContext);
  }

  for (Drawable drawable : drawables) {
    drawable.draw(graphics2d);
  }
} while (gameRunning);

当一个实体被指示自我更新时,它将根据施加在它上面的当前力来调整它的速度和位置。但是,我需要实体表现出其他行为;例如,如果一个“坏人”被玩家射杀,该实体应该被摧毁并从游戏世界中移除。

我的问题是:以面向对象的方式实现这一目标的最佳方法是什么?到目前为止,我所看到的所有示例都将游戏循环合并到一个名为 类似 的 God 类中,该类执行以下步骤:检测碰撞、检查坏人死亡、检查玩家是否死亡、重绘等,并封装所有游戏状态(剩余生命等)。换句话说,这是非常程序化的所有的逻辑都在Game类中。任何人都可以推荐更好的方法吗?Game

以下是到目前为止我想到的选项:

  • 将 a 传递给每个实体,如果需要,实体可以从中删除自身或更新游戏状态(例如,如果玩家被杀,则更新为“不运行”)。GameContext
  • 将每个人注册为中心类的听众,并采取面向事件的方法;例如,碰撞会导致碰撞中的两个参与者被触发。GameEntityGameCollisionEvent

答案 1

我曾与两个商业游戏引擎密切合作,它们遵循类似的模式:

  • 对象表示游戏实体的组件或方面(如物理、可渲染等),而不是整个实体。对于每种类型的组件,都有一个巨大的组件列表,每个具有该组件的实体实例都有一个列表。

  • “游戏实体”类型本身只是一个唯一的 ID。每个巨大的组件列表都有一个映射,用于查找与实体 ID 对应的组件(如果存在)。

  • 如果组件需要更新,则由服务或系统对象调用。每个服务都直接从游戏循环更新。或者,您可以从计划程序对象调用服务,该计划程序对象从依赖关系图中确定更新顺序。

以下是此方法的优点:

  • 您可以自由组合功能,而无需为每个组合编写新类或使用复杂的继承树。

  • 对于可以放入游戏实体基类中的所有游戏实体,您几乎没有任何功能可以假设(灯光与赛车或天空盒有什么共同之处?

  • ID 到组件查找可能看起来很昂贵,但服务通过循环访问特定类型的所有组件来完成大部分密集型工作。在这些情况下,最好将所需的所有数据存储在单个整洁的列表中。


答案 2

在我使用的一个特定引擎中,我们将逻辑与图形表示分离,然后具有对象,这些对象将发送他们想要执行的操作的消息。我们这样做是为了让游戏存在于本地机器上或联网上,从代码的角度来看,它们彼此之间是无法区分的。(命令模式)

我们还在一个单独的对象中完成了实际的物理建模,该对象可以动态更改。这让我们很容易地搞砸重力等。

我们大量使用事件驱动的代码(侦听器模式)和很多很多计时器。

例如,我们有一个可互切的对象的基类,可以侦听碰撞事件。我们将其子分类为运行状况框。在碰撞时,如果它被玩家实体击中,它会向碰撞体发送命令,要求它应该获得生命值,发送消息以向所有可以听到它的人广播声音,停用碰撞,激活动画以从场景图中删除图形,并设置计时器以稍后重新确认自身。这听起来很复杂,但事实并非如此。

如果我记得(已经12年了),我们有抽象的场景概念,所以游戏是一系列场景。场景完成后,将触发一个事件,该事件通常会发送命令,删除当前场景并启动另一个场景。