近期出现一款魔性的消除类HTML5游戏《神奇的六边形》,今天我们一起来看看如何通过开源免费的青瓷引擎(www.zuoyouxi.com)来实现这款游戏。
(点击图片可进入游戏体验)
因内容太多,为方便大家阅读,所以分成四部分来讲解。
本文为第二部分,主要包括:
6. 历史最高分显示
7. 当前分数显示
8. 绘制棋盘
9. 形状池设计与实现
10. 形状预制的实现
若要一次性查看所有文档,也可点击这里。
六. 历史最高分显示
对于DOM节点,其实就是个div,可以指定其样式,指定其样式表类名,也可以内嵌html元素。
在Scripts/ui下新建文件:BestScore.js,处理最高分数的显示逻辑,并将此逻辑脚本挂载到UIRoot/best节点上。
/**
* 绘制最高分数
*/
var BestScore = qc.defineBehaviour('qc.tetris.BestScore', qc.Behaviour, function() {
var self = this;
self.runInEditor = true;
}, {
}); /**
* 初始化处理
*/
BestScore.prototype.awake = function() {
var self = this, div = self.gameObject.div;
div.className = 'score_best';
self.setScore(qc.Tetris.score.current);
}; /**
* 更新最新的高分
*/
BestScore.prototype.setScore = function(best) {
this.gameObject.div.innerHTML = 'Best: ' + best;
};
本脚本可以在编辑器下运行(方便在编辑状态下查看效果),首先设置DOM的样式表类名为score_best,然后获取最高分数并显示之。
2. 增加score_best样式表。打开Assets/css/style.css,添加样式表:
.score_best {
font-weight:;
font-size:30px;
color: #ffffff; text-align: right;
}
3.刷新下页面,查看效果:
4. 注意:更改样式表目前需要刷新页面才能看到效果。
七. 当前分数显示
1. 在Scripts/ui下新建文件:CurrentScore.js,处理当前分的显示逻辑,并将此逻辑脚本挂载到UIRoot/score节点上。
/**
* 绘制当前分数
*/
var CurrentScore = qc.defineBehaviour('qc.tetris.CurrentScore', qc.Behaviour, function() {
var self = this;
self.runInEditor = true;
}, {
}); /**
* 初始化处理
*/
CurrentScore.prototype.awake = function() {
var self = this, div = self.gameObject.div; div.className = 'score_current';
self.setScore(qc.Tetris.score.current);
}; /**
* 更新最新的分数
*/
CurrentScore.prototype.setScore = function(best) {
this.gameObject.div.innerHTML = '' + qc.Tetris.score.current;
};
本脚本可以在编辑器下运行(方便在编辑状态下查看效果),首先设置DOM的样式表类名为score_current,然后获取当前分数并显示之。
2.增加score_current样式表。打开Assets/css/style.css,添加样式表:
.score_current{
color: #ffffff;
font-weight:;
font-size:50px;
text-align: center;
}
3.刷新下页面,查看效果
八. 绘制棋盘
DOM的层次
DOM节点可以绘制在最底层(当工程背景设置为非透明时,将不可见),也可以绘制在最上层(在所有精灵、UIImage等节点之上)。
本棋盘放在最底层,因为棋盘上面还需要拖拽形状、显示可放入指示等。方法是:选中board节点,在Inspector中设置Pos=BACK:
开始绘制棋盘
棋盘中的每个格子都作为一个div元素,采用绝对定位。
格子可能表现为7种图片形式(空时为灰色,其他为形状的对应颜色),这7种图片通过不同的样式类来区分。打开Assets/css/style.css,加入如下几个样式表:
.board { width: 61px; height: 67px; position: absolute; background-repeat: no-repeat; }
.board_gray {
background-image: url("../raw/gray.png");
}
.board_blue {
background-image: url("../raw/blue.png");
}
.board_cyan {
background-image: url("../raw/cyan.png");
}
.board_green {
background-image: url("../raw/green.png");
}
.board_lightyellow {
background-image: url("../raw/lightyellow.png");
}
.board_red {
background-image: url("../raw/red.png");
}
.board_yellow {
background-image: url("../raw/yellow.png");
}
这些样式表指明了棋盘格子中的图片
3. 编辑Tetris.js,加入IMAGES常量,指明在不同的值下面格子所使用的className
window.Tetris = qc.Tetris = {
// 棋盘的大小(半径)
SIZE: 4, // 棋盘中,每个格子的宽度和高度
BLOCK_W: 61,
BLOCK_H: 67, // 所有的格子图片
IMAGES: [
'gray', //
'blue', //
'cyan', //
'green', //
'lightyellow', //
'red', //
'yellow' //
], // 所有的操作指令集合
operation: {}
};
4. 在Scripts/ui下创建脚本BoardUI.js,负责棋盘的绘制逻辑:
var s = qc.Serializer; /**
* 管理棋盘的数据并绘制棋盘
*/
var BoardUI = qc.defineBehaviour('qc.tetris.BoardUI', qc.Behaviour, function() {
var self = this; /**
* 棋盘的棋子元素
*/
self.pieces = {}; // 本脚本在编辑模式下可以运行
self.runInEditor = true;
}, {
linePrefab: s.PREFAB
}); /**
* 初始化处理
*/
BoardUI.prototype.awake = function() {
var self = this;
self.reset(); // 立刻重绘制下
self.redraw(); // 设置游戏画布的背景色
self.gameObject.div.parentNode.style.background = '#1F1E1E'; // 缓存图片,防止在图片切换过程中出现卡顿
if (self.game.device.editor) return;
qc.Tetris.IMAGES.forEach(function(c) {
var div = document.createElement('div');
div.className = 'board board_' + c;
div.style.left = '-2000px';
div.style.left = '-2000px';
self.gameObject.div.appendChild(div);
});
}; /**
* 重绘棋盘
* @private
*/
BoardUI.prototype.redraw = function() {
var self = this; // 绘制背景
self.drawBackground();
}; /**
* 绘制棋盘背景
*/
BoardUI.prototype.drawBackground = function() {
var self = this; for (var pos in self.pieces) {
var div = self.pieces[pos];
div.className = 'board board_' + qc.Tetris.IMAGES[qc.Tetris.board.data[pos].value];
}
}; /**
* 初始化棋盘
*/
BoardUI.prototype.reset = function() {
var self = this, o = self.gameObject; // 构建棋盘数据
if (o.children.length === 0) {
for (var pos in qc.Tetris.board.data) {
var info = qc.Tetris.board.data[pos];
var div = self.pieces[pos] = document.createElement('div');
div.className = 'board board_' + qc.Tetris.IMAGES[info.value];
div.style.left = Math.round(info.x + (o.width - qc.Tetris.BLOCK_W) / 2) + 'px';
div.style.top = Math.round(info.y + (o.height - qc.Tetris.BLOCK_H) / 2) + 'px';
o.div.appendChild(div);
}
}
else {
o.children.forEach(function(child) {
self.pieces[child.name] = child;
});
}
};
本脚本运行在编辑模式下,这样就可以实时看到棋盘。对本脚本做一些解释:
- 属性pieces存放了下面所有的div元素(显示格子),key为其逻辑坐标
- 初始化时,会将底下的所有格子创建出来,并设置上合适的位置(由于在Board.js中计算坐标时,是以棋盘中心为原点;但格子div是以棋盘的左上角为原点,因此代码中做了换算)
- redraw方法中,以格子的值获取对应的className,对应的设置到格子div就可以了
- 工程设置的背景是为透明的,因此在初始化时,顺便将游戏背景的颜色设置为:1F1E1E(最底层div的background-color属性)
- 另外,初始时我们把所有格子的图片都加载进来(方法是创建个屏幕内不可见的div),这样在className切换过程中,就可以直接从本地缓存读取图片,避免加载图片影响体验
5. 将此脚本挂载到board节点上,保存场景并刷新页面,就可以看到效果了:
九. 形状池设计与实现
1. 本游戏中,总共有23种形状,每种类型的形状,其颜色是不同的。
在Scripts/logic下创建脚本Shapes.js,负责各种形状的配置、抽取等。
var Shapes = qc.Tetris.Shapes = {
// 所有可能的形状
tiles: [
// 1个点的
{
value: 1,
list: [[[0, 0]]]
}, {
value: 2,
list: [
[[1, -1], [0, 0], [1, 0], [0, 1]],
[[0, 0], [1, 0], [-1, 1], [0, 1]],
[[0, 0], [1, 0], [0, 1], [1, 1]]
]
}, {
value: 3,
list: [
[[0, -1], [0, 0], [0, 1], [0, 2]],
[[0, 0], [1, -1], [-1, 1], [-2, 2]],
[[-1, 0], [0, 0], [1, 0], [2, 0]]
]
}, {
value: 4,
list: [
[[0, 0], [0, 1], [0, -1], [-1, 0]],
[[0, 0], [0, -1], [1, -1], [-1, 1]],
[[0, 0], [0, 1], [0, -1], [1, 0]],
[[0, 0], [1, 0], [-1, 0], [1, -1]],
[[0, 0], [1, 0], [-1, 0], [-1, 1]]
]
}, {
value: 5,
list: [
[[0, 0], [0, 1], [0, -1], [1, -1]],
[[0, 0], [1, -1], [-1, 1], [-1, 0]],
[[0, 0], [1, -1], [-1, 1], [1, 0]],
[[0, 0], [1, 0], [-1, 0], [0, -1]],
[[0, 0], [1, 0], [-1, 0], [0, 1]]
]
}, {
value: 6,
list: [
[[0, -1], [-1, 0], [-1, 1], [0, 1]],
[[-1, 0], [0, -1], [1, -1], [1, 0]],
[[0, -1], [1, -1], [1, 0], [0, 1]],
[[-1, 1], [0, 1], [1, 0], [1, -1]],
[[-1, 0], [-1, 1], [0, -1], [1, -1]],
[[-1, 0], [-1, 1], [0, 1], [1, 0]]
]
}
], /**
* 重新开始的逻辑
*/
restart: function() {
qc.Tetris.Shapes.pool = [];
for (var i = 0; i < 3; i++) {
qc.Tetris.Shapes.pool.push(qc.Tetris.Shapes.random());
}
}, /**
* 随机抽取一个形状
*/
random: function() {
// 先抽取分类
var math = qc.Tetris.game.math;
var shapes = Shapes.tiles;
var shape = shapes[math.random(0, shapes.length - 1)]; // 再抽子类
var list = shape.list[math.random(0, shape.list.length - 1)];
return {
color: shape.color,
value: shape.value,
list: list
};
}, /**
* 当前的pool数据
*/
pool: []
};
代码说明如下:
- value指明了格子应该使用哪个图片
- list包含了多个形状,形状由数组组成,每个元素指明了逻辑坐标
- pool属性存储了当前屏幕上3个形状的数据信息
修改Tetris.js的qc.initGame方法,最后面添加3个形状的初始化逻辑:
qc.initGame = function(game) {
// 将游戏实例记录下来,便于访问
Tetris.game = game; // 帧率显示为60帧(满帧)
game.time.frameRate = 60; // 初始化分数信息
Tetris.score = new qc.Tetris.Score(); // 构建棋盘对象
Tetris.board = new qc.Tetris.Board(); // 3个形状
qc.Tetris.Shapes.restart();
};
十. 形状预制的实现
本章节我们进行形状的绘制实现,如下图:
1. 在UIRoot/pool节点下,创建一空的Node节点,设置如下图
- 定位在父亲的中心点
- 大小为200*100
- pivot设置为:(0.5, 0.5)
- 本对象需要可以交互(需要被拖放),勾选Interactive。并设置碰撞盒类型为Rectangle(正方形),按图示设置大小(碰撞盒大小会比节点实际大小更大)
2.在Scripts/ui创建文件BlocksUI.js
/**
* 绘制一个形状
*/
var BlocksUI = qc.defineBehaviour('qc.tetris.BlocksUI', qc.Behaviour, function() {
var self = this; // 格子的预置,一个形状下有多个格子
self.blockPrefab = null; // 下属所有的格子
self._blocks = {};
}, {
blockPrefab: qc.Serializer.PREFAB
}); Object.defineProperties(BlocksUI.prototype, {
/**
* 关联的数据
*/
data: {
get: function() { return this._data; },
set: function(v) {
this._data = v;
this.redraw();
}
}, /**
* 第几个?
*/
index: {
get: function() {
return this.gameObject.parent.getChildIndex(this.gameObject);
}
}
}); /**
* 初始化
*/
BlocksUI.prototype.awake = function() {
// 点击时的偏移量
var self = this;
self.offsetY = self.game.device.desktop ? 0 : 50;
}; /**
* 重新绘制区块
*/
BlocksUI.prototype.redraw = function() {
var self = this;
var frame = qc.Tetris.IMAGES[self.data.value];
self.data.list.forEach(function(pos) {
var x = pos[0], y = pos[1];
var block = self.game.add.clone(self.blockPrefab, self.gameObject);
block.find('block').frame = frame + '.png';
block.name = x + '_' + y;
self._blocks[qc.Tetris.makePos(x, y)] = block;
});
self.reset();
}; /**
* 重设区块大小和排列下属格子的位置
*/
BlocksUI.prototype.reset = function() {
var self = this, o = self.gameObject;
for (var pos in self._blocks) {
var p = qc.Tetris.readPos(pos);
var pt = qc.Tetris.board.toWorld(p, qc.Tetris.POOL_DISTANCE_NORMAL);
var block = self._blocks[pos];
block.anchoredX = pt.x;
block.anchoredY = pt.y;
}
};
- 本脚本根据形状的数据,动态创建出格子并显示出来
- blockPrefab为格子的预置,后续步骤创建
- 形状的大小会比棋盘中显示小,因此计算格子的屏幕坐标时,指明了常量:qc.Tetris.POOL_DISTANCE_NORMAL
- 在初始化时,设置了非PC模式下需要做偏移为50。(在手机上拖拽时方式被手指完全挡住,从而看不清形状)
3. 修改Tetris.js,加入POOL_DISTANCE_NORMAL配置:
window.Tetris = qc.Tetris = {
// 棋盘的大小(半径)
SIZE: 4, // 棋盘中,每个格子的宽度和高度
BLOCK_W: 61,
BLOCK_H: 67, // 没有点击时,格子之间的距离
POOL_DISTANCE_NORMAL: 45, ...
4.在上述Blocks节点下,创建空的节点Node,名字修改为block2,属性为:
- 相对于父亲居中显示
- pivot=(0.5, 0.5)
5. 在block2节点下,创建Image节点,名字修改为shadow,属性设置如下:
- 相对于父亲居中显示
- pivot=(0.5, 0.5)
- 大小为60*65
- 使用ui图集
6. 在block2节点下,创建Image节点,名字修改为block,属性设置如下:
- 相对于父亲居中显示
- pivot=(0.5, 0.5)
- 大小为40*45
- 使用ui图集
至此,你的场景应该是:
7. 将block2节点拖入到目录Assets/prefab,创建预置。然后将节点从场景中删除。
8. 将BlocksUI.js挂载到Blocks节点,并设置blockPrefab的值为上步骤创建的预制。设置完成后,将此节点拖入Assets/prefab目录,创建预置。
9. 至此,形状的预置创建完毕了
JS开发HTML5游戏《神奇的六边形》(二)的更多相关文章
-
JS开发HTML5游戏《神奇的六边形》(一)
近期出现一款魔性的消除类HTML5游戏<神奇的六边形>,今天我们一起来看看如何通过开源免费的青瓷引擎(www.zuoyouxi.com)来实现这款游戏. (点击图片可进入游戏体验) 因内容 ...
-
JS开发HTML5游戏《神奇的六边形》(四)
近期出现一款魔性的消除类HTML5游戏<神奇的六边形>,今天我们一起来看看如何通过开源免费的青瓷引擎(www.zuoyouxi.com)来实现这款游戏. (点击图片可进入游戏体验) 因内容 ...
-
JS开发HTML5游戏《神奇的六边形》(三)
近期出现一款魔性的消除类HTML5游戏<神奇的六边形>,今天我们一起来看看如何通过开源免费的青瓷引擎(www.zuoyouxi.com)来实现这款游戏. (点击图片可进入游戏体验) 因内容 ...
-
HTML5外包注意事项-开发HTML5游戏的九大坑与解决方法剖析
随着移动社区兴起,势必带动HTML5的革命.未来一两年内,HTML5移动游戏必将呈现大爆发趋势. 以下是整理的HTML5游戏研发.市场趋势以及渠道布局和技术解决方案的内容.希望大家能从本文中找到对HT ...
-
JAVASCRIPT开发HTML5游戏--斗地主(网络对战PART4)
继之前用游戏引擎(青瓷引擎)做了斗地主单机版游戏之后,这里分享下使用socket.io来实现网络对战,代码可已放到github上,在此谈谈自己整个的开发思路吧. 客户端代码 服务端代码 (点击图片进入 ...
-
javascript开发HTML5游戏--斗地主(单机模式part3)
最近学习使用了一款HTML5游戏引擎(青瓷引擎),并用它尝试做了一个斗地主的游戏,简单实现了单机对战和网络对战,代码可已放到github上,在此谈谈自己如何通过引擎来开发这款游戏的. 客户端代码 服务 ...
-
javascript开发HTML5游戏--斗地主(单机模式part2)
最近学习使用了一款HTML5游戏引擎(青瓷引擎),并用它尝试做了一个斗地主的游戏,简单实现了单机对战和网络对战,代码可已放到github上,在此谈谈自己如何通过引擎来开发这款游戏的. 客户端代码 服务 ...
-
使用 video.js 开发 HTML5 视频页面
时间 2015-05-13 17:11:58 The GIS Guy 原文 http://thegisguy.tk/html5-video-using-video-js/ 主题 Video.js H ...
-
javascript开发HTML5游戏--斗地主(单机模式part1)
最近学习使用了一款HTML5游戏引擎(青瓷引擎),并用它尝试做了一个斗地主的游戏,简单实现了单机对战和网络对战,代码可已放到github上,在此谈谈自己如何通过引擎来开发这款游戏的. 客户端代码 ...
随机推荐
-
主流的单元测试工具之-JAVA新特性-Annotation 写作者:组长 梁伟龙
1:什么是Annotation?Annotation,即“@xxx”(如@Before,@After,@Test(timeout=xxx),@ignore),这个单词一般是翻译成元数据,是JAVA的一 ...
-
Qt使用自带的windeployqt 生成exe来发布软件
集成开发环境 QtCreator 目前生成图形界面程序 exe 大致可以分为两类:Qt Widgets Application 和 Qt Quick Application.下面分别介绍这两类exe ...
-
Jquery各个版本的区别
一: 一般原则是越新越好,jQuery版本是在不断进步和发展的,最新版是当时最高技术水平,也是最先进的技术理念. 但个人的角度来看.是最新版本x.x.0的上一版本最好.比如说1.10.0版,上一版本是 ...
-
【FE前端学习】第二阶段任务-基础
技能学习部分: 1.需要熟练掌握HTML标签以及CSS各个常用属性. 2.掌握CSS3 常用属性 3.掌握jquery的基本用法,对于JS基本逻辑语句需要熟练掌握 上文 [FE前端学习]第二阶段任务- ...
-
循环语句for
循环语句for 格式: for(int i=1/*初始条件*/;i<=100/*循环条件*/;i++/*状态改变*/) { //循环体,执行代码:(break:跳出循环体) } 给出初始条件,先 ...
-
MySQL [Warning] Can’t create test file xxx lower-test(转)
add by zhj:修改的数据库的datadir,然后数据库就无法启动了,错误如下 2014-12-11 16:22:57 26309 [Warning] Can't create test fil ...
-
asp.net用户检测的两种方式
第一种方式(继承System.Web.UI.Page类,重写OnInit方法): public class CheckSession : System.Web.UI.Page { ...
-
.jar是什么文件?(转载)
JAR(Java ARchive,Java 归档)是一种与平台无关的文件格式,可将多个文件合成一个文件.用户可将多个 Java applet 及其所需组件(.class 文件.图像和声音)绑定到 JA ...
-
不老的新丁 Python何以让人着迷
Python是一门美丽的语言.它简单易学,跨平台,而且运转良好.达成了许多Java一直求索的技术目标.一言以蔽之就是:其他的语言是与时代同 步,而Python则是未雨绸缪,而且计划得颇为出色.当然,这 ...
-
Android Multimedia框架总结(七)C++中MediaPlayer的C/S架构补充及MediaService介绍
转载请把头部出处链接和尾部二维码一起转载,本文出自逆流的鱼,文章链接: http://blog.csdn.net/hejjunlin/article/details/52465168 前面一篇主要介绍 ...