游戏对象的双缓冲,什么是一个很好的干净的通用C++方式?

gtr*_*rak 8 c++ oop class operator-overloading operators

这是用C++编写的.

因此,我从头开始编写游戏引擎,以便从头开始学习乐趣和学习.我想实现的一个想法是让游戏对象状态(一个结构)是双缓冲的.例如,通过保证游戏对象中存储的一致状态(来自上次的数据),我可以让子系统更新新游戏对象数据,同时渲染线程从旧数据渲染.渲染旧并更新完成后,我可以交换缓冲区并再次执行.

问题是,在尝试尽可能隐藏实现细节的同时,将这个暴露给我的类是什么是一个很好的前瞻性和通用的OOP方式?想了解您的想法和注意事项.

我在想可以使用运算符重载,但是如何在缓冲区类中为模板化类的成员重载赋值?

例如,我认为这是我想要的一个例子:

doublebuffer<Vector3> data;
data.x=5; //would write to the member x within the new buffer
int a=data.x; //would read from the old buffer's x member
data.x+=1; //I guess this shouldn't be allowed
Run Code Online (Sandbox Code Playgroud)

如果可以,我可以选择启用或禁用双缓冲结构,而无需更改太多代码.

这就是我在考虑的事情:

template <class T>
class doublebuffer{
    T T1;
    T T2;
    T * current=T1;
    T * old=T2;
public:
    doublebuffer();
    ~doublebuffer();
    void swap();
    operator=()?...
};
Run Code Online (Sandbox Code Playgroud)

并且游戏对象将是这样的:

struct MyObjectData{
    int x;
    float afloat;
}

class MyObject: public Node {
    doublebuffer<MyObjectData> data;

    functions...
}
Run Code Online (Sandbox Code Playgroud)

我现在所拥有的是返回旧缓冲区和新缓冲区指针的函数,我想任何使用它们的类都必须知道这一点.有没有更好的办法?

Hos*_*ork 6

我最近通过"快照" 在引擎盖下使用Copy-On-Write的数据结构以一种通用的方式处理了类似的愿望.我喜欢这个策略的一个方面是,如果你需要它,你可以制作许多快照,或者只是一次一个地获得你的"双缓冲区".

没有出汗过多的实现细节,这里有一些伪代码:

snapshottable<Vector3> data;
data.writable().x = 5; // write to the member x

// take read-only snapshot
const snapshottable<Vector3>::snapshot snap (data.createSnapshot());

// since no writes have happened yet, snap and data point to the same object

int a = snap.x; //would read from the old buffer's x member, e.g. 5

data.writable().x += 1; //this non-const access triggers a copy

// data & snap are now pointing to different objects in memory
// data.readable().x == 6, while snap.x == 5
Run Code Online (Sandbox Code Playgroud)

在您的情况下,您将快照您的状态并将其传递给渲染.然后,您将允许您的更新对原始对象进行操作.使用const访问来读取它readable()不会触发副本...访问时writable() 触发副本.

我在Qt的QSharedDataPointer上使用了一些技巧来做到这一点.它们通过( - >)区分const和非const访问,这样从const对象读取不会触发写入机制上的副本.


Wil*_*ean 5

如果我是你,我不会做任何"聪明"的操作员重载.将它用于完全不令人惊讶的东西,尽可能接近本机操作员所做的事情,而不是别的.

不清楚你的方案特别有助于多个写入线程 - 当几个线程读取旧状态并写入相同的新状态,覆盖任何先前的写入时,您如何知道哪个'获胜'?

但是如果它在你的应用程序中是一种有用的技术,那么我将拥有'GetOldState'和'GetNewState'方法,这些方法可以让它完全清楚发生了什么.