Merancang mesin berbasis ubin yang fleksibel

8

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?

Vee
sumber
Bagaimana cara menggunakan array 3D memperbaiki masalah Anda dengan situasi pemeriksaan dinding itu. Bukankah masih sama?
Michael Coleman
Saya akan tahu bahwa Walls hanya tinggal pada layer nomor 1. Jadi saya bisa melakukannya: Tiles [Wall.X - 1, Wall.Y, 1] adalah Wall?
Vee
Daripada Anda tidak bisa hanya memeriksa elemen pertama dalam daftar? Saya tidak melihat bagaimana daftar menimbulkan masalah.
Michael Coleman
Dinding mungkin ada di mana saja dalam daftar dengan pendekatan kedua. Saya perlu mengulangi setiap Entitas, dan memeriksa apakah itu tembok.
Vee
4
Apakah Anda benar-benar memiliki masalah kinerja, atau apakah Anda hanya khawatir akan melakukannya? Sudahkah Anda membuat profil?
murah hati

Jawaban:

2

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.

Sudahlah
sumber
2

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.

Tile {
  Texture tex;
  //...other static data...
  List currentObjects;
}

Tile t = Tiles[x][y];

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.

Nick Van Brunt
sumber
1

Kamu berkata:

Saya telah 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 bekerja dengan baik sampai 20 menit yang lalu, ketika saya menyadari bahwa terlalu mahal untuk melakukan banyak hal

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:

  • Cara memodelkan tumpukan ubin
  • Bagaimana menampilkan tumpukan ubin

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.

ashes999
sumber
3
Saya tidak melihat bagaimana MVC (yang tidak umum dalam game dari pengalaman saya) akan membantu di sini. Jika ada, itu akan membuatnya lebih buruk: Anda akan berakhir dengan beberapa redundansi antara model dan tampilan yang harus tetap sinkron.
murah hati
1
Ya, ketika Anda memiliki masalah, gunakan saja <buzzword>. Sekarang Anda memiliki dua masalah.
Nevermind
1
np, saya membuka lebih banyak detail.
ashes999
OK saya mengambil kembali downvote saya. Masih, saya tidak berpikir MVC berguna di sini. Sebagian besar waktu, objek berbeda dengan logika, tidak (hanya) oleh representasi grafis.
Nevermind
Tidak bisa menyenangkan semuanya, kurasa. Bagi saya, MVC segera melompat keluar sebagai bagian dari solusi untuk bagian dari masalah. Tetapi saya setuju bahwa saya tidak memberikan solusi lengkap untuk semua masalah - yang akan membutuhkan esai!
ashes999
0

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.

Nate
sumber
0

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.

Madmenyo
sumber