如何组织游戏的代码以适应 MVC 模式?

我是大学一年级学生,正在攻读计算机科学学位... 过去几年我编写了很多程序,但是最近我开始更多地从理论上思考如何组织代码、设计模式、语言的差异等等。

我有一个 Java 类,所以我放弃了 C + + 的研究/开发,转而使用 Java 和 JOGL (JavaOpenGL)。太棒了!但这不是重点。

我想做一个小小的角色扮演游戏,但是这个问题确实适用于任何类型的游戏。您如何以一种结构化的方式组织游戏对象,比如模型-视图-控制器模式?它看起来是一个令人惊奇的模式,非常广泛地使用,并且非常有意义,但是我在找出如何实现它方面遇到了麻烦。

例如,我需要跟踪 GL 对象,以便将其绘制到屏幕上。我必须拥有实现 MouseListener、 MouseMotionListener、 MouseWheelListener 和 KeyListener 的类(或者一个类,一个一体化的输入管理器)。我必须把我的游戏数据放在所有这些不同的类可以访问和修改它的地方; 如果有人按下键盘上的一个按钮,输入管理类需要以某种方式执行键被映射到的动作; 当需要绘制一个框架时,图形类需要找到一种方法来循环遍历所有不同的“东西”并绘制它们。

我最大的问题是 GUI; 它与这一切有什么联系?它有点像输入,但不完全一样,它需要从实际的游戏模拟中设置和获取数据片段... 更复杂的是,如果我决定尝试添加网络,它(类似于图形用户界面)也需要访问大量的数据进行修改和阅读..。

我只是很困惑。我不知道如何以面向对象的方式将所有这些工作结合在一起... ... 写一些明显符合模式的东西很容易,但是当你有成千上万的事情都发生在一个游戏循环中,修改彼此和游戏数据等等,... ... 我甚至不知道更多。也许我只是把这事看得太重了。

还有其他人有这种感觉吗?请澄清我的情况,这样我就可以花更少的时间担心和不知道从哪里开始!

编辑: 找到一个不错的图表,可能会帮助我弄清楚这一切... 来源: (注意,PS 文件!) http://www.tucs.fi/publications/attachment.php?fname=TR553.ps.gz

编辑2: 我也喜欢这个家伙对他如何计划他的 MVC 游戏的解释: http://interactivesection.wordpress.com/2007/11/19/dum-de-dum-drum-my-first-mvc-game-development/

编辑3: 又一篇好文章! Http://dewitters.koonsolo.com/gamemvc.html

20346 次浏览

你们相处得不错。基本上,问问你自己“如果我必须改变程序的某些部分,哪些代码会改变?”

如果它可以在不改变基本数据的情况下改变外观,那么它就在视图中。如果说数据可以以多种方式查看,那么它就是模型。如果你是这么玩的,那就是控制。

因此,如果你用两片刀片或一片刀片画一把“斧头”,那就是视图。如果是你用斧头造成多少点伤害,那就是模型。如果你是通过键入“ s”或右键挥动斧头,那就是控制。

集中用户交互逻辑的 MVC 概念是一个很好的游戏开发模型。

我做了一些关于 Flash 游戏开发的工作。给你是一篇关于 Flash 中对象池的文章。这个概念是跨平台的,可能会给你一些想法。

你同时关心所有的事情是对的。根据您的游戏设计,您的游戏循环可以有很多处理。在这里,您将学到所有肮脏的优化技巧,通常是艰难的:)

有许多方法来组织您的代码-一个选项可能是编写一个单例的 GameManager 类。所有的游戏对象都和它绑定在一起,以便管理和用户交互。GameManager 处理所有用户输入并将消息发送到其对象池。您可以使用接口来定义游戏对象和 GameManager 之间的通用通信模式。

就性能优化而言,线程非常强大。异步操作可以确保您不会浪费这些宝贵的周期。

所有的监听器和处理程序都需要进入 Controller 类,屏幕上对象的状态(例如位置、颜色等)应该是 Model 类的一部分,在屏幕上绘制东西的任何代码都应该是 View 的一部分。

它可以帮助您将 Model 视为一种游戏 API。如果游戏从一开始就没有用户界面,你的游戏会变成什么样子?你提到你想要的是一个 RPG,所以在这种情况下你可以想象玩家角色,他/她的背包,法术,能力,NPC,甚至像地图和战斗规则都是模型的一部分。它就像大富翁游戏的规则和片段,没有最终游戏如何显示的细节,或者用户将如何与它交互。它就像是一个抽象的3D 物体集合,通过一个水平移动,像交叉和碰撞计算,但没有渲染,阴影,或声音效果的东西。

