Haruskah entitas menangani pergerakannya sendiri?
Saat ini saya sedang membangun game sederhana berbasis giliran dengan Ruangan yang terdiri dari array 2D objek Ubin. Itu bisa berupa WallTile atau FloorTile. Benda Tile memiliki Neighbor utara, timur, selatan dan barat. Ubin Lantai memiliki Tumpukan Entitas sehingga saya dapat dengan mudah menggambar entitas teratas.
Sekarang saya bertanya-tanya, Pemain saya adalah Entitas, ketika pemain bergerak, haruskah pemain menangani logika itu, atau Game yang menahan Pemain saya?
Dalam kasus pertama, itu akan menjadi sesuatu di sepanjang baris:
class Player : Entity {
public Tile CurrentLocation
public bool CanMoveTo(Direction) {
// Let's say that direction is East
return CurrentLocation.EastNeighbour == FloorTile
}
// This method does the actual move
public void MoveTo(Direction)
}
Dalam kasus kedua akan seperti ini:
class Game {
public Player Player;
public Room Room;
public void Update() {
// Lets say we get direction from some input from somewhere
if Room.TileAt(player.Y, player.X) is FloorTile then MoveThere()
}
}
Saya tidak begitu yakin apa yang terbaik dari kedua opsi tersebut. Awalnya saya memikirkan solusi pertama. Bantuan atau tip apa pun akan dihargai.
Jawaban
Tidak ada cara yang benar atau salah untuk melakukan sesuatu. Hanya cara yang berhasil untuk Anda atau tidak untuk Anda.
Ada beberapa filosofi yang bersaing dalam arsitektur game mainstream.
J: Arsitektur berorientasi objek
Setiap entitas harus diwakili oleh sebuah objek. Objek-objek itu harus berisi semua logikanya sendiri, merangkum keadaan internalnya dan berkomunikasi dengan objek lain melalui antarmuka yang terdefinisi dengan baik. Mesin permainan inti hanya memanggil metode "Pembaruan" dan "Render" dari semua entitas dalam satu putaran dan kemudian membiarkan entitas melakukan sisanya.
Ketika Anda memiliki objek yang berbagi beberapa fungsionalitas, Anda biasanya akan melakukannya melalui pewarisan - dengan mengekstrak fungsionalitas umum ke dalam kelas dasar yang sama. Misalnya, Anda mungkin ingin memiliki pemain kelas dan musuh kelas yang keduanya mewarisi dari kelas kombatan yang berisi semua kode tempur dan mewarisi dari entitas yang berisi kode dasar untuk gerakan. Dan Musuh kemungkinan akan menjadi kelas abstrak yang hanya berisi logika yang umum untuk semua musuh, dengan tipe musuh yang berbeda dan perilaku unik mereka yang diterapkan di kelas yang diwarisi dari Musuh.
Pada dasarnya cara Anda seharusnya melakukan OOP menurut buku.
Gaya ini sering terlihat pada pengembang yang berasal dari pengembangan aplikasi, karena gaya ini paling dominan di sana. Dan apa yang berhasil untuk aplikasi belum tentu sepenuhnya salah untuk game.
B: Arsitektur Entity-Component
Gaya ini lebih memilih komposisi daripada warisan . Entitas bukanlah satu objek, ini adalah kumpulan objek dengan setiap objek mengimplementasikan fitur berbeda dari entitas itu. Jadi, Anda tidak memiliki kelas "Pemain" yang menerapkan setiap hal yang dapat dilakukan pemain. Anda memiliki Entitas generik dengan komponen "Sprite", "Mover", "Shooter", "Hitpoints", dan "PlayerInput".
Keuntungan dari pendekatan ini adalah bahwa komponen sangat mudah untuk dipadupadankan untuk membuat jenis entitas game baru. Ini sangat berguna untuk iterasi cepat pada desain game Anda. Ini adalah pendekatan favorit oleh beberapa mesin game populer. Seperti Unity, misalnya.
C: Arsitektur Entity-Component-System
Entitas harus berupa kumpulan komponen seperti dalam arsitektur "Komponen-Entitas". Namun dalam arsitektur ini, komponen tersebut seharusnya hanya menjadi pemegang data yang bodoh. Biasanya dalam bentuk struktur dengan hanya variabel publik dan tanpa metode. Semua logika harus ada dalam sistem. Setiap sistem bertanggung jawab untuk mengelola satu jenis komponen, atau sekumpulan komponen. Misalnya, Anda memiliki Sistem Gerakan yang memperbarui komponen Posisi setiap entitas dengan komponen Gerakan.
Tapi ini hanya penyederhanaan yang berlebihan. Jika Anda ingin tahu lebih banyak, lihat pertanyaan "Apa itu ECS murni?" . Anda juga dapat melihat pertanyaan lain di bawah tag sistem komponen entitas kami .
Pendekatan ECS saat ini sangat populer. Argumen utamanya adalah bahwa ia memungkinkan beberapa pengoptimalan kinerja yang sangat rapi (terutama bila menyangkut lokalitas memori dan multithreading) tanpa mengorbankan modularitas dan kecepatan iterasi dari pendekatan Komponen-Entitas. Tetapi kerugiannya adalah arsitektur ECS yang solid dan fleksibel membutuhkan cukup banyak kode arsitektur yang berjalan "di belakang layar" dan yang mungkin sulit diterapkan untuk pemula.
Mana yang harus Anda gunakan?
Itu adalah sesuatu yang perlu Anda pecahkan sendiri. Tetapi pendekatan mana pun yang Anda pilih untuk gim Anda, Anda akan disarankan untuk tetap melakukannya. Hindari pola arsitektur padu-padan dalam game Anda jika memungkinkan.
Ini pada dasarnya tergantung pada jumlah data yang melintasi jaringan game Anda. Multiplayer masif apa pun perlu melacak siapa di mana melakukan apa yang selalu (jika tidak, kecurangan besar akan terjadi). Namun, menerima dan mengirim paket dari server ke setiap dan setiap klien (yang dikenal sebagai server otoratif) jarang praktis untuk sejumlah pengguna yang signifikan. Jadi, filosofi tampaknya adalah seberapa banyak logika yang bisa Anda dapatkan agar pemain dapat mengontrol tanpa memengaruhi pemain lain. Dengan kata lain, apa yang memengaruhi Anda dan hanya Anda (kecuali untuk penjarahan) yang dapat ditangani oleh klien. Sedangkan apapun yang mempengaruhi beberapa pemain harus ditangani oleh server. Atau, jika tidak ditangani, setidaknya diizinkan sebelum efek apa pun terjadi.