MVCHelloWorld:Cocos2d-js MVC模块化开发

[size=5]简介[/size]

模块化两个概念:
[list][li]软件设计模块化[/li][li]软件代码模块化[/li][/list]软件设计模块化——分层——MVC——PureMVC
软件代码模块化——JavaScript模块化——CommonJS——Browserify
实现:
[list][li]关注点分离[/li][li]代码重用[/li][/list][size=5]
分层
[/size]
将一个复杂的程序进行层次划分。为每一层进行设计,每层都是内聚的而且只依赖与它的下层。采用标准的架构模式来完成与上层的松散关联。将所有与领域模型相关的代码都集中在一层,并且将它与用户界面层、应用层和基础结构层的代码分离。领域对象可以将重点放在表达领域模型上,不需要关心它们自己的显示、存储和管理应用任务等内容。这样使模型发展得足够丰富和清晰,足以抓住本质的业务知识并实现它。
[size=5]
MVC
[/size]
MVC全名是Model View Controller,是模型(model)-视图(view)-控制器(controller)的缩写,一种软件设计典范,用一种业务逻辑、数据、界面显示分离的方法组织代码,将业务逻辑聚集到一个部件里面,在改进和个性化定制界面及用户交互的同时,不需要重新编写业务逻辑。MVC被独特的发展起来用于映射传统的输入、处理和输出功能在一个逻辑的图形化用户界面的结构中。
[size=5]
PureMVC
[/size]
PureMVC是在基于模型,视图和控制器MVC模式建立的一个轻量级的应用框架,而且是免费的,它最初是执行的ActionScript 3语言使用的Adobe Flex、Flash和AIR,现在已经移植到几乎所有主要的发展平台。
PureMVC框架的目标很明确,即把程序分为低耦合的三层:Model、View和Controller。降低模块间的耦合性,各模块如何结合在一起工作对于创建易扩展,易维护的应用程序是非常重要的。
[size=5]
JavaScript模块化
[/size]
随着前段JavaScript代码越来越重,如何组织JavaScript代码变得非常重要,好的组织方式,可以让别人和自己很好的理解代码,也便于维护和测试。模块化是一种非常好的代码组织方式。
[size=5]
CommonJS
[/size]
CommonJS是服务器端模块的规范,Node.js采用了这个规范。
根据CommonJS规范,一个单独的文件就是一个模块。每一个模块都是一个单独的作用域,也就是说,在该模块内部定义的变量,无法被其他模块读取,除非定义为global对象的属性。
[size=5]
Browserify
[/size]
Browserify是一个node.js模块,允许你在浏览器中使用require。
Browserify是NPM在前端项目里延伸的神器,有了它之后,前后端可以共用一个CommonJS规范的模块。
[size=5]
程序结构
[/size]
[list][li]MVCHelloWorld[list][li]data[/li][li]js[list][li]profile[list][li]flow[/li][/list][/li][li]model[list][li]domain [/li][li]proxy[/li][/list][/li][li]view[list][li]mediator
[/li][li]component[/li][li]ui[/li][/list][/li][li]controller[list][li]command[/li][/list][/li][li]test[/li][li]app.js[/li][/list][/li][li]res[/li][li]index.html[/li][/list][/li][li]node_modules[/li][/list][size=5]
开发环境
[/size]
IDE:
[list][li]WebStorm[/li][/list]编译运行:
[list][li]Node.js[/li][li]Browserify[/li][li]UglifyJS[/li][/list]JavaScript库:
[list][li]Cocos2d-js(single js file ) http://www.cocos2d-x.org/filecenter/jsbuilder/[/li][li]PureMVC[/li][li]Underscore.js[/li][li]GNU ease.js[/li][/list][size=5]
源代码
[/size]
[list][li]本文代码:https://github.com/guyoung/GeneCocosMVC/tree/master/MVCHelloWorld-Part01[/li][li]项目地址:https://github.com/guyoung/GeneCocosMVC[/li][/list][size=4]
编译及运行
[/size]

http-server
<pre class="brush:shell; toolbar: true; auto-links: false;">
node_modules.bin\http-server.cmd
</pre>

