如何以模块化方式模拟游戏对象渲染和行为?

Bob*_*age 8 java oop android

我正在为Android手机制作Java射击游戏.我在游戏中有20个奇怪的敌人,每个人都有一些独特的行为,但大多数人都会重复使用某些行为.我需要模拟子弹,爆炸,小行星等以及其他所有有点像敌人的东西.我目前的设计倾向于组合而不是继承,并且代表游戏对象有点像这样:

// Generic game object
class Entity
{
  // Current position
  Vector2d position;

  // Regular frame updates behaviour
  Behaviour updateBehaviour;
  // Collision behaviour
  Behaviour collideBehaviour;

  // What the entity looks like
  Image image;
  // How to display the entity
  Renderer renderer;

  // If the entity is dead and should be deleted
  int dead;
}

abstract class Renderer { abstract void draw(Canvas c); }

abstract class Behaviour { abstract void update(Entity e); }
Run Code Online (Sandbox Code Playgroud)

要只绘制存储为实体图像的内容,您可以附加一个简单的渲染器,例如

class SimpleRenderer extends Renderer
{
  void draw(Canvas c)
  {
    // just draw the image
  }
}
Run Code Online (Sandbox Code Playgroud)

要使实体每帧随机飞行,只需附加如下行为:

class RandomlyMoveBehaviour extends Behaviour
{
  void update(Entity e)
  {
    // Add random direction vector to e.position
  }
}
Run Code Online (Sandbox Code Playgroud)

或者添加更复杂的行为,例如在归位前等待玩家关闭:

class SleepAndHomeBehaviour extends Behaviour
{
  Entity target;
  boolean homing;

  void init(Entity t) { target = t; }

  void update(Entity e)
  {
    if (/* distance between t and e < 50 pixels */)
    {
      homing = true;
      // move towards t...
    }
    else
    {
      homing = false;
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

到目前为止,我对这个设计非常满意.它很好而且灵活,你可以例如模块化后一类,这样你可以提供"睡眠"行为和"清醒"行为,所以你可以说新的WaitUntilCloseBehaviour(播放器,50/像素 /,新的MoveRandomlyBehaviour(),new HomingBehaviour()).这使得制造新敌人变得非常容易.

困扰我的唯一部分是行为和渲染器的沟通方式.目前,Entity包含一个Image对象,如果行为选择这样做,行为可以修改.例如,一种行为可以改变睡眠和清醒图像之间的对象,渲染器只会绘制图像.我不确定这会如何扩展,例如:

  • 那个面向某个方向的炮塔式敌人怎么样?我想我可以向Entity添加一个旋转字段,行为和渲染器都可以修改/读取.

    • 那个坦克的主体和坦克的枪有不同方向的坦克怎么样?现在,渲染器需要访问来自某处的两个旋转以及要使用的两个图像.如果只有一个坦克,你真的不想用这个膨胀Entity类.

    • 当他的枪充电时,一个发光的敌人怎么样?您真的想将充电时间存储在Behavior对象中,但Renderer类无法看到它.

我无法考虑如何对上述模型进行建模,因此渲染器和行为可以保持一定程度的分离.我能想到的最好的方法是让行为对象包含额外的状态渲染器对象,然后行为对象调用渲染器绘制方法,并在需要时传递额外的状态(例如旋转).

然后你可以有一个像坦克一样的行为物体,它需要一个像坦克一样的渲染器,后者要求两个图像和两个旋转绘制.如果你想让你的坦克只是一个普通的图像,你只需要编写一个忽略旋转的子类渲染器.

谁能想到任何替代品?我真的很想要简单.因为它是一个游戏,效率可能也是一个问题,例如,当我有50个敌人以60fps飞行时,绘制单个5x5敌人图像,涉及多层函数调用.

PAT*_*ume 1

合成设计是有效的,因为它允许混合搭配行为和渲染。

在我们正在玩的游戏中,我们添加了一个“数据包”,其中包含基本信息(在您的情况下是位置和死/活状态)以及由行为和碰撞子系统设置/取消设置的变量数据。然后渲染器可以使用这些数据(如果不需要,则不使用)。这工作得很好,并且可以实现简洁的效果,例如为给定的图形效果设置“目标”。

有几个问题:

  • 如果渲染器请求行为未设置的数据。在我们的例子中,事件被记录,并使用默认值(在渲染器中定义)。
  • 事先检查所需的信息有点困难(即渲染器 A 的数据包中应包含哪些数据?行为 B 设置了哪些数据?)。我们尝试使文档保持最新,但我们正在考虑记录类的设置/获取,并生成文档页面...

目前我们使用 HashMap 作为数据包,但这是在 PC 上,而不是 iPhone。我不知道性能是否足够,在这种情况下另一个结构可能会更好。

同样在我们的例子中,我们决定使用一组专门的渲染器。例如,如果实体拥有非空盾数据,则 ShieldRenderer 显示该表示形式...在您的情况下,坦克可以拥有链接到两个(初始化定义的)数据的两个渲染器:

Renderer renderer1 = new RotatedImage("Tank.png", "TankRotation");
Renderer enderer2 = new RotatedImage("Turret.png", "TurretRotation");
Run Code Online (Sandbox Code Playgroud)

通过行为设置“TankRotation”和“TurretRotation”。渲染器只需旋转图像,然后将其显示在该位置即可。

  image.rotate (entity.databag.getData(variable));
Run Code Online (Sandbox Code Playgroud)

希望这有帮助

问候
纪尧姆