Является ли динамическое литье? Объекты Хороший дизайн?

В моей игре

Все наследуется от Entity, затем другие вещи, такие как Player, PhysicalObject и т. д., наследуются от Entity. Механизм физики отправляет обратные вызовы коллизий, которые имеют Entity * к B, на котором столкнулся A. Затем, скажем, A - это Bullet, A пытается передать объект в качестве игрока, если он преуспеет, он уменьшает здоровье игрока.

Это хороший дизайн?

Проблема с системой сообщений заключается в том, что мне нужны сообщения для всего: entity.sendMessage (SET_PLAYER_HEALTH, 16);

Вот почему я считаю, что отливка чище.

5 голосов | спросил jmasterx 18 J0000006Europe/Moscow 2011, 07:05:24

5 ответов


9

Виртуальные вызовы функций являются вашими сообщениями:

void Player::onCollision(const Entity& collisionEntity)
{
    Player::setHealth(Player::getHealth() - collisionEntity.damageValue());
}

Предоставьте им (пустые) реализации по умолчанию, чтобы объект Entity обрабатывал только те события, которые он хочет.

Когда ваш класс Entity неизбежно начинает раздуваться, нужно либо направить некоторые методы вниз по иерархии, либо перейти к компоненту на основе дизайна .

ответил BlueRaja - Danny Pflughoeft 18 J0000006Europe/Moscow 2011, 08:43:34
3

Пуля сталкивается с объектом (в зависимости от того, что ответит) и отправляет сообщение объекту. bullet.sendMessage (other_object, BULLET_IMPACT, 16); пуле не нужно знать детали объекта судьбы.

Если объект является игроком.

void Player::handleMessage( Message* msg )
{
   if ( msg->type() == BULLET_IMPACT )
       doDamage( msg->data() );
}

Судьба решает действие.

Избегайте броска, где бы вы ни находились.

ответил momboco 18 J0000006Europe/Moscow 2011, 07:13:31
2

Динамическое кастинг действительно не то, что вы хотите создать свой код.

Вместо этого виртуальные функции на ваших сайтах Entity /Player /PhysicsObject /etc - ваши лучшие друзья .

ответил Trevor Powell 18 J0000006Europe/Moscow 2011, 07:14:19
2

Обработка столкновений - обычная проблема в играх. Сложная часть заключается в том, что способ обработки столкновений зависит от обеих вещей, которые сталкиваются. Вы хотите иметь возможность выбрать подходящий метод, основанный на паре классов, а не только на одном. К сожалению, большинство языков ООП, таких как C ++, поддерживают только динамическую диспетчеризацию single (что и есть виртуальные методы и переопределение).

Вы хотите двойную отправку . Вы можете представить себе четыре функции:

void playerToPlayerCollision(Player* a, Player* b) { /* ... */ }
void playerToBulletCollision(Player* a, Bullet* b) { /* ... */ }
void bulletToPlayerCollision(Bullet* a, Player* b) { /* ... */ }
void bulletToBulletCollision(Bullet* a, Bullet* b) { /* ... */ }

И каким-то образом язык волшебным образом выберет правильный, основанный на двух объектах Entity*, которые столкнулись. Вы можете сделать эту магическую работу, используя комбинацию переопределения (для первой отправки) и шаблона посетителя (для второго). Это выглядит так:

class Entity {
  // Physics engine calls this:
  virtual void collide(Entity* other) = 0;

  virtual void collideWithPlayer(Player* player) = 0;
  virtual void collideWithBullet(Bullet* bullet) = 0;
}

class Player : public Entity {
  // Double dispatch:
  virtual void collide(Entity* other) {
    other->collideWithPlayer(this);
  }

  // Actual collision-handling functions:
  virtual void collideWithPlayer(Player* player) {
    // Player -> Player collision.
  }

  virtual void collideWithBullet(Bullet* bullet) {
    // Player -> Bullet collision.
  }
}

class Bullet : public Entity {
  // Double dispatch:
  virtual void collide(Entity* other) {
    other->collideWithBullet(this);
  }

  // Actual collision-handling functions:
  virtual void collideWithPlayer(Player* player) {
    // Bullet -> Player collision.
  }

  virtual void collideWithBullet(Bullet* bullet) {
    // Bullet -> Bullet collision.
  }
}

Когда физический движок вызывает collide, который переопределяется Player и Bullet. Эти переопределения отправляются на первый из сталкивающихся объектов. Они немедленно вызывают другой виртуальный метод на другом сталкивающемся объекте. Этот метод выполняет вторую динамическую отправку, и вы в конечном итоге выбираете один из четырех методов, основанный на типах обоих аргументов. Не требуется литье.

Этот шаблон имеет только два реальных ограничения:

  1. Это сложно и неясно. Если вы не узнаете шаблон, код здесь выглядит странно и трудно понять.

  2. Вы ограничены фиксированным набором подклассов. Вы заметите, что Entity теперь известно о Bullet и Player. Он должен знать о подклассах all , которые вы отправляете, что побеждает открытые подклассы, которые вы обычно получаете на C ++.

Если вы можете жить с ними, этот шаблон работает очень хорошо.

ответил munificent 19 J0000006Europe/Moscow 2011, 01:14:31
0

Помимо использования виртуальных функций, как уже упоминалось ранее, вы также должны сохранить перечисление в «базовом» классе, который указывает тип. Что-то вроде:

enum eEntType{
ENT_PLAYER, 
ENT_PHYS, 
ENT_ETC
};
eEntType m_eType;

Создайте конструктор базового класса в eEntType, который устанавливает его в get-go. Затем сделайте для них доступ только для чтения. Это более быстрый способ дифференцировать эти объекты, и это хорошо на ходу /в любое время.

Все производные подклассы должны использовать список инициализаторов членов, передавая «жестко запрограммированное» значение своего типа на базовый ctor.

ответил Balk 23 J0000006Europe/Moscow 2011, 05:01:33

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

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132