Bagaimana cara saya memperbarui pengaturan Tampilan dari layar Opsi tanpa memulai ulang?

9

Saat ini saya sedang membuat RPG 2D dalam C ++ 11 dengan Allegro 5 dan boost.

Tujuan saya adalah entah bagaimana memperbarui pengaturan gim saya ketika opsi diubah di Menu Opsi. Saya tidak ingin memaksa pengguna untuk memulai kembali gim saya. Game lain tidak membutuhkan restart saat mengubah resolusi atau beralih dari layar penuh ke windowed, jadi game saya juga tidak. Silakan lihat tampilan yang disederhanakan dari sistem di bawah ini.

Harap dicatat bahwa saya tidak selalu ingin langsung memanggil objek Game saya dari OptionsScreen. Garis putus-putus hanyalah untuk menggambarkan efek yang saya coba capai; entah bagaimana menyebabkan pembaruan game ketika opsi diubah di bagian yang berbeda dari sistem.

Penjelasan detail

ScreenManager berisi daftar semua GameScreenobjek yang saat ini ada. Ini akan menjadi berbagai layar dalam gim termasuk popup. Desain ini mematuhi kurang lebih sampel Manajemen Status Game di C # / XNA .

The ScreenManagerberisi referensi ke saya Gameobjek. The Gameobjek menginisialisasi dan memodifikasi pengaturan permainan. Jika saya ingin mengubah resolusi, buka layar penuh, atau bisu volume saya akan melakukannya di Gamekelas.

Namun, LayarScreen saat ini tidak dapat mengakses kelas Game. Lihat diagram di bawah ini:

GameScreen dapat memberi sinyal tiga peristiwa onFinished,, onTransitionStartdan onTransitionEnd. Tidak ada onOptionsChangedkarena hanya satu layar yang melakukan itu. ScreenManager tidak dapat mengatur penanganan acara untuk itu karena ia menangani semua layar GameScreens.

Pertanyaan saya adalah, bagaimana saya bisa mengubah desain saya sehingga perubahan pada OptionsMenu tidak memerlukan restart, tetapi segera diubah? Saya lebih baik meminta Gameobjek saya untuk memperbarui setelah tombol terapkan diklik.

IAE
sumber
Pertanyaan ini (meskipun itu terkait dengan game) sepertinya sangat cocok untuk programmer
.stackexchange.com
Dari mana Anda mendapatkan grafik yang tampak luar biasa?
joltmode
@psycketom: Yang pertama dari Visio 2013 dan yang kedua dihasilkan dari kode oleh VS2012. Semoga itu bisa membantu!
IAE

Jawaban:

1

Dari apa yang saya lihat, pendekatan termudah adalah membaca file opsi saat startup untuk menentukan pengaturan tampilan saat ini; kemudian, ketika layar opsi Anda ditampilkan, muat semua opsi saat ini dari file.

Ketika perubahan diselesaikan melalui tombol applyatau ok, mereka disimpan kembali ke file. Jika ada perubahan yang memengaruhi tampilan, beri tahu pengguna bahwa game harus dimulai ulang agar dapat diterapkan.

Ketika game dimulai kembali, pengaturan tampilan (sekarang baru) dibaca lagi dari file.

--EDIT--

Annd ... itu akan membantu jika aku memperhatikan kalimat terakhir itu. Anda tidak ingin harus memulai ulang. Membuat segalanya sedikit lebih sulit tergantung pada implementasi Anda dan Perpustakaan Grafik back-end Anda.

IIRC, Allegro memiliki panggilan fungsi yang memungkinkan Anda untuk mengubah pengaturan tampilan dengan cepat. Saya belum bangun pada Allegro 5 dulu, tapi saya tahu Anda bisa di 4.

