开发一个teris游戏我得出的结论是,使用通常的MVC模式可能会使我的代码混乱,以及由于OpenGL在GLEW下工作的方式,使其更难以构建。相反,我提出了这个整洁的修改,也依赖于观察者模式,这会更有意义,至少在短期内(图像不反映完整的类树):
解释:
- 每个框都是一个类,Engine
包含Entities
的实例,Game
包含Figure
的实例。
- Figure
继承Entity
。
- Engine
观察Game
,Game
由观察员与Figures
耦合。
它应该如何工作:
理想情况下,我应该实例化Engine
,它将设置GLEW和GLFW以及构成窗口的所有其他内容,然后创建一个Game
对象,在新线程中,它将创建一个数字,并通知启动绘图循环的引擎,当设置该数字时,通过Observer将对象指针传递给Engine
。
这样可以很好地工作,我可以通过继承Entity
来添加各种数字,数字不会从屏幕上掉落,因为每个坐标更新都会通过Game
,我可以,如果有必要的话,可能会给每个人物一个独特的着色器。
它是如何工作的:
初始化引擎,初始化游戏,在另一个线程中调用图,然后抛出
atioglxx.dll: 0xC0000005: Access violation reading location 0x00000728.
当被要求访问任何OpenGL功能时。
我怀疑这是因为Figure
并不知道所有支持功能都是在Engine
中启动的。我无法在Figure
再次这样做。我可以将与View有关的所有内容移动到Engine
,但之后我将无法设置单独的着色器,并且我必须为{{1}内的每个数字构建VAO(顶点数组对象) }。
那么如何尽可能少地引入错误呢?
答案 0 :(得分:0)
简短的回答是,给定上下文的所有OpenGL调用都需要在同一个线程上。更长的答案就在路上......
首先,Entities
需要能够使用GL调用绘制自己。您不能将一个线程中的绘图代码与另一个线程混合,OpenGL客户端状态将不正确。 (将OpenGL视为'C'状态机)。
其次,您需要按帧缓冲实体状态。当您在Engine
主题中开始下一帧时,Game
可能会或可能不会完成提交绘制调用。因此,您需要一些同步方式来提交帧的所有Entity
个状态。这有点棘手,因为您希望避免可能会使管道停滞或导致阻塞的同步原语(例如互斥)。
您可以阅读使用双缓冲管道的Doom III source code,以便向Engine
后端提交绘图调用。诀窍是Doom在主线程上执行大部分操作,然后在后端(Engine
)线程上执行Draw Calls并在{{{Entities
上提交绘制状态(Game
)。 1}}主线程。然后它等待Engine
线程完成并交换缓冲区。
阅读Metal和Vulkan多线程。这些非常相似。
需要在Engine
上加载资源并返回要引用的实体的句柄(着色器,纹理,静态几何等)。