[hr]https://github.com/guyoung/GeneCocosMVC
By Guyoung Studio
http://www.guyoung.net

[size=5]Browserify简介[/size]
Browserify是一个node.js模块,允许你在浏览器中使用require。
Browserify是NPM在前端项目里延伸的神器,有了它之后,前后端可以共用一个CommonJS规范的模块。
Browserify 通过预编译的方法,让Javascript前端可以直接使用Node后端的程序。我们可以用一套代码完成前后端,不仅工作量变少了,程序重用性增强,还可以直接在浏览器中使用大量的NPM第三方开源库的功能。

[size=5]安装 browserify[/size]
首先,安装Node.js。
使用NPM,安装browserify
<pre class="brush:shell; toolbar: true; auto-links: false;">
npm install -g browserify
</pre>

因为这是命令行使用的,所以推荐使用-g参数

[size=5]Browserify命令[/size]

<pre class="brush:shell; toolbar: true; auto-links: false;">
browserify [entry files] {OPTIONS}
</pre>

[list][li]-outfile, -o: browserify日志打印到文件[/li][li]-require, -r: 绑定模块名或文件,用逗号分隔[/li][li]-entry, -e: 应用程序的入口[/li][li]-ignore, -i: 省略输出[/li][li]-external, -x: 从其他绑定引入文件[/li][li]-transform, -t: 对上层文件进行转换[/li][li]-command, -c: 对上层文件使用转换命令[/li][li]-standalone -s: 生成一个UMB的绑定的接口,提供给其他模块使用。[/li][li]-debug -d: 激活source maps调试文件[/li][li]-help, -h: 显示帮助信息[/li][li]
[/li][/list][size=5]使用 browserify[/size]
首先定义一个commonjs规范的模块,功能比较简单,名为calcu.js
<pre class="brush:js; toolbar: true; auto-links: false;">
var calcu = {
    add: function(a, b){
        return a + b;
    },
    subtract: function(a, b){
        return a - b;
    }
}
// 此处对外导出模块功能
module.exports = calcu;
</pre>

然后我们来定义一个使用这个模块的文件,名为app.js

<pre class="brush:js; toolbar: true; auto-links: false;">
// 此处引用模块跟nodejs里一样
var app = require('./calcu.js')

alert(calcu.add(8, 5));
alert(calcu.subtract(8, 5));
</pre>

也可以使用 npm 机制加载 node_modules下的模块。

<pre class="brush:js; toolbar: true; auto-links: false;">
var _ = require("underscore")._;

_.each([1, 2, 3], function (ele, idx) {
    alert(idx + ":" + ele);
});
</pre>

假如直接在html文件里引用app.js文件的话,肯定会报错。

执行browserify命令

<pre class="brush:js; toolbar: true; auto-links: false;">
browserify app.js app-all.js
</pre>

上面的app-all.js可以自定义别的名字,最后只需要把这个新生成的文件引入到html文件内即可,不用再引入别的文件

<pre class="brush:js; toolbar: true; auto-links: false;">
<!doctype html>
<html>
<head>
    <title></title>
    <meta charset="utf8">
</head>
<body>  
    <script src="js/app-all.js"></script>
</body>
</html>
</pre>

最后在Chrome里打开这个页面进行测试,

calcu.js文件也可以拿到Node.js里去引用,因为它遵守commonjs规范。

[size=5]源代码[/size]
[list][li]本文代码:https://github.com/guyoung/GeneCocosMVC/tree/master/MVCHelloWorld-Part02[/li][li]项目地址:https://github.com/guyoung/GeneCocosMVC[/li][/list][size=4]
编译及运行
[/size]

browserify
<pre class="brush:shell; toolbar: true; auto-links: false;">
browserify MVCHelloWorld-Part02\js\app.js -o MVCHelloWorld-Part02\js\app-all.js
</pre>
or
<pre class="brush:shell; toolbar: true; auto-links: false;">
browserify MVCHelloWorld-Part02\js\app.js -o MVCHelloWorld-Part02\js\app-all.js --debug
</pre>
uglifyjs
<pre class="brush:shell; toolbar: true; auto-links: false;">
uglifyjs MVCHelloWorld-Part02\js\app-all.js -o MVCHelloWorld-Part02\js\app-all.js
</pre>
http-server
<pre class="brush:shell; toolbar: true; auto-links: false;">
node_modules.bin\http-server.cmd
</pre>

