Cara yang tepat untuk menangani penghancuran entitas game

10

Bayangkan sebuah dunia game di mana banyak dan banyak entitas secara dinamis dimuat sepanjang waktu, saya akan menyatakan bahwa sebagai daftar entitas mungkin, tetapi bagaimana dengan menghapusnya?

Sementara ketika menambahkan saya bisa mendorong kembali entitas baru, saya bisa memiliki kebutuhan untuk menghapus di mana saja dalam wadah. Untuk menghindari pencarian elemen untuk menemukan posisinya untuk dihapus, pilihan apa yang saya miliki?

Saya kira saya bisa menyimpan entitas id sebagai posisinya di wadah, membuat jalur untuk penghapusan langsung, tetapi bukankah itu menghasilkan semacam 'gangguan' saling ketergantungan?

Saya tahu cara yang benar akan menjadi sesuatu seperti List.RemoveAt (whereToRemove); tetapi bagaimana jika hanya entitas yang tahu kapan harus mati?

Atau apakah saya hanya melewatkan sesuatu dan daftar kontainer akan tahu kapan suatu objek dihancurkan dan mengurangi ukurannya sendiri?

Grimshaw
sumber

Jawaban:

10

Inilah kondisi Anda:

  • Objek lain mungkin masih tergantung pada entitas Anda yang dihapus, setelah dihapus.

  • Anda hanya menginginkan entitas untuk menentukan penghapusannya sendiri.

Anda tidak dapat memiliki keduanya. Mengapa? Karena kode pada tingkat yang lebih tinggi daripada entitas Anda sendiri (lihat contoh di bawah) memutuskan kapan entitas itu perlu digunakan. Akibatnya, hanya kode pada tingkat yang sama yang dapat menentukan apakah entitas Anda cocok untuk dihapus atau tidak.

Namun , apa yang bisa terjadi adalah bahwa entitas dapat meminta penghapusannya sendiri, dengan mematikan suatu acara yang didengarkan oleh kode tingkat yang lebih tinggi. Level yang lebih tinggi itu kemudian menyimpan permintaan ini untuk dihapus dalam daftar.


Contoh 1: tanpa acara

Anda sedang memeriksa tabrakan antar entitas di dunia Anda. Ini ditangani lebih tinggi, biasanya di loop permainan utama Anda, yang memeriksa setiap entitas terhadap satu sama lain. Dalam contoh ini secara khusus, ketika suatu entitas bertabrakan dengan yang lain, hanya logika internal entitas yang dapat menentukan berapa banyak kerusakan yang telah terjadi, dan apakah itu telah "kadaluwarsa" atau tidak. Jadi mari kita ikuti alur logika untuk tabrakan di mana Anda memiliki empat entitas di dunia Anda, A, B, C, dan D. A adalah entitas kami yang kami perhatikan.

Kami memeriksa A untuk tabrakan dengan B. Ada tabrakan. A mengambil kerusakan 50%.

Kami memeriksa A untuk tabrakan dengan C. Ada tabrakan. A mengambil kerusakan 50%. Karena kerusakan mencapai 0, A menentukan bahwa ia telah "mati". Itu menghapus dirinya sendiri dari daftar.

Kami memeriksa A untuk tabrakan dengan D. Tidak akan ada tabrakan, tetapi Anda tidak akan pernah sampai sejauh itu: Anda mendapatkan pengecualian runtime karena daftar entitas Anda telah dimodifikasi di tengah-tengah operasi traveral.

Contoh 2: dengan acara

Setup yang sama seperti sebelumnya.

Kami memeriksa A untuk tabrakan dengan B. Ada tabrakan. A mengambil kerusakan 50%.

Kami memeriksa A untuk tabrakan dengan C. Ada tabrakan. A mengambil kerusakan 50%. Karena kerusakan mencapai 0, A menentukan bahwa ia telah "mati". Ini memancarkan suatu peristiwa ke kode manajemen entitas untuk mengatakan, "Hapus saya ASAP". Kode manajemen entitas melihat referensi entitas yang dikirim sebagai bagian dari acara, dan menyimpan referensi itu dalam daftar entitas yang akan dihapus.

Kami memeriksa A untuk tabrakan dengan D. Tidak ada tabrakan, dan cek berfungsi dengan baik.

Sekarang, di akhir iterasi loop game saat ini , jalankan melalui daftar entitas yang akan dihapus, dan hapus semua entitas ini dari daftar entitas utama Anda.


Anda dapat melihat bagaimana ini menghindari masalah sekaligus. Anda tidak perlu menggunakan acara, Anda dapat menggunakan sinyal atau sesuatu yang lain, tetapi prinsipnya sama - jangan menghapus entitas sampai Anda dapat melakukannya dengan aman. Sisi lain dari pendekatan ini, untuk menjaga hal-hal tetap bersih dan teratur, melakukan hal yang sama dengan entitas untuk menambahkan - pastikan Anda menyimpan referensi untuk mereka, dan hanya menambahkannya pada awal iterasi loop game berikutnya.

Terakhir, jangan lupa untuk menghapus daftar to-remove dan to-add Anda, setiap kali Anda menggunakannya untuk melakukan penambahan / penghapusan pada daftar entitas utama Anda.

PS. Jangan takut untuk mencari melalui daftar utama Anda untuk melakukan pemindahan individu. Itu adalah bagian tak terpisahkan dari manajemen entitas, dan bahkan daftar besar cenderung sangat cepat untuk dilalui - lagipula, itulah tujuan mereka direkayasa.

Insinyur
sumber
0

Anda pasti mencari HashMap / HashTable . Hashtable adalah peta yang cocok dengan kunci ke nilai tertentu. Kuncinya bisa apa saja (seperti ID Entitas).

Setheron
sumber
0

Saya kira Anda bisa menggunakan ide smartpointer untuk menangani deallocations untuk Anda, dalam hal ini tidak perlu menyimpan daftar semua entitas di dalam kode Anda.

dalam beberapa kasus, Anda perlu daftar untuk mengulangi semua objek dalam gim Anda. daftar ini bisa berupa daftar tautan di mana memasukkan dan menghapus objek darinya akan memakan waktu tepat O (1).

bahkan untuk meningkatkan kecepatan Anda lebih banyak, Anda dapat menggunakan beberapa array statis (mungkin vektor). dalam hal ini Anda harus melacak 2 daftar tertaut di dalam vektor yang sama, satu akan beralih di atas objek yang valid dan satu akan beralih di atas objek gratis. setiap kali smartpointer menandai beberapa tempat untuk dihapus, Anda cukup menghapus pointer itu dan menambahkan ruang itu ke daftar spasi kosong. dan setiap kali Anda menambahkan beberapa entitas Anda hanya perlu menghapus freespace pertama mengisinya dengan pointer entitas dan kemudian menambahkannya ke daftar objek yang valid.

Ali1S232
sumber