Solusi terbaik untuk "level string"?

10

Saya memiliki permainan yang menghasilkan peta level acak di awal level. Saya ingin menerapkan beberapa cara untuk menyimpan dan memuat level.

Saya berpikir mungkin XML akan menjadi pilihan yang baik untuk menyimpan semua variabel, maka akan mudah bagi saya untuk membangun sesuatu yang dapat mem-parsing XML itu dan menghasilkan tingkat yang sama persis.

Tetapi XML mungkin berlebihan untuk kebutuhan saya. Saya ingat kembali pada hari itu dengan konsol Sega tua yang tidak memiliki kemampuan untuk menyelamatkan gim Anda (saya pikir gim Worms juga melakukannya), bahwa mereka akan memberi Anda banyak karakter yang dapat Anda tulis. Jika Anda menekan string itu nanti, itu akan memuat level yang tepat.

Apakah "string level" menjadi pilihan yang baik? Apakah itu akan menjadi semacam konversi "base60"? Bagaimana saya menerapkan ini?

Adam Harte
sumber

Jawaban:

20

Agaknya yang Anda butuhkan untuk menyelamatkan adalah benih acak, yang umumnya hanya int. Anda dapat menyandikan int ke base64 jika Anda ingin membuatnya sedikit lebih buram, tapi itu mungkin tidak diperlukan.

pembuat kode
sumber
Anda juga dapat menghasilkan benih dari kata asli (mungkin membeli menambahkan karakter untuk mendapatkan benih Anda) dan dengan cara itu mengembalikan sesuatu yang lebih bermakna. Anda harus menyimpan kata-kata itu di dalam gim Anda atau mengambilnya.
Jonathan Fischoff
Itu bagus, tetapi itu juga harus menyimpan data dinamis jika permainan sedang dimainkan. String perlu menyimpan posisi karakter / skor dll. Jadi bagaimana cara terbaik untuk menghasilkan string ini?
Adam Harte
Saya mungkin akan menggunakan JSON (atau XML jika Anda suka) untuk membuat serialisasi keadaan dunia dan kemudian base64-encode string itu. Tidak yakin bahwa semua itu berguna, mengapa tidak membuat sistem penyimpanan / pemuatan yang lebih berorientasi GUI? Saya berasumsi bahwa ini adalah berbasis web dan Anda ingin tidak menangani sisi server ini. Mungkin lihat shygypsy.com/farm/p.cgi sebagai contoh?
coderanger
23

Apa pun format yang Anda gunakan untuk menyimpan permainan, demi kebaikan masukkan nomor versi. Anda akan dapat memiliki banyak kompilasi yang kompatibel dengan bercabang pada nomor versi, atau Anda akan dapat dengan aman mengenali simpanan yang terlalu lama untuk memuat.

Anda akan menyesal jika tidak melakukannya.

tenpn
sumber
7
+1 tidak benar-benar menjawab pertanyaan tetapi sangat penting.
Jonathan Fischoff
10

JSON baik, tetapi YAML lebih baik. :) http://www.yaml.org/ dan http://code.google.com/p/yaml-cpp/ untuk salah satu implementasi yang lebih baik untuk digunakan.

YAML adalah superset dari JSON yang menambahkan dukungan untuk beberapa fitur bagus, terutama:

  • Node biner. Ini bagus untuk membuat serialisasi jenis data yang mungkin Anda hadapi untuk deskripsi level. JSON mengharuskan Anda untuk menerjemahkan ke beberapa format perantara pilihan Anda, seperti Base64, sebelum menulis / setelah parsing. YAML memiliki tipe !! binary node yang memberitahu parser library untuk melakukannya untuk Anda.
  • Referensi intra-dokumen. Jika objek yang sama muncul dua kali dalam dokumen, JSON akan menulisnya dua kali, dan ketika Anda membacanya kembali, Anda akan mendapatkan dua salinan. Banyak penghasil YAML dapat mendeteksi situasi ini dan alih-alih salinan kedua, mengeluarkan referensi ke yang pertama, kapan dapat dideteksi saat memuat.
  • Jenis simpul khusus. Anda dapat menandai setiap peta dalam daftar dengan misalnya !! Pemain, !! Musuh, dll., Dan jaga agar informasi jenis Anda lebih banyak keluar-dari-band.
  • YAML mendukung pemformatan yang lebih mudah dibaca.
  • Karena JSON adalah bagian dari YAML, sebagian besar pembaca YAML tidak akan kesulitan membaca dokumen JSON.

sumber
1
Yaml sangat keren, dan jika Anda menghindari beberapa fitur superset, ia dapat dikonversi ke json tanpa kesulitan.
Jethro Larson
3

Jika Anda ingin membuat serial semua data dalam game, saya akan merekomendasikan JSON sebagai format file Anda, itu sebabnya lebih mudah menggunakan XML dan dukungannya sangat bagus di banyak bahasa.

Saya telah menggunakan perpustakaan ini untuk C ++ dan berfungsi dengan sangat baik.