[hr]https://github.com/guyoung/GeneCocosMVC
By Guyoung Studio
http://www.guyoung.net

1赞

为什么没人顶这么好的帖子???

[size=5]MVC[/size]

MVC全名是Model View Controller,是模型(Model)-视图(View)-控制器(Controller)的缩写,一种软件设计典范,用一种业务逻辑、数据、界面显示分离的方法组织代码,将业务逻辑集中到一个部件里面,在改进和个性化定制界面及用户交互的同时,不需要重新编写业务逻辑。MVC被独特的发展起来用于映射传统的输入、处理和输出功能在一个逻辑的图形化用户界面的结构中。
[attachment=80494]

MVC主要把逻辑层和表现层进行了解耦,将一个问题划分成了不同的关注点。增强了应用的稳定性,易修改性和易复用性。
[list][li]视图(View):就是用户看到并与之交互的界面。它不做数据逻辑方面的工作,通常来说就是显示从模型中获得的数据,或者获取用户的操作。当模型更新时,它需要得知模型已经更新并获取更新后的数据以刷新界面。因此需要在模型处注册关注该模型的视图,以便模型通知视图更新显示。[/li][li]模型(Model):用于封装与应用程序的业务逻辑相关的数据以及对数据的处理方法。“模型”有对数据直接访问的权力,例如对数据库的访问。因此它常常也用来与远程服务器作交互,作为一个与外界访问的代理。加载外部资源,如图片,xml等也是在这里操作。模型不关心自己会被如何操作或显示,只要在数据更新时,向关注它的视图发送通知则可。[/li][li]控制器(Controller):本身不作业务逻辑操作,它负责关联视图和模型,就像一个纽带一样。同时它也负责应用的流程。通常控制器会获得模型和视图的实例,然后条用它们内部的函数。[/li][/list][size=5]
[/size]
[size=5]PureMVC[/size]
PureMVC 是在基于模型、视图和控制器 MVC 模式建立的一个轻量级的应用框架,这是一个开源框架,它最初是被用于 ActionScript 3 语言使用的 Adobe Flex、Flash 和 AIR 之上,现在已经移植到几乎所有主要的软件平台之上。
[attachment=80495]
[size=5]
构造PureMVC应用
[/size]
在 PureMVC 实现的经典 MVC 元设计模式中,Model、View 和 Controller 分别由一个单例类来管理,合称为核心层或核心角色。 另外,在 PureMVC 中还提供了一个单例类 —— Façade,主要作用是作为与核心层通信的唯一接口,简化开发复杂度。
除了这几个主要对象以外,框架还有如下类 Proxy、Mediator 和 Command。
[list][li]Proxy 对象负责操作数据模型,与远程服务通信存取数据,这样可以保证 Model 层的可移植性。通常 Proxy 对象的引用保存在 Model 中。[/li][li]View 保存对 Mediator 对象的引用。由 Mediator 对象来操作具体的视图组件(View Component,它的作用还包括:添加事件监听器,发送或接收 Notification,直接改变视图组件的状态。通过这样,就可以把视图和控制它的逻辑分离开来。[/li][li]Command 对象是无状态的,只在需要时才被创建。Command 可以获取 Proxy 对象并与之交互,发送 Notification,执行其他的 Command。经常用于复杂的或系统范围的操作,如应用程序的“启动”和“关闭”。应用程序的业务逻辑应该在这里实现。[/li][/list]除了基本的对象结构以外,为了解耦合,PureMVC 框架中引入了事件机制,这是个非常简单观察者设计模式,所有的事件都是一个 Notification,不同对象之间通过 Notification 来同步操作和交换信息。例如如果想更新界面中某个 Mediator,首先我们定义 Notification 用于此目的,然后注册 Mediator 监听该 Notification,然后就可以在程序中任何地方生成一个 Notification,通过事件机制,Mediator 就会接收到 Notification,然后更新需要的部分。整个过程 Mediator 只和 Notification 有关,没有其他依赖,有效的降低了对象之间的依赖程度。
[size=4]
Facade
[/size]
Facade子类——AppFacade.js
<pre class="brush:js; toolbar: true; auto-links: false;">
var AppFacade = module.exports = puremvc.define(
    // CLASS INFO
    {
        name: 'AppFacade',
        parent: puremvc.Facade,

        constructor: function (multitonKey) {
            puremvc.Facade.call(this, multitonKey);
        }
    },
    // INSTANCE MEMBERS
    {
        initializeController: function () {
            puremvc.Facade.prototype.initializeController.call(this);
            this.registerCommand(AppFacade.STARTUP, StartupCommand);
        },
        initializeModel: function () {
            puremvc.Facade.prototype.initializeModel.call(this);
        },
        initializeView: function () {
            puremvc.Facade.prototype.initializeView.call(this);
        },
        startup: function () {
            this.sendNotification(AppFacade.STARTUP);
        }
    },
    // STATIC MEMBERS
    {
        getInstance: function(multitonKey) {
            var instanceMap = puremvc.Facade.instanceMap;
            var instance = instanceMap[multitonKey];
            if(instance) {
                return instance;
            }
            return instanceMap[multitonKey] = new AppFacade(multitonKey);
        },
        NAME: 'AppFacade',
        STARTUP: 'Startup'
    }
);
</pre>

类方法getInstance用于返回AppFacade的单例。Facade是pureMVC的核心,标准版的Facade只会存在一个,多核版本Facade会有多个,它的实例会在instanceMap中保存。
[size=4]
Model
[/size]
Proxy子类——AppConfigProxy.js
<pre class="brush:js; toolbar: true; auto-links: false;">
module.exports = puremvc.define
(
    // CLASS INFO
    {
        name: 'model.proxy.AppConfigProxy',
        parent:puremvc.Proxy,

        constructor: function() {
            puremvc.Proxy.call(this);
        }
    },

    // INSTANCE MEMBERS
    {
        _config: null,

        onRegister: function() {
            this.loadData();
        },
        loadData: function() {
            var self = this;
            var xmlhttp = new XMLHttpRequest();
            var url = "js/app.config";

            xmlhttp.onreadystatechange = function() {
                if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
                    self._config = JSON.parse(xmlhttp.responseText);

                    self.sendNotification('WriteAppConfig');
                }
            }
            xmlhttp.open("GET", url, true);
            xmlhttp.send();
        },
        getAppName: function() {
            return this._config.AppName;
        },
        getAppVersion: function() {
            return this._config.AppVersion;
        },
        getAppDescription: function() {
            return this._config.AppDescription;
        }
    },
    // STATIC MEMBERS
    {
        NAME: 'AppConfigProxy'
    }
);
</pre>

