GC DevKit 快速入门 -- 游戏概览(二)
接上节 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
监听器来捕获点击与触摸事件,最后,我们出发一个事件用以通知标题视图已经运行。
事件流程
我们目前只看到如何捕获用户的输入并传递给主程序,下面来介绍整个游戏的事件流程,之后会看到其余的事件
程序成功运行,并装载好游戏后,用户首先会进入标题视图。单击开始按钮后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
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· .NET周刊【3月第1期 2025-03-02】
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· [AI/GPT/综述] AI Agent的设计模式综述
2008-04-13 (c#)数据结构与算法分析 --树