我正在为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;
}
}
}
到目前为止,我对这个设计非常满意。它很好,也很灵活,你可以模块化后一类,这样你就可以提供“睡眠”行为和“清醒”行为,这样你就可以说新的WaitUntilCloseBehaviour(玩家,50 / 像素 /,新的MoveRandomlyBehaviour(),新的HomingBehaviour( ))。这使得制造新敌人变得非常容易。
困扰我的唯一部分是行为和渲染器的沟通方式。目前,Entity包含一个Image对象,如果行为选择这样做,行为可以修改。例如,一种行为可以改变睡眠和清醒图像之间的对象,渲染器只会绘制图像。我不确定这会如何扩展,例如:
面向某个方向的炮塔式敌人怎么样?我想我可以向Entity添加一个旋转字段,行为和渲染器都可以修改/读取。
水箱的主体和水箱的枪有不同方向的水箱怎么样?现在,渲染器需要访问来自某处的两个旋转以及要使用的两个图像。如果只有一个坦克,你真的不想用这个膨胀Entity类。
当他的枪充电时,一个发光的敌人怎么样?您真的想将充电时间存储在Behavior对象中,但Renderer类无法看到它。
我无法考虑如何对上述模型进行建模,因此渲染器和行为可以保持一定程度的分离。我能想到的最好的方法是让行为对象包含额外的状态和渲染器对象,然后行为对象调用渲染器绘制方法并传递额外的状态(例如旋转),如果他们想要的话到。
然后你可以有一个像坦克一样的行为物体需要一个像坦克一样的渲染器,后者要求两个图像和两个旋转绘制。如果你想让你的坦克只是一个普通的图像,你只需要编写一个忽略旋转的子类渲染器。
任何人都可以想到其他选择吗?我真的很想要简单。因为它是一种游戏,所以如果例如效率可能也是一个问题。绘制一个5x5的敌人图像,当我有50个敌人以60fps左右飞行时,涉及多层函数调用。
答案 0 :(得分:1)
组合设计是有效的,因为它允许混合和匹配行为和渲染。
在我们玩弄的游戏中,我们添加了一个“数据库”,其中包含基本信息(在您的情况下是位置和死/活状态),以及由行为设置/取消设置的变量数据碰撞子系统。然后,渲染器可以使用这些数据(如果不需要则不使用)。这很好用,并且允许整洁的效果,例如为给定的图形效果设置“目标”。
一些问题:
目前我们正在使用HashMap作为数据库,但这是在PC上,而不是在iPhone上。我不知道性能是否足够,在这种情况下,另一个结构可能会更好。
同样在我们的案例中,我们决定使用一套专门的渲染器。例如,如果实体拥有非空屏蔽数据,则ShieldRenderer显示表示...在您的情况下,坦克可以拥有两个链接到两个(初始化定义的)数据的渲染器:
Renderer renderer1 = new RotatedImage("Tank.png", "TankRotation");
Renderer enderer2 = new RotatedImage("Turret.png", "TurretRotation");
用“TankRotation”和“TurretRotation”设置行为。并且渲染器只是在将图像显示在该位置之前旋转图像。
image.rotate (entity.databag.getData(variable));
希望这个帮助
问候
纪尧姆
答案 1 :(得分:1)
你要去的设计对我来说很好看。关于components的这一章可能会对您有所帮助。