载入AppConfig数据,并发送Notification。
[size=4]
View
[/size]
Mediator子类——AppMediator.js
<pre class="brush:js; toolbar: true; auto-links: false;">
module.exports = puremvc.define
(
    // CLASS INFO
    {
        name: 'view.mediator.AppMediator',
        parent: puremvc.Mediator,
        constructor: function() {
            puremvc.Mediator.call(this, this.constructor.NAME);
        }
    },
    // INSTANCE MEMBERS
    {
        _appConfigProxy: null,

        /** @override */
        listNotificationInterests: function () {
            return [ 'WriteAppConfig' ];
        },

        /** @override */
        handleNotification: function (notification) {
            switch (notification.getName()) {
                case 'WriteAppConfig':
                    document.write('<p>AppName:' + this._appConfigProxy.getAppName() + '</p>');
                    document.write('<p>AppVersion:' + this._appConfigProxy.getAppVersion() + '</p>');
                    document.write('<p>AppVersion:' + this._appConfigProxy.getAppDescription() + '</p>');

                    break;
            }
        },

        /** @override */
        onRegister: function () {
            this._appConfigProxy  = this.facade.retrieveProxy('AppConfigProxy');
        },

        /** @override */
        onRemove: function () {

        }
    },
    // STATIC MEMBERS
    {
    NAME: 'AppMediator'
    }
);
</pre>

