JS开发HTML5游戏《神奇的六边形》(四)
近期出现一款魔性的消除类HTML5游戏《神奇的六边形》,今天我们一起来看看如何通过开源免费的青瓷引擎(www.zuoyouxi.com)来实现这款游戏。
(点击图片可进入游戏体验)
因内容太多,为方便大家阅读,所以分成四部分来讲解。
本文为第四部分,主要包括:
16.分数往上飘动画
17.形状飞入动画
18.其他动画表现添加
19.游戏结束界面
20. 添加LOGO
21. 渲染优化
若要一次性查看所有文档,也可点击这里。
十六. 分数往上飘的动画
在表现加分时,分数会有个缩放的效果,然后往上移动并淡出。这些效果可以通过Tween Group来组合实现。
1. 在board节点下,创建UIText节点,取名为score,属性设置如下:
- 文本居中显示
- 文本颜色为白色,大小40,外加6像素描边
2. 为score节点,添加TweenScale组件,控制缩放动画,属性设置如下图(注意设置Tween Group=1):
3. 为score节点,添加TweenPosition组件,控制节点向上移动,属性设置如下图(注意设置Tween Group=1):
4. 为score节点,添加TweenAlpha组件,控制节点淡出,属性设置如下图(注意设置Tween Group=1):
5. 将score节点拖拽到Assets/prefab目录,创建预制。然后从场景中删除。
6. 在Scripts/ui下新建脚本:FlyScore.js
/**
* 分数飘出来的特效
*/
var FlyScore = qc.defineBehaviour('qc.tetris.FlyScore', qc.Behaviour, function() {
var self = this;
}, {
scorePrefab: qc.Serializer.PREFAB
}); /**
* 开始播放冒分数动画
*/
FlyScore.prototype.play = function(pos, score) {
var self = this; var scoreOb = self.game.add.clone(self.scorePrefab, self.gameObject);
scoreOb.text = '' + score;
var tp = scoreOb.getScript('qc.TweenPosition');
scoreOb.anchoredX = qc.Tetris.board.data[pos].x;
scoreOb.anchoredY = qc.Tetris.board.data[pos].y;
tp.from = new qc.Point(scoreOb.x, scoreOb.y);
tp.to = new qc.Point(tp.from.x, tp.from.y - 80);
tp.resetGroupToBeginning();
tp.playGroupForward();
self.game.timer.add(600, function() {
scoreOb.destroy();
});
};
7. 将FlyScore脚本挂载到board节点,设置scorePrefab属性为Assets/prefab/score.bin。保存场景。
十七. 形状飞入动画
1. 双击Assets/prefab/Blocks.bin,编辑预制
2. 选中Blocks节点,添加TweenPosition组件,属性设置如下:
3. 保存预置
4. 打开Scripts/ui/Pool.js,添加flyIn接口,处理飞入动画的播放
/**
* 播放飞入的动画
*/
Pool.prototype.flyIn = function(index) {
var self = this, o = self.gameObject, children = o.children;
var offset = o.width * (0.5 - 0.165); // 先确保位置都正确
self.resize(); if (index === 0) {
var o = children[0], c = o.getScript('qc.tetris.BlocksUI');
c.flyIn(offset);
}
if (index === 0 || index === 1) {
var o = children[1], c = o.getScript('qc.tetris.BlocksUI');
c.flyIn(offset);
} var o = children[2], c = o.getScript('qc.tetris.BlocksUI');
c.flyIn(offset);
};
5. 打开Scripts/ui/BlocksUI.js,添加flyIn接口,处理单个形状飞入动画
/**
* 飞入动画
*/
BlocksUI.prototype.flyIn = function(offset) {
var self = this,
tp = self.getScript('qc.TweenPosition'); tp.delay = 0.5;
tp.to = new qc.Point(self.gameObject.x, self.gameObject.y);
tp.from = new qc.Point(tp.to.x + offset, tp.to.y);
tp.resetToBeginning();
tp.playForward();
};
6. 运行游戏,查看下效果:已经可以正常游戏了不是?
十八. 其他动画表现添加
目前还缺少两个表现:加分动画(数字跳动)、形状回弹效果。其方法和之前讲述的大致一样,这里简略做个说明。
加分动画
1. 修改CurrentScore.js代码,添加动画播放代码:
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) {
best = best || qc.Tetris.score.current; // 做动画表现,从old -> best
var old = this.gameObject.div.innerHTML * 1;
this.delta = best - old;
if (this.delta <= 0)
this.gameObject.div.innerHTML = '' + best; // 0.2s内需要播放完毕,计算每秒增加的数量
this.step = this.delta / 0.2; // 播放缩放动画
var ts = this.getScript('qc.TweenScale');
ts.resetToBeginning();
ts.playForward();
}; /**
* 动画表现
*/
CurrentScore.prototype.update = function() {
if (this.delta <= 0) {
// 动画表现完毕了
return;
} var step = Math.round(this.step * this.game.time.deltaTime / 1000);
this.delta -= step;
var old = this.gameObject.div.innerHTML * 1 + step;
if (old > qc.Tetris.score.current) {
old = qc.Tetris.score.current;
this.delta = 0;
}
this.gameObject.div.innerHTML = '' + old;
};
2. 为场景节点UIRoot/score添加TweenScale组件,属性设置如下:
形状回弹效果
修改BlocksUI.js代码,添加backAni方法:
/**
* 退回到原来位置的动画表现
*/
BlocksUI.prototype.backAni = function(x, y) {
var self = this, o = self.gameObject,
tp = self.getScript('qc.TweenPosition');
if (tp.enable) return;
tp.delay = 0;
tp.from = new qc.Point(x, y);
tp.to = new qc.Point(self.gameObject.x, self.gameObject.y);
tp.stop();
tp.resetToBeginning();
self.gameObject.interactive = false;
tp.onFinished.addOnce(function() {
self.gameObject.interactive = true;
o.parent.getScript('qc.tetris.Pool').resize();
});
tp.playForward();
};
在onDragEnd方法中,当无法放入棋盘的分支中,加入backAni的调用:
BlocksUI.prototype.onDragEnd = function(e) {
var self = this,
o = self.gameObject;
self.drag = false; if (self.flagBlocks.visible && self.lastPos) {
// 放到这个位置中去
self.drop = true;
qc.Tetris.operation.putIn(self.index, self.lastPos, self.data);
}
else {
// !!!!!!
// 在这个分支中修改为如下代码
var x = o.x, y = o.y;
self.reset();
o.parent.getScript('qc.tetris.Pool').resize();
self.backAni(x, y);
} // 显示标记可以干掉了
self.flagBlocks.destroy();
delete self.flagBlocks;
};
十九. 游戏结束界面
游戏界面包含2个页面:
这两个页面使用html+css元素快速搭建(DOM节点)。步骤如下:
1. 在UIRoot下创建Dom节点,取名GameOver
- 居中显示,大小为340*441
- 缩放1.5倍
- 设置节点可以交互(碰撞范围非常大,这样底部游戏所有的元素都无法接收事件了)
- 设置className=gameover
2. 在Scripts/ui下新建脚本:GameOverUI.js
/**
* 游戏结束界面
*/
var GameOverUI = qc.defineBehaviour('qc.tetris.GameOverUI', qc.Behaviour, function() {
var self = this;
qc.Tetris.gameOver = self;
self.runInEditor = true;
}, {
shareClue: qc.Serializer.PREFAB
}); GameOverUI.prototype.awake = function() {
var div = this.gameObject.div;
var score = qc.Tetris.score.current;
var percent = 40; this.rawHtml =
'<div class="gameover_title">Game Over</div>' +
'<div class="gameover_score">__SCORE__</div>' +
'<div class="gameover_pos">你击败了全球__PERCENT__%的玩家</div>' +
'<div class="gameover_desc">让朋友们来膜拜大神吧!</div>' +
'<div class="gameover_share" onclick="qc.Tetris.gameOver.share()" ontouchstart="qc.Tetris.gameOver.share()">马上告诉他们</div>' +
'<div class="gameover_restart" onclick="qc.Tetris.gameOver.restart()" ontouchstart="qc.Tetris.gameOver.restart()">再玩一次</div>' +
'<div class="gameover_act">' +
' <div class="gameover_logo"></div><div class="gameover_act_desc">点击关注送好礼</div> ' +
'</div>' +
'<div class="clear"></div>';
this.rawHtml = this.rawHtml.replace('__SCORE__', '' + score);
this.rawHtml = this.rawHtml.replace('__PERCENT__', '' + percent);
div.innerHTML = this.rawHtml;
}; GameOverUI.prototype.onDestroy = function() {
delete qc.Tetris.gameOver;
}; GameOverUI.prototype.share = function() {
// 打开share界面
this.game.add.clone(this.shareClue, this.gameObject.parent);
}; GameOverUI.prototype.restart = function() {
this.gameObject.destroy();
qc.Tetris.operation.restart();
};
本界面主要通过内置的DOM来进行处理,具体不多作解释(您需要有一定的web前端开发基础)
1. 打开Assets/css/style.css,添加如下样式表:
/* Game Over */
.gameover {
text-align: center;
width: 100%;
font-family: arial, sans serif;
background: url("../raw/bg.png") no-repeat;
color: #000000;
}
.gameover_title {
font-size: 40px;
margin-top: 10px;
height: 50px;
text-align: center;
}
.gameover_score {
font-size: 90px;
margin-top: -15px;
height: 98px;
text-align: center;
}
.gameover_pos {
text-align: center; font-size: 28px;
height: 40px;
}
.gameover_desc {
text-align: center; color: #ffffff;
height: 30px; font-size: 20px; line-height: 100%;
}
.gameover_share {
background: url("../raw/btn_blue.png") center no-repeat;
height: 76px;
line-height: 76px;
font-size: 30px;
color: #ffffff;
text-align: center;
}
.gameover_restart {
background: url("../raw/btn_yellow.png") center no-repeat;
text-align: center; color: #ffffff;
height: 76px;
line-height: 76px;
font-size: 30px;
margin-top: 10px;
} .gameover_logo {
float: left;
background: url("../raw/logo.png") no-repeat;
width: 64px;
height: 62px;
margin: 8px 0px 0px 2px;
}
.gameover_act_desc {
color: #ffffff;
float: right;
width: 250px;
text-align: left;
height: 62px;
line-height: 62px;
margin-top: 8px;
font-size: 28px;
}
.clear { clear: both; }
2. GameOverUI.js脚本挂载到GameOver对象,刷新查看下效果。
3. 将GameOver节点拖拽到Assets/prefab下,创建预制。然后从场景中删除。游戏结束界面就完成了。下面构建分享页面
4. 在UIRoot下新建Dom节点:shareClue,参数设置如下:
大小设置为铺满整个屏幕,className=share
5.在shareClue新建Dom节点:arraw,用来显示箭头,定位为右上角,参数设置如下:
6. 在shareClue新建Dom节点:desc,用来显示提示语内容。参数设置如下:
7. 在Scripts/ui新建文件ShareClue.js
/**
* 分享提示页面
*/
var ShareClue = qc.defineBehaviour('qc.tetris.ShareClue', qc.Behaviour, function() {
var self = this;
self.runInEditor = true;
}, {
descNode: qc.Serializer.NODE
}); /**
* 初始化
*/
ShareClue.prototype.awake = function() {
this.descNode.div.innerHTML = '请点击右上角<br/>分享给您的好友吧<br/>看下他们能取得多少分';
}; /**
* 点击时干掉本页面
*/
ShareClue.prototype.onClick = function() {
this.gameObject.destroy();
};
8. 将ShareClue脚本挂载到shareClue节点上,设置Desc Node为下面的desc节点
9. 编辑Assets/css/style.css,添加样式表:
/* 分享提示 */
.share {
background-color: #000000;
opacity:0.5;
filter:alpha(opacity=50);
text-align: center; color: #ffffff;
}
.share_clue {
background-image: url("../raw/arrows.png");
}
.share_desc {
color: #ffffff; font-size: 60px; text-align: center;
line-height: 70px;
}
10. 保存场景并刷新之,查看效果。
11. 将shareClue拖拽到Assets/prefab,创建预置,然后从场景中删除。
12. 选中UIRoot节点,设置UIManager组件的gameOverPrefab=Assets/prefab/GameOver.bin
13. 双击Assets/prefab/GameOver.bin编辑预置,设置shareClue = Assets/prefab/shareClue.bin
14. 打开Scripts/logic/Board.js,补齐死亡逻辑:
Object.defineProperties(Board.prototype, {
/**
* @property {boolean} die - 当前是否已经死亡了
* @readonly
*/
die: {
get: function() {
// 如果有单个点形状的,一定死不了
var pool = qc.Tetris.Shapes.pool;
for (var i = 0; i < pool.length; i++) {
if (pool[i].list.length === 1) return false;
} // 逐一检查,各形状能否扔来进来
for (var pos in this.data) {
for (var i = 0; i < pool.length; i++) {
if (this.checkPutIn(pos, pool[i].list)) return false;
}
}
return true;
}
}
});
15. 在Scripts/operation创建脚本Restart.js,处理重新开始游戏的逻辑:
/**
* 请求重新开始游戏
*/
qc.Tetris.operation.restart = function() {
var game = qc.Tetris.game,
ui = game.ui; // 清空棋盘信息
qc.Tetris.board.restart(); // 当前分数清0
qc.Tetris.score.current = 0; // 3个形状重新替换掉
qc.Tetris.Shapes.restart(); // 界面初始化
ui.restart();
};
16. 游戏的整体逻辑已经完成,测试看看
二十. 添加Logo
具体请自行参考工程理解,涉及的场景节点有:UIRoot/logo和UIRoot/company
涉及的脚本有:Scripts/ui/Company.js
涉及的样式表:
/* logo */
.logo {
background-image: url("../raw/qici.png");
}
.company {
color:#ffffff;font-size: 24px;
}
二十一. 渲染优化
本游戏,使用图片比较少,并且大部分都采用DOM的方式渲染,非常高效。
唯一可以做优化的是3个形状:每个形状下面挂载了多个格子节点,并且大部分时间是保持不变的,因此可以将这些格子节点缓存到canvas以提升渲染效率(多耗了点内存)。步骤如下:
1. 双击Assets/Prefab/Blocks.bin编辑预置,在预置根节点添加内置组件:CacheAsBitmap,设置属性如下图:
这个组件的用途是将节点渲染到独立的canvas上并缓存起来。
2. 保存预制。当内部的格子发生变化时,需要“设脏”(确保缓存能被刷新)。打开BlocksUI.js,在reset方法最后面加入:
self.getScript('qc.CacheAsBitmap').dirty = true;
添加帧率查看
在UIRoot挂载Dom节点:debug,属性设置如下:
2. 编辑style.css,添加样式表:
.debug { color:green; font-size:18px; }
3. 为debug挂载内置脚本:DebugViewer,刷新下页面,就可以查看帧率情况了:
其中,FPS为游戏实际运行帧率;Total为游戏一次主循环所使用的时间;Logic为游戏逻辑损耗的时间(即Preupdate、Update等),Render为渲染时间。
4. 在最终发布时,需要将debug隐藏掉
《神奇的六边形》 到此就分享完毕了,感谢各位的耐心阅读,若发现问题,还请大家及时指出,帮助我们不断完善。以后还将陆续分享其他好游戏的开发经验,望大家继续关注,谢谢!
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上,在此谈谈自己如何通过引擎来开发这款游戏的. 客户端代码 ...
随机推荐
- 关于CPU Cache:程序猿需要知道的那些
天下没有免费的午餐,本文转载于:http://cenalulu.github.io/linux/all-about-cpu-cache/ 先来看一张本文所有概念的一个思维导图: 为什么要有CPU Ca ...
- 备忘:文本编辑器(z.B. Sublime Text 2)策略,git策略
1.以Sublime Text 2 为例: 新建一个test.py文件,敲完例程 代码 之后,再另存为比如 if.py, list_tuple.py云云 而test.py可以一直用来编辑 2.git ...
- 【温故而知新-Javascript】理解 DOM
DOM(Document Object Model,文档对象模型)允许我们用 JavaScript 来探查和操作 HTML 文档里的内容.它对于创建丰富性内容而言是必不可少的一组功能. 1. 理解文档 ...
- 常用中文字体 Unicode 编码
各大网站的字体选择 网站 字体 腾讯 font: 12px "宋体","Arial Narrow",HELVETICA; 淘宝 font: 12px/1.5 t ...
- python3使用套接字遇到TypeError: 'str' does not support the buffer interface如何解决
这是我查看的博客 http://blog.csdn.net/chuanchuan608/article/details/17915959 直接引用里面的关键语句: When you use clien ...
- LoadRunner 11 完整卸载
实现彻底删除LR的步骤 打开任务管理器,关闭所有LR相关的进程 请备份好所有LR脚本 进入控制面板-添加与删除,找到HP LoadRunner并点击删除按钮,若出现提示“shared DLLs”消息框 ...
- TestLink学习三:发送邮件的两种配置方法
第一种:修改config.inc.php中的[smtp],配置为默认本地发送,用hotmail用户做接收,调试成功!(本人未尝试这种) // ----------------------------- ...
- java14-4 Pattern和Matcher类的使用
获取功能 Pattern和Matcher类的使用 模式和匹配器的基本使用顺序 import java.util.regex.Matcher; import java.util.regex.Pat ...
- android stuio eclipse映射下的快捷键
转:关于 android stuio eclipse映射下的快捷键 http://www.cnblogs.com/0616--ataozhijia/p/3870064.html 会持续更新)这边讲的常 ...
- Gradle的安装
1.Gradle依赖JDK,所以先在机器上安装好JDK,设置好JAVA_HOME与PATH环境变量 2.从官网下载合适的Gradle发行包 3.发行包是一个zip文件,解压后,将 GRADLE_HOM ...