Як я можу оновити налаштування дисплея на екрані параметрів без перезавантаження?


9

Наразі я створюю 2D RPG в C ++ 11 з Allegro 5 і збільшую.

Моя мета - якось оновити мої налаштування гри, коли параметр буде змінено в меню «Параметри». Я не хочу змушувати користувача перезапустити свою гру. Інші ігри не потребують перезавантаження при зміні роздільної здатності або переході з повноекранного режиму на віконний, тому і моя гра не повинна. Будь ласка, дивіться спрощений вигляд системи нижче.

Зауважте, що я не обов'язково хочу безпосередньо зателефонувати на свій ігровий об'єкт із екрана параметрів. Пунктирна лінія - це лише проілюструвати ефект, який я намагаюся досягти; щоб якось викликати оновлення гри при зміні опції в іншій частині системи.

Детальне пояснення

ScreenManager містить перелік усіх GameScreenіснуючих в даний час об'єктів. Це будуть різні екрани в грі, включаючи спливаючі вікна. Цей дизайн більш-менш дотримується зразка управління державними іграми в C # / XNA .

ScreenManagerМістить посилання на мій Gameоб'єкт. В Gameоб'єкт ініціалізується і змінює настройки гри. Якщо я хочу змінити роздільну здатність, перейдіть на повний екран або вимкніть гучність, я б це робив у Gameкласі.

Однак в даний час OptionsScreen не може отримати доступ до ігрового класу. Дивіться схему нижче:

GameScreen може сигналізувати три події, onFinished, onTransitionStartі onTransitionEnd. Немає, onOptionsChangedтому що це робить лише один екран. ScreenManager не може налаштувати обробку події для цього, оскільки він обробляє всі екрани як GameScreens.

Моє запитання полягає в тому, як я можу змінити дизайн, щоб зміна в OptionsMenu не вимагала перезавантаження, а була змінена негайно? Я бажаю попросити мій Gameоб’єкт оновити після натискання кнопки застосувати.


Це питання (навіть якщо це пов'язано з грою) виглядає ідеально підходящим для programmers.stackexchange.com, оскільки йдеться більше про загальний дизайн OO, ніж про власне гру
bughi

Де ти взяв такі дивовижні графіки?
joltmode

@psycketom: Перша - від Visio 2013, а друга - з коду VS2012. Сподіваюся, що це допомагає!
IAE

Відповіді:


1

З того, що я бачив, найпростішим підходом є читання файлів параметрів при запуску для визначення поточних налаштувань дисплея; тоді, коли відобразиться екран ваших опцій, завантажте всі поточні параметри з файлу.

Коли зміни допрацьовуються за допомогою кнопки applyабо ok, вони зберігаються назад у файл. Якщо якісь зміни впливають на дисплей, повідомте користувача про те, що гра повинна бути перезапущена, щоб вони набули чинності.

Після перезапуску гри налаштування дисплея (тепер нові) знову читаються з файлу.

--EDIT--

Енд і ... допомогло б, якби я помітив це останнє речення. Вам не потрібно перезапускати. Складає речі дещо складніше, залежно від вашої реалізації та резервної графічної бібліотеки.

IIRC, Allegro має функціональний виклик, що дозволяє змінювати налаштування дисплея на льоту. На Allegro 5 я поки що не піднімаюсь, але я знаю, що ти міг би в 4.


Я не думаю, що це питання пов'язане з Allegro та його можливостями. "Моє запитання полягає в тому, як я можу змінити дизайн, щоб зміна в OptionsMenu не вимагала перезавантаження, але була змінена негайно?" Перезапуск відбувається через те, що "OptionsScreen в даний час не може отримати доступ до ігрового класу" і повинен завантажити їх з файлу налаштувань, якщо я правильно розумію.
ClassicThunder

@Casey: Привіт Кейсі! :) Так, я використовую файл конфігурації для зберігання відповідних відображуваних даних, але я хочу мати можливість уникнути перезавантаження. Це невелика гра, і інші ігри можуть змінювати роздільну здатність, не потребуючи перезавантаження, тому я не бачу, чому я повинен змусити користувача перезапустити мою. Це питання зручності використання. Хоча я міг просто викликати функції відключення алегро, я намагаюся залишатися OOP і не змішувати графічні дзвінки лише тому, що можу; Я не вважаю це гарним дизайном.
IAE

Я виділив біт "без перезавантаження", щоб інші не виходили з цього ж останнього речення. Такий важливий факт не повинен був настати наприкінці, прошу вибачення):
IAE

@SoulBeaver Хто каже, що ви повинні зробити це, щоб ви не перезапускалися? Це вимагати життєздатності, адже це стає все частіше зараз. Деякі останні випуски великобюджетних ігор (XCOM: Enemy Unknown, Skyrim тощо) потребують перезавантаження. (той факт, що вони перебувають на Steam, може бути винуватцем через синхронізацію опцій на стороні сервера, але не будемо туди йти ...)
Кейсі

1
@Casey: Правда, і для певних варіантів я бачу, чому це навіть потрібно, але для таких речей, як повноекранний / віконний або роздільна здатність екрана? Я ніколи не бачив гри, яка потребувала перезавантаження цих налаштувань. Моє основне питання: чому я повинен змусити свого користувача перезапустити, коли гра може змінити налаштування автоматично?
IAE

1