Casey
sumber
Saya tidak berpikir masalah ini terkait dengan Allegro dan kemampuannya. "Pertanyaan saya adalah, bagaimana saya bisa mengubah desain saya sehingga perubahan pada OptionsMenu tidak memerlukan restart, tetapi segera diubah?" Restart adalah karena "OptionsScreen saat ini tidak dapat mengakses kelas Game" dan harus memuatnya dari file pengaturan jika saya mengerti dengan benar.
ClassicThunder
@Casey: Halo Casey! :) Ya, saya menggunakan file konfigurasi untuk menyimpan data tampilan yang relevan, tetapi saya ingin menghindari restart. Ini adalah game kecil, dan game lainnya dapat mengubah resolusi tanpa harus memulai ulang, jadi saya tidak mengerti mengapa saya harus memaksa pengguna untuk memulai kembali dengan milik saya. Ini masalah kegunaan. Meskipun saya hanya bisa memanggil fungsi allegro dispay, saya mencoba untuk tetap OOP dan tidak mencampur panggilan grafis saya hanya karena saya bisa; Saya tidak menganggap desain yang bagus.
IAE
Saya menyoroti bit "tanpa restart" sehingga orang lain tidak tersandung pada kalimat terakhir yang sama. Fakta penting seperti itu seharusnya tidak datang pada akhirnya, saya minta maaf):
IAE
@ SoulBeaver Siapa bilang Anda harus membuatnya sehingga Anda tidak memulai ulang? Adalah suatu hal yang layak untuk mengharuskan itu, pada kenyataannya itu menjadi lebih umum sekarang-a-hari. Beberapa rilis terbaru (XCOM: Musuh Tidak Diketahui, Skyrim, dll.) Dari game beranggaran besar memerlukan restart. (fakta bahwa mereka menggunakan Steam mungkin adalah penyebabnya karena sinkronisasi opsi di sisi server tetapi jangan pergi ke sana ...)
Casey
1
@ Casey: Benar, dan untuk opsi tertentu saya bisa melihat mengapa itu bahkan perlu, tetapi untuk hal-hal seperti layar penuh / berjendela atau resolusi layar? Saya belum pernah melihat game yang membutuhkan restart untuk pengaturan itu. Pertanyaan mendasar saya adalah: mengapa saya harus memaksa pengguna saya untuk memulai kembali ketika game dapat mengubah pengaturan secara otomatis?
IAE
1

Inilah yang saya lakukan untuk permainan saya. Saya memiliki 2 fungsi terpisah untuk menginisialisasi barang, 'init' dan 'reset'. Init hanya dipanggil sekali saat startup dan melakukan hal-hal yang tidak bergantung pada pengaturan apa pun, seperti memuat aset utama. Reset melakukan hal-hal seperti meletakkan UI berdasarkan resolusi layar, demikian disebut setiap kali pengaturan berubah.

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();
}

Saya tidak terbiasa dengan Allegro, tetapi jawaban saya cukup umum, jadi saya harap ini membantu Anda atau orang lain dengan masalah yang sama.

DaleyPaley
sumber
Itu solusi yang menarik. Saya mencoba untuk memiliki kontrol ketat setiap kali reset dipanggil, tetapi Anda melakukannya terlepas dari perubahan. Itu pasti sesuatu yang bisa saya terapkan, dan saya akan memeriksanya, terima kasih!
IAE
1

Tanpa mengacaukan arsitektur Anda saat ini, saya melihat dua cara. Pertama, Anda bisa menyimpan pointer ke Gameinstance di OptionsScreenkelas. Kedua, Anda dapat Gamekelas mengambil pengaturan saat ini dalam interval yang diberikan, katakan setiap detik.

Untuk benar-benar beradaptasi dengan pengaturan baru, Gamekelas harus mengimplementasikan semacam fungsi reset yang mengambil pengaturan saat ini dan menginisialisasi ulang berdasarkan itu.

Untuk solusi bersih, Anda memerlukan semacam manajer global, sehingga lebih banyak upaya untuk diterapkan. Misalnya sistem acara atau sistem pesan. Sangat berguna untuk membiarkan kelas berkomunikasi tanpa ikatan yang kuat seperti agregasi atau komposisi, dan sebagainya.

Dengan manajer acara global, perusahaan OptionsScreendapat secara global memecat acara redraw yang Gametelah terdaftar untuk didengarkan sebelumnya.

Secara umum Anda dapat mengimplementasikan kelas manajer yang menyimpan acara dan panggilan balik mendengarkannya di peta hash. Kemudian Anda dapat membuat satu instance dari manajer itu dan meneruskan pointer ke komponen Anda. Menggunakan C ++ yang lebih baru cukup mudah karena Anda dapat menggunakan std::unordered_mapsebagai peta hash dan std::functionuntuk menyimpan panggilan balik. Ada beberapa pendekatan berbeda yang dapat Anda gunakan sebagai kunci. Misalnya, Anda bisa membuat string manajer acara berbasis yang membuat komponen lebih mandiri. Dalam hal ini Anda akan menggunakan std::stringsebagai kunci di peta hash. Saya pribadi suka ini dan ini jelas bukan masalah kinerja, tetapi kebanyakan sistem acara tradisional bekerja dengan acara sebagai kelas.

danijar
sumber
Halo danijar. Saya sudah menggunakan boost :: signal untuk mengatur skema penanganan kejadian yang belum sempurna. Garis yang kuat dari GameScreen ke ScreenManager sebenarnya adalah penanganan acara. Apakah Anda memiliki sumber daya yang merinci arsitektur manajer acara global? Lebih banyak bekerja atau tidak, ini terdengar seperti bisa mengarah pada implementasi yang bersih.
IAE
Meskipun saya belum membaca penelitian tentang ini, saya menerapkan event manager acara global untuk mesin kecil saya sendiri. Jika Anda tertarik dengan implementasinya, saya akan mengirimkan Anda tautan. Saya memperbarui jawaban saya untuk mencakup lebih detail.
danijar
1

Nah, ini adalah beberapa kasus spesifik dari pola Observer.

Ada solusi yang melibatkan panggilan balik. Ini adalah cara terbaik untuk melakukan ini jika Anda ingin kopling longgar, dan saya pikir itu juga yang terbersih. Ini tidak akan melibatkan manajer global atau lajang.

Pada dasarnya, Anda harus memiliki semacam SettingsStore. Di sana Anda menyimpan pengaturan. Saat Anda membuat layar baru, mereka membutuhkan pointer ke toko. Dalam hal OptionsScreenini akan memodifikasi beberapa nilai pengaturan itu sendiri. Dalam hal GameScreenini hanya akan membacanya. Jadi, dalam gim Anda, Anda hanya akan membuat satu instance, yang akan diteruskan di semua layar yang membutuhkannya.

Sekarang, SettingsStorekelas itu akan memiliki daftar notifiables. Mereka adalah kelas yang mengimplementasikan ISettingChangedantarmuka tertentu . Antarmuka akan menjadi sederhana yang berisi metode berikut:

void settingChanged(std::string setting);

Kemudian di layar Anda, Anda akan menerapkan logika untuk setiap pengaturan yang Anda pedulikan. Kemudian, tambahkan diri Anda ke toko untuk diberitahu: store->notifyOnChange(this);. Ketika suatu pengaturan diubah, callback dipanggil dengan nama pengaturan. Nilai pengaturan baru kemudian dapat diambil dari menu SettingsStore.

Sekarang, ini dapat ditambah dengan ide-ide berikut:

  • Gunakan kelas yang menyimpan string pengaturan - mungkin bahkan SettingsStore(string const) untuk mencegah string copy-paste di sekitar.
  • Bahkan lebih baik, daripada string, gunakan enum untuk menentukan pengaturan apa yang Anda miliki
  • Anda bahkan dapat menentukan nilai lama dan baru sebagai argumen dalam panggilan balik, tetapi itu akan lebih berbelit-belit, karena Anda dapat memiliki nilai string atau int, atau yang lainnya. Terserah kamu.
Timotei
sumber
0

Baca pengaturan Anda dari file menjadi variabel. Miliki track Screen Manager Anda jika layar itu baru saja muncul dari layar Options, dan jika ya, muat ulang pengaturan Anda dari variabel. Saat pengguna keluar dari game Anda, tulis pengaturan di variabel kembali ke file.

Tidak
sumber