Seberapa berorientasi objek videogame? [Tutup]

18

Saya selalu bertanya-tanya sejauh mana orientasi objek digunakan oleh videogame, terutama proyek 3D besar. Saya rasa akan keren kalau keduanya trolldan werewolfmewarisi sifat-sifatnya dari enemydan menimpa beberapa dari mereka. Tapi mungkin kelas terlalu berat untuk praktis, saya tidak tahu ...

vemv
sumber
2
Bagaimana seseorang mengukur (atau bahkan secara objektif memenuhi syarat) orientasi objek? Apakah Anda ingin jawaban dalam Meyers atau Dahl-Nygaards?
Jelas mereka sangat berat sehingga bahasa berbasis OO adalah standar industri.
Bebek Komunis
4
Jika maksud Anda C ++, itu dipilih karena ini adalah bahasa yang baik untuk menjelajahi pemrograman generik tipe-aman dengan cara yang sadar kecepatan; beberapa fitur OOP jelas merupakan misdesign malang yang disimpan hanya untuk kompatibilitas. ;)

Jawaban:

20

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 Trolldan Werewolfakan diperluas Enemy, yang meluas Entity. Entitymerawat 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 Entitykelas, yang memiliki komponen. Suatu komponen bisa Moveableatau Enemy. 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.

Marco
sumber
2
Kedengarannya menarik. Namun saya tidak akan berbohong, saya tidak tahu apa yang componentada dalam konteks ini. Tautan akan sangat dihargai.
vemv
Komponen adalah entitas yang memiliki tanggung jawab untuk satu fungsi. Entitas berbasis komponen akan memiliki komponen (jika ada) yang tidak akan diwarisi darinya. Kepemilikan menyiratkan bahwa suatu entitas dapat menonaktifkan salah satu komponennya yang mengubah perilakunya. Dalam paradigma Extension klasik, perilaku ini disebabkan "milik" kelas-super. Entitas dapat menjadi komponen dan komponen dapat dimodelkan sebagai kelas atau sebagai struct jika Anda suka.
FxIII
Komponen (kadang-kadang disebut sistem Entitas) - Anda dapat mencari di blog ini ide-ide t-machine.org Ada varian tetapi ide dasarnya adalah bahwa komponen adalah objek tujuan khusus dan aktor Anda mengikat banyak komponen, seperti membangun model dari Lego.
Patrick Hughes
2
Saya memulai sebuah blog tentang pengembangan game dan menulis entri blog pertama saya tentang ini. Tidak ada yang baru, tetapi dengan sedikit kode: jagamedev.wordpress.com/2011/06/26/…
Marco
23

Saya pikir itu akan keren bahwa troll dan manusia serigala mewarisi atributnya dari musuh dan menimpa beberapa dari mereka.

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.

Tapi mungkin kelas terlalu berat untuk praktis, saya tidak tahu ...

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.

Kylotan
sumber
3
Suka jawaban ini :)
Czarek Tomczak
8

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.

Patrick Hughes
sumber
2

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.

DeadMG
sumber
Pengiriman di antara berbagai jenis polimorfik dilakukan dengan cara yang memberikan memori lokalitas yang buruk. Bahkan dalam implementasi dengan bobot paling ringan seperti C ++ vtables atau Objective-C IMP caching, jika Anda benar-benar menggunakan polimorfisme untuk menangani objek dari berbagai jenis, Anda akan membuat cache Anda. Tentu saja jika Anda tidak menggunakan polimorfisme daripada vtable tetap di cache atau pesan cache IMP mengarah ke tempat yang benar, tetapi mengapa repot-repot? Dan di Jawa atau C # biayanya lebih berat, dan dalam JavaScript atau Python biayanya masih lebih berat.
1
@ Jo Wreschnig: Jika Anda menggunakan bahasa yang lebih lambat, maka biaya OO sepele dibandingkan dengan biaya lain seperti interpretasi / JIT. Lebih penting lagi, Anda dapat membuat teori tentang apa yang Anda inginkan tentang lokalitas memori yang buruk, tetapi faktanya adalah bahwa prediksi cabang, eksekusi out-of-order dan fitur serupa pada CPU hampir sepenuhnya meniadakan biaya. Selain itu, mengapa begitu banyak perangkat lunak berkinerja tinggi ditulis menggunakan orientasi objek?
DeadMG
1

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) ...

jheriko
sumber
0

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.

Chris
sumber
3
Hai, Chris. Meskipun berbagi pengalaman dan rencana Anda hebat, itu tidak benar-benar menjawab pertanyaan secara langsung. Saya pikir pertanyaannya lebih tentang bagaimana hal-hal ini biasanya dilakukan ketika Anda menjawab bagaimana Anda berencana melakukannya . Itu adalah pertanyaan yang serupa, tetapi tidak benar-benar sama.
MichaelHouse