接上节 http://www.cnblogs.com/hangxin1940/archive/2013/04/11/3011555.html ## 创建屏幕视图 当导入屏幕视图类后,我们会在`initUI`函数中对它进行实例化,这时,游戏引擎就准备就绪了。 var titlescreen = new TitleScreen(), gamescreen = new GameScreen(); 之后的内容会详细介绍屏幕视图的构造的。 当游戏引擎将场景创建好后,它会被存储在 `GC.app.view` 的根节点。任何 `View` 只要附加到根节点上,都会被呈现到屏幕上,而根节点视图有些特殊,它是 `ui.StackView` 的实例,`ui.StackView` 又是 `ui.View` 的子类, 它另外的功能就是压入和弹出视图栈,并且做相应的转换。 这里还有一些声音相关的代码,我们将会在结尾看到详细的说明。`soundcontroller`模块会返回一个 `AudioManager` 的单例对象,当我们转到游戏视图时,它会播放关卡音乐。 ## 事件管理 在事件处理代码中,我们在两个屏幕视图中监听了游戏开始与结束的事件,并且管理 `StackView` titlescreen.on('titlescreen:start', function () { //... GC.app.view.push(gamescreen); gamescreen.emit('app:start'); }); gamescreen.on('gamescreen:end', function () { //... GC.app.view.pop(); }); 在收到游戏开始事件后,游戏视图会被压入`rootView`视图栈中,这里没有必要将已存在与试图栈中的标题视图删除,因为压入栈顶后这个游戏视图已经可见。默认情况下,压入另一个视图进入视图栈时会有一个横向滚动的动画,当然也可以关闭动画。下面我们通过标题视图来看看整个程序的事件流程的细节。 ## 游戏等待状态: `TitleScreen.js` 标题视图是 `TitleScreen`类 的一个实例,在 `./src/TitleScreen.js` 文件中定义,在 `./src/Application.js` 中被实例化一次并加入到根书图,在整个生命周期中存在。 ## 视图剖析 `TitleScreen`类的视图结构相对来说是比较简单的。它由一个图片来填充背景,以及被放置在背景中央并且看不见的一个视图,它被作为`Play`按钮。这个按钮将检测输入事件,然后向主程序发送一个事件并通知用户准备好开始游戏。下面来分析这个类: import ui.View; import ui.ImageView; exports = Class(ui.ImageView, function (supr) { this.init = function (opts) { opts = merge(opts, { x: 0, y: 0, image: "resources/images/title_screen.png" }); supr(this, 'init', [opts]); var startbutton = new ui.View({ superview: this, x: 58, y: 313, width: 200, height: 100 }); startbutton.on('InputSelect', bind(this, function () { this.emit('titlescreen:start'); })); }; }); 首先,需要导入一下两个模块: import ui.View; import ui.ImageView; `ui.View`类被用作一个基础的显示对象将元素渲染在屏幕上,要做到这点,一个视图必须得附加到游戏的场景中(视图树中的节点)。 视图具有样式属性,用来控制如何被渲染到屏幕上,并且可以触发和订阅事件,也可以增加/删除子视图或父视图。 `ui.ImageView` 类是 `ui.View`的子类,不但`ui.View`继承了父类的属性,而且还可以在视图中设置图像。 现在我们已经导入了所依赖的模块,现在可以定义我们的 `TitleScreen` 类。 exports = Class(ui.ImageView, function (supr) { this.init = function (opts) { opts = merge(opts, { //... }); supr(this, 'init', [opts]); }; }); 每一个类中定义的`init`方法都会在实例化的时候被执行,`merge`函数用来合并属性(犹如两个集合选取合集),用来将它合并的属性传递给构造函数。这之后,调用父类的`init`方法,并传入合并后的属性对象。 下面是完整的`init`方法: this.init = function (opts) { opts = merge(opts, { x: 0, y: 0, image: "resources/images/title_screen.png" }); supr(this, 'init', [opts]); this.build(); }; `title_screen.png`将会作为 `ui.ImageView`类的`image`属性加载。`supr`函数将当前对象以参数形式传递给父类来进行初始化。这三个参数分别是当前对象,以及将要调用的当前对象的方法名,还有包含当前对象属性的数组。 ## `Play`按钮 还记得在`init`结束时调用的这个`build`函数么: this.build = function() { var startbutton = new ui.View({ superview: this, x: 58, y: 313, width: 200, height: 100 }); startbutton.on('InputSelect', bind(this, function () { this.emit('titlescreen:start'); })); }; 在标题视图中,我们创建了一个不可见的开始按钮,它位于背景图的中央,这个按钮视图通过`superview`属性附加于当前类,然后通过`InputSelect`监听器来捕获点击与触摸事件,最后,我们出发一个事件用以通知标题视图已经运行。 ## 事件流程 我们目前只看到如何捕获用户的输入并传递给主程序,下面来介绍整个游戏的事件流程,之后会看到其余的事件 ![devkit](http://docs.gameclosure.com/guide/assets/game-walkthrough/game-event-flow.png "devkit") 程序成功运行,并装载好游戏后,用户首先会进入标题视图。单击开始按钮后`titlescreen:start`事件会被发出,并被上层的程序捕获,在那里,游戏视图将会加载,之后,用户开完游戏,直到 `gamescreen:end` 事件发出,上层代码删除游戏试图,最终又回到标题视图。 ## 进行游戏: `GameScreen.js` `GameScreen`类定义在 `./src/GameScreen.js` 文件,它也是项目中最长的代码了。其中大部分代码都是在构建视图结构,我们在前面已经了解其中的一些细节。除了建立子视图与游戏资源,它还定义了游戏逻辑相关的函数以及游戏结束时显示得分的方法。后面我们将会看到比较重要的一些代码。 ## 设置屏幕 与之前的代码一样,首先会导入一些模块 import animate; import device; import ui.View; import ui.ImageView; import ui.TextView; import src.MoleHill as MoleHill; 之前已经讲过 `ui.View`, `ui.ImageView`, 与 `device`,现在主要看看其他的模块。 `ui.TextView`的作用,应该很容易猜到,它主要是显示文字,除了常规试图的样式之外,还可以对它进行字号与颜色的设置。 `animate`模块主要用来为视图、对象以及样式生成动画,它所生成的是`补间动画`,也就在移动位置之间进行插值,以生成动画。更重要的是,它针对原生设备进行了专门的优化,我们应该在游戏中善加利用此模块,而不是手动的进行额外的计算。之后的代码中我们会遇到它,到时候在进行详细的说明。 最后的一个模块导入语句比较有意思: import src.MoleHill as MoleHill; `src.MoleHill`类引用了工程目录中的`./src/MoleHill.js` 文件。除了Devkit引擎的模块与类之外,我们还可以自己定义,并且被项目导入并引用。`as`语句用来给模块或类起个别名,方便我们更加方便的引用,不必输入繁长的路径。 同`TitleScreen`类相同,`GameScreen`也只在`Application.js`中被实例化一次,`init`函数用来定义尺寸以进行屏幕适配,并且将绿草地填充为背景,通过`supr`函数为父类传递构造属性。 this.init = function (opts) { opts = merge(opts, { x: 0, y: 0, width: 320, height: 480, backgroundColor: '#37B34A' }); supr(this, 'init', [opts]); this.build(); }; this.build = function() { this.on('app:start', bind(this, start_game_flow)); this._scoreboard = new ui.TextView({ superview: this, x: 0, y: 15, width: device.width, height: 50, autoSize: false, size: 38, verticalAlign: 'middle', textAlign: 'center', multiline: false, color: '#fff' }); var x_offset = 5; var y_offset = 160; var y_pad = 25; var layout = [[1, 0, 1], [0, 1, 0], [1, 0, 1]]; this._molehills = []; //循环,布局网格,先是行然后是列 for (var row = 0, len = layout.length; row < len; row++) { for (var col = 0; col < len; col++) { //如果是1,则创建一个鼹鼠 if (layout[row][col] !== 0) { var molehill = new MoleHill(); molehill.style.x = x_offset + col * molehill.style.width; molehill.style.y = y_offset + row * (molehill.style.height + y_pad); this.addSubview(molehill); this._molehills.push(molehill); //打到鼹鼠时,更新得分 molehill.on('molehill:hit', bind(this, function () { if (game_on) { score = score + hit_value; this._scoreboard.setText(score.toString()); } })); } } } this._countdown = new ui.TextView({ superview: this._scoreboard, visible: false, x: 260, y: -5, width: 50, height: 50, size: 24, color: '#fff', opacity: 0.7 }); }; `build`函数的代码比之前看到过的稍微有点长,但是它很容易看懂。首先,在启动游戏时监听`app:start`事件,`app:start`是游戏的根所派发的事件,当开始按钮被处理后,会执行`start_game_flow`函数。 定义好用户得分牌后,会在屏幕上定义鼹鼠洞网格以及定义它们的位置与大小,这里创建了一定数量的`MoleHill`对象,将它们作为子视图附加到`GameScreen`对象,并且为每一个`MoleHill`对象都注册了敲打事件用以更新用户得分。 `MoleHill`类定义在工程中的`./src/MoleHill.js`文件,稍后会说到。基本上它是一个图像的集合,用来生成鼹鼠出洞,敲头等复合图像,以及动画相关的代码。 最后,创建一个倒计时文本,作为得分牌的子视图。 GC DevKit 快速入门 -- 游戏概览(三) http://www.cnblogs.com/hangxin1940/archive/2013/04/13/3017640.html
转载于:https://www.cnblogs.com/hangxin1940/archive/2013/04/13/3015553.html