ОО дизайн для моей (основной) игры Pacman - PullRequest
3 голосов
/ 20 февраля 2011

Я пытаюсь создать базовую игру Pacman на C ++ (в этом вопросе я буду использовать синтаксис Java, так как это несколько проще продемонстрировать), но я не могу найти хороший вариант дизайна.

Пока у меня есть 4 класса:
- Монстр: может быть разделен на подклассы для специфического поведения монстра и содержит всю логику для монстров
- Player: содержит логику игрока
- Карта: содержит двумерный массив, представляющий карту. Этот массив определяет, какие позиции являются стенами или едой Pacman
- Игра: содержит игрока, карту и список монстров.

Для простоты:

public class Game {
  Player player;
  Map map;
  ArrayList<Monster> monsters;

  public Game() {
    player = new Player();
    map = new Map();
    monsters = new ArrayList<Monster();
    monsters.add(new ScaryMonster());
    monsters.add(new DumpMonster());
  }

  public void update() {
    player.update();
    map.update();

    for (Monster monster: monsters) {
      monster.update();
    }

  public void draw() {
    map.draw();
    player.draw();

    for (Monster monster: monsters) {
      monster.draw();
  }
}

Итак, все, что мне теперь нужно сделать, - это создать объект Game и каждый раз вызывать update () и draw () для него. Очень просто. Но это не работает.

Предположим, я вызываю update () для объекта player, и игрок (который является Pacman ofcourse) попадает в еду. В этом случае объект карты должен получить уведомление об этом (и о позиции), чтобы удалить еду из 2d-массива. Предположим, что игрок убил монстра, позиция монстра должна измениться (класс Monster имеет «поле позиции»). И вы можете представить гораздо больше таких ситуаций.

Можно было бы передать карту и объект монстра в качестве параметров в методе update () и draw () объекта player. И передать объекты игрока и монстра в качестве параметров в вызовах методов карты. Но это, конечно, не похоже на хороший дизайн ОО.

Какой хороший ОО способ решить эту проблему? Я думал об использовании паттерна Observer (таким образом, Game - это субъект, игрок, карта и монстры - наблюдатели), но это не имеет никакого смысла: таким образом наблюдатели должны будут сообщать субъекту о любых изменениях, что очевидно, неправильный способ использования этого.

Любые советы приветствуются.

Большое спасибо:)

1 Ответ

4 голосов
/ 20 февраля 2011

Почему бы вам не попробовать составить карту действий?

Каждое действие имеет реакцию.Допустим, пакман бьет едой.Это действие, «ударяя еду», которое, в свою очередь, реагирует (уведомляя карту, или еду, или все, что вам нравится), что еды больше нет.

Теперь представьте, что пакман поражаетмонстр, это еще одно действие ... какова будет реакция на это?Что ж, это может привести к смерти монстра (вызов метода BeDeath: P), или это может привести к смерти пакмана ... что бы это ни было, это позволит вам связывать действия с реакциями в игре.

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

Редактировать: простой пример (очень простой,по мере того, как игра становится все более сложной, вам нужно больше думать о структуре действий и реакций)

public void IGameInfo
{
  List<Monster> Monsters {get;}
  Pacman Pacman {get;}
  Map Map {get;}
}

public void ComputeReactions()
{
  foreach (actionChecker in Actions)
  {
    actionChecker.Check(gameInfo);
  }
}

public void ComputeDotEaten(IGameInfo gameInfo)
{
  foreach (dot in gameInfo.Map.Dots)
    if (pacman.location == dot.location)
      dot.MarkEaten();
}

public void ComputeMonsterEaten(IGameInfo gameInfo)
{
  foreach (Monster in gameInfo.monsters)
    if (gameInfo.pacman.location == gameInfo.monster.location &&
        gameInfo.pacman.Invulnerable)
      monster.MarkDeath();
    else
      Game.EndGame();
}

Или, если хотите, вы также можете отобразить реакции

public void ComputeDotEaten(IGameInfo gameInfo)
{
  foreach (dot in gameInfo.Map.Dots)
    if (pacman.location == dot.location)
      Reactions["DotEaten"].Execute(dot);
}

Обратите внимание, что длячто для выполнения всех ваших реакций необходимо использовать общую сигнатуру (т. е. брать массив объектов, приведенных к ожидаемым параметрам)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...