http://jsoncpp.sourceforge.net/

Jonathan Fischoff
sumber
3

XML adalah pilihan yang baik jika Anda tidak dibatasi oleh ukuran dan didukung secara native (misalnya dalam. NET dan Flash) tetapi jika Anda menginginkan format yang ramping, Anda dapat membuat format dan parser Anda sendiri dengan mudah. Saya biasanya menggunakan 1 karakter misalnya. koma untuk memisahkan setiap objek. Untuk mendekode string, lakukan split pada koma. Sekarang setiap objek membutuhkan properti yang berbeda sehingga pisahkan dengan karakter yang berbeda, misalnya titik koma, dan gunakan karakter lain untuk memisahkan nama properti dari properti, misalnya. Usus besar. Semua dengan demikian dapat diterjemahkan dengan mudah tanpa regex hanya dengan menggunakan string.split. Berikut ini sebuah contoh:

id:1;x:5;y:45.2;angle:45,id:28;x:56;y:89;angle:12;health:78

Anda dapat menghemat lebih banyak ruang dengan mempertahankan nama properti hingga 1 karakter, mis. h untuk kesehatan. Misalnya.

i:1;x:5;y:45.2;a:45,i:28;x:56;y:89;a:12;h:78

Bandingkan dengan alternatif JSON:

{"o":[{"i":1, "x":5, "y":45.2, "a":45}, {"i":28, "x":56, "y":89, "a":12, "h":78}]}

Selain itu, jika Anda ingin menurunkan ukuran angka, Anda dapat menyandikannya menggunakan set karakter UTF16 yang dapat dicetak. Utas ini mengilhami saya untuk mengajukan pertanyaan tentang Stack Overflow tentang berapa banyak data yang dapat Anda masukkan ke dalam satu karakter di layar . Jawabannya tampaknya ada di suatu tempat lebih dari 40.000 nilai untuk bilangan bulat, jika Anda tidak keberatan memiliki kepingan, kanji, dan bidak catur: ♔♕♖♗♘♙♚♛♜♝♞♟

Untuk mendapatkan pengurangan ukuran lebih lanjut, Anda dapat menggunakan urutan baca / tulis untuk menentukan nilai mana, jadi dua karakter pertama mewakili id, dua berikutnya adalah posisi x, dua berikutnya y, lalu sudut, lalu kesehatan , dll. Jadi:

F5DGP@%&002DFTK#OP1F

dapat menyimpan semua informasi yang sama dengan contoh lainnya.

Grid ubin dapat disimpan hanya sebagai string dengan setiap karakter mewakili jenis ubin yang berbeda misalnya:

i789pog5h3kl

di mana saya bisa berarti lava, 9 berarti rumput dll

Iain
sumber
Ini lebih sesuai dengan apa yang saya tanyakan. Saya menyebutkan XML dalam pertanyaan saya, tetapi masih ada orang yang menyarankannya!
Adam Harte
1
Tambahkan {} di sekitar itu dan Anda pada dasarnya memiliki JSON ;-)
coderanger
Anda perlu menambahkan banyak tanda kutip juga. Mungkin akan menggandakan jumlah karakter, tetapi Anda akan mendapatkan objek bersarang.
Iain
1

Jika Anda melakukan pengkodean dalam .Net maka XML sangat mudah digunakan, karena Anda dapat membuat serial / deserialize kelas level Anda menjadi / keluar dari XML hanya dengan beberapa baris, dan kemudian semuanya dalam kelas yang dikelola dengan baik.

TheMap akan menjadi variabel tipe Peta yang Anda masukkan semua data Anda.

Dim TheMap As New Map

Dengan asumsi Anda memiliki kelas Peta yang sudah dibangun, ini akan menyimpan peta Anda ke XML:

Dim Serializer As New System.Xml.Serialization.XmlSerializer(GetType(TheMap))
Dim Strm As New FileStream("c:\Map.xml", FileMode.Create, FileAccess.Write, FileShare.None)
Serializer.Serialize(Strm, TheMap)
Strm.Close()

Ini kemudian akan memuat XML itu kembali ke kelas peta Anda, untuk digunakan lagi dalam kode.

Dim Reader As New StreamReader("map.xml")
Dim Serializer As New System.Xml.Serialization.XmlSerializer(GetType(TheMap))

TheMap = Serializer.Deserialize(Reader)
Reader.Close()

Dari titik ini, file XML Anda sekarang dimuat ke dalam kelas Anda agar mudah digunakan.

Adapun masalah "Level String" Anda, apa yang dinyatakan sebelumnya akan bekerja dengan baik, Anda bisa menggunakan nomor Seed sebagai "Level String".

Jika tidak, Anda hanya dapat melakukan pra-menghasilkan berbagai peta yang Anda inginkan, dan menyimpan semuanya dengan "Level String" dan kemudian menggunakannya untuk menarik peta yang tepat.

