Cá nhân tôi khuyên bạn nên giữ chức năng vẽ ra khỏi lớp Object. Tôi thậm chí khuyên bạn nên giữ vị trí / tọa độ của Đối tượng khỏi chính Đối tượng.
Phương thức draw () đó sẽ xử lý API kết xuất cấp thấp của OpenGL, OpenGL ES, Direct3D, lớp gói của bạn trên các API đó hoặc API công cụ. Có thể là bạn phải trao đổi giữa lúc đó (Nếu bạn muốn hỗ trợ OpenGL + OpenGL ES + Direct3D chẳng hạn.
GameObject đó chỉ nên chứa thông tin cơ bản về hình thức trực quan của nó như Lưới hoặc có thể là một gói lớn hơn bao gồm các đầu vào shader, trạng thái hoạt hình, v.v.
Ngoài ra, bạn sẽ muốn một đường ống đồ họa linh hoạt. Điều gì xảy ra nếu bạn muốn đặt hàng các đối tượng dựa trên khoảng cách của chúng với máy ảnh. Hoặc loại vật liệu của họ. Điều gì xảy ra nếu bạn muốn vẽ một đối tượng 'được chọn' một màu khác. Điều gì sẽ xảy ra nếu thay vì thực sự rending như soo khi bạn gọi một hàm vẽ trên một đối tượng, thay vào đó, nó đưa nó vào một danh sách lệnh hành động để kết xuất (có thể cần thiết cho luồng). Bạn có thể làm điều đó với hệ thống khác nhưng đó là PITA.
Những gì tôi khuyên là thay vì vẽ trực tiếp, bạn liên kết tất cả các đối tượng bạn muốn với cấu trúc dữ liệu khác. Sự ràng buộc đó chỉ thực sự cần phải có một tham chiếu đến vị trí đối tượng và thông tin kết xuất.
Cấp độ / khối / khu vực / bản đồ / trung tâm / wholeworld / bất cứ thứ gì được cung cấp chỉ số không gian, cái này chứa các đối tượng và trả về chúng dựa trên các truy vấn phối hợp và có thể là một danh sách đơn giản hoặc một cái gì đó giống như Octree. Nó cũng có thể là một vỏ bọc cho thứ gì đó được thực hiện bởi động cơ vật lý của bên thứ 3 như một cảnh vật lý. Nó cho phép bạn thực hiện những việc như "Truy vấn tất cả các đối tượng trong chế độ xem của máy ảnh với một số khu vực phụ xung quanh chúng" hoặc cho các trò chơi đơn giản hơn, nơi bạn có thể hiển thị mọi thứ lấy toàn bộ danh sách.
Chỉ mục không gian không phải chứa thông tin định vị thực tế. Chúng hoạt động bằng cách lưu trữ các đối tượng trong các cấu trúc cây liên quan đến vị trí của các đối tượng khác. Chúng có thể mặc dù là một loại bộ nhớ cache bị mất cho phép tra cứu nhanh đối tượng dựa trên vị trí của nó. Không có nhu cầu thực sự để nhân đôi tọa độ X, Y, Z thực tế của bạn. Đã nói rằng bạn có thể nếu bạn muốn giữ
Trong thực tế, các đối tượng trò chơi của bạn thậm chí không cần chứa thông tin vị trí của riêng họ. Ví dụ, một đối tượng chưa được đưa vào một cấp độ không nên có tọa độ x, y, z, điều đó không có ý nghĩa. Bạn có thể chứa nó trong chỉ mục đặc biệt. Nếu bạn cần tra cứu tọa độ của đối tượng dựa trên tham chiếu thực tế của nó thì bạn sẽ muốn có một ràng buộc giữa đối tượng và biểu đồ cảnh (biểu đồ cảnh là để trả về đối tượng dựa trên tọa độ nhưng chậm khi trả lại tọa độ dựa trên đối tượng) .
Khi bạn thêm một đối tượng vào một cấp độ. Nó sẽ làm như sau:
1) Tạo cấu trúc vị trí:
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
};
Đây cũng có thể là một tham chiếu đến một đối tượng trong động cơ vật lý của bên thứ 3. Hoặc nó có thể là tọa độ bù có tham chiếu đến vị trí khác (đối với camera theo dõi hoặc đối tượng hoặc ví dụ đính kèm). Với tính đa hình, nó có thể tùy thuộc vào việc nó là đối tượng tĩnh hay động. Bằng cách giữ một tham chiếu đến chỉ mục không gian ở đây khi tọa độ được cập nhật, chỉ số không gian cũng có thể.
Nếu bạn lo lắng về việc cấp phát bộ nhớ động, hãy sử dụng nhóm bộ nhớ.
2) Một liên kết / liên kết giữa đối tượng của bạn, vị trí của nó và biểu đồ cảnh.
typedef std::pair<Object, Location> SpacialBinding.
3) Binding được thêm vào chỉ số không gian bên trong cấp độ tại điểm thích hợp.
Khi bạn đang chuẩn bị kết xuất.
1) Lấy máy ảnh (Nó sẽ chỉ là một đối tượng khác, ngoại trừ vị trí của nó sẽ theo dõi nhân vật người chơi và trình kết xuất của bạn sẽ có một tham chiếu đặc biệt đến nó, thực tế đó là tất cả những gì nó thực sự cần).
2) Nhận SpacialBinding của máy ảnh.
3) Lấy chỉ số không gian từ ràng buộc.
4) Truy vấn các đối tượng (có thể) hiển thị trước máy ảnh.
5A) Bạn cần xử lý thông tin hình ảnh. Hoạ tiết được tải lên GPU, v.v. Điều này sẽ được thực hiện tốt nhất trước (chẳng hạn như khi tải mức) nhưng có lẽ có thể được thực hiện trong thời gian chạy (đối với một thế giới mở, bạn có thể tải công cụ khi bạn đang ở gần một đoạn nhưng vẫn nên được thực hiện trước).
5B) Tùy chọn xây dựng cây kết xuất được lưu trong bộ nhớ cache, nếu bạn muốn phân loại độ sâu / vật liệu hoặc theo dõi các đối tượng gần đó, có thể hiển thị sau đó. Nếu không, bạn chỉ có thể truy vấn chỉ mục không gian mỗi lần nó sẽ phụ thuộc vào yêu cầu trò chơi / hiệu suất của bạn.
Trình kết xuất của bạn có thể sẽ cần một đối tượng RenderBinding sẽ liên kết giữa Đối tượng, tọa độ
class RenderBinding {
Object& object;
RenderInformation& renderInfo;
Location& location // This could just be a coordinates class.
}
Sau đó, khi bạn kết xuất, chỉ cần chạy qua danh sách.
Tôi đã sử dụng các tài liệu tham khảo ở trên nhưng chúng có thể là con trỏ thông minh, con trỏ thô, xử lý đối tượng và như vậy.
BIÊN TẬP:
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
}
}
Đối với việc làm cho mọi thứ 'nhận thức' về nhau. Đó là phát hiện va chạm. Nó sẽ được thực hiện trong Octree có lẽ. Bạn sẽ cần cung cấp một số cuộc gọi lại trong đối tượng chính của bạn. Công cụ này được xử lý tốt nhất bởi một công cụ vật lý thích hợp như Bullet. Trong trường hợp đó, chỉ cần thay thế Octree bằng ChemistryScene và Position bằng một liên kết đến một cái gì đó như CollisionMesh.getPocation ().