Це те, що я роблю для своєї гри. У мене є дві окремі функції для ініціалізації матеріалів, 'init' та 'reset'. Init викликається лише один раз при запуску, і він робить речі, які не покладаються на будь-які налаштування, наприклад завантаження основних активів. Скидання робить такі дії, як викладення інтерфейсу користувача на основі роздільної здатності екрана, тому викликається щоразу, коли налаштування змінюються.

init();
bool quit = false;
while( !quit )
{
    createWindow();
    reset();

    bool settings_changed = false;
    while( !quit && !settings_changed )
    {
        ... main loop
        // set quit=true if user clicks 'quit' in main menu
        // set settings_changed=true if user clicks 'apply' in options
    }

    destroyCurrentWindow();
}

Я не знайомий з Allegro, але моя відповідь є досить загальною, тому я сподіваюся, що це допоможе вам або комусь із подібною проблемою.


Це цікаве рішення. Я намагався мати жорсткий контроль над кожним викликом скидання, але ви робите це незалежно від змін. Це, безумовно, щось, що я міг би реалізувати, і я перегляну це, дякую!
IAE

1

Не псуючи вашу поточну архітектуру, я бачу два способи. По-перше, ви можете зберегти вказівник на Gameекземпляр у OptionsScreenкласі. По-друге, ви могли Gameотримати клас за поточними налаштуваннями в заданий інтервал, скажімо, кожну секунду.

Щоб фактично адаптуватися до нових налаштувань, Gameклас повинен реалізувати якусь функцію скидання, яка вибирає поточні налаштування та повторно реалізується на основі цих.

Для чистого рішення вам потрібен якийсь глобальний менеджер, таким чином, це докласти більше зусиль. Наприклад, система подій або система обміну повідомленнями. Дуже корисно дозволити заняттям спілкуватися без таких сильних прив’язок, як агрегація чи композиція тощо.

За допомогою глобального менеджера подій він OptionsScreenможе просто глобально запустити перемальовану подію, яку Gameзареєстрували для прослуховування раніше.

Як правило, ви можете реалізувати клас менеджера, який зберігає події та зворотні виклики, слухаючи їх у хеш-карті. Тоді ви можете створити один екземпляр цього менеджера і передати вказівники на нього до своїх компонентів. Використовувати новіші C ++ це досить просто, оскільки ви можете використовувати std::unordered_mapяк хеш-карту і std::functionзберігати зворотні дзвінки. Існують різні підходи, які можна використовувати як ключові. Наприклад, ви можете створити рядок менеджера подій, що робить компоненти ще більш незалежними. У такому випадку ви б використовували std::stringяк ключ у хеш-карті. Мені особисто це подобається, і це, безумовно, не викликає виступів, але більшість традиційних систем подій працюють з подіями, як класи.


Привіт, Даніаре. Я вже використовую сигнали boost :: для створення рудиментарної схеми обробки подій. Сильна лінія від GameScreen до ScreenManager насправді - це обробка подіями. Чи є у вас ресурси, що деталізують архітектуру глобального менеджера подій? Більше роботи чи ні, це здається, що це може призвести до чистої реалізації.
IAE

Хоча я не читав жодного дослідження з цього приводу, я застосував глобальний менеджер подій подій для власного маленького двигуна. Якщо вас зацікавила реалізація, я надішлю вам посилання. Я оновив свою відповідь, щоб висвітлити детальніше.
danijar

1

Ну, це певний випадок шаблону спостерігача.

Є рішення, яке передбачає зворотні дзвінки. Це найкращий спосіб зробити це, якщо ви хочете вільне з'єднання, і я думаю, що це також найчистіший. Це не буде залучати жодних глобальних менеджерів або одиночних.

В основному, вам потрібно мати якесь SettingsStore. Там ви зберігаєте налаштування. Коли ви створюєте новий екран, їм знадобиться вказівник на магазин. У випадку з цим OptionsScreenвона сама змінить деякі параметри. У випадку з цим GameScreenвін просто їх прочитає. Отже, у вашій грі ви створили б лише один екземпляр, який буде переданий по всіх екранах, які потребують такого.

Тепер цей SettingsStoreклас матиме список notifiables. Це класи, які реалізують певний ISettingChangedінтерфейс. Інтерфейс був би простим, який містить наступний метод:

void settingChanged(std::string setting);

Тоді на екрані ви будете реалізовувати логіку для кожного з ваших параметрів. Потім, додайте себе в магазин , щоб отримувати повідомлення: store->notifyOnChange(this);. Коли налаштування змінюється, виклик викликається з назвою налаштування. Нове значення налаштування потім можна отримати з SettingsStore.

Тепер це можна додатково доповнити такими ідеями:

  • Використовуйте клас, який зберігає рядки налаштувань - це може бути навіть SettingsStore(const рядки), щоб уникнути копіювання рядків навколо.
  • Ще краще замість рядка використовуйте enum, щоб вказати, які налаштування у вас є
  • Ви навіть можете вказати старі та нові значення в якості аргументів у зворотному дзвінку, але це було б більш складно, оскільки у вас можуть бути рядкові чи int значення чи що. Тобі вирішувати.

0

Прочитайте свої налаштування з файлу в змінні. Запропонуйте своєму Диспетчеру екрана відстежувати, якщо екран, з якого він щойно з'явився, був екран "Параметри", і якщо він був, перезавантажте свої налаштування зі змінних. Коли користувач виходить з вашої гри, запишіть налаштування у змінні назад у файл.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.