shawind 发表于 2007-11-24 19:57:35

[翻译]MVC for Game Engine Core

只是节译,机翻效果,也就是看看大意罢了。

原作者:Rasmus Christian Kaae


2.0在引擎核心中应用Model-View-Control
    引擎的核心应该处理游戏中的所有任务。也就是说可以处理用户的输入,处理其他用户的可能的输入(网络游戏),处理游戏事件,当然还包括处理声音和图形输出。为了这个目的,我将使用一个Model-View-Control设计模式的衍生模式。这个模式将把引擎分成三个重要的部分。Model-View-Control 对GUI程序特别有用。因为它提供了一定程度的模块化,使得它可以转化一个已有的实现到别的图形驱动。例如,现有一个游戏引擎可能是用最新的DirectX SDK实现的,那么可以就把它移植到OpenGL。因为所有关于游戏引擎对DirectX的调用代码都在View类中。这使得移植变得容易一些——虽然只有View类须要改造。更多关于Model-View-Control构架信息,你可以在http://ootips.org/mvc-pattern.html和http://compsci.about.com/cs/mvcpattern/index.htm找到。

2.1 Model
    Model模块是这个构架的一部分,用来包含所有的游戏结构。
    例如,3D游擎的结构就放在这个类中。还有行为模式,也就是当给出一个用户输入后,将怎么去作的信息也存放在这里。作为构架的一部分,Model和View、Control模块没有任何关系。也就是说Model模块完全可以单独用在另外一个环境中。

2.2 View
    View模块包含所有涉及输出给用户的东西,如声音播放和图形显示。例如,在这里实现OpengGL和DirectX驱动。View模块和model模块相关,View模块能把Model 模块的当前状态显示给用户。

2.3 Control
    Control模块是这个构架中最根本的部分。当它被初始化后,它将分配一个View和Model的实例,并等待用户的输入。用户输入被解析然后传去Model模块处理,很快View会反映出Model的当前状态。

2.4 例子代码
下面的代码是伪代码,不能通过编译。
/*InputBlock 包含用户的当前输入*/
class InputBlock{
    // todo : 加入有趣的变量和显示用户输入的函数
};

/* Model模块*/
class Model {
public:
    Engine3D *m_engine;
    Sound*m_sound;

    Model();

    UpdateControl(InputBlock *input) {
      // todo : 对当前输入的反应
    }
};

/* ViewVisual是各具体驱动实现的接口类 */
class ViewVisual {
public:
   ViewVisual() {
   }
    virtual void Update(Model *model)=0;   //纯虚函数处理当前Model的变化
}

/* ViewVisualOpenGL是ViewVisual接口的实现*/
class ViewVisualOpenGL {
public:
    ViewVisualOpenGL(){
      // todo : 初始化
    }
   
    void Update(Model *model) {// 显示Model的当前状态
      // todo : 用model->m_engine 画图
    }
};

/* ViewAudio是各声音驱动实现的接口类 */
class ViewAudio {
public:
    ViewAudio() {
      // todo: 初始化
}

    virtual void Update(Model *model)=0;   // 纯虚函数处理当前Model的改变
};

/* ViewAudioDirectSound是ViewAudio的实现,用DirectSound播放声音 */
class ViewAudioDirectSound {
public:
    ViewAudioDirectSound() {
    // todo : 初始化
    }
   
    void Update(Model *model) {// todo : 用model->m_sound播放当前声音
   }
};

/* View类连接图形和声音驱动*/
class View {
protected:
    ViewVisual *m_visual;
    ViewAudio *m_audio;
public:
    View(Model *model, ViewVisual *visual, ViewAudio *audio) {
      m_model=model;
      m_visual=visual;
      m_audio=audio;
}

    void Update() {
      m_visual->Update(m_model);
      m_audio->Update(m_model);
   }
};

/* Control is the class that handles input from the user and starts the output */
class Control {
    enum {
      ESCAPE_IS_PRESSED,
      USER_INPUT
    };
private:
    View *m_view;
    Model *m_model;
public:
    Control() {
      m_model = new Model();
      m_view = new View(m_model, new ViewVisualOpenGL(),
      new ViewAudioDirectSound());
   }
      
   ~Control() {
      delete m_model;
      delete m_view;
   }

    InputBlock Input(int which) {
    switch (which) {
      case USER_EXIT :
            if (escape_is_pressed)
                return new InputBlock(ESCAPE_IS_PRESSED);
      break;

      case USER_INPUT :
            if (user_has_made_an_input)
                return new InputBlock(the_new_input_info);
      break;
    }
}

    void Run() {
      while (!Input(USER_EXIT)) {
            if (Input(USER_INPUT))
                m_model->UpdateControl(Input(USER_INPUT));
                m_view->Update();
          }
   }
};

/* 调用框架的主函数*/
void Main(int argc, char **argv) {
    Control *control = new Control();
    control->Run();
    delete control;
}

2.4.1 代码解说
上面的代码最终将创建一个控制器。这个控制器然后创建一个OpenGL驱动,一个DirectSound驱动,和一个Model。在创建结束后,主程序调用控制器的Run()函数。这个成员函数把它自己放在一个循环中,直到用户按下退出按钮。在用户退出前,程序将根据用户的输入更新Model和View。当一个输入信息给出时。这个输入被解析并传到Model中处理。当输入处理结束后,控制器将调用View来更新显示。结束时,退出代码将清理资源。

2.5 一个图形化的示意
   CONTROL
    ↓    ↓
MODEL   VIEW

上面的箭头代表了这个model-view-control结构中的联系. Control模块和Model、View都有联系。而View从Model中检索信息。这些关系可以根据实际需求而改变。我喜欢上面的那种联系,这给了每个模块足够的独立性。当然,给Model和View到Control间加上一条通信线路也是个不错的主意,可以让它们通报突发错误!

正在玩crysis呢,被叫出来修改完毕 -_-!

rednaxela 发表于 2007-11-24 21:00:09

[-code-]标签里的标签都不会被解析……或许应该用[-quote-]?

shawind 发表于 2007-11-24 22:46:17

代码部分我没用code.所有的翻译部分加在一起用了一个code.和我自己的话区别开来。

lw 发表于 2007-11-25 09:53:55

其他没有什么,只是想问问为什么要把VIEW和MODEL分开啊?

rednaxela 发表于 2007-11-25 11:59:51

因为表现层逻辑跟业务逻辑不应该混在一起吧……

lw 发表于 2007-11-26 21:18:16

但是如果确实可能需要调用不是也蛮麻烦的嘛……
不过可能代码少的时候直接调用方便,多的时候就不一样了罢……

不过偶看不到……
页: [1]
查看完整版本: [翻译]MVC for Game Engine Core