Как смоделировать игровой рендеринг объекта и поведение модульным способом?

Я заставляю 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 футов в секунду, включает много слоев вызовов функции.

8
задан Bob Page 11 February 2010 в 19:54
поделиться

2 ответа

Дизайн композиции является допустимым, поскольку он позволяет смешивать и согласовывать поведение (я) и визуализировать.

В игру, с которой мы играем, мы добавили «тег данных», который содержит основную информацию (в вашем случае положение и статус мертвого / живого), а также данные переменных, которые устанавливаются / не устанавливаются поведением и подсистема столкновений. Затем средство визуализации может использовать эти данные (или не использовать, если они не нужны). Это работает хорошо и позволяет получить изящный эффект, такой как установка «цели» для данного графического эффекта.

Несколько проблем:

  • если средство визуализации запрашивает данные, которые не были заданы поведением. В нашем случае событие регистрируется, и используются значения по умолчанию (определенные в рендерере).
  • Немного сложнее заранее проверить необходимую информацию (т.е. какие данные должны быть в теге данных для Renderer A? Какие данные устанавливаются поведением B?). Мы стараемся поддерживать документ в актуальном состоянии, но мы думаем о том, чтобы записать набор / получение по классам и сгенерировать страницу документа ...

В настоящее время мы используем 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));

Надеюсь на эту помощь

С уважением
Гийом

1
ответ дан 6 December 2019 в 01:40
поделиться

Дизайн, который вы выбрали, мне нравится. Эта глава о компонентах может вам помочь.

1
ответ дан 6 December 2019 в 01:40
поделиться
Другие вопросы по тегам:

Похожие вопросы: