Generasi Prosedural, Pembaruan Game, & Efek Kupu-Kupu

10

CATATAN: Saya menanyakan hal ini di Stack Overflow beberapa hari yang lalu tetapi hanya memiliki sedikit tampilan dan tidak ada respons. Kupikir aku harus bertanya pada gamdev.stackexchange sebagai gantinya.

Ini adalah pertanyaan / permintaan umum untuk saran tentang pemeliharaan sistem pembuatan prosedural melalui beberapa pembaruan pasca-rilis, tanpa merusak konten yang dihasilkan sebelumnya.

Saya mencoba mencari informasi dan teknik untuk menghindari masalah "Butterfly Effect" ketika membuat konten prosedural untuk game. Saat menggunakan generator nomor acak yang diunggulkan, urutan nomor acak yang diulang dapat digunakan untuk membuat dunia yang dapat direproduksi. Sementara beberapa gim hanya menyimpan dunia yang dihasilkan ke disk yang pernah dihasilkan, salah satu fitur canggih generasi prosedural adalah fakta bahwa Anda dapat mengandalkan kemampuan reproduksi urutan nomor untuk menciptakan kembali suatu wilayah beberapa kali dengan cara yang sama, menghilangkan kebutuhan akan kegigihan. Karena kendala situasi khusus saya, saya harus meminimalkan kegigihan, dan perlu mengandalkan konsentrasi murni semaksimal mungkin.

Bahaya utama dalam pendekatan ini adalah bahwa perubahan sekecil apa pun dalam sistem generasi prosedural dapat menyebabkan efek kupu-kupu yang mengubah seluruh dunia. Ini membuatnya sangat sulit untuk memperbarui permainan tanpa menghancurkan dunia yang dijelajahi para pemain.

Teknik utama yang saya gunakan untuk menghindari masalah ini adalah merancang generasi prosedural dalam beberapa fase, yang masing-masing memiliki generator nomor acak unggulan sendiri. Ini berarti bahwa setiap sub-sistem mandiri, dan jika ada yang rusak itu tidak akan mempengaruhi semua yang ada di dunia. Namun ini sepertinya masih memiliki banyak potensi untuk "kerusakan", bahkan jika di bagian yang terisolasi dari permainan.

Cara lain yang mungkin untuk menangani masalah ini bisa dengan mempertahankan versi lengkap generator Anda di dalam kode, dan tetap menggunakan generator yang tepat untuk instance dunia tertentu. Ini tampaknya seperti mimpi buruk pemeliharaan bagi saya, dan saya ingin tahu apakah ada yang benar-benar melakukan ini.

Jadi, pertanyaan saya sebenarnya adalah permintaan saran umum, teknik, dan pola desain untuk menangani masalah efek kupu-kupu ini, terutama dalam konteks pembaruan game pasca-rilis. (Semoga itu bukan pertanyaan yang terlalu luas.)

Saat ini saya bekerja di Unity3D / C #, meskipun ini adalah pertanyaan agnostik bahasa.

MEMPERBARUI:

Terima kasih atas balasannya.

Terlihat lebih dan lebih seperti data statis adalah pendekatan terbaik dan teraman, dan juga bahwa ketika menyimpan banyak data statis bukanlah suatu pilihan, memiliki kampanye panjang di dunia yang dihasilkan akan membutuhkan versi ketat dari generator yang digunakan. Alasan keterbatasan dalam kasus saya adalah perlunya cloud save / sync berbasis mobile. Solusi saya mungkin menemukan cara menyimpan sejumlah kecil data ringkas tentang hal-hal penting.

Saya menemukan konsep Stormwind tentang "Kandang" menjadi cara yang sangat berguna untuk memikirkan berbagai hal. Kandang pada dasarnya adalah titik reseed, mencegah efek perubahan kecil, yaitu mengurung kupu-kupu.

batal
sumber
Saya memberikan suara untuk menutup pertanyaan ini sebagai di luar topik karena terlalu luas.
Almo
Saya sadar ini sangat luas. Apakah Anda merekomendasikan saya mencoba forum gamedev atau semacamnya? Sebenarnya tidak ada cara untuk membuat pertanyaan lebih spesifik. Saya berharap saya akan mendengar dari seseorang dengan banyak pengalaman di bidang ini, dengan beberapa trik licik yang belum terpikir oleh saya.
null
2
Almo salah. Sama sekali tidak luas. Ini adalah pertanyaan yang sangat bagus dan cukup sempit untuk diberikan jawaban yang baik. Itu sesuatu yang saya pikir banyak dari kita orang prosedural sering merenungkan.
Insinyur

Jawaban:

8

Saya pikir Anda sudah membahas pangkalan di sini:

  • Menggunakan beberapa generator atau penyemaian ulang pada interval (misalnya menggunakan hash spasial) untuk membatasi limpahan dari perubahan. Ini mungkin berfungsi untuk konten kosmetik, tetapi seperti yang Anda tunjukkan itu masih dapat menyebabkan kerusakan yang terkandung dalam satu bagian.

  • Melacak versi generator yang digunakan dalam menyimpan file dan merespons dengan tepat. Apa yang "sesuai" artinya bisa ...

    • Menyimpan riwayat semua versi generator sebelumnya di permainan Anda yang dapat dieksekusi, dan menggunakan yang mana saja yang cocok dengan save. Ini membuatnya lebih sulit untuk menambal bug jika pemain terus menggunakan simpanan lama.
    • Peringatan kepada pemain bahwa file penyimpanan ini berasal dari versi lama, dan menyediakan tautan untuk mengakses versi itu sebagai executable terpisah. Baik untuk game dengan kampanye yang berlangsung beberapa jam hingga berhari-hari, buruk untuk kampanye yang Anda harapkan akan bermain selama berminggu-minggu atau lebih.
    • Simpan hanya nversi generator terakhir di executable Anda. Jika file simpan menggunakan salah satu versi terbaru, (tawarkan untuk) perbarui file simpan ke versi terbaru. Ini menggunakan generator yang sesuai untuk membongkar keadaan usang ke literal (atau ke delta dari output generator baru pada seed yang sama, jika mereka sangat mirip). Segala keadaan baru dari sini berasal dari generator terbaru. Pemain yang tidak bermain untuk waktu yang lama bisa tertinggal. Dan dalam kasus terburuk Anda akhirnya menyimpan seluruh kondisi permainan dalam bentuk literal, dalam hal ini Anda mungkin juga ...
  • Jika Anda berharap untuk sering mengubah logika generasi Anda dan tidak ingin memutus kompatibilitas dengan versi sebelumnya, jangan mengandalkan determinisme generator: simpan seluruh negara Anda di file save Anda. (mis. "Nuke dari orbit. Ini satu-satunya cara untuk memastikan")

DMGregory
sumber
Jika Anda membuat aturan generasi, apakah ada cara bagi Anda untuk membalikkan generasi? IE, diberi status permainan, dapatkah Anda mengembalikannya menjadi seed? Jika itu mungkin dengan data Anda, alih-alih menautkan pemain ke versi gim yang berbeda, Anda bisa memberikan utilitas pembaruan yang menghasilkan dunia dari seed dengan sistem yang lebih lama, lalu menggunakan status yang dihasilkan untuk menghasilkan seed untuk generator baru. Anda mungkin harus memperingatkan pemain Anda tentang menunggu konversi.
Joe
1
Ini secara umum tidak mungkin. Anda bahkan tidak dijamin bahwa ada benih untuk generator baru yang memberikan output yang sama seperti yang lama. Biasanya biji-bijian ini mengandung sekitar 64 bit, tetapi jumlah dunia yang mungkin didukung oleh game Anda cenderung lebih besar dari 2 ^ 64, sehingga setiap generator hanya menghasilkan sebagian dari ini. Mengubah generator kemungkinan besar akan menghasilkan subset level baru, yang mungkin memiliki sedikit atau bahkan tidak ada persimpangan dengan set generator sebelumnya.
DMGregory
Sulit untuk memilih jawaban "Benar". Saya memilih yang ini karena ringkas dan merangkum masalah utama dengan cara yang jelas. Terima kasih.
null
4

Sumber utama Efek Kupu-kupu semacam ini bisa dibilang bukan generasi nomor - yang harus cukup mudah untuk tetap deterministik dari generator nomor tunggal - melainkan penggunaan angka-angka itu dengan kode klien. Perubahan kode adalah tantangan nyata dalam menjaga stabilitas.

Kode: Tes Unit Cara terbaik untuk memastikan bahwa beberapa perubahan kecil di suatu tempat tidak bermanifestasi di tempat lain tanpa disengaja, adalah dengan memasukkan tes unit menyeluruh untuk setiap aspek generatif, dalam bangunan Anda. Ini berlaku untuk setiap bagian dari kode ringkas tempat mengubah satu hal dapat berdampak pada banyak hal lainnya - Anda perlu pengujian untuk semua sehingga Anda dapat melihat pada satu bangunan apa yang telah terpengaruh.

Bilangan: Urutan / Slot Berkala Katakanlah Anda memiliki satu generator angka yang berfungsi untuk semuanya. Itu tidak memberikan makna, itu hanya memuntahkan angka secara berurutan - seperti PRNG lainnya. Mengingat seed yang sama dalam dua run, kita mendapatkan urutan yang sama, ya? Sekarang Anda memikirkan beberapa hal dan memutuskan bahwa mungkin ada 30 aspek permainan Anda yang secara teratur perlu diberikan nilai acak. Di sini kami menetapkan urutan siklus 30 slot, misalnya setiap angka pertama dalam urutan adalah tata letak medan kasar, setiap angka kedua adalah gangguan medan ... dll ... setiap nomor ke-10 menambahkan beberapa kesalahan pada keadaan AI untuk realisme. Jadi haid Anda adalah 30.

Setelah 10, Anda memiliki 20 slot gratis yang dapat Anda gunakan untuk aspek lain saat desain game berkembang. Biaya di sini tentu saja Anda harus menghasilkan angka untuk slot 11-30 meskipun saat ini sedang tidak digunakan , yaitu menyelesaikan periode, untuk kembali ke urutan 1-10 berikutnya. Itu memiliki biaya CPU, meskipun harus kecil (tergantung pada jumlah slot gratis). Kelemahan lainnya adalah Anda perlu memastikan bahwa desain akhir Anda dapat ditampung dalam jumlah slot yang Anda sediakan di awal proses pengembangan Anda ... dan semakin banyak Anda menetapkan di awal, semakin banyak slot "kosong" Anda berpotensi harus melalui masing-masing, untuk membuat semuanya berfungsi.

Efek dari ini adalah:

  • Anda memiliki satu generator yang menghasilkan angka untuk semuanya
  • Mengubah jumlah aspek yang Anda butuhkan untuk menghasilkan angka, tidak akan berdampak pada determinisme (asalkan periode Anda cukup besar untuk mengakomodasi semua aspek)

Tentu saja, akan ada periode yang lama di mana permainan Anda tidak tersedia untuk umum - dalam alpha, jadi untuk berbicara - sehingga Anda dapat mengurangi dari mengatakan 30 hingga 20 aspek tanpa mempengaruhi pemain, hanya diri Anda sendiri, jika Anda menyadari bahwa Anda telah ditugaskan cara terlalu banyak slot di awal. Ini tentu saja akan menghemat beberapa siklus CPU. Namun perlu diingat bahwa fungsi hash yang baik (yang dapat Anda tulis sendiri) harus secepat kilat. Jadi harus menjalankan slot tambahan tidak harus mahal.

Insinyur
sumber
Hai. Kedengarannya mirip dengan beberapa hal yang saya lakukan. Saya biasanya menghasilkan banyak sub-benih di muka berdasarkan pada benih dunia awal. Baru-baru ini saya mulai membuat array noise agak panjang, dan kemudian masing-masing "slot" hanyalah sebuah indeks ke array itu. Dengan cara itu setiap subsistem hanya bisa mengambil benih yang tepat dan bekerja secara terpisah. Teknik hebat lainnya adalah dengan menggunakan koordinat x, y untuk menghasilkan benih untuk setiap lokasi. Saya menggunakan kode dari jawaban Euphoric di halaman tumpukan ini: programmers.stackexchange.com/questions/161336/…
null
3

Jika Anda ingin kegigihan dengan PCG, saya sarankan Anda memperlakukan kode PCG itu sendiri sebagai data . Sama seperti Anda akan bertahan data lintas revisi dengan konten biasa, dengan konten yang dihasilkan, jika Anda ingin bertahan di seluruh revisi, Anda harus bertahan generator.

Tentu saja, pendekatan yang paling populer adalah mengubah data yang dihasilkan menjadi data statis, seperti yang telah Anda sebutkan.

Saya tidak tahu contoh gim yang menyimpan banyak versi generator, karena kegigihan tidak biasa dalam gim PCG - itulah sebabnya permadeath sering berjalan seiring dengan PCG. Namun ada banyak contoh beberapa PCG, bahkan dari jenis yang sama, dalam game yang sama. Misalnya, Unangband memiliki banyak generator terpisah untuk ruang bawah tanah, dan saat yang baru ditambahkan, yang lama masih berfungsi sama. Apakah itu dapat dikelola, terserah implementasi Anda. Salah satu cara untuk mempertahankannya adalah dengan menggunakan skrip untuk mengimplementasikan generator Anda, menjaga mereka tetap terisolasi dengan sisa kode gim.

congusbongus
sumber
Itu ide yang cerdas, hanya menggunakan generator yang berbeda untuk area yang berbeda.
null
2

Saya memelihara area seluas 30000 kilometer persegi, menampung sekitar 1 juta bangunan dan objek lainnya, selain penempatan acak hal-hal yang bersifat misc. Simulasi luar ruangan ofc. Data yang disimpan adalah sekitar 4 GB. Saya beruntung memiliki ruang penyimpanan, namun ini tidak terbatas.

Acak acak, tidak terkendali. Tapi orang bisa mengurungnya sedikit:

  • Kontrol itu mulai ujungnya akhir (seperti yang disebutkan dalam posting lain, nomor benih dan berapa banyak angka yang dihasilkan)
  • Batasi ruang numeriknya, mis. menghasilkan bilangan bulat antara 0 dan 100 saja.
  • Mengimbangi ruang numeriknya, dengan menambahkan nilai (mis. 100 + [angka yang dihasilkan antara 0 dan 100] menghasilkan angka acak antara 100 dan 200)
  • Skala itu (mis. Kalikan dengan 0,1)
  • Dan aplikasikan berbagai kandang di sekitarnya. Ini mengurangi, menghapus bagian dari generasi. Misalnya. jika menghasilkan dalam ruang 2 dimensi, seseorang dapat menempatkan persegi panjang di atas pasangan angka dan memo apa yang ada di luar. Atau lingkaran, atau poligon. Jika dalam ruang 3D, seseorang hanya dapat menerima misalnya kembar tiga yang berada di dalam bola, atau bentuk lain (sekarang berpikir secara visual, tetapi ini tidak harus ada hubungannya dengan visualisasi atau posisi aktual).

Itu saja. Kandang juga mengkonsumsi data, sayangnya.

Ada pepatah dalam bahasa Finlandia, Hajota ja hallitse. Diterjemahkan menjadi Divide and Conquer .

