【发布时间】:2011-01-15 21:06:42
【问题描述】:
我正在为 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); }
要绘制存储为实体图像的任何内容,您可以附加一个简单的渲染器,例如
class SimpleRenderer extends Renderer
{
void draw(Canvas c)
{
// just draw the image
}
}
要让实体在每一帧随机飞行,只需附加如下行为:
class RandomlyMoveBehaviour extends Behaviour
{
void update(Entity e)
{
// Add random direction vector to e.position
}
}
或者添加更复杂的行为,比如等到玩家靠近后再归位:
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;
}
}
}
到目前为止,我对这个设计非常满意。它很好而且很灵活,你可以例如模块化后一个类,这样你就可以提供“睡眠”行为和“清醒”行为,这样你就可以说 new WaitUntilCloseBehaviour(player, 50/pixels/, new MoveRandomlyBehaviour(), new HomingBehaviour( ))。这使得结交新敌人变得非常容易。
唯一困扰我的部分是行为和渲染器之间的通信方式。目前,Entity 包含一个 Image 对象,如果 Behavior 选择这样做,它可以修改该对象。例如,一种行为可以在睡眠和清醒图像之间改变对象,而渲染器只会绘制图像。我不确定这将如何扩展,例如:
-
面对某个方向的炮塔状敌人呢?我想我可以向 Entity 添加一个 Behavior 和 Renderer 都可以修改/读取的旋转字段。
如果坦克的车身和坦克的火炮有不同的方向呢?现在渲染器需要从某个地方访问两个旋转和两个要使用的图像。如果只有一个坦克,你真的不想用这个来膨胀实体类。
如果敌人在他的枪充电时会发光呢?您确实想将充电时间存储在 Behavior 对象中,但是 Renderer 类看不到它。
我在考虑如何建模上述内容时遇到了麻烦,因此渲染器和行为可以保持一定程度的分离。我能想到的最好方法是让行为对象包含额外的状态和渲染器对象,然后行为对象调用渲染器的绘制方法并在需要时传递额外的状态(例如旋转)到。
然后你可以例如有一个类似坦克的 Behavior 对象,它需要一个类似坦克的渲染器,后者要求两个图像和两个旋转来绘制。如果您希望您的坦克只是一个普通图像,您只需编写一个忽略旋转的子类 Renderer。
谁能想到任何替代方案?我真的想要简单。由于这是一场游戏,因此效率也可能是一个问题,例如绘制一个 5x5 的敌人图像,当我有 50 个敌人以 60fps 的速度飞来飞去时,涉及到多层函数调用。
【问题讨论】: