Помогите с дизайном программы

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

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

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

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

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

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

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

Чего я стараюсь избегать:

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

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

Что я думаю в данный момент:

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

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


person bjrnt    schedule 23.11.2010    source источник
comment
Можете ли вы быть более конкретным с вашим вопросом?   -  person jzd    schedule 23.11.2010
comment
@jzd: Честно говоря, я бы сказал, что это довольно подробный вопрос.   -  person Adamski    schedule 23.11.2010
comment
@Adamski извините, похоже, я как-то неправильно прочитал третий абзац, в котором есть его основной вопрос.   -  person jzd    schedule 23.11.2010
comment
Это 3D, 2D или консольная игра?   -  person a sandwhich    schedule 23.11.2010
comment
На основе консоли вы просто вводите текстовые команды.   -  person bjrnt    schedule 23.11.2010


Ответы (4)


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

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

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

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

person Mark Storer    schedule 23.11.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);
person Adamski    schedule 23.11.2010

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

Например:

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

person Ray    schedule 23.11.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);
}

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

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

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

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

person StriplingWarrior    schedule 23.11.2010