制作游戏时,您通常会创建以下所有实体继承的游戏对象:
public class GameObject{
abstract void Update(...);
abstract void Draw(...);
}
因此,在更新循环中,您遍历所有游戏对象,并给它们提供更改状态的机会,然后在下一个绘制循环中,您遍历所有游戏对象,并给它们提供绘制自己的机会。
尽管这在带有简单前向渲染器的简单游戏中效果很好,但通常会导致一些巨大的游戏对象需要存储其模型,多种纹理以及最糟糕的胖子绘制方法,从而在游戏对象之间产生紧密的联系,当前的渲染策略以及任何与渲染相关的类。
如果要将渲染策略从向前更改为推迟,则必须更新很多游戏对象。而且,我制作的游戏对象没有尽可能地可重用。当然,继承和/或组合可以帮助我应对代码重复并使更改实现变得容易一些,但仍然感到缺乏。
也许更好的方法是从GameObject类中完全删除Draw方法并创建一个Renderer类。GameObject仍将需要包含一些有关其视觉效果的数据,例如用来表示它的模型以及应该在模型上绘制哪些纹理,但是如何完成将留给渲染器。但是,渲染时通常会遇到很多边界情况,因此尽管这将消除从GameObject到Renderer的紧密耦合,但Renderer仍必须全部了解所有会使它发胖的游戏对象,所有人都知道并紧密耦合。这将违反许多良好做法。也许面向数据的设计可以解决问题。游戏对象肯定是数据,但是渲染器将如何驱动呢?我不确定。
所以我很茫然,无法想到一个好的解决方案。我尝试使用MVC的原理,过去我对如何在游戏中使用它有一些想法,但是最近它似乎并不像我想的那样适用。我很想知道大家如何解决这个问题。
无论如何,让我们回顾一下,我对如何实现以下设计目标很感兴趣。
- 游戏对象中没有渲染逻辑
- 游戏对象与渲染引擎之间的松耦合
- 没有所有知道的渲染器
- 最好在渲染引擎之间进行运行时切换
理想的项目设置是一个不需要相互引用的单独的“游戏逻辑”和渲染逻辑项目。
当我听到约翰·卡马克在推特上说他的系统如此灵活,他可以在运行时更换渲染引擎,甚至可以告诉他的系统同时使用渲染器(软件渲染器和硬件加速渲染器)时,这种思想训练就开始了。同时他可以检查差异。到目前为止,我编写的系统还没有这么灵活