Помогите с дизайном программы - PullRequest
4 голосов
/ 23 ноября 2010

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

Мне нужна помощь:

Создание хорошего класса "Event" для моей игры. Я хотел бы, чтобы все работало так, чтобы каждый предмет и комната могли быть связаны с событием.

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

Я хочу иметь возможность создавать различные виды событий, например:

  • Выведите текст, а затем задайте игроку вопрос. Если игрок дает правильный ответ, сделайте что-нибудь.

  • Выведите некоторый текст, затем удалите предмет из инвентаря игрока, а затем переместите игрока в другую комнату.

Чего я пытаюсь избежать:

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

  • Необходимо жестко закодировать каждое событие, чтобы элемент или комната просто вызывали определенный метод в классе Event.

Что я думаю сейчас:

Создание нескольких подклассов, чтобы я мог, например, создавать новые события (и связывать их), используя: itemObject.setEvent (новое событие (новый вопрос ("introText", "outroText", "correctAnswer")));

Пожалуйста, дайте мне знать, если вам нужна дополнительная информация! Спасибо!

Ответы [ 4 ]

2 голосов
/ 23 ноября 2010

Когда мы говорим о событиях, на ум приходит образец наблюдателя .Вы можете думать, что ваша игра будет представлена ​​внутри нескольких конечных автоматов (вы также можете посмотреть это в Википедии, я не могу добавить 2-ю ссылку самостоятельно, потому что она новичок в SO).Каждый переход с одного этапа на другой - это событие, которое может быть передано зарегистрированным оберсерверам этого события.

Например:

ИСПОЛЬЗОВАТЬ КЛЮЧ НА БЛОКИРОВКЕ: инициирует удаление ключа и открытие двери;имплицитно «каскадный» переход к следующему событию без дополнительного взаимодействия с пользователем (открытие двери): запуск комнаты с дополнительным выходом и т. д.

2 голосов
/ 23 ноября 2010

Книги Game Programming Gems великолепны ... хотя и немного дорогостоящи.

Возможно, вы найдете одну или две статьи на Список статей GameDev , и, возможно, есть несколько хорошихвещи, похороненные в их форумах

Что касается класса Event, вам почти наверняка понадобится базовый класс с некоторым количеством подклассов (MoveEvent, InventoryEvent и т. д.).И если вы действительно хотите избежать жесткого кодирования, вы должны определить свою игру в файлах данных.Комнаты, предметы и события ... плюс все остальное, что вы добавите позже.Формат, который вы используете для определения вещей, полностью зависит от вас.Я рекомендую кое-что, что даст вам практический опыт, так как это учебное упражнение: например, анализатор XML, который вы не использовали.Не самый эффективный формат для синтаксического анализа, но это консольная игра, так что это не такая проблема.

Одно из предложений, которое я имею для подкласса Event, - это то, что может связывать другие события вместе.Интерфейс не меняется, и он позволяет вам делать такие вещи, как «добавить это в инвентарь игрока, забрать это и переместить их сюда».

2 голосов
/ 23 ноября 2010

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

Например, ваш домен может состоять из следующих интерфейсов:

public enum Action { HIT, TALK_TO, EAT, USE };

public interface GameEntity {
  /**
   * Performs the specified action on this GameEntity, passing in zero or
   * more other GameEntity instances as parameters.
   */
  void applyAction(Action action, GameEntity... params);    
}

public interface Item extends GameEntity { }
public interface Person extends GameEntity { }

Кроме того, вы можете определить класс TextParser, который будет обрабатывать входную строку и делать результирующие вызовы на уровне домена, или же возвращать ответ по умолчанию: «Я не понимаю».Например, вводимая фраза «использовать ключ на двери» приведет к вызову метода:

key.applyAction(Action.USE, door);
1 голос
/ 23 ноября 2010

Я недавно реализовал нечто похожее на то, что вы описываете. Я начал с создания класса EventManager, в котором есть методы «Опубликовать» и «Подписаться». Когда система запускается, она сканирует все загруженные сборки (библиотеки) на предмет классов, которые реализуют интерфейс IEventListener:

/// <summary>
/// A class that intends to listen for specific events to be published by an
/// event manager.
/// <see cref="EventManager"/>
/// </summary>
public interface IEventListener
{
    /// <summary>
    /// Subscribes to the event types that this listener wishes to listen for.
    /// </summary>
    /// <param name="eventManager"></param>
    void RegisterSubscriptions(EventManager eventManager);
}

... и вызывает метод RegisterSubscription для каждого из них. (Существует только один экземпляр EventManager, который используется повсеместно; я использую внедрение зависимостей, чтобы связать его как одноэлементный экземпляр.)

RegisterSubscription просто вызывает метод Subscribe для каждого типа события и обработчика, которые данный класс предназначен для обработки. (Я использую .NET, поэтому с событиями и обработчиками немного проще работать, но вы можете сделать то же самое в Java, используя анонимные подклассы.)

Типичным событием может быть что-то вроде RoomEntered, а аргументы, связанные с этим событием, включают идентификатор комнаты и, возможно, некоторые другие свойства комнаты. Движок игры публикует это событие, когда пользователь входит в комнату, предоставляя соответствующие аргументы события для этой комнаты, и класс EventManager отвечает за вызов каждого обработчика, подписавшегося на этот тип события. Одним из обработчиков этого события может быть «HandleEnterRoomWithMonsters», который проверяет, есть ли в комнате монстры, и выполняет соответствующее действие.

Имеет ли это смысл в целом? Есть ли у вас какие-либо вопросы об этом подходе?

...