โดยส่วนตัวผมแนะนำให้เอาฟังก์ชั่นการดึงออกจากคลาส Object เอง ฉันยังแนะนำให้เก็บตำแหน่ง / พิกัดของวัตถุออกจากตัววัตถุเอง
วิธีการวาด () นั้นกำลังจะจัดการกับ API การเรนเดอร์ระดับต่ำทั้ง OpenGL, OpenGL ES, Direct3D, เลเยอร์ของคุณบน API เหล่านั้นหรือเอ็นจิ้น API อาจเป็นไปได้ว่าคุณต้องสลับระหว่าง (ถ้าคุณต้องการสนับสนุน OpenGL + OpenGL ES + Direct3D เป็นต้น
GameObject นั้นควรมีข้อมูลพื้นฐานเกี่ยวกับรูปลักษณ์ภายนอกเช่นตาข่ายหรืออาจเป็นชุดที่ใหญ่กว่ารวมถึงอินพุต shader สถานะภาพเคลื่อนไหวและอื่น ๆ
นอกจากนี้คุณจะต้องการไปป์ไลน์กราฟิคแบบยืดหยุ่น จะเกิดอะไรขึ้นถ้าคุณต้องการสั่งวัตถุตามระยะทางจากกล้อง หรือประเภทวัสดุ จะเกิดอะไรขึ้นถ้าคุณต้องการวาดวัตถุ 'ที่เลือก' ให้เป็นสีอื่น จะเกิดอะไรขึ้นถ้าแทนที่จะส่งเป็น soo ในขณะที่คุณเรียกใช้ฟังก์ชั่นการวาดบนวัตถุแทนมันจะใส่ไว้ในรายการคำสั่งของการกระทำเพื่อให้การเรนเดอร์ใช้ (อาจจำเป็นสำหรับเธรด) คุณสามารถทำสิ่งนั้นกับระบบอื่น แต่มันเป็น PITA
สิ่งที่ฉันแนะนำคือแทนที่จะวาดโดยตรงคุณผูกวัตถุทั้งหมดที่คุณต้องการโครงสร้างข้อมูลอื่น การเชื่อมโยงนั้นจำเป็นต้องมีการอ้างอิงไปยังตำแหน่งวัตถุและข้อมูลการแสดงผลเท่านั้น
ระดับ / ชิ้น / พื้นที่ / แผนที่ / ฮับ / ทั้งโลกของคุณ / สิ่งที่ได้รับดัชนีพิเศษนี้มีวัตถุและส่งกลับพวกเขาตามแบบสอบถามการประสานงานและอาจเป็นรายการที่เรียบง่ายหรือบางอย่างเช่น Octree มันอาจจะเป็นสิ่งห่อหุ้มสำหรับสิ่งที่นำไปใช้โดยเอนจิ้นฟิสิกส์ของบุคคลที่สามในฐานะฉากฟิสิกส์ มันช่วยให้คุณทำสิ่งต่าง ๆ เช่น "ค้นหาวัตถุทั้งหมดที่อยู่ในมุมมองของกล้องพร้อมกับพื้นที่พิเศษรอบ ๆ พวกมัน" หรือสำหรับเกมที่ง่ายกว่าซึ่งคุณสามารถแสดงทุกสิ่งได้ทั่วทั้งรายการ
ดัชนีพิเศษไม่จำเป็นต้องมีข้อมูลการระบุตำแหน่งจริง พวกมันทำงานโดยเก็บวัตถุไว้ในโครงสร้างต้นไม้โดยสัมพันธ์กับตำแหน่งของวัตถุอื่น พวกเขาสามารถเป็นแคชแคชแบบสูญเสียซึ่งช่วยให้สามารถค้นหาวัตถุได้อย่างรวดเร็วตามตำแหน่งของวัตถุ ไม่จำเป็นต้องทำซ้ำพิกัด X, Y, Z ที่แท้จริงของคุณ ต้องบอกว่าคุณทำได้ถ้าคุณต้องการที่จะเก็บ
ในความเป็นจริงแล้ววัตถุในเกมของคุณไม่จำเป็นต้องมีข้อมูลตำแหน่งของตัวเองด้วยซ้ำ ตัวอย่างเช่นวัตถุที่ไม่ได้ใส่ในระดับไม่ควรมีพิกัด x, y, z ที่ไม่มีเหตุผล คุณสามารถมีสิ่งนั้นในดัชนีพิเศษ หากคุณต้องการค้นหาพิกัดของวัตถุตามการอ้างอิงจริงของมันคุณจะต้องมีการเชื่อมโยงระหว่างวัตถุกับกราฟฉาก (กราฟฉากใช้สำหรับคืนวัตถุตามพิกัด แต่ช้าที่พิกัดคืนตามวัตถุ) .
เมื่อคุณเพิ่มวัตถุในระดับ มันจะทำสิ่งต่อไปนี้:
1) สร้างโครงสร้างตำแหน่ง:
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
};
สิ่งนี้อาจเป็นการอ้างอิงถึงวัตถุในเอ็นจิ้นฟิสิกส์ของบุคคลที่สาม หรืออาจเป็นพิกัดออฟเซ็ตที่มีการอ้างอิงไปยังตำแหน่งอื่น (สำหรับกล้องติดตามหรือวัตถุหรือตัวอย่างที่แนบมา) ด้วยความหลากหลายมันอาจเป็นได้ทั้งขึ้นอยู่กับว่ามันเป็นวัตถุแบบคงที่หรือแบบไดนามิก โดยการอ้างอิงถึงดัชนีพิเศษที่นี่เมื่อพิกัดได้รับการปรับปรุงดัชนีอวกาศอาจเกินไป
หากคุณกังวลเกี่ยวกับการจัดสรรหน่วยความจำแบบไดนามิกให้ใช้พูลหน่วยความจำ
2) การเชื่อมโยง / เชื่อมโยงระหว่างวัตถุของคุณที่ตั้งและกราฟฉาก
typedef std::pair<Object, Location> SpacialBinding.
3) การผูกจะถูกเพิ่มเข้าไปในดัชนีพิเศษภายในระดับที่จุดที่เหมาะสม
เมื่อคุณกำลังเตรียมที่จะเรนเดอร์
1) รับกล้อง (มันจะเป็นวัตถุอื่นยกเว้นที่ตั้งจะติดตามตัวละครของผู้เล่นและนักแสดงของคุณจะมีการอ้างอิงพิเศษกับมันในความเป็นจริงนั่นคือทั้งหมดที่มันต้องการจริงๆ)
2) รับ SpacialBinding ของกล้อง
3) รับดัชนีพิเศษจากการผูก
4) ค้นหาวัตถุที่กล้องมองเห็น
5A) คุณต้องมีการประมวลผลข้อมูลภาพ พื้นผิวที่อัปโหลดไปยัง GPU และอื่น ๆ สิ่งนี้จะทำได้ดีที่สุดล่วงหน้า (เช่นในระดับโหลด) แต่อาจจะทำที่รันไทม์ (สำหรับโลกเปิดคุณสามารถโหลดสิ่งต่าง ๆ เมื่อคุณเข้าใกล้ก้อน แต่ควรจะทำล่วงหน้า)
5B) เลือกสร้างต้นไม้เรนเดอร์แคชถ้าคุณต้องการจัดเรียงเชิงลึก / วัสดุหรือติดตามวัตถุใกล้เคียงอาจปรากฏให้เห็นในภายหลัง มิฉะนั้นคุณสามารถสืบค้นดัชนีพิเศษทุกครั้งที่มันขึ้นอยู่กับข้อกำหนดของเกม / ประสิทธิภาพ
ผู้สร้างภาพของคุณจะต้องมีวัตถุ RenderBinding ที่จะเชื่อมโยงระหว่างวัตถุพิกัด
class RenderBinding {
Object& object;
RenderInformation& renderInfo;
Location& location // This could just be a coordinates class.
}
จากนั้นเมื่อคุณแสดงผลให้เรียกใช้ผ่านรายการ
ฉันใช้การอ้างอิงข้างต้น แต่อาจเป็นตัวชี้อัจฉริยะตัวชี้ดิบตัวจัดการวัตถุและอื่น ๆ
แก้ไข:
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
}
}
สำหรับทำให้สิ่งต่าง ๆ 'ตระหนักถึง' ซึ่งกันและกัน นั่นคือการตรวจจับการชนกัน มันจะถูกนำมาใช้ใน Octree อาจ คุณจะต้องให้การติดต่อกลับในวัตถุหลักของคุณ สิ่งนี้จัดการได้ดีที่สุดโดยเอ็นจิ้นฟิสิกส์ที่เหมาะสมเช่น Bullet ในกรณีนี้ให้แทนที่ Octree ด้วย PhysicsScene และ Position ด้วยลิงก์ไปยังสิ่งที่ต้องการ CollisionMesh.getPosition ()