接收Notification,输出信息。
[size=4]
Controller
[/size]
Command子类——StartupCommand.js
<pre class="brush:js; toolbar: true; auto-links: false;">
module.exports = puremvc.define
(
    // CLASS INFO
    {
        name: 'controller.command.StartupCommand',
        parent:puremvc.SimpleCommand
    },
    // INSTANCE MEMBERS
    {
        /** @override */
        execute: function (notification)
        {
            this.facade.registerProxy( new AppConfigProxy() );
            this.facade.registerMediator( new AppMediator() );
        }
    },
    // STATIC MEMBERS
    {
        NAME: 'StartupCommand'
    }
);
</pre>

初始化及注册ConfigProxy、AppMediator。

[size=4]
调用PureMVC
[/size]
<pre class="brush:js; toolbar: true; auto-links: false;">
(function() {
    var key = 'MVC_HELLOWORLD';
    AppFacade.getInstance(key).startup();
})();
</pre>
[size=5]
源代码
[/size]
[list][li]本文代码:https://github.com/guyoung/GeneCocosMVC/tree/master/MVCHelloWorld-Part03[/li][li]项目地址:https://github.com/guyoung/GeneCocosMVC[/li][/list][size=4]
编译及运行
[/size]
browserify
<pre class="brush:shell; toolbar: true; auto-links: false;">
browserify MVCHelloWorld-Part03\js\app.js -o MVCHelloWorld-Part03\js\app-all.js
</pre>
or
<pre class="brush:shell; toolbar: true; auto-links: false;">
browserify MVCHelloWorld-Part03\js\app.js -o MVCHelloWorld-Part03\js\app-all.js --debug
</pre>
uglifyjs
<pre class="brush:shell; toolbar: true; auto-links: false;">
uglifyjs MVCHelloWorld-Part03\js\app-all.js -o MVCHelloWorld-Part03\js\app-all.js
</pre>
http-server
<pre class="brush:shell; toolbar: true; auto-links: false;">
node_modules.bin\http-server.cmd
</pre>[size=5]
[/size]
[hr]https://github.com/guyoung/GeneCocosMVC
By Guyoung Studio
http://www.guyoung.net

演示地址:

http://genecocosmvc.coding.io/MVCHelloWorld/index.html

楼主幸苦,好贴啊。我来迟了。 :6:

楼主写的好详细,顶完再细细研究:867:

请教楼主,这种方法支持原生开发方式吗?
我的意思是使用jsb,在ios或安卓上,不使用浏览器

一个简单Cocos2d-js游戏的策划、流程定义
[size=5]游戏策划[/size]
游戏场景流程
[attachment=80746]

[size=5]游戏状态机[/size]
使用有限状态机实现流程控制。
有限状态机(finite-state machine,缩写:FSM)又称有限状态自动机,简称状态机,是表示有限个状态以及在这些状态之间的转移和动作等行为的数学模型。
[attachment=80747]

[size=5]创建状态机对象[/size]
[size=4]场景状态[/size]
<pre class="brush:js; toolbar: true; auto-links: false;">
var SceneState = GeneJS.Class({
    'public const MENU_MEDIATOR': 'MenuMediator',
    'public const HELLO_MEDIATOR': 'HelloMediator',
    'public const GAME_MEDIATOR': 'GameMediator',
    'public const GAME_OVER_MEDIATOR': 'GameOverMediator',
    'public const DRAW_MEDIATOR': 'DrawMediator',
    'public const BOOK_MEDIATOR': 'BookMediator'
});
</pre>

[size=4]场景动作[/size]
<pre class="brush:js; toolbar: true; auto-links: false;">
var SceneAction = GeneJS.Class({
    'public const HOME_ACTION': 'HomeAction',
    'public const MENU_ACTION': 'MenuAction',
    'public const HELLO_ACTION': 'HelloAction',
    'public const GAME_ACTION': 'GameAction',
    'public const GAME_OVER_ACTION': 'GameOverAction',
    'public const DRAW_ACTION': 'DrawAction',
    'public const BOOK_ACTION': 'BookAction'
});
</pre>

