Saya selalu bertanya-tanya sejauh mana orientasi objek digunakan oleh videogame, terutama proyek 3D besar. Saya rasa akan keren kalau keduanya troll
dan werewolf
mewarisi sifat-sifatnya dari enemy
dan menimpa beberapa dari mereka. Tapi mungkin kelas terlalu berat untuk praktis, saya tidak tahu ...
18
Jawaban:
Untuk melihat contoh Anda, saya akan menjelaskan pemikiran saya tentang Entites di videogame. Saya tidak akan membahas keuntungan dan kerugian umum dari objek dan kelas, tidak juga seluruh peran mereka dalam Videogame.
Entitas dalam videogame kecil sebagian besar ditentukan oleh kelas yang terpisah, dalam permainan besar mereka sering didefinisikan dalam file. Ada dua pendekatan umum yang harus diikuti:
Ekstensi : Dalam contoh Anda
Troll
danWerewolf
akan diperluasEnemy
, yang meluasEntity
.Entity
merawat hal-hal dasar seperti gerakan, kesehatan dll., sementaraEnemy
akan menyatakan subclass sebagai musuh dan melakukan hal-hal lain (Minecraft mengikuti pendekatan ini).Berbasis komponen : Pendekatan kedua (dan favorit saya) adalah satu
Entity
kelas, yang memiliki komponen. Suatu komponen bisaMoveable
atauEnemy
. Komponen-komponen ini menangani satu hal seperti gerakan atau fisika. Metode ini memutus rantai ekstensi yang lama dan meminimalkan risiko mengalami konflik. Misalnya: Bagaimana Anda bisa membuat Musuh yang tidak bisa bergerak, jika mereka mewarisi dari Karakter yang bisa dipindahkan? .Di videogame besar seperti World of Warcraft atau Starcraft 2, Entitas bukan kelas, tetapi kumpulan data, yang menentukan seluruh Entitas. Scripting juga penting, karena Anda mendefinisikan apa yang Entity tidak dalam Kelas, tetapi dalam Script (jika unik, bukan hal-hal seperti bergerak).
Saat ini saya sedang memprogram RTS dan saya mengambil pendekatan berbasis komponen dengan file Descriptor dan Script untuk Entites, Skill, Items, dan segala sesuatu yang dinamis di dalam game.
sumber
component
ada dalam konteks ini. Tautan akan sangat dihargai.Sayangnya pendekatan polimorfisme ini, populer pada tahun 90-an, telah menunjukkan dirinya sebagai ide yang buruk dalam praktik. Bayangkan Anda menambahkan 'serigala' ke daftar musuh - yah, ia berbagi beberapa atribut dengan manusia serigala, jadi Anda ingin mengkonsolidasikan mereka ke dalam kelas dasar bersama, misalnya. 'WolfLike'. Sekarang Anda menambahkan 'Manusia' ke daftar musuh, tetapi manusia serigala kadang-kadang manusia, sehingga mereka berbagi atribut juga, seperti berjalan dengan 2 kaki, bisa berbicara, dll. Apakah Anda membuat pangkalan umum 'Humanoid' untuk manusia dan manusia serigala , dan apakah Anda kemudian harus menghentikan manusia serigala yang berasal dari WolfLike? Atau apakah Anda berlipat ganda mewarisi dari keduanya - dalam hal ini, atribut mana yang didahulukan ketika sesuatu di Humanoid berselisih dengan sesuatu di WolfLike?
Masalahnya adalah bahwa mencoba dan memodelkan dunia nyata sebagai pohon kelas tidak efektif. Ambil 3 hal dan Anda mungkin dapat menemukan 4 cara berbeda untuk memfaktorkan perilaku mereka menjadi bersama dan tidak dibagi. Inilah sebabnya mengapa banyak yang beralih ke model berbasis modular atau komponen, di mana suatu objek terdiri dari beberapa objek yang lebih kecil yang membentuk keseluruhan, dan objek yang lebih kecil dapat ditukar atau diubah untuk membentuk perilaku yang Anda inginkan. Di sini Anda mungkin hanya memiliki 1 kelas Musuh, dan berisi sub-objek atau komponen untuk cara berjalannya (mis. Bipedal vs Quadrupedal), metode serangannya (misalnya, gigitan, cakar, senjata, kepalan tangan), kulitnya (hijau untuk troll, berbulu untuk manusia serigala dan serigala), dll.
Ini masih sepenuhnya berorientasi objek, tetapi gagasan tentang apa yang merupakan objek berguna berbeda dari apa yang biasanya diajarkan dalam buku teks. Daripada memiliki pohon warisan besar dari berbagai kelas abstrak dan beberapa kelas konkret di ujung pohon, Anda biasanya hanya memiliki 1 kelas beton yang mewakili konsep abstrak (mis. 'Musuh') tetapi yang berisi lebih banyak kelas konkret yang mewakili konsep yang lebih abstrak (mis. serangan, jenis kulit). Kadang-kadang kelas kedua ini dapat diimplementasikan dengan baik melalui 1 level warisan (mis. Kelas serangan dasar dan beberapa kelas turunan untuk serangan tertentu) tetapi pohon warisan yang dalam hilang.
Di sebagian besar bahasa modern, kelas tidak 'berat'. Mereka hanyalah cara lain untuk menulis kode, dan mereka biasanya hanya membungkus pendekatan prosedural yang akan Anda tulis, kecuali dengan sintaks yang lebih mudah. Tetapi dengan segala cara, jangan menulis kelas di mana fungsi akan dilakukan. Kelas pada hakekatnya tidak lebih baik, hanya di mana mereka membuat kode lebih mudah untuk dikelola atau dimengerti.
sumber
Saya tidak yakin apa yang Anda maksud dengan "terlalu berat," tetapi C ++ / OOP adalah lingua franca pengembangan game untuk alasan yang sama seperti yang digunakan di tempat lain.
Bicara tentang meniup cache adalah masalah desain, bukan fitur bahasa. C ++ tidak bisa terlalu buruk karena sudah digunakan dalam game selama 15-20 tahun terakhir. Java tidak bisa terlalu buruk karena digunakan di lingkungan waktu yang sangat ketat pada ponsel pintar.
Sekarang ke pertanyaan nyata: selama bertahun-tahun hirarki kelas menjadi dalam dan mulai menderita masalah yang berkaitan dengan itu. Dalam waktu yang lebih baru, hierarki kelas telah rata dan komposisi dan desain berbasis data lainnya lebih daripada warisan berbasis logika.
Semuanya OOP dan masih digunakan sebagai dasar ketika merancang perangkat lunak baru, hanya berbeda fokus pada apa yang terkandung dalam kelas.
sumber
Kelas tidak melibatkan overhead run-time. Polimorfisme run-time hanya memanggil melalui pointer fungsi. Overhead ini sangat minimal dibandingkan dengan biaya lain seperti Panggilan undian, sinkronisasi konkurensi, disk I / O, sakelar mode kernel, lokalitas memori yang buruk, penggunaan alokasi memori dinamis yang berlebihan, pilihan algoritma yang buruk, penggunaan bahasa skrip, dan daftar terus. Ada alasan mengapa orientasi objek pada dasarnya menggantikan apa yang datang sebelumnya, dan itu karena jauh lebih baik.
sumber
Satu hal yang perlu diperhatikan adalah bahwa konsep kode berorientasi objek seringkali lebih berharga daripada penerapannya dalam bahasa. Secara khusus, harus melakukan 1000-an panggilan pembaruan virtual pada entitas dalam loop utama dapat menyebabkan kekacauan dalam cache di C ++ pada platform seperti 360 atau PS3 - sehingga implementasinya mungkin menghindari kata kunci "virtual" atau bahkan "kelas" demi itu. kecepatan.
Seringkali meskipun masih akan mengikuti konsep OO pewarisan dan enkapsulasi - hanya menerapkannya secara berbeda dengan bagaimana bahasa itu sendiri (misalnya templat rekursif, komposisi bukannya pewarisan (metode berbasis komponen yang dijelaskan oleh Marco)). Jika warisan selalu dapat diselesaikan pada waktu kompilasi maka masalah kinerja hilang, tetapi kode dapat menjadi sedikit berbulu dengan templat, implementasi RTTI khusus (sekali lagi yang bawaan biasanya lambat lambat) atau logika waktu kompilasi dalam makro dll
Di Objective-C untuk iOS / Mac ada yang serupa, tetapi masalah yang lebih buruk dengan skema pengiriman pesan (bahkan dengan hal-hal caching mewah) ...
sumber
Metode yang saya akan mencoba untuk menggunakan warisan kelas campuran dan komponen. (Pertama-tama, saya tidak menjadikan Musuh sebuah kelas - Saya menjadikannya komponen.) Saya tidak suka gagasan menggunakan satu kelas Entitas generik untuk semuanya dan kemudian menambahkan komponen yang diperlukan untuk menyempurnakan entitas. Sebagai gantinya, saya lebih suka memiliki kelas secara otomatis menambahkan komponen (dan nilai default) di konstruktor. Kemudian subkelas menambahkan komponen tambahan mereka dalam konstruktor mereka, sehingga subkelas akan memiliki komponen dan komponen kelas induknya. Misalnya, kelas Senjata akan menambahkan komponen dasar yang umum untuk semua senjata, dan kemudian subkelas Pedang akan menambahkan komponen tambahan yang spesifik untuk pedang. Saya masih memperdebatkan apakah akan menggunakan aset teks / xml untuk menentukan nilai entitas (atau pedang spesifik misalnya), atau untuk melakukan itu semua dalam kode, atau apa campuran yang tepat. Ini masih memungkinkan gim untuk menggunakan informasi jenis dan polimorfisme bahasa kode, dan membuat ObjectFactories jauh lebih mudah.
sumber