Nasihat ini tidak benar-benar spesifik untuk rendering tetapi harus membantu memunculkan sistem yang membuat hal-hal terpisah. Pertama-tama coba dan pisahkan data 'GameObject' dari informasi posisi.
Perlu dicatat bahwa informasi posisi XYZ sederhana mungkin tidak sesederhana itu. Jika Anda menggunakan mesin fisika maka data posisi Anda dapat disimpan di dalam mesin pihak ke-3. Anda perlu menyinkronkan di antara mereka (yang akan melibatkan banyak penyalinan memori yang tidak berguna) atau meminta informasi langsung dari mesin. Tetapi tidak semua benda membutuhkan fisika, beberapa akan diperbaiki di tempat sehingga satu set float sederhana berfungsi dengan baik di sana. Beberapa bahkan mungkin melekat pada objek lain, sehingga posisinya sebenarnya merupakan offset dari posisi lain. Dalam pengaturan lanjutan Anda mungkin memiliki posisi disimpan hanya pada GPU satu-satunya waktu yang dibutuhkan sisi komputer adalah untuk scripting, penyimpanan dan replikasi jaringan. Jadi, Anda kemungkinan akan memiliki beberapa pilihan yang memungkinkan untuk data posisi Anda. Di sini masuk akal untuk menggunakan warisan.
Daripada objek yang memiliki posisi itu, sebaliknya objek itu sendiri harus dimiliki oleh struktur data pengindeksan. Misalnya 'Level' mungkin memiliki Oktree, atau mungkin 'adegan' mesin fisika. Saat Anda ingin merender (atau mengatur adegan rendering), Anda menanyakan struktur khusus Anda untuk objek yang terlihat oleh kamera.
Ini juga membantu memberikan manajemen memori yang baik. Dengan cara ini sebuah objek yang sebenarnya tidak ada di suatu area bahkan tidak memiliki posisi yang masuk akal daripada mengembalikan 0,0 coords atau coord yang dimilikinya ketika itu terakhir di suatu area.
Jika Anda tidak lagi menyimpan koordinat di objek, alih-alih object.getX () Anda akan berakhir memiliki level.getX (objek). Masalah dengan itu adalah mencari objek di tingkat kemungkinan akan menjadi operasi yang lambat karena harus melihat semua objek itu dan cocok dengan yang Anda query.
Untuk menghindari itu saya mungkin akan membuat kelas 'tautan' khusus. Yang mengikat antara level dan objek. Saya menyebutnya "Lokasi". Ini akan berisi koordinat xyz serta pegangan ke tingkat dan pegangan ke objek. Kelas tautan ini akan disimpan dalam struktur spasial / level dan objek akan memiliki referensi yang lemah untuk itu (jika level / lokasi dihancurkan, referensi objek perlu diperbarui ke nol. Mungkin juga layak memiliki kelas Lokasi sebenarnya 'memiliki' objek, dengan cara itu jika level dihapus, demikian juga struktur indeks khusus, lokasi yang dikandungnya, dan Objeknya.
typedef std::tuple<Level, Object, PositionXYZ> Location;
Sekarang informasi posisi disimpan hanya di satu tempat. Tidak diduplikasi antara Object, struktur pengindeksan spasial, renderer dan sebagainya.
Struktur data spasial seperti Octrees seringkali bahkan tidak perlu memiliki koordinat objek yang mereka simpan. Posisi ada disimpan di lokasi relatif dari node dalam struktur itu sendiri (bisa dianggap sebagai semacam kompresi lossy, mengorbankan akurasi untuk waktu pencarian cepat). Dengan objek lokasi di Octree maka koordinat aktual ditemukan di dalamnya setelah kueri selesai.
Atau jika Anda menggunakan mesin fisika untuk mengelola lokasi objek Anda atau campuran antara keduanya, kelas Lokasi harus menangani itu secara transparan sambil menyimpan semua kode Anda di satu tempat.
Keuntungan lain sekarang adalah posisi dan referensi ke level disimpan di lokasi yang sama. Anda dapat mengimplementasikan object.TeleportTo (other_object) dan membuatnya bekerja lintas level. Demikian pula, pencarian jalur AI dapat mengikuti sesuatu ke area yang berbeda.
Berkenaan dengan rendering. Render Anda dapat memiliki ikatan yang sama dengan Lokasi. Kecuali itu akan memiliki hal-hal khusus rendering di sana. Anda mungkin tidak perlu 'Objek' atau 'Level' untuk disimpan dalam struktur ini. Objek bisa berguna jika Anda mencoba melakukan sesuatu seperti memilih warna, atau merender hitbar yang melayang di atasnya dan seterusnya, tetapi jika tidak, pemberi render hanya peduli dengan jala dan semacamnya. RenderableStuff akan menjadi Mesh, bisa juga memiliki kotak pembatas dan sebagainya.
typedef std::pair<RenderableStuff, PositionXYZ> RenderThing;
renderer.render(level, camera);
renderer: object = level.getVisibleObjects(camera);
level: physics.getObjectsInArea(physics.getCameraFrustrum(camera));
for(object in objects) {
//This could be depth sorted, meshes could be broken up and sorted by material for batch rendering or whatever
rendering_que.addObjectToRender(object);
}
Anda mungkin tidak perlu melakukan ini setiap frame, Anda bisa memastikan Anda mengambil wilayah yang lebih besar dari yang ditunjukkan kamera saat ini. Cache, lacak pergerakan objek untuk melihat apakah ada kotak pembatas yang berada dalam jangkauan, lacak pergerakan kamera, dan sebagainya. Tapi jangan mulai mengacaukan hal-hal semacam itu sampai Anda telah membandingkannya.
Anda mesin fisika itu sendiri mungkin memiliki abstraksi yang sama, karena itu juga tidak memerlukan data Object, hanya tabrakan dan sifat fisika.
Semua data objek inti Anda akan berisi nama mesh yang digunakan objek. Mesin permainan kemudian dapat melanjutkan dan memuat ini dalam format apa pun yang disukainya tanpa membebani kelas objek Anda dengan sekelompok render hal-hal tertentu (yang mungkin khusus untuk rendering API Anda, yaitu DirectX vs OpenGL).
Itu juga membuat komponen yang berbeda terpisah. Ini membuatnya mudah untuk melakukan hal-hal seperti mengganti mesin fisika Anda karena hal-hal itu sebagian besar mandiri di satu lokasi. Ini juga membuat unittesting jauh lebih mudah. Anda dapat menguji hal-hal seperti kueri fisika tanpa harus memiliki pengaturan objek palsu yang sebenarnya karena semua yang Anda butuhkan adalah kelas Lokasi. Anda juga dapat mengoptimalkan barang dengan lebih mudah. Itu membuat lebih jelas kueri apa yang perlu Anda lakukan pada kelas apa dan lokasi tunggal untuk mengoptimalkannya (misalnya level di atas. GetVisibleObject akan menjadi tempat Anda dapat men-cache hal-hal jika kamera tidak banyak bergerak).
m_renderable
anggota tersebut. Dengan begitu, Anda dapat memisahkan logika Anda dengan lebih baik. Jangan memaksakan "antarmuka" yang dapat di-render pada objek umum yang juga memiliki fisika, ai dan yang lainnya. Setelah itu, Anda dapat mengelola renderable secara terpisah. Anda memerlukan lapisan abstrakisasi melalui pemanggilan fungsi OpenGL untuk memisahkan hal-hal lebih banyak lagi. Jadi, jangan berharap mesin yang bagus untuk memiliki panggilan API GL di dalam berbagai implementasi renderable nya. Singkatnya, singkatnya.