Я заставляю Java стрелять в них игра для телефонов на базе Android. У меня есть 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 ()). Это делает действительно легким сделать новых врагов.
Единственная часть это беспокоит меня, - то, как поведения и рендереры связываются. В данный момент Объект содержит Объект изображения, который могло изменить Поведение, если бы это приняло решение сделать так. Например, одно поведение могло изменить объект между сном и пробудить изображение, и рендерер просто нарисует изображение. Я не уверен, как это выходит на более высокий уровень хотя, например:
Что относительно подобного башенке врага, который сталкивается с определенным направлением? Я предполагаю, что мог добавить поле вращения к Объекту, который могут оба изменять/читать Поведение и Рендерер.
Что относительно корпуса, где корпус корпуса и оружие корпуса имеют отдельные направления? Теперь рендереру нужен доступ к двум вращениям от где-нибудь и двум изображениям для использования. Вы действительно не хотите чрезмерно увеличивать размер класса Объекта с этим, если существует только один корпус.
Что относительно врага, который светится, поскольку его оружие перезаряжает? Вы действительно хотели бы сохранить перезаряжать время в объекте Поведения, но затем класс Рендерера не видит его.
Я испытываю затруднения, думающие о способах смоделировать вышеупомянутое так рендереры, и поведения могут быть сохранены несколько отдельными. Лучший подход, о котором я могу думать, должен иметь объекты поведения, содержат дополнительное состояние, и рендерер возражают затем, что объекты поведения звонят, рендереры рисуют метод и передают дополнительное состояние (например, вращение), если они хотят.
Вы могли затем, например, иметь громадный объект Поведения, который хочет громадный Рендерер, где последний просит два изображения и два вращения тянуть с. Если бы Вы хотели, чтобы Ваш корпус просто был простым изображением, то Вы просто записали бы Рендерер подкласса, который проигнорировал вращения.
Кто-либо может думать о каких-либо альтернативах? Я действительно хочу простоту. Поскольку это - игра, эффективность может быть беспокойством также, если, например, рисование сингла 5x5 вражеское изображение, когда у меня есть 50 врагов, суетящихся на уровне 60 футов в секунду, включает много слоев вызовов функции.
Дизайн композиции является допустимым, поскольку он позволяет смешивать и согласовывать поведение (я) и визуализировать.
В игру, с которой мы играем, мы добавили «тег данных», который содержит основную информацию (в вашем случае положение и статус мертвого / живого), а также данные переменных, которые устанавливаются / не устанавливаются поведением и подсистема столкновений. Затем средство визуализации может использовать эти данные (или не использовать, если они не нужны). Это работает хорошо и позволяет получить изящный эффект, такой как установка «цели» для данного графического эффекта.
Несколько проблем:
В настоящее время мы используем HashMap для тега данных, но это на ПК, а не на iPhone. Я не знаю, хватит ли производительности, в этом случае другая структура могла бы быть лучше.
Также в нашем случае мы решили использовать набор специализированных средств визуализации. Например, если объект имеет непустые данные щита, ShieldRenderer отображает представление ... В вашем случае резервуар может иметь два модуля рендеринга, связанных с двумя (определяемыми инициализацией) данными:
Renderer renderer1 = new RotatedImage("Tank.png", "TankRotation");
Renderer enderer2 = new RotatedImage("Turret.png", "TurretRotation");
с "TankRotation" и " TurretRotation "задается поведением. а средство визуализации просто поворачивает изображение перед его отображением в позиции.
image.rotate (entity.databag.getData(variable));
Надеюсь на эту помощь
С уважением
Гийом