Saya membuat game yang menggunakan objek game berbasis komponen, dan saya mengalami kesulitan menerapkan cara untuk setiap komponen berkomunikasi dengan objek game-nya. Daripada menjelaskan semuanya sekaligus, saya akan menjelaskan setiap bagian dari kode sampel yang relevan:
class GameObjectManager {
public:
//Updates all the game objects
void update(Time dt);
//Sends a message to all game objects
void sendMessage(Message m);
private:
//Vector of all the game objects
std::vector<GameObject> gameObjects;
//vectors of the different types of components
std::vector<InputComponent> input;
std::vector<PhysicsComponent> ai;
...
std::vector<RenderComponent> render;
}
The GameObjectManager
memegang semua objek game dan komponennya. Ini juga bertanggung jawab untuk memperbarui objek game. Ini dilakukan dengan memperbarui vektor komponen dalam urutan tertentu. Saya menggunakan vektor alih-alih array sehingga hampir tidak ada batasan jumlah objek game yang bisa ada sekaligus.
class GameObject {
public:
//Sends a message to the components in this game object
void sendMessage(Message m);
private:
//id to keep track of components in the manager
const int id;
//Pointers to components in the game object manager
std::vector<Component*> components;
}
The GameObject
kelas tahu apa komponennya dan dapat mengirim pesan kepada mereka.
class Component {
public:
//Receives messages and acts accordingly
virtual void handleMessage(Message m) = 0;
virtual void update(Time dt) = 0;
protected:
//Calls GameObject's sendMessage
void sendMessageToObject(Message m);
//Calls GameObjectManager's sendMessage
void sendMessageToWorld(Message m);
}
The Component
kelas begitu virtual murni bahwa kelas untuk berbagai jenis komponen dapat menerapkan cara menangani pesan dan update. Itu juga mampu mengirim pesan.
Sekarang muncul masalah tentang bagaimana komponen dapat memanggil sendMessage
fungsi dalam GameObject
dan GameObjectManager
. Saya datang dengan dua solusi yang mungkin:
- Berikan
Component
pointer ke nyaGameObject
.
Namun, karena objek permainan berada dalam vektor, pointer dapat dengan cepat menjadi tidak valid (Hal yang sama dapat dikatakan tentang vektor dalam GameObject
, tetapi mudah-mudahan solusi untuk masalah ini juga dapat menyelesaikannya). Saya bisa meletakkan objek game dalam array, tapi kemudian saya harus memberikan angka arbitrer untuk ukurannya, yang bisa dengan mudah menjadi tinggi dan membuang-buang memori.
- Berikan
Component
pointer keGameObjectManager
.
Namun, saya tidak ingin komponen dapat memanggil fungsi pembaruan manajer. Saya satu-satunya orang yang mengerjakan proyek ini, tetapi saya tidak ingin terbiasa menulis kode yang berpotensi berbahaya.
Bagaimana saya bisa mengatasi masalah ini sambil menjaga kode saya aman dan ramah cache?
Menjadi 'cache friendly' adalah keasyikan yang dimiliki game besar . Ini sepertinya menjadi optimasi dini bagi saya.
Salah satu cara untuk menyelesaikan ini tanpa menjadi 'cache friendly' adalah dengan membuat objek Anda di heap, bukan di stack: gunakan
new
dan (smart) pointer untuk objek Anda. Dengan cara ini, Anda dapat merujuk objek Anda dan referensi mereka tidak akan dibatalkan.Untuk solusi yang lebih ramah cache, Anda bisa mengelola de / alokasi objek sendiri, dan menggunakan pegangan untuk objek-objek ini.
Pada dasarnya, pada inisialisasi program Anda, sebuah objek menyimpan sepotong memori pada heap (sebut saja MemMan), kemudian, ketika Anda ingin membuat komponen, Anda memberi tahu MemMan bahwa Anda memerlukan komponen ukuran X, itu ' Saya akan mencadangkannya untuk Anda, membuat pegangan dan menjaga internal di mana alokasi itu adalah objek untuk pegangan itu. Ini akan mengembalikan pegangan, dan bahwa satu-satunya yang Anda simpan tentang objek, tidak pernah pointer ke lokasi di memori.
Saat Anda membutuhkan komponen, Anda akan meminta MemMan untuk mengakses objek ini, yang dengan senang hati akan ia lakukan. Tetapi jangan menyimpan referensi karena ....
Salah satu tugas MemMan adalah menjaga benda-benda saling berdekatan dalam memori. Setelah setiap beberapa frame game, Anda dapat memberitahu MemMan untuk mengatur ulang objek dalam memori (atau bisa melakukannya secara otomatis saat Anda membuat / menghapus objek). Ini akan memperbarui peta pegangan-ke-lokasi-memori. Pegangan Anda akan selalu valid, tetapi jika Anda menyimpan referensi ke ruang memori (sebuah pointer atau referensi ), Anda hanya akan menemukan keputusasaan dan penghancuran.
Buku teks mengatakan bahwa cara mengelola memori Anda ini memiliki setidaknya 2 keuntungan:
Perlu diingat bahwa cara Anda menggunakan MemMan dan bagaimana Anda akan mengatur memori secara internal sangat tergantung pada bagaimana Anda akan menggunakan komponen Anda. Jika Anda akan mengulanginya berdasarkan jenisnya, Anda ingin menyimpan komponen berdasarkan jenisnya, jika Anda mengulanginya berdasarkan objek permainan mereka, Anda harus menemukan cara untuk memastikan mereka dekat dengan lain berdasarkan itu, dll ...
sumber