Dalam tabrakan apa pun, ada dua GameObjects yang terlibat bukan? Yang ingin saya ketahui adalah, Bagaimana saya memutuskan objek mana yang harus berisi objek saya OnCollision*
?
Sebagai contoh, misalkan saya memiliki objek Player dan objek Spike. Pikiran pertama saya adalah meletakkan skrip pada pemain yang berisi beberapa kode seperti ini:
OnCollisionEnter(Collision coll) {
if (coll.gameObject.compareTag("Spike")) {
Destroy(gameObject);
}
}
Tentu saja, fungsionalitas yang sama persis dapat dicapai dengan alih-alih memiliki skrip pada objek Spike yang berisi kode seperti ini:
OnCollisionEnter(Collision coll) {
if (coll.gameObject.compareTag("Player")) {
Destroy(coll.gameObject);
}
}
Sementara keduanya valid, lebih masuk akal bagi saya untuk memiliki skrip pada Player karena, dalam hal ini, ketika tabrakan terjadi, suatu tindakan sedang dilakukan pada Player .
Namun, yang membuat saya ragu ini adalah bahwa di masa depan Anda mungkin ingin menambahkan lebih banyak objek yang akan membunuh Player saat bertabrakan, seperti Musuh, Lava, Laser Beam, dll. Objek-objek ini kemungkinan akan memiliki tag yang berbeda. Maka skrip pada Player akan menjadi:
OnCollisionEnter(Collision coll) {
GameObject other = coll.gameObject;
if (other.compareTag("Spike") || other.compareTag("Lava") || other.compareTag("Enemy")) {
Destroy(gameObject);
}
}
Sedangkan, dalam kasus di mana skrip berada di Spike, yang harus Anda lakukan adalah menambahkan skrip yang sama ke semua objek lain yang dapat membunuh Player dan beri nama skrip seperti KillPlayerOnContact
.
Juga, jika Anda memiliki tabrakan antara Player dan Musuh, maka Anda mungkin ingin melakukan aksi pada keduanya . Jadi dalam hal itu, objek mana yang harus menangani tabrakan? Atau haruskah keduanya menangani tabrakan dan melakukan tindakan yang berbeda?
Saya belum pernah membuat game dengan ukuran yang masuk akal sebelumnya dan saya bertanya-tanya apakah kodenya bisa menjadi berantakan dan sulit untuk dipertahankan saat tumbuh jika Anda mendapatkan hal yang salah pada awalnya. Atau mungkin semua cara itu valid dan tidak masalah?
Wawasan apa pun sangat dihargai! Terima kasih atas waktu Anda :)
sumber
Tag.SPIKE
gantinya?Jawaban:
Saya pribadi lebih suka sistem arsitek sehingga tidak ada objek yang terlibat dalam tabrakan menanganinya, dan sebagai gantinya beberapa proxy penanganan tabrakan bisa menanganinya dengan panggilan balik seperti
HandleCollisionBetween(GameObject A, GameObject B)
. Dengan begitu saya tidak perlu memikirkan logika apa yang seharusnya ada di mana.Jika itu bukan pilihan, seperti ketika Anda tidak mengendalikan arsitektur respons tabrakan, segalanya menjadi sedikit kabur. Umumnya jawabannya adalah "itu tergantung."
Karena kedua objek akan mendapatkan collback callback, saya akan memasukkan kode di keduanya, tetapi hanya kode yang relevan dengan peran objek itu di dunia game , sementara juga berusaha mempertahankan ekstensibilitas sebanyak mungkin. Ini berarti jika beberapa logika masuk akal sama dalam kedua objek, lebih memilih untuk meletakkannya di objek yang kemungkinan akan menyebabkan lebih sedikit perubahan kode dalam jangka panjang karena fungsi baru ditambahkan.
Dengan kata lain, antara dua jenis objek yang dapat bertabrakan, salah satu dari jenis objek tersebut umumnya memiliki efek yang sama pada lebih banyak jenis objek daripada yang lain. Menempatkan kode untuk efek dalam jenis yang mempengaruhi lebih banyak jenis lain berarti lebih sedikit pemeliharaan dalam jangka panjang.
Misalnya, objek pemain dan objek peluru. Dapat diperdebatkan, "menerima kerusakan akibat tabrakan dengan peluru" masuk akal logis sebagai bagian dari pemain. "Menerapkan kerusakan pada benda yang terkena" masuk akal sebagai bagian dari peluru. Namun, peluru kemungkinan memberikan kerusakan pada jenis objek yang lebih berbeda daripada pemain (di sebagian besar gim). Seorang pemain tidak akan menderita kerusakan karena terrain block atau NPC, tetapi sebuah peluru mungkin masih memberikan kerusakan pada mereka. Jadi saya lebih suka untuk menempatkan penanganan tabrakan karena memberikan kerusakan pada peluru, dalam hal ini.
sumber
TL; DR Tempat terbaik untuk meletakkan detektor tumbukan adalah tempat di mana Anda menganggapnya sebagai elemen aktif dalam tumbukan, bukan elemen pasif dalam tumbukan, karena mungkin Anda akan memerlukan perilaku tambahan untuk dijalankan dalam logika aktif tersebut (dan, mengikuti pedoman OOP yang baik seperti SOLID, adalah tanggung jawab elemen aktif ).
Detail :
Ayo lihat ...
Pendekatan saya ketika saya memiliki keraguan yang sama, terlepas dari mesin gim , adalah menentukan perilaku mana yang aktif dan perilaku mana yang pasif sehubungan dengan tindakan yang ingin saya picu saat pengumpulan.
Harap dicatat: Saya menggunakan perilaku yang berbeda sebagai abstraksi dari berbagai bagian dari logika kami untuk mendefinisikan kerusakan dan - sebagai contoh lain - inventaris. Keduanya adalah perilaku terpisah yang saya tambahkan nanti ke Player, dan tidak mengacaukan Player kustom saya dengan tanggung jawab terpisah yang akan lebih sulit untuk dipertahankan. Menggunakan anotasi seperti RequireComponent, saya akan memastikan perilaku Player saya memiliki, juga, perilaku yang saya definisikan sekarang.
Ini hanya pendapat saya: menghindari mengeksekusi logika tergantung pada tag, tetapi sebaliknya menggunakan perilaku dan nilai yang berbeda seperti enum untuk memilih di antara .
Bayangkan perilaku ini:
Perilaku untuk menentukan objek sebagai tumpukan di tanah. Game RPG menggunakan ini untuk item di tanah yang bisa diambil.
Perilaku untuk menentukan objek yang mampu menghasilkan kerusakan. Ini bisa lava, asam, zat beracun, atau proyektil terbang.
Sejauh ini, pertimbangkan
DamageType
danInventoryObject
sebagai enum.Perilaku ini tidak aktif , dengan cara berada di tanah atau terbang di sekitar mereka tidak bertindak sendiri. Mereka tidak melakukan apa pun. Misalnya, jika Anda memiliki bola api yang terbang di ruang kosong, itu tidak siap untuk melakukan kerusakan (mungkin perilaku lain harus dianggap aktif dalam bola api, seperti bola api memakan kekuatannya saat bepergian dan mengurangi kekuatan kerusakannya dalam proses, tetapi bahkan ketika
FuelingOut
perilaku potensial dapat dikembangkan, itu masih merupakan perilaku lain, dan bukan perilaku DamageProducer yang sama), dan jika Anda melihat objek di tanah, itu tidak memeriksa seluruh pengguna dan berpikir apakah mereka dapat memilih saya?Kami membutuhkan perilaku aktif untuk itu. Rekannya adalah:
Satu perilaku untuk mengambil kerusakan (Ini akan memerlukan perilaku untuk menangani hidup dan mati, karena menurunkan kehidupan dan menerima kerusakan biasanya merupakan perilaku yang terpisah, dan karena saya ingin menjaga contoh ini sesederhana mungkin) dan mungkin menolak kerusakan.
Kode ini belum diuji dan harus berfungsi sebagai konsep . Apa tujuannya? Kerusakan adalah sesuatu yang dirasakan seseorang , dan relatif terhadap objek (atau bentuk kehidupan) yang rusak, seperti yang Anda pertimbangkan. Ini adalah contoh: dalam game RPG biasa, pedang merusak Anda , sedangkan di RPG lain yang mengimplementasikannya (mis. Summon Night Swordcraft Story I dan II ), pedang juga dapat menerima kerusakan dengan memukul bagian yang keras atau memblokir baju besi, dan bisa membutuhkan perbaikan . Jadi, karena logika kerusakan relatif terhadap penerima dan bukan ke pengirim, kami hanya memasukkan data yang relevan di pengirim, dan logika di penerima.
Hal yang sama berlaku untuk pemegang inventaris (perilaku lain yang diperlukan adalah perilaku yang terkait dengan objek yang berada di tanah, dan kemampuan untuk menghapusnya dari sana). Mungkin ini adalah perilaku yang sesuai:
sumber
Seperti yang dapat Anda lihat dari berbagai jawaban di sini, ada tingkat gaya pribadi yang adil yang terlibat dalam keputusan ini, dan penilaian berdasarkan kebutuhan permainan khusus Anda - tidak ada pendekatan terbaik mutlak.
Rekomendasi saya adalah untuk memikirkannya dalam hal bagaimana pendekatan Anda akan skala saat Anda mengembangkan game Anda , menambah dan mengulangi fitur. Akankah menempatkan logika penanganan benturan di satu tempat akan menghasilkan kode yang lebih rumit nantinya? Atau apakah itu mendukung lebih banyak perilaku modular?
Jadi, Anda memiliki paku yang merusak pemain. Bertanya pada diri sendiri:
Jelas, kami tidak ingin terlena dengan hal ini dan membangun sistem over-engineered yang dapat menangani jutaan kasus, bukan hanya satu kasus yang kami butuhkan. Tetapi jika itu sama saja artinya (mis. Letakkan 4 baris ini di kelas A vs kelas B) tetapi satu skala lebih baik, itu adalah aturan praktis yang baik untuk membuat keputusan.
Untuk contoh ini, khususnya di Unity, saya condong ke arah menempatkan logika penanganan kerusakan di paku , dalam bentuk sesuatu seperti
CollisionHazard
komponen, yang pada saat tabrakan memanggil metode kerusakan padaDamageable
komponen. Inilah alasannya:Damageable
komponen pada mereka (jika Anda memerlukan beberapa yang kebal terhadap paku saja, Anda dapat menambahkan tipe kerusakan & biarkanDamageable
komponen menangani kekebalan)sumber
Tidak masalah siapa yang menangani tabrakan, tetapi konsistenlah dengan pekerjaan siapa.
Dalam permainan saya, saya mencoba untuk memilih
GameObject
yang "melakukan" sesuatu ke objek lain sebagai orang yang mengendalikan tabrakan. IE Spike merusak pemain sehingga menangani benturan. Ketika kedua objek "melakukan" sesuatu untuk satu sama lain, minta mereka masing-masing menangani aksi mereka pada objek lainnya.Juga, saya akan menyarankan mencoba merancang tumbukan Anda sehingga tumbukan ditangani oleh objek yang bereaksi terhadap tumbukan dengan lebih sedikit hal. Lonjakan hanya perlu tahu tentang tabrakan dengan pemain, membuat kode tabrakan dalam skrip Spike bagus dan ringkas. Objek pemain dapat bertabrakan dengan lebih banyak hal yang akan membuat skrip tabrakan membengkak.
Terakhir, cobalah untuk membuat penangan benturan Anda lebih abstrak. Spike tidak perlu tahu bahwa itu bertabrakan dengan pemain, ia hanya perlu tahu bahwa itu bertabrakan dengan sesuatu yang ia butuhkan untuk menangani kerusakan. Katakanlah Anda memiliki skrip:
Anda dapat subkelas
DamageController
di GameObject pemain Anda untuk menangani kerusakan, kemudian dalamSpike
kode tabrakansumber
Saya memiliki Masalah yang sama ketika saya mulai jadi begini: Dalam kasus khusus ini gunakan Musuh. Anda biasanya ingin Tabrakan ditangani oleh Objek yang melakukan aksi (dalam hal ini - musuh, tetapi jika pemain Anda memiliki senjata, maka senjata tersebut harus menangani tabrakan), karena jika Anda ingin men-tweak atribut (misalnya kerusakan musuh) Anda pasti ingin mengubahnya dalam skrip musuh dan bukan dalam skrip players (terutama jika Anda memiliki beberapa Pemain). Demikian juga jika Anda ingin mengubah kerusakan senjata apa pun yang digunakan Pemain, Anda pasti tidak ingin mengubahnya di setiap musuh permainan Anda.
sumber
Kedua objek akan menangani tabrakan.
Beberapa objek akan langsung berubah bentuk, rusak, atau dihancurkan oleh tabrakan. (peluru, panah, balon air)
Yang lain hanya akan terpental dan berguling ke samping. (Batu) Ini masih bisa menerima kerusakan jika benda yang mereka pukul cukup keras. Batuan tidak menerima kerusakan dari manusia yang menghantam mereka, tetapi mereka mungkin dari palu godam.
Beberapa benda licin seperti manusia akan mengalami kerusakan.
Yang lain akan terikat satu sama lain. (magnet)
Kedua tabrakan akan ditempatkan pada acara yang menangani antrian untuk aktor yang bertindak pada objek pada waktu dan tempat tertentu (dan kecepatan). Ingatlah bahwa pawang hanya harus berurusan dengan apa yang terjadi pada objek. Bahkan mungkin bagi pawang untuk menempatkan pawang lain pada antrian untuk menangani efek tambahan dari tabrakan berdasarkan pada sifat-sifat aktor atau objek yang sedang ditindaklanjuti. (Bom meledak dan ledakan yang dihasilkan sekarang harus menguji tabrakan dengan benda lain.)
Saat membuat skrip, gunakan tag dengan properti yang akan diterjemahkan ke dalam implementasi antarmuka oleh kode Anda. Kemudian referensi antarmuka dalam kode penanganan Anda.
Misalnya, pedang mungkin memiliki tag untuk Melee yang diterjemahkan ke antarmuka bernama Melee yang mungkin memperluas antarmuka DamageGiving yang memiliki properti untuk tipe kerusakan dan jumlah kerusakan yang ditentukan menggunakan nilai tetap atau rentang, dll. Dan bom mungkin memiliki tag peledak yang memiliki antarmuka Explosive juga memperluas antarmuka DamageGiving yang memiliki properti tambahan untuk radius dan mungkin seberapa cepat kerusakannya berdifusi.
Mesin game Anda kemudian akan mengkodekan antarmuka, bukan tipe objek spesifik.
sumber