Secara pribadi saya merekomendasikan menjaga fungsi draw dari kelas Object itu sendiri. Saya bahkan merekomendasikan menjaga lokasi Objek / koordinat keluar dari Objek itu sendiri.
Metode draw () akan berurusan dengan rendering API tingkat rendah baik OpenGL, OpenGL ES, Direct3D, layer pembungkus Anda pada API tersebut atau API engine. Mungkin Anda harus menukar antara waktu itu (Jika Anda ingin mendukung OpenGL + OpenGL ES + Direct3D misalnya.
GameObject itu seharusnya hanya berisi informasi dasar tentang penampilan visualnya seperti Mesh atau mungkin bundel yang lebih besar termasuk input shader, keadaan animasi, dan sebagainya.
Anda juga akan menginginkan pipa grafis yang fleksibel. Apa yang terjadi jika Anda ingin memesan objek berdasarkan jaraknya ke kamera. Atau jenis bahannya. Apa yang terjadi jika Anda ingin menggambar objek yang 'dipilih' dengan warna yang berbeda. Bagaimana jika alih-alih benar-benar rending sama seperti ketika Anda memanggil fungsi draw pada suatu objek, alih-alih memasukkannya ke dalam daftar perintah tindakan yang harus diambil render (mungkin diperlukan untuk threading). Anda dapat melakukan hal semacam itu dengan sistem lain tetapi itu adalah PITA.
Apa yang saya sarankan adalah daripada menggambar secara langsung, Anda mengikat semua objek yang Anda inginkan ke struktur data lain. Penjilidan itu hanya benar-benar perlu memiliki referensi ke lokasi objek dan informasi render.
Level / chunk / area / peta / hub / wholeworld Anda / apa pun yang diberikan indeks spasial, ini berisi objek dan mengembalikannya berdasarkan permintaan koordinat dan bisa berupa daftar sederhana atau sesuatu seperti Oktree. Itu juga bisa menjadi pembungkus untuk sesuatu yang diimplementasikan oleh mesin fisika pihak ke-3 sebagai adegan fisika. Hal ini memungkinkan Anda untuk melakukan hal-hal seperti "Permintaan semua objek yang ada dalam pandangan kamera dengan beberapa area tambahan di sekitar mereka", atau untuk permainan yang lebih sederhana di mana Anda bisa membuat semuanya mengambil seluruh daftar.
Indeks spasial tidak harus mengandung informasi posisi yang sebenarnya. Mereka bekerja dengan menyimpan objek dalam struktur pohon dalam kaitannya dengan lokasi objek lain. Mereka dapat dianggap sebagai semacam cache lossy yang memungkinkan pencarian cepat objek berdasarkan posisinya. Tidak perlu menduplikasi koordinat X, Y, Z Anda yang sebenarnya. Setelah mengatakan bahwa Anda bisa jika Anda ingin tetap
Bahkan objek game Anda bahkan tidak perlu mengandung informasi lokasi mereka sendiri. Misalnya objek yang belum dimasukkan ke level seharusnya tidak memiliki koordinat x, y, z, itu tidak masuk akal. Anda dapat memuatnya di indeks khusus. Jika Anda perlu mencari koordinat objek berdasarkan referensi aktualnya maka Anda ingin memiliki ikatan antara objek dan grafik adegan (grafik adegan adalah untuk mengembalikan objek berdasarkan koordinat tetapi lambat mengembalikan koordinat berdasarkan objek) .
Ketika Anda menambahkan Obyek ke Tingkat. Ini akan melakukan hal berikut:
1) Buat Struktur Lokasi:
class Location {
float x, y, z; // Or a special Coordinates class, or a vec3 or whatever.
SpacialIndex& spacialIndex; // Note this could be the area/level/map/whatever here
};
Ini juga bisa menjadi referensi ke objek dalam mesin fisika pihak ke-3. Atau bisa juga merupakan koordinat offset dengan referensi ke lokasi lain (untuk kamera pelacakan atau objek atau contoh yang dilampirkan). Dengan polimorfisme itu bisa tergantung pada apakah itu objek statis atau dinamis. Dengan menyimpan referensi ke indeks spasial di sini ketika koordinat diperbarui indeks spasial juga bisa.
Jika Anda khawatir tentang alokasi memori dinamis, gunakan kumpulan memori.
2) Ikatan / tautan antara objek Anda, lokasi dan grafik adegan.
typedef std::pair<Object, Location> SpacialBinding.
3) Binding ditambahkan ke indeks spasial di dalam level pada titik yang sesuai.
Saat Anda bersiap untuk membuat.
1) Dapatkan kamera (Ini hanya akan menjadi objek lain, kecuali lokasi itu akan melacak karakter pemain dan penyaji Anda akan memiliki referensi khusus untuk itu, pada kenyataannya hanya itu yang benar-benar dibutuhkan).
2) Dapatkan SpacialBinding kamera.
3) Dapatkan indeks spasial dari pengikatan.
4) Permintaan objek yang (mungkin) terlihat oleh kamera.
5A) Anda perlu memproses informasi visual. Tekstur diunggah ke GPU dan sebagainya. Ini akan lebih baik dilakukan di muka (seperti pada beban level) tetapi mungkin bisa dilakukan saat runtime (untuk dunia terbuka, Anda dapat memuat barang saat Anda mendekati bongkahan tetapi harus tetap dilakukan di muka).
5B) Secara opsional membangun pohon render cache, jika Anda ingin kedalaman / mengurutkan bahan atau melacak objek di dekatnya yang mungkin terlihat di lain waktu. Kalau tidak, Anda bisa menanyakan indeks spasial setiap kali itu tergantung pada persyaratan permainan / kinerja Anda.
Penyaji Anda kemungkinan akan membutuhkan objek RenderBinding yang akan menautkan antara Objek, koordinat
class RenderBinding {
Object& object;
RenderInformation& renderInfo;
Location& location // This could just be a coordinates class.
}
Kemudian ketika Anda membuat, jalankan saja daftar.
Saya telah menggunakan referensi di atas tetapi bisa berupa pointer pintar, pointer mentah, pegangan objek dan sebagainya.
EDIT:
class Game {
weak_ptr<Camera> camera;
Level level1;
void init() {
Camera camera(75.0_deg, 1.025_ratio, 1000_meters);
auto template_player = loadObject("Player.json")
auto player = level1.addObject(move(player), Position(1.0, 2.0, 3.0));
level1.addObject(move(camera), getRelativePosition(player));
auto template_bad_guy = loadObject("BadGuy.json")
level1.addObject(template_bad_guy, {10, 10, 20});
level1.addObject(template_bad_guy, {10, 30, 20});
level1.addObject(move(template_bad_guy), {50, 30, 20});
}
void render() {
camera->getFrustrum();
auto level = camera->getLocation()->getLevel();
auto object = level.getVisible(camera);
for(object : objects) {
render(objects);
}
}
void render(Object& object) {
auto ri = object.getRenderInfo();
renderVBO(ri.getVBO());
}
Object loadObject(string file) {
Object object;
// Load file from disk and set the properties
// Upload mesh data, textures to GPU. Load shaders whatever.
object.setHitPoints(// values from file);
object.setRenderInfo(// data from 3D api);
}
}
class Level {
Octree octree;
vector<ObjectPtr> objects;
// NOTE: If your level is mesh based there might also be a BSP here. Or a hightmap for an openworld
// There could also be a physics scene here.
ObjectPtr addObject(Object&& object, Position& pos) {
Location location(pos, level, object);
objects.emplace_back(object);
object->setLocation(location)
return octree.addObject(location);
}
vector<Object> getVisible(Camera& camera) {
auto f = camera.getFtrustrum();
return octree.getObjectsInFrustrum(f);
}
void updatePosition(LocationPtr l) {
octree->updatePosition(l);
}
}
class Octree {
OctreeNode root_node;
ObjectPtr add(Location&& object) {
return root_node.add(location);
}
vector<ObjectPtr> getObjectsInRadius(const vec3& position, const float& radius) { // pass to root_node };
vector<ObjectPtr> getObjectsinFrustrum(const FrustrumShape frustrum;) {//...}
void updatePosition(LocationPtr* l) {
// Walk up from l.octree_node until you reach the new place
// Check if objects are colliding
// l.object.CollidedWith(other)
}
}
class Object {
Location location;
RenderInfo render_info;
Properties object_props;
Position getPosition() { return getLocation().position; }
Location getLocation() { return location; }
void collidedWith(ObjectPtr other) {
// if other.isPickup() && object.needs(other.pickupType()) pick it up, play sound whatever
}
}
class Location {
Position position;
LevelPtr level;
ObjectPtr object;
OctreeNote octree_node;
setPosition(Position position) {
position = position;
level.updatePosition(this);
}
}
class Position {
vec3 coordinates;
vec3 rotation;
}
class RenderInfo {
AnimationState anim;
}
class RenderInfo_OpenGL : public RenderInfo {
GLuint vbo_object;
GLuint texture_object;
GLuint shader_object;
}
class Camera: public Object {
Degrees fov;
Ratio aspect;
Meters draw_distance;
Frustrum getFrustrum() {
// Use above to make a skewed frustum box
}
}
Adapun hal-hal yang 'disadari' satu sama lain. Itu deteksi tabrakan. Mungkin akan diterapkan di Octree. Anda perlu memberikan beberapa panggilan balik di objek utama Anda. Hal ini paling baik ditangani oleh mesin fisika yang tepat seperti Bullet. Dalam hal ini, ganti saja Octree dengan PhysicsScene dan Position dengan tautan ke sesuatu seperti CollisionMesh.getPosition ().