通过把所有这些放入模型中,游戏本身现在是 UI 不可知的。它可以像 Rogue 游戏那样连接到 ASCII 文本界面,或者类似于 Zork 的命令行界面,或者基于 Web 的界面,或者3D 用户界面。根据游戏机制的不同,其中一些 UI 可能非常适合,但它们都是可能的。

视图层是依赖于 UI 的层。它反映了用户对 UI 的具体选择,并将非常专注于该技术。它可能负责读取模型的状态并将其绘制成3D、 ASCII 或网页的图像和 HTML。它还负责显示任何控制机制的球员需要使用的互动与游戏。

Controller 层是两者之间的粘合剂。它不应该有任何实际的游戏逻辑在其中,也不应该负责驱动的视图层。相反,它应该将视图层中的操作(点击按钮,点击屏幕上的区域,操纵杆操作,等等)转换为模型上的操作。例如,掉落一个物品,攻击一个 NPC,等等。它还负责收集数据,并进行任何转换或处理,使视图层更容易显示数据。

现在,我在上面所描述的方式就好像有一个非常独特的事件序列驱动着游戏,而这个事件序列可能只适用于网络游戏。那是因为我最近一直在研究这个。在一个不受用户请求和服务器响应驱动的游戏中(比如在用户机器上运行的游戏) ,你可能需要确保模型层很好地实现了观察者模式。例如,如果操作发生在模型中,因为时间在流逝,那么您可能不希望视图层不断轮询模型以获得更新。相反,通过使用观察者模式,模型可以在模型对象发生变化时通知任何观察者。这可以反过来用于提示立即更新视图以反映更改。

然后,如果60秒过去导致一些修复发生在球员的基地,基地可以实施修复,并立即通知任何观察员附属于它的基地已更新。视图可以作为观察者附加,并注意它需要重新显示基础,因为它的状态已经改变。通知本身可能包含了足够的信息来更新视图,或者为了更新它可能不得不回过头来查看模型,但是结果是一样的。

我觉得和你在一起,我记得当我第一次发现 MVC 的时候,我试图把所有的东西都塞进去。我确实做了一个利用 MVC 模式的游戏。后来我发现,我所做的是过度杀戮。我试图把我制作的每一个类都归入 MVC 的一个类别。

我建议大家读一读四人小组的《设计模式》。除了 MVC 之外,还有许多有用的模式。有时候使用 MVC 根本没有任何意义。尤其是对于游戏,我不确定 MVC 是否是一个好主意。原因是您不希望以许多不同的方式(视图)显示游戏对象,但是您希望为许多不同类型的游戏对象重用绘图代码。

对于我自己的2D 游戏引擎,我非常积极地使用 策略模式。游戏对象,比如玩家和我称之为 雪碧的怪物。我让一个 策略模式处理精灵的绘图。当我打电话给 精灵,画()时,我会这样做:

class Sprite {
void draw() {
this.view.draw(this.currentPosition, this.currentOrientation);
}


Point  currentPosition;    // Current position of this sprite
double currentOrientation; // Facing angle of sprite
};

这种方法的好处是您可以在几个精灵之间共享一个视图对象。因为通常会有很多例如怪物,它们看起来一样,但是位置不同,行为也可能不同。

所以行为我也会使用一个策略模式,它是一个包含描述行为的代码的对象。这样我就可以把同样的行为应用到不同位置的几个怪物身上。所以每帧我会调用一个 更新()函数来更新位置方向和怪物做什么。

class Sprite {
void setUpdateAction(Action action) {
this.updateAction = action;
}


void update(double start_time, double delta_time)
{
this.prevPosition = position();
advance(delta_time); // Advance to next position based on current speed and orientation


this.updateAction.execute(this, start_time, delta_time);
}


Action updateAction;
};

这种情况有很多种。在我当前的实现中,我甚至将 当前位置速度定位预付款()分离成一个称为 MotionState的单独对象。这样我就可以在做路径搜索算法时建立一个可能位置和方向的搜索树。然后,我不想携带我的信息,如何行为每个更新或精灵应该如何绘制。

我认为 MVC 就是 MDUC
模特
展示
用户输入控制器

模型包含域模型对象
显示屏上显示了域模型对象的当前状态和行为。
用户输入控制器处理所有用户输入。

这是完全相同的模式,但是名称只是稍微更具描述性,所以我发现模式的每个部分的责任更加清晰,因此模式的意义更加难忘。

一旦看到将数据和模型操作从用户输入中分离出来,就很容易看到在自己的代码中将什么分组。