Saya segera meninggalkan ide definisi yang tepat untuk detail terkecil. Random menginginkan kebebasan, jadi ia mendapat kebebasan. Biarkan kupu-kupu terbang - di dalam kandangnya. Sebaliknya saya fokus pada cara yang kaya untuk mendefinisikan (dan memelihara !!) kandang. Tidak masalah apa mobil mereka, asalkan biru atau biru gelap (majikan yang membosankan pernah berkata :-)). "Biru atau biru gelap" adalah kandang (sangat kecil) di sini, di sepanjang dimensi warna.

Apa yang bisa dikelola, untuk mengendalikan dan mengelola ruang numerik?

  • Grid boolean adalah (bit kecil!)
  • Poin sudut adalah
  • Seperti struktur pohon (= untuk mengikuti "kandang memegang kandang")

Pemeliharaan-bijaksana, dan versi antar-kebijaksanaan-bijaksana ... kita memiliki
: jika versi = n maka
: elseif versi = m maka ...
Yap, basis kode tumbuh lebih besar :-).

Hal-hal yang biasa. Cara Anda yang benar untuk terus maju adalah mendefinisikan metode kaya untuk membagi dan menaklukkan , dan mengorbankan beberapa data tentang itu. Kemudian, jika memungkinkan, berikan kebebasan pengacakan (lokal), di mana tidak penting untuk mengendalikannya.

Tidak sepenuhnya tidak kompatibel dengan "nuke it fom orbit" lucu yang diusulkan oleh DMGregory, tetapi mungkin menggunakan nuklir kecil dan akurat? :-)

Angin badai
sumber
Terima kasih atas jawaban anda. Kedengarannya seperti area prosedural yang sangat besar untuk dipertahankan. Saya dapat melihat bagaimana untuk area yang begitu luas, bahkan ketika Anda memiliki akses ke banyak penyimpanan, masih tidak mungkin untuk hanya menyimpan semuanya. Sepertinya generator versi harus menjadi jalan ke depan. Jadilah itu :)
null
Dari semua jawaban, saya mendapati diri saya paling memikirkan hal ini. Saya menikmati deskripsi Anda yang sedikit filosofis tentang hal-hal. Saya menemukan istilah "Kandang" sangat berguna ketika menjelaskan ide-ide, jadi terima kasih untuk itu. Biarkan kupu-kupu terbang ... di dalam kurungannya :)
null
PS Saya benar-benar ingin tahu game mana yang Anda garap. Apakah Anda dapat membagikan informasi itu?
null
Dapat menambahkan satu hal lagi tentang ruang numerik: Layak untuk selalu dekat dengan nol. Anda mungkin sudah tahu. Close to zero memberikan akurasi numerik terbaik dan paling menggedor untuk bit terkecil. Anda selalu dapat mengimbangi sejumlah angka hampir nol di kemudian hari, tetapi Anda hanya perlu satu angka untuk itu. Demikian pula, Anda dapat (saya hampir mengatakan Anda HARUS) memindahkan perhitungan jauh lebih dekat ke nol, dengan offset. - Stormwind
Stormwind
Mengevaluasi sebelumnya, pertimbangkan pergerakan kendaraan kecil, peningkatan 1-frame 0,01 [meter, unit]: Anda tidak dapat secara akurat menghitung 10000,1 + 0,01 dalam akurasi numerik 32-bit (tunggal) tetapi Anda BISA menghitung 0,1 + 0,01. Oleh karena itu, jika "aksi" berlangsung jauh (di belakang gunung :-)), jangan pergi ke sana, alih-alih pindahkan gunung ke Anda (bergerak dengan 10.000, maka Anda berada di 0,1 sekarang). Berlaku juga untuk ruang penyimpanan. Seseorang bisa serakah dengan penyimpanan nilai numerik yang saling berdekatan. Simpan bagian umum dari mereka satu kali, dan variasi satu per satu - dapat menghemat bit! Apakah Anda menemukan tautannya? ;-)
Stormwind