Saya mencoba membuat mesin game berbasis ubin yang fleksibel untuk membuat semua jenis game puzzle non-realtime, seperti Bejeweled, Civilization, Sokoban, dan sebagainya.
Pendekatan pertama yang saya miliki adalah memiliki array 2D objek Tile, dan kemudian memiliki kelas yang mewarisi dari Tile yang mewakili objek game. Sayangnya dengan cara itu saya tidak bisa menumpuk lebih banyak elemen game di Tile yang sama tanpa memiliki array 3D.
Lalu saya melakukan sesuatu yang berbeda: Saya masih memiliki array 2D objek Tile, tetapi setiap objek Tile berisi Daftar tempat saya meletakkan dan entitas yang berbeda. Ini berfungsi dengan baik hingga 20 menit yang lalu, ketika saya menyadari bahwa terlalu mahal untuk melakukan banyak hal, lihat contoh ini:
Saya memiliki entitas Wall. Setiap pembaruan saya harus memeriksa 8 Ubin yang berdekatan, lalu memeriksa semua entitas dalam Daftar Ubin, memeriksa apakah ada entitas yang merupakan Dinding, lalu akhirnya menggambar sprite yang benar. (Ini dilakukan untuk menggambar dinding yang bersebelahan dengan mulus)
Satu-satunya solusi yang saya lihat sekarang adalah memiliki array 3D, dengan banyak lapisan, yang dapat sesuai dengan setiap situasi. Tapi dengan begitu saya tidak bisa menumpuk dua entitas yang berbagi lapisan yang sama di ubin yang sama. Setiap kali saya ingin melakukan itu, saya harus membuat layer baru.
Apakah ada solusi yang lebih baik? Apa yang akan kamu lakukan?
sumber
Jawaban:
Apakah Anda benar-benar melihat masalah ini, atau Anda baru saja memikirkannya? Karena saya gagal melihat bagaimana pengulangan pada daftar objek memiliki efek nyata pada kinerja. Anda harus memiliki ratusan objek per ubin agar ini penting. Sebagian besar game yang saya pikirkan memiliki 10, teratas.
Jika Anda benar-benar have a problem, the best idea is to cache data, not change representation. In your example, wall configuration probably doesn't change every frame. Just cache correct sprite type, don't recalculate it constantly.
Jika Anda ingin membuat game gila yang memiliki banyak objek, dan mereka berubah setiap saat, Anda dapat membuat layer berbeda dengan semantik yang berbeda. Misalnya, lapisan dinding hanya berisi dinding, tidak lebih dari 1 per ubin, dan, katakanlah, lapisan dekorasi berisi daftar objek yang tidak pernah berubah.
Akhirnya, jika Anda ingin memiliki arsitektur ultra-fleksibel yang idealnya mendukung setiap game yang mungkin - keberuntungan, tidak ada yang seperti itu.
sumber
Dua saran. Pertama, Anda harus menyelesaikan sprite yang akan digambar setiap ubin selama memuat peta / level ubin Anda. Seharusnya cukup mudah untuk melintasi array 2D satu tingkat Anda dimuat dan memutuskan bahwa dinding certian perlu bentuk L dan yang lain harus menjadi |bentuk.
Kedua, saya akan menyimpan data statis yang terkait dengan ubin di tempat yang berbeda dari data aktif. Jadi objek ubin mungkin memiliki daftar objek yang datang dan pergi dari ubin tetapi tidak perlu melintasi ini untuk melihat apakah, misalnya kita hanya ingin tahu apakah ubin itu walkable atau tidak.
Kode psudo ini kurang lebih bagaimana saya telah mendekati sistem berbasis ubin.
Ini mengasumsikan bahwa ada ubin statis di game Anda, tetapi itu adalah asumsi yang cukup bagus di banyak game berbasis ubin di mana Anda berhadapan dengan dinding dan sejenisnya.
sumber
Kamu berkata:
Inilah situasi yang ingin Anda pecahkan menggunakan pola MVC (model view controller) untuk memisahkan model Anda dari tampilan Anda. MVC membuat masalah ini menjadi dua bagian:
Alih-alih memiliki array 2D ubin, atau array 2D daftar ubin, model Anda akan menyimpan array 2D objek game. Kemudian array 2D dari kelas ubin Anda akan melihat objek game yang sesuai dan memutuskan cara merendernya.
Alih-alih memiliki instance Tile tunggal membuat objek game tunggal, Anda dapat memiliki instance Tile tunggal membuat sesuatu yang tampak seperti tumpukan objek. Ini akan lebih efisien, dan akan memberi Anda pemisahan yang bersih dari logika kode inti Anda, dan tampilannya.
Sama seperti dinding. Logikanya sangat sepele, tetapi renderingnya lebih kompleks.
sumber
Saya setuju dengan @Onnion. Gunakan pendekatan daftar, tetapi tetap diurutkan jika kinerja adalah masalah. Artinya menggunakan pendekatan hybrid. Gunakan daftar sebagai dimensi ketiga Anda, tetapi hanya mengidentifikasi 5 item pertama sebagai jenis tertentu, dan apa pun setelah itu adalah jenis tinta sendiri, atau jenis yang tidak perlu diperiksa beberapa kali per bingkai.
sumber
Anda harus "tidak pernah" membuat kelas terpisah untuk hal-hal seperti ubin. Anda harus membuat struct dari byte, celana pendek dan int yang merujuk pada jenis ubin dan objek di atasnya. Kinerja yang bijaksana adalah yang terbaik untuk digunakan atau bahkan lama pada sistem 64 bit. Tetapi jika Anda ingin menyimpan peta Anda, Anda harus pergi dengan byte atau celana pendek di mana pun Anda bisa, terutama untuk peta besar.
Dalam gim saya, saya memiliki kelas peta yang memiliki bidang seperti: byte tileType; 256 jenis medan yang berbeda sudah cukup untuk gim ini. Membutuhkan 1 byte. ushort tileObject; Ada 65.536 objek yang berbeda. Membutuhkan 2 byte dll.
Jika saya mengambil contoh di atas setiap ubin hanya membutuhkan 3 byte dalam memori. Jadi 10000x10000 akan 300mb dalam memori dan seharusnya tidak menjadi masalah. Setiap kali Anda perlu mencari sesuatu, Anda menentukan di mana di peta Anda ingin mencari dan apa yang Anda cari dan mengulangi array sesuai.
Jika Anda memiliki hal-hal dinamis di seluruh peta, tanyakan pada diri sendiri apakah pemain benar-benar memperhatikan hal-hal yang jauh dari viewport itu.
sumber