В настоящее время я создаю 2D RPG на C ++ 11 с Allegro 5 и boost.
Моя цель состоит в том, чтобы каким-то образом обновить мои игровые настройки при изменении параметра в меню параметров. Я не хочу заставлять пользователя перезагружать мою игру. Другие игры не требуют перезапуска при смене разрешения или переходе от полноэкранного к оконному, поэтому моя игра также не должна этого делать. Пожалуйста, смотрите упрощенный вид системы ниже.
Обратите внимание, что я не обязательно хочу напрямую вызывать мой объект Game с экрана настроек. Пунктирная линия просто иллюстрирует эффект, которого я пытаюсь достичь; каким-то образом вызывать обновление игры, когда опция меняется в другой части системы.
Детальное объяснение
ScreenManager содержит список всех GameScreen
существующих в данный момент объектов. Это будут различные экраны в игре, включая всплывающие окна. Этот дизайн более или менее соответствует образцу Game State Management в C # / XNA .
ScreenManager
Содержит ссылку на мой Game
объект. В Game
объект инициализируется и изменяет настройки игры. Если я хочу изменить разрешение, перейти в полноэкранный режим или отключить звук, который я сделал бы в Game
классе.
Тем не менее, в настоящее время OptionsScreen не может получить доступ к классу Game. Смотрите ниже схему:
GameScreen может сигнализировать о трех событиях onFinished
, onTransitionStart
и onTransitionEnd
. Нет, onOptionsChanged
потому что только один экран делает это. ScreenManager не может настроить обработку событий для этого, потому что он обрабатывает все экраны как GameScreen
s.
У меня вопрос, как я могу изменить свой дизайн, чтобы изменение в OptionsMenu не требовало перезапуска, а было изменено немедленно? Желательно, чтобы мой Game
объект обновлялся после нажатия кнопки «Применить».
Ответы:
Из того, что я видел, самый простой подход - это прочитать файл опций при запуске, чтобы определить текущие настройки дисплея; затем при отображении экрана параметров загрузите все текущие параметры из файла.
Когда изменения завершаются с помощью кнопки
apply
илиok
, они сохраняются обратно в файл. Если какие-либо изменения влияют на отображение, уведомите пользователя, что игра должна быть перезапущена, чтобы он вступил в силу.Когда игра перезапускается, настройки дисплея (теперь новые) снова считываются из файла.
--РЕДАКТИРОВАТЬ--
И ... это помогло бы, если бы я заметил это последнее предложение. Вы не хотите перезапускать. Делает все немного сложнее в зависимости от вашей реализации и вашей внутренней библиотеки графики.
IIRC, Allegro имеет функцию вызова, которая позволяет изменять настройки дисплея на лету. Я пока не изучаю Allegro 5, но я знаю, что вы могли бы в 4.
источник
Это то, что я делаю для своей игры. У меня есть 2 отдельные функции для инициализации вещи, 'init' и 'reset'. Init вызывается только один раз при запуске и выполняет действия, которые не зависят от каких-либо настроек, такие как загрузка основных ресурсов. Reset выполняет раскладку пользовательского интерфейса в зависимости от разрешения экрана, поэтому вызывается каждый раз при изменении настроек.
Я не знаком с Allegro, но мой ответ довольно общий, поэтому я надеюсь, что он поможет вам или кому-либо еще с подобной проблемой.
источник
Не портя вашу нынешнюю архитектуру, я вижу два пути. Во-первых, вы можете сохранить указатель на
Game
экземпляр вOptionsScreen
классе. Во-вторых, вы могли быGame
класс извлекать текущие настройки в заданном интервале, скажем каждую секунду.Чтобы на самом деле адаптироваться к новым настройкам,
Game
класс должен реализовать какие-то функции сброса, которые выбирают текущие настройки и реинициализируют на их основе.Для чистого решения вам нужен какой-то глобальный менеджер, поэтому для его реализации требуется больше усилий. Например, система событий или система обмена сообщениями. Очень полезно, чтобы классы общались без таких сильных привязок, как агрегация или композиция и т. Д.
С глобальным менеджером событий, он
OptionsScreen
может просто глобально запустить событие перерисовки, котороеGame
зарегистрировано для прослушивания ранее.Обычно вы можете реализовать класс менеджера, хранящий события и обратные вызовы, слушая их в хэш-карте. Затем вы можете создать один экземпляр этого менеджера и передать ему указатели на ваши компоненты. Используя более новый C ++, это довольно просто, так как вы можете использовать
std::unordered_map
как хэш-карту иstd::function
хранить обратные вызовы. Есть разные подходы, которые вы можете использовать в качестве ключа. Например, вы можете создать строку менеджера событий, которая сделает компоненты еще более независимыми. В этом случае вы будете использовать вstd::string
качестве ключа в хэш-карте. Мне лично это нравится, и это определенно не проблема производительности, но большинство традиционных систем событий работают с событиями как с классами.источник
Ну, это какой-то особый случай паттерна Observer.
Существует решение, которое включает в себя обратные вызовы. Это лучший способ сделать это, если вы хотите слабую связь, и я думаю, что это также самый чистый. Это не будет включать каких-либо глобальных менеджеров или синглетонов.
По сути, вам нужно иметь какой-то
SettingsStore
. Там вы храните настройки. При создании нового экрана им понадобится указатель на магазин. В случае этогоOptionsScreen
он сам изменит некоторые значения настроек. В случае сGameScreen
ним просто прочтут их. Итак, в вашей игре вы бы создали только один экземпляр, который будет передаваться по всем экранам, для которых он нужен.Теперь этот
SettingsStore
класс будет иметь списокnotifiables
. Это классы, которые реализуют определенныйISettingChanged
интерфейс. Интерфейс будет простым, который содержит следующий метод:Затем на своем экране вы реализуете логику для каждого параметра, который вас интересует. Затем, добавьте себя в магазин , чтобы получать уведомления:
store->notifyOnChange(this);
. Когда настройка изменяется, вызывается обратный вызов с именем настройки. Новое значение настройки затем может быть получено изSettingsStore
.Теперь это может быть дополнено следующими идеями:
SettingsStore
(const strings), чтобы предотвратить копирование строк вокруг.источник
Читайте ваши настройки из файла в переменные. Попросите вашего менеджера экрана отслеживать, был ли экран, с которого он только что появился, экраном настроек, и если это так, перезагрузите настройки из переменных. Когда пользователь выходит из вашей игры, запишите настройки переменных в файл.
источник