jblaske
sumber
+1 walaupun saya membenci XML - Jika bahasa ini menyediakan format serialisasi default, yang terbaik adalah mempertimbangkannya terlebih dahulu, terutama jika itu format alat lain yang secara teoritis dapat diuraikan (seperti XML / JSON / YAML).
0

Saya akan menggunakan perangkat sederhana structatau serupa (tergantung pada bahasa Anda) untuk menyimpan semua status permainan di tempat sentral. Jika Anda menginginkan perlindungan setter / getter, Anda dapat membungkus struct dalam a class.

Jika Anda merasa sanggup melakukannya, gunakan bitfields atau lakukan manipulasi bit sendiri menggunakan operator bitwise.

Ketahuilah bahwa dalam beberapa bahasa, aturan untuk bantalan dan pengemasan struct mungkin sedikit rumit - tetapi mungkin juga tidak terlalu menjadi masalah bagi kasus Anda jika Anda memiliki satu atau dua byte bantalan.

Anda mungkin juga dapat menggunakan #pragma(seperti #pragma pack(1)) atau __attribute__untuk mengemas secara dekat struct, menghilangkan bantalan. Ini mungkin atau mungkin tidak berfungsi tergantung pada kompiler dan arsitektur target Anda.

Perhatikan bahwa penggunaan bitfields dan paket pragma atau atribut dapat mengurangi portabilitas. Di seluruh arsitektur perangkat keras, endianness bidang struct (urutan byte) juga dapat berubah. Jadi, Anda mungkin ingin menghindari ini jika Anda mencoba untuk portabilitas.

(Untuk misalnya Pac-Man, struct ini mungkin secara naif mengandung peta id atau peta seed, posisi Pac-Man x dan y, empat posisi ghost x dan y, dan bitfield besar untuk ada atau tidaknya 32-64 pelet, apa pun maksimumnya.)

Setelah Anda memiliki struct Anda, meneruskannya ke sesuatu seperti fungsi xxencode :

encode_save( char * outStringBuf, size_t outStringBufSize,
             const SaveStruct * inSaveData, size_t inSaveDataSize )

Menulis fungsi ini agak rawan kesalahan; Anda perlu menggeser dan menggabungkan byte yang diperlukan untuk mendapatkan misalnya 6 bit sekaligus, kemudian menerjemahkannya ke dalam karakter yang sesuai. Saya pribadi mencoba memburu kode orang lain, kecuali saya melakukan ini untuk "bersenang-senang" (dan saya mungkin ingin test suite untuk itu).

Jangan pernah meremehkan kekuatan sekolah lama structdi tempat yang tepat. Kami telah menggunakannya satu ton untuk game GBA dan DS di sini.

Leander
sumber
Serialisasi struktur mentah adalah kode baru non-portabel dan sangat rapuh. Kecuali itu sebagai langkah terakhir memanggang data untuk platform dengan sumber daya yang sangat terbatas, itu optimasi yang sangat prematur. Apakah ada alasan Anda memilih 6 bit hingga 8? Formatnya tidak akan dapat dibaca manusia, Anda mungkin juga memanfaatkan kecepatan dan kemampuan debuggability dari tata letak struktur yang sebenarnya.
@ Jo: Saya memang menyebutkan bahwa itu non-portable dan beberapa kekhawatiran potensial. Pertanyaannya secara khusus meminta "string level" yang dapat dibaca manusia seperti game Sega lama dan disebutkan konversi base60; melewati struct melalui sesuatu seperti xxencode akan melakukan ini. Ini belum tentu optimasi prematur: struct sederhana, bukan bitpacked, adalah cara "sentral" yang baik untuk menyimpan data yang disimpan, dan mungkin menyederhanakan banyak kode yang berinteraksi dengan data. Lihat misalnya artikel terbaru Noel Llopis tentang struktur bukan-anggota yang bukan anggota dan program "dalam ke luar". Ini hanya CIUMAN.
leander
1
Saya setuju sepenuhnya dengan cara ini. Ya, ini tidak portabel di semua versi, atau sistem, tapi sekali lagi save-game bukanlah sumber daya yang perlu digunakan kembali selama pengembangan, atau disalin di seluruh platform. Debuggability bukan masalah dengan membaca / menulis di tempat, menerapkannya sekali dan itu akan bekerja selamanya. JIKA diperpanjang adalah benar-benar masalah - tambahkan nomor versi sebagai ybyte / kata pertama dan Anda dapat mengaktifkannya (meskipun itu akan menyebabkan kerentanan data). Ini tidak seperti xml akan menyelesaikan masalah versi - kecenderungan untuk lebih terlibat daripada hanya menetapkan nilai. Ya, saya pragmatis.
Kaj
0

XML baik untuk dokumen terstruktur sewenang-wenang (elemen dapat muncul di berbagai tingkatan pohon) atau embedding format asing (seperti menempatkan svg di halaman xhtml). Jika Anda tidak memiliki persyaratan itu, ini adalah format yang benar-benar tidak efisien, dan sesuatu yang lebih sederhana seperti csv atau json lebih disukai.

Jethro Larson
sumber