![]() |
1
6
我最近以一种广义的方式处理了类似的需求,即“快照”一种使用 Copy-On-Write 在引擎盖下面。我喜欢这个策略的一个方面是,如果需要的话,您可以创建许多快照,或者一次只创建一个快照来获得“双缓冲区”。 不必担心太多的实现细节,这里有一些伪代码:
在您的情况下,您将快照您的状态并将其传递给渲染。然后您将允许您的更新操作原始对象。通过常量访问读取
我在qt的基础上使用了一些技巧 QSharedDataPointer 这样做。它们通过(->)区分const和non-const访问,这样从const对象读取就不会触发写时复制机制。 |
![]() |
2
5
如果我是你,我不会对操作符重载做任何“聪明”的事情。使用它来处理完全不令人惊讶的事情,这些事情尽可能接近本地操作人员所做的,而不是其他任何事情。 不太清楚您的方案对多个写入线程特别有帮助——当多个线程读取旧状态并写入相同的新状态,覆盖任何以前的写入时,您如何知道哪个线程“获胜”? 但如果这是一个有用的技术在你的应用程序中,那么我会有“getoldstate”和“getnewstate”方法,使它完全清楚发生了什么。 |
![]() |
3
2
我不确定有效地拥有两个状态将意味着您在访问可写状态时不需要任何同步(如果您有多个线程正在写入),但是… 我认为下面是一个简单而明显的(为了维护和理解)模式,您可以使用很少的开销。
基本上,我做了一些类似于您的建议的事情,但是使用了重载。如果你想小心/偏执,我会有一个空类,用虚拟getter/setter方法作为基类,而不是如上所述,这样编译器就可以保证代码的正确性。 这为您提供了一个状态的只读版本,只有当您调用swap和一个干净的接口时,状态才会发生变化,调用方可以在处理状态时忽略双缓冲区问题(不需要了解旧状态和新状态的所有内容都可以处理myrealstate“接口”),或者您可以下调/要求doublebufferedstate接口,如果您关心状态前后(可能是imho)。 干净的代码更容易被理解(包括您在内的每个人),也更容易测试,所以我个人会避开操作符过载。 对不起,任何C++语法错误,我现在有点爪哇人了。 |
![]() |
4
2
游戏状态越大,保持两个副本同步的成本就越高。为渲染线程创建一个游戏状态的副本同样简单;您必须将所有数据从前端复制到后端缓冲区Ayways,所以您也可以在运行中进行复制。 您可以一直尝试最小化缓冲区之间的复制量,但这样您就有了跟踪哪些字段已更改的开销,从而知道要复制什么。这将是一个不太出色的解决方案,在一个视频游戏引擎的核心,性能是相当关键的。 |
![]() |
5
1
也许您甚至想在每个勾选中创建一个新的渲染状态。这样,游戏逻辑就是生产者,渲染器就是渲染状态的消费者。旧状态是只读的,可以用作呈现和新状态的引用。一旦渲染,就处理它。 对于小物体, Flyweight 模式可能是合适的。 |
![]() |
6
1
你需要做两件事:
为什么? 出于渲染目的,您只需要“返回版本”对象的影响渲染的属性(如位置、方向等),但不需要对象关系。这将使您摆脱悬空指针,并允许更新游戏状态。cow(copy-on-write)应该是1层的深度,因为您只需要一个“其他”缓冲区。 简而言之 :我认为运算符重载的选择与此问题完全正交。只是红糖。无论您是写+=还是写setNewState,都是完全不相关的,因为它们占用了相同的CPU时间。 |
![]() |
7
1
通常,只有在运算符重载是自然的情况下才应使用它。如果您正在寻找适合某些功能的运算符,那么这是一个很好的迹象,表明您不应该在问题上强制使用运算符重载。
尽管如此,您要做的是拥有一个代理对象,它将读写事件分派给一对对象中的一个。代理对象经常重载
你可能有两个超负荷
您可以做的是从存储中分离访问,并创建一个多缓冲区类模板和一个访问适当成员的缓冲区访问器模板,使用
此类存储模板参数的多个实例
此类抽象缓冲区选择。它引用了
请注意
把它和一个测试类放在一起,注意通过重载
也不是在单缓冲和双缓冲之间切换。如果您可以找到对三重缓冲的需求,那么实现三重缓冲也很简单。
|