我正在创建基于SDL2库的简单游戏渲染引擎。我的设计看起来类似于这个ASCII图。
DrawTarget RenderTarget
| |
| |
+---> Window <---+
DrawTarget
是适用于SDL_Surface blitting的绘制目标的抽象类。
RenderTarget
是适用于SDL_Texture的渲染目标的抽象类。
Window
是派生类,管理SDL_Window,SDL_Renderer以及所有绘制和渲染函数。
Renderable
| | |
| | |
| | +-> Player
| | ^
| | |
| +----> Animation
| ^
| |
+-------> Texture
Renderable
是一切,可以渲染到屏幕或其他RenderTarget。
Texture
是SDL_Texture实现。纹理不应该知道它自己的位置。
Animation
有一个私有纹理成员,允许设置动画帧。动画本身不应该知道渲染位置。
Player
有一个私人动画会员。玩家应该知道当前的位置。
在这个时候,我每个窗口都有一个SDL_Renderer
并将它全部传递给纹理,动画等。纹理是SDL_Renderer
知识渲染到屏幕上的。但我不认为一直调用Texture-&gt; draw(x,y)是高效且缓存友好的。
我喜欢SFML呈现的方式。所有可渲染对象都有draw
方法,它只调用窗口的绘制方法。我想实现类似的系统。
这会破坏我的要求,一些Renderable对象知道它们的渲染位置,有些则不然。
例如,类Player不应该有render( x, y )
方法,因为它知道它的位置。另一方面,Texture类不应该有render( void )
方法,因为它不是它的位置。
我的问题如下:如何以尽可能少的开销设计SDL2合适的渲染引擎?
答案 0 :(得分:3)
回答你的问题:&#34;我的问题如下:如何以尽可能少的开销设计SDL2合适的渲染引擎?&#34;
快速解释可缩放的懒惰渲染器方案,以尽量减少SDL2渲染器开销:
A&#34;层&#34;由具有相同z属性的所有纹理组成。 只要修改了该图层中的纹理,图层就会被标记为无效。 在渲染器运行时管理图层,这是在设置的帧速率下。 跟踪最大层和最高无效层。渲染器 从最高的无效层开始,到最大层结束。每一层都是 设置为渲染器目标并清除。然后将上一层复制到 当前图层。然后它遍历图层中的每个纹理, 重绘那些标记为无效的,并将每个纹理复制到当前的顶部 层。结果是前一层是背景而后 在其上绘制的当前图层。此纹理在缓存时无效 该图层标记为无效。运行任何无效图层后,设置 将目标渲染回默认值(null),将最高纹理复制到屏幕, 和现在。
在具有图层用户界面类型的环境的2d中,以上是 可扩展和懒惰。在我的低端Celeron n2830上,我的测试应用程序闲置在 0%cpu使用率。即使我加了一百个,它或多或少都保持这种状态 测试层。因为它只是从哪个层向上变换,而且都是 变化以合理的帧速率排列,实际上很少有工作 最终完成了。将出现无效图层到最大图层的迭代 渐渐变得更加友好,然后每次运行遍历所有层。运行 渲染器以设定的间隔进行所有绘图然后有助于节省时间 因为它会忽略那些无论如何都看不到的多余变化。 使用一些应用程序代码以避免必须绘制是值得的 东西和复制纹理。如果检查和那些,往往需要更长的时间 属性查找。
请注意,此设计适用于带有图层的2D,例如用户界面。 某些原则可能不会在其他环境中很好地运作。
此外,上述仅支持纹理而非表面。混合两者 对我来说不值得复杂。让sdl2渲染器绘制到 特别的质地花了一些时间,但很好地满足了我的需求 单独。如果你把两者混合起来,似乎很难避免一些额外的工作。 加上纹理受益于gpu,这增加了效率 cpu time。
在我的系统中,窗口对象有一个draw方法。这种方法将绘制排队 使用渲染器进行操作,而不是立即绘制它们。窗口 对象具有区域属性。支持没有区域的对象 属性,也许你可以应用一个围绕你的对象的包装器 才不是。这样当提示某个区域时,它仍然可以提供一个区域 虽然它内部没有。或者也许使用映射表 你的对象是一个区域,或者是一个跟踪它的对象的方法调用 质地。我不确定这种限制的性质。
请注意,此绘制方法是绘制自身和对象的混合方法 渲染器绘制对象。这些物体似乎是在绘制自己,而在 渲染器实际上做了工作。
简而言之:
答案 1 :(得分:2)
在我看来,你所说的是你希望实体只知道它们的位置,但是为了让你想让它完全分开。每个实体都需要存储某种渲染数据。我会说你应该看一个基于组件的实体系统。有位置,renderdata,输入等不同的类。请尝试Component Based Entity System