2D游戏中的对象应该渲染吗?


16

我正在制作不是基于图块的2D街头霸王般的游戏。通常人们建议将实体提供给渲染它们的渲染器,而不是渲染它们自己,但是看起来反函数更好,

为什么一个比另一个更好?

谢谢


为什么您认为反比更好?

1
@Martin因为该对象将始终暗示要使用哪个位图,所以为什么不做object-> render();呢?
jmasterx 2011年

Answers:


11

有两个注意事项:

  • 正如您所提到的,每个精灵都必须“提示”要使用的位图,但是如果实体必须渲染自己的话。那是什么“提示”?如果每个小精灵都引用了不同的位图,小精灵表等,那么您可能最终会使用比必要更多的内存,或者在管理该内存时遇到麻烦。单独的渲染器的优点是您只有一个类负责任何资产管理。也就是说,在类似SF2的格斗游戏中,您可能只有两个Sprite;)

  • 正如其他地方提到的,每当要更改图形API时,都必须更改所有精灵的代码。

  • 如果不参考某些图形上下文,则很少执行渲染。因此,要么有一个表示此概念的全局变量,要么每个子画面都有一个与render(GraphicalContext ctx)的接口。这混合了图形API和游戏逻辑(有些人会觉得这些逻辑不明确),并可能导致编译问题。

  • 我个人发现,将渲染与单个实体分开是朝着将您的游戏视为完全不需要图形的系统方向迈出的有趣的第一步。我的意思是,当您不进行渲染时,您会意识到很多游戏玩法都是在“非图形世界”中发生的,其中实体的坐标,内部状态等很重要。这为自动化测试,更多解耦的系统等打开了大门。

总而言之,我倾向于使用由单独的类进行渲染的系统。这并不意味着您的子画面不能具有“图形相关”的某些属性(动画名称,动画帧,高度x宽度,子画面ID等...),如果这会使渲染器更容易编写或更有效。

而且我不知道这是否适用于3D(其中网格的概念以及您将使用的坐标变量可能与3D API绑定;而x,y,h,w几乎与任何2D无关API)。

希望这会有所帮助。


11

您希望渲染系统控制何时绘制的内容。取而代之的是,精灵控制着渲染,您会在效率方面的大量提高和灵活性上变得松懈。我认为将渲染系统置于控制之下会产生更简洁的代码。

集中渲染的一些优点:

  • z顺序:
    如果游戏对象本身负责渲染,则必须确保以正确的顺序调用它们。否则,可能会在前景对象上绘制背景对象。
    通过控制渲染系统,它可以选择对所有渲染对象进行排序,在渲染时检测重叠,然后仅渲染这些对象,或者放弃所有顺序。关键是现在可以轻松做出决定。
  • 批处理:
    允许渲染系统处于控制状态的另一个明显优势是批处理。这里,渲染系统必须再次选择批处理精灵渲染共享纹理。它可以使用三角形切片来一次调用即可呈现所有内容。它可能能够缓存一些渲染计算。或者它可以只依次渲染每个子画面而没有任何花哨的东西。(注意:每个对象都可以渲染时进行批处理,但问题效率较低且更为复杂)。

我在游戏中实现此方法的方式是让游戏对象注册要使用渲染系统绘制的精灵。当对象不再需要绘制对象时,它将取消注册精灵,或将其标记为不活动。

所有这些。如果更容易让您的游戏对象通过各种方式呈现自己,请按照这种方式进行。与拥有完善的体系结构相比,取得进展并获得某些事物/东西要重要得多。


关于z排序如果对象绘制自己,系统是否可以决定调用绘制方法的顺序?我的意思是集中式与非集中式似乎对z顺序没有影响。
大猩猩2015年

3

免责声明:您的问题并没有提供太多细节,因此我在回答时遵循的是一般原则。如果我误解了您的使用或“渲染”,请原谅。

我通常使用外部对象在场景中渲染各种角色,作为封装场景级别属性和方法的方法,这些属性和方法位于各个“角色对象”之外。场景中的对象应仅包含内部方法和属性;他们应该只知道自己是什么,做什么。据推测,它们将受到游戏中其他对象以及用户输入的影响。这将影响它们在屏幕上的呈现方式/是否呈现。例如,“导演对象”可以转换“ w”按键以跳转,然后告诉演员对象.jump()。这种导演级逻辑还可以告诉演员完全进入或退出场景。

干杯,大卫


但是从这个意义上说,导演不能只是说acton-> setVisible(false);。?
jmasterx 2011年

即使在setVisible(false)情况下,它也是一个外部实体,它通过检查actor的可见变量并仅在它为true时才进行渲染来进行渲染。
导航

仅使演员不可见并不能将其从场景中删除。它还必须停止参与碰撞等
finnw

3

如果有一天您想将游戏移植到其他分辨率(例如iPhone和朋友),该怎么办?因此,关于渲染更改的全局属性,如何轻松地更新代码?


3

我使用的是基于观察者的设计。创建要渲染的类的实例时,指向它的指针存储在中央Renderer类中。您打电话的时候RenderFrame(),渲染器已经具有渲染所需的所有现有对象,并访问了它们的属性来执行此操作。类本身根本不知道将要渲染它们。这个API很好,干净而且易于使用。


1
+1有趣。在将“ 访客图案”用于图形时,我已经使用了这种方法来产生声音。我认为这对声音更有意义,因为当图形和AI在同一时钟上运行时,混音器在另一时钟上运行,因此事件模型更加容易。如果移动事件(导致音频通道的声像/混响发生变化)延迟几毫秒到达,这也不是关键,但如果以错误的状态绘制精灵,这也很关键。
finnw 2011年

2

通常,总是与维护和扩展代码有多容易有关。明天您会发现您不喜欢当前使用的图形API,并且想要切换。您现在是否必须遍历所有对象类并更改所有内容,还是只需要在项目的一个中心点更改代码?

这取决于调用render()时对象实际在做什么。只要它们将方法调用包装在您的图形引擎周围,就可以了,因为仍然会给出逻辑<->图形区别。

例如,如果您的render()方法基本上是便捷方法,并且看起来像这样:

void MyClass::render(const Graphics &g)
{
    g.draw(this);
}

要么

void MyClass::render()
{
   mySprite->render();
}

要么

void MyClass::render()
{
    mySprite->UseShader(thatshader);
    mySprite->render();
}

或接近那个,我认为这不是一个问题。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.