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

时间:2009-02-17 01:59:04

标签: java oop design-patterns model-view-controller

我是大学新生,攻读我的计算机科学学位......过去几年我编写了大量的课程,但最近我对组织代码,设计模式,语言差异的理论思路越来越深入了解等等。

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

我想制作一款小型角色扮演游戏,但这个问题确实适用于任何类型的游戏。如何以结构化的方式组织游戏对象,如模型 - 视图 - 控制器模式?它看起来是一个惊人的模式,使用非常广泛并且很有意义,但我无法弄清楚如何实现它。

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

我最大的问题,GUI;它与哪里结合在一起?它类似于输入,但并不完全,它需要设置和获取实际游戏模拟中的数据......如果我决定尝试添加网络,那就更复杂了(类似于GUI )还需要访问大量数据进行修改和阅读......

哦,我只是困惑。我不知道如何以面向对象的方式将所有这些工作结合在一起......编写明显符合模式的东西很容易,但是当你发生的大量事情都与一个游戏循环相关时,相互修改和游戏数据等,...我甚至不知道。也许我只是把它变成了比实际更大的交易。

还有其他人有这种感觉吗?请为我的情况提供一些清晰的信息,这样我就可以花更少的时间担心而不知道从哪里开始!

-Ricket

编辑:找到一个漂亮的图表,可以帮助我解决这个问题...来源:(小心,PS文件!)http://www.tucs.fi/publications/attachment.php?fname=TR553.ps.gz

http://img10.imageshack.us/img10/6278/mvcdiagramgamesbl5.png

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

Edit3:另一篇很棒的文章! http://dewitters.koonsolo.com/gamemvc.html

6 个答案:

答案 0 :(得分:55)

它可能会帮助您将模型视为一种游戏API。如果从一开始就开始的游戏根本没有用户界面,你的游戏会被减少到什么程度呢?你提到你的想法是一个RPG,所以在这种情况下你可以想象拥有玩家角色,他/她的库存,法术,能力,NPC,甚至地图和战斗规则都是模型的一部分。它就像大富翁的规则和部分,没有最终游戏如何显示或者用户如何与之交互的具体细节。它就像Quake一样,是一组3D物体,它通过一个水平线移动,其中包括交叉和碰撞,但没有渲染,阴影或声音效果。

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

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

Controller层是两者之间的粘合剂。它应该永远不会有任何实际的游戏逻辑,也不应该负责驱动View层。相反,它应该将在视图层中执行的操作(单击按钮,单击屏幕区域,操纵杆操作等)转换为对模型执行的操作。例如,丢弃一个项目,攻击一个NPC,无论如何。它还负责收集数据并进行任何转换或处理,以便View层更容易显示它。

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

然后,如果60秒的传球导致球员基地发生了一些修理,那么基地可能会进行修复,并立即通知任何附属的观察员基地已经更新。视图可以作为观察者附加,并注意它需要重新显示基础,因为它的状态已经改变。通知本身可能包含足够的信息来更新视图,或者它可能需要转向并参考模型才能更新,但结果将是相同的。

答案 1 :(得分:19)

你在那里相处。基本上,问自己一个问题“如果我必须改变程序的某些部分,哪些代码会改变?”

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

因此,无论你是用两个刀片还是一个刀片绘制“斧头”,它都是视图。如果你用斧头造成多少点伤害,那就是它的模型。如果你是通过键入“s”或右键单击来摆动斧头,那就是它的控制权。

答案 2 :(得分:8)

我觉得和你在一起我记得当我第一次发现MVC时,我试图把所有东西塞进去。我的确做了一个利用MVC模式的游戏。我后来发现的是,我所做的就是矫枉过正。我试图将我在MVC中制作的每个类都放入一个类别。

我建议的是四人一组阅读“设计模式”。除了MVC之外,还有很多有用的模式。有时使用MVC没有任何意义。特别是对于游戏,我不确定MVC是否是一个好主意。原因是您不希望以多种不同的方式(视图)显示游戏对象,但是您想要为许多不同类型的游戏对象重用绘图代码。

对于我自己的2D游戏引擎,我非常积极地使用策略模式。游戏对象,如玩家和怪物,我称之为精灵。我让sprite的绘图由策略模式处理。那时我打电话给 sprite.draw()我会做这样的事情:

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

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

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

所以行为我也会使用一个策略模式,它将是一个包含描述行为的代码的对象。这样我可以将相同的行为应用于不同位置的几个怪物。因此,每个框架我都会调用 update()函数来更新位置方向以及怪物的作用。

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;
};

这有很多变化。在我目前的实施中,我甚至将 currentPosition 速度方向 advance()分离为单独的对象称为 MotionState 。这样我就可以在进行路径搜索算法时构建可能位置和方向的搜索树。然后我不想随身携带有关如何处理每次更新或如何绘制精灵的信息。

答案 3 :(得分:2)

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

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

你一直关注所有正在发生的事情。根据您的游戏设计,您的游戏循环可以有很多处理。这是你将学习所有肮脏的优化技巧的地方,通常很难:)

组织代码的方法有很多种 - 一种选择可能是将GameManager类编写为Singleton。所有游戏对象都与其相关联,以进行管理和用户交互。 GameManager处理所有用户输入并将消息分派到其对象池。您可以使用接口来定义游戏对象和GameManager之间的通用通信模式。

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

答案 4 :(得分:1)

所有的侦听器和处理程序都需要进入Controller类,屏幕上对象的状态(例如位置,颜色等)应该是Model类的一部分,并且在屏幕上绘制内容的任何代码都将是成为观点的一部分。

答案 5 :(得分:1)

我对MVC的思考方式与MDUC一样 型号
显示
用户输入控制器

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

它的模式完全相同,但名称只是描述性更强,因此我发现模式的每个部分的责任更清晰,因此模式的含义更令人难忘。 / p>

一旦您看到您从显示中分割数据和模型操作,从用户的输入中,就可以更轻松地查看在您自己的代码中对哪些内容进行分组。