[size=4]状态机[/size]
<pre class="brush:js; toolbar: true; auto-links: false;">
var SceneFsm = GeneJS.Class({
'public createFsm': function() {
    var fsm = {
        // 开始状态
        "@initial": SceneState.(&#39;MENU_MEDIATOR&#39;), &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&quot;state&quot;: [ &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;{ &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;// Menu &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&quot;@name&quot;: SceneState.('MENU_MEDIATOR'),
                //"@changed": SceneTransition ,
                "transition": [
                    {
                        "@action": SceneAction.(&#39;HELLO_ACTION&#39;), &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&quot;@target&quot;: SceneState.('HELLO_MEDIATOR')
                    },
                    {
                        "@action": SceneAction.(&#39;GAME_ACTION&#39;), &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&quot;@target&quot;: SceneState.('GAME_MEDIATOR')
                    },
                    {
                        "@action": SceneAction.(&#39;DRAW_ACTION&#39;), &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&quot;@target&quot;: SceneState.('DRAW_MEDIATOR')
                    },
                    {
                        "@action": SceneAction.(&#39;BOOK_ACTION&#39;), &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&quot;@target&quot;: SceneState.('BOOK_MEDIATOR')
                    }
                ]
            },
            {
                // Hello
                "@name": SceneState.(&#39;HELLO_MEDIATOR&#39;), &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;//&quot;@changed&quot;: SceneTransition , &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&quot;transition&quot;: [ &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;{ &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&quot;@action&quot;: SceneAction.('HOME_ACTION'),
                        "@target": SceneState.(&#39;MENU_MEDIATOR&#39;) &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;} &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;] &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;}, &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;{ &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;// Game &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&quot;@name&quot;: SceneState.('GAME_MEDIATOR'),
                //"@changed": SceneTransition ,
                "transition": [
                    {
                        "@action": SceneAction.(&#39;GAME_OVER_ACTION&#39;), &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&quot;@target&quot;: SceneState.('GAME_OVER_MEDIATOR')
                    }
                ]
            },
            {
                // GameOver
                "@name": SceneState.(&#39;GAME_OVER_MEDIATOR&#39;), &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;//&quot;@changed&quot;: SceneTransition , &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&quot;transition&quot;: [ &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;{ &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&quot;@action&quot;: SceneAction.('HOME_ACTION'),
                        "@target": SceneState.(&#39;MENU_MEDIATOR&#39;) &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;} &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;] &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;}, &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;{ &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;// Draw &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&quot;@name&quot;: SceneState.('DRAW_MEDIATOR'),
                //"@changed": SceneTransition ,
                "transition": [
                    {
                        "@action": SceneAction.(&#39;HOME_ACTION&#39;), &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&quot;@target&quot;: SceneState.('MENU_MEDIATOR')
                    }
                ]
            },
            {
                // Book
                "@name": SceneState.(&#39;BOOK_MEDIATOR&#39;), &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;//&quot;@changed&quot;: SceneTransition , &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&quot;transition&quot;: [ &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;{ &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&quot;@action&quot;: SceneAction.('HOME_ACTION'),
                        "@target": SceneState.$('MENU_MEDIATOR')
                    }
                ]
            }
        ]
    };

    return fsm;
}
});
</pre>

[size=5]状态机初始化[/size]
PureMVC框架提供了FSM实现。
[size=4]定义InjectFSMCommand[/size]
<pre class="brush:js; toolbar: true; auto-links: false;">
module.exports = puremvc.define
(
// CLASS INFO
{
    name: 'controller.command.InjectFSMCommand',
    parent:puremvc.SimpleCommand
},
// INSTANCE MEMBERS
{
    /** @override */
    execute: function (notification)
    {
        cc.log('InjectFSMCommand execute');

        var sceneFsm = new SceneFsm();
        var fsm = sceneFsm.createFsm();

        var injector = new puremvc.statemachine.FSMInjector(fsm);
        injector.initializeNotifier(this.multitonKey);
        injector.inject();

    }
},
// STATIC MEMBERS
{
    NAME: 'PrepControllerCommand'
}
);
</pre>

[size=4]StartupCommand调用InjectFSMCommand[/size]
<pre class="brush:js; toolbar: true; auto-links: false;">
module.exports = puremvc.define
(
// CLASS INFO
{
    name: 'controller.command.StartupCommand',
    parent:puremvc.MacroCommand
},
// INSTANCE MEMBERS
{
    /** @override */
    initializeMacroCommand: function (notification)
    {
        this.addSubCommand(PrepModelCommand);
        this.addSubCommand(PrepViewCommand);
        this.addSubCommand(PrepControllerCommand);
        this.addSubCommand(InjectFSMCommand );

    }
},
// STATIC MEMBERS
{
    NAME: 'StartupCommand'
}
);
</pre>

[size=4]AppMediator监听StateMachine Notification[/size]
<pre class="brush:js; toolbar: true; auto-links: false;">
module.exports = puremvc.define
(
// CLASS INFO
{
     name: 'view.mediator.AppMediator',
     parent: puremvc.Mediator,
     constructor: function() {
         puremvc.Mediator.call(this, this.constructor.NAME);
     }
},
// INSTANCE MEMBERS
{
     /** @override */
     listNotificationInterests: function () {
         return [
             puremvc.statemachine.StateMachine.CHANGED
         ];
     },

     /** @override */
     handleNotification: function (notification) {
         switch (notification.getName()) {
             case puremvc.statemachine.StateMachine.CHANGED:
                 alert(notification.getBody().name);

                 break;
         }
     },

     /** @override */
     onRegister: function () {

      },

     /** @override */
     onRemove: function () {

     }
},
// STATIC MEMBERS
{
     NAME: 'AppMediator'
}
);
</pre>

[size=5]
源代码
[/size]
[list][li]本文代码:https://github.com/guyoung/GeneCocosMVC/tree/master/MVCHelloWorld-Part04[/li][li]项目地址:https://github.com/guyoung/GeneCocosMVC[/li][/list][size=4]
编译及运行
[/size]
browserify
<pre class="brush:shell; toolbar: true; auto-links: false;">
browserify MVCHelloWorld-Part04\js\app.js -o MVCHelloWorld-Part04\js\app-all.js
</pre>
or
<pre class="brush:shell; toolbar: true; auto-links: false;">
browserify MVCHelloWorld-Part04\js\app.js -o MVCHelloWorld-Part04\js\app-all.js --debug
</pre>
uglifyjs
<pre class="brush:shell; toolbar: true; auto-links: false;">
uglifyjs MVCHelloWorld-Part04\js\app-all.js -o MVCHelloWorld-Part04\js\app-all.js
</pre>
http-server
<pre class="brush:shell; toolbar: true; auto-links: false;">
node_modules.bin\http-server.cmd
</pre>[size=5]
[/size]
[hr]https://github.com/guyoung/GeneCocosMVC
By Guyoung Studio
http://www.guyoung.net

学习一下, 多谢分享

— Begin quote from ____

引用第7楼zj167793于2014-11-13 11:06发表的 :
请教楼主,这种方法支持原生开发方式吗?
我的意思是使用jsb,在ios或安卓上,不使用浏览器 http://www.cocoachina.com/bbs/job.php?action=topost&tid=238648&pid=1098310

— End quote

同问,请楼主解答。

project.json只需载入生成后的文件即可

{
“debugMode” : 1,
“showFPS” : true,
“frameRate” : 60,
“id” : “gameCanvas”,
“renderMode” : 0,
“engineDir”:"…/…/frameworks/cocos2d-html5",

"modules" : "cocos2d"],

"jsList" : 
app-all.js
]

}

牛!!!一直在想nodejs的实现方式

我想问一下,多个FSM实例,如何操作?
var injector1 = new puremvc.statemachine.FSMInjector(FSM1);
injector1.initializeNotifier(this.multitonKey);
injector1.inject();

var injector2 = new puremvc.statemachine.FSMInjector(FSM2);
injector2.initializeNotifier(this.multitonKey);
injector2.inject();

测试只有第一个会监听到

请问楼主,我用你的方法,在native上测试,提示 TypeError: cc.Layer.extend is not a function 该如何解决呢?期待回复~~~:7:

感谢分享~~