Saya akui, saya telah berbuat dosa karena terlalu banyak menggunakan, dan bahkan menyalahgunakan warisan. Proyek game (teks) pertama yang saya buat ketika saya mengambil kursus OOP saya berjalan sejauh "Locked door" dan "unlocked door" dari "Door" dan "Room with one door", "Room with two door", dan seterusnya dari "Kamar".
Dengan game (grafis) yang saya garap baru-baru ini, saya pikir saya telah mempelajari pelajaran saya dan membatasi penggunaan warisan. Namun saya perhatikan masalah segera mulai muncul. Kelas root saya mulai membengkak semakin banyak, dan kelas daun saya penuh dengan kode duplikat.
Saya pikir saya masih melakukan hal-hal yang salah, dan setelah mencari secara online saya menemukan bahwa saya bukan satu-satunya yang memiliki masalah ini. Begitulah akhirnya saya menemukan sistem Entity setelah beberapa penelitian menyeluruh (baca: googlefu)
Ketika saya mulai membacanya, saya bisa melihat betapa jelasnya ia bisa menyelesaikan masalah yang saya alami dengan hierarki OOP tradisional dengan komponen. Namun ini ada dalam bacaan pertama. Ketika saya menemukan lebih banyak ... pendekatan "radikal" ES, seperti yang ada di T-machine .
Saya mulai tidak setuju dengan metode yang mereka gunakan. Sistem komponen murni tampak berlebihan, atau lebih tepatnya, tidak intuitif, yang mungkin merupakan kekuatan OOP. Penulis melangkah lebih jauh dengan mengatakan bahwa sistem ES adalah kebalikan dari OOP, dan sementara itu dapat digunakan di sepanjang OOP, itu sebenarnya tidak seharusnya. Saya tidak mengatakan itu salah, tapi saya tidak merasa seperti solusi yang ingin saya terapkan.
Jadi bagi saya, dan untuk menyelesaikan masalah yang saya alami di awal posting, tanpa bertentangan dengan intuisi saya, adalah masih menggunakan hierarki, namun itu tidak akan menjadi hierarki monolitik seperti yang saya gunakan sebelumnya, melainkan sebuah polylithic (saya tidak dapat menemukan kata yang berlawanan dengan monolitik), yang terdiri dari beberapa pohon yang lebih kecil.
Contoh berikut menunjukkan apa yang saya maksud (ini terinspirasi oleh contoh yang saya temukan di Arsitektur Mesin Game, Bab 14).
Saya akan memiliki pohon kecil untuk kendaraan. Kelas root kendaraan akan memiliki komponen rendering, komponen tabrakan, komponen posisi dll.
Kemudian sebuah tangki, subkelas kendaraan akan mewarisi komponen-komponen itu darinya, dan diberi komponen "meriam" itu sendiri.
Hal yang sama berlaku untuk Karakter. Karakter akan memiliki komponennya sendiri, maka Kelas Pemain akan mewarisinya, dan diberi pengontrol Input, sedangkan kelas musuh lainnya akan mewarisi dari kelas Karakter dan diberi pengontrol AI.
Saya tidak benar-benar melihat masalah dengan desain ini. Meskipun tidak menggunakan Sistem Pengendali Entitas murni, masalah dengan efek menggelegak, dan kelas akar besar diselesaikan dengan menggunakan hierarki multi-pohon, dan masalah berat, daun duplikasi kode hilang karena daun tidak memiliki kode untuk memulai, hanya komponen. Jika perubahan perlu dilakukan ke level daun, maka itu semudah mengubah satu komponen, daripada menyalin paste kode di mana-mana.
Tentu saja, karena tidak berpengalaman seperti saya, saya tidak melihat masalah ketika saya mulai menggunakan hirarki tunggal, model berat warisan, jadi jika ada masalah dengan model yang saat ini saya pikirkan untuk diterapkan, saya tidak akan dapat melihatnya.
Pendapat Anda?
PS: Saya menggunakan Java, jadi menggunakan multiple inheritance untuk mengimplementasikan ini daripada menggunakan komponen normal tidak mungkin.
PPS: Komunikasi antar komponen akan dilakukan dengan menghubungkan komponen-komponen yang saling bergantung satu sama lain. Ini akan mengarah pada penggandengan, tapi saya pikir ini merupakan trade off yang baik.
sumber
Jawaban:
Pertimbangkan contoh ini:
Anda sedang membuat RTS. Dalam logika lengkap, Anda memutuskan untuk membuat kelas dasar
GameObject
, dan kemudian dua subclass,Building
danUnit
. Ini berfungsi dengan baik, tentu saja, dan Anda berakhir dengan sesuatu yang terlihat seperti ini:GameObject
ModelComponent
CollisionComponent
Building
ProductionComponent
Unit
AimingAIComponent
WeaponComponent
ParticleEmitterComponent
AnimationComponent
Sekarang setiap subkelas yang
Unit
Anda buat sudah memiliki semua komponen yang Anda butuhkan. Dan sebagai bonus, Anda memiliki satu tempat untuk meletakkan semua kode pengaturan membosankan yangnew
s sebuahWeaponComponent
, menghubungkan ke sebuahAimingAIComponent
danParticleEmitterComponent
-indah!Dan tentu saja, karena masih memasukkan logika ke dalam komponen, ketika Anda akhirnya memutuskan bahwa Anda ingin menambahkan
Tower
kelas yang merupakan bangunan tetapi memiliki senjata, Anda dapat mengelolanya. Anda dapat menambahkanAimingAIComponent
, aWeaponComponent
, danParticleEmitterComponent
ke subkelas Anda dariBuilding
. Tentu saja, maka Anda harus melalui dan menggali kode inisialisasi dariUnit
kelas dan meletakkannya di tempat lain, tetapi itu bukan kerugian besar.Dan sekarang, tergantung pada berapa banyak tinjauan ke depan yang Anda miliki, Anda mungkin atau mungkin tidak berakhir dengan bug halus. Ternyata mungkin ada beberapa kode di tempat lain dalam game yang terlihat seperti ini:
Itu diam-diam tidak bekerja untuk
Tower
bangunan Anda , meskipun Anda benar-benar ingin itu bekerja untuk apa pun dengan senjata. Sekarang harus terlihat seperti ini:Jauh lebih baik! Terjadi pada Anda setelah mengubah ini bahwa salah satu metode accessor yang Anda tulis dapat berakhir dalam situasi ini. Jadi hal paling aman untuk dilakukan adalah menghapus semuanya, dan mengakses setiap komponen melalui
getComponent
metode yang satu ini , yang dapat bekerja dengan subkelas apa pun. (Sebagai alternatif, Anda dapat menambahkan setiap jenis tunggalget*Component()
ke superclassGameObject
dan menimpanya dalam subkelas untuk mengembalikan komponen. Namun, saya akan menganggap yang pertama.)Sekarang kelas
Building
dan AndaUnit
cukup banyak kantong komponen, bahkan tanpa aksesor pada mereka. Dan tidak ada inisialisasi yang bagus juga, karena sebagian besar dari itu perlu diseret untuk menghindari duplikasi kode dengan satu objek khusus lainnya di suatu tempat.Jika Anda mengikuti ini secara ekstrem, Anda selalu membuat subclass Anda benar-benar tas komponen lembam, pada titik mana bahkan tidak ada titik memiliki subclass di sekitar. Anda dapat memperoleh hampir semua manfaat memiliki hierarki kelas dengan hierarki metode yang menciptakan komponen yang tepat. Alih-alih memiliki
Unit
kelas, Anda memilikiaddUnitComponents
metode yang membuatAnimationComponent
dan juga panggilanaddWeaponComponents
, yang membuatAimingAIComponent
, sebuahWeaponComponent
, danParticleEmitterComponent
. Hasilnya adalah bahwa Anda memiliki semua manfaat dari sistem entitas, semua penggunaan kembali kode hierarki, dan tidak ada godaan untuk memeriksainstanceof
atau melemparkan ke tipe kelas Anda.sumber
Komposisi atas Warisan adalah terminologi OOP (setidaknya cara saya mempelajarinya / diajarkan). Untuk memilih antara komposisi dan warisan Anda mengatakan dengan suara keras "Mobil adalah jenis roda" (warisan) dan "Mobil memiliki roda" (komposisi). Satu harus terdengar lebih benar daripada yang lain (komposisi dalam hal ini), dan jika Anda tidak dapat memutuskan, default komposisi sampai Anda memutuskan sebaliknya.
sumber
Ketika datang untuk mengintegrasikan sistem berbasis komponen ke permainan yang ada berdasarkan objek permainan ada artikel di pemrograman koboi http://cowboyprogramming.com/2007/01/05/evolve-your-heirachy/ yang mungkin memberi Anda beberapa petunjuk tentang cara transisi dapat dilakukan.
Mengenai masalah, model Anda masih harus menangani pemain secara berbeda dari musuh lain. Anda tidak akan dapat beralih status (yaitu pemain menjadi dikendalikan AI) ketika pemain memutus atau dalam kasus khusus tanpa memegangnya secara berbeda dari karakter lain.
Terlepas dari penggunaan kembali komponen yang banyak di seluruh entitas yang berbeda, gagasan permainan berbasis komponen adalah keseragaman dari keseluruhan sistem. Setiap entitas memiliki komponen yang dapat dilampirkan dan dilepas sesuka hati. Semua komponen dari jenis yang sama ditangani dengan cara yang persis sama dengan satu set panggilan yang dibuat oleh antarmuka (komponen dasar) dari masing-masing jenis (posisi, render, skrip ...)
Memadukan pewarisan objek game dengan pendekatan berbasis komponen memberi Anda beberapa keuntungan dari pendekatan berbasis komponen dengan kelemahan dari kedua pendekatan tersebut.
Ini bisa bekerja untuk Anda. Tetapi saya tidak akan mencampur keduanya di luar periode transisi dari satu arsitektur ke arsitektur lainnya.
PS ditulis di telepon jadi saya kesulitan menghubungkan ke sumber daya eksternal.
sumber