JS开发HTML5游戏《神奇的六边形》(四)

本文详细介绍了如何使用青瓷引擎实现一款魔性的消除类HTML5游戏《神奇的六边形》,内容涵盖了从分数动画、形状飞入动画、加分动画、形状回弹效果、游戏结束界面到添加Logo和渲染优化的全过程。

近期出现一款魔性的消除类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. 游戏的整体逻辑已经完成,测试看看

 

具体请自行参考工程理解,涉及的场景节点有: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游戏《神奇的六边形》(三)

青瓷引擎是一套开源免费的JavaScript游戏引擎类库,其基于开源免费的Phaser游戏引擎,并提供了一套完全基于浏览器的跨平台集成式HTML5游戏编辑器。 采用青瓷引擎开发HTML5游戏和传统Web网页开发一样,使用任何你喜欢的编辑器,使用任何你喜欢的浏览器,利用JavaScript语言和所有先进的Web开发工具,让青瓷引擎处理底层技术的复杂性,你只需要关注最重要的事情:做游戏青瓷引擎技术堆栈 青瓷引擎由三部分组成:QICI Core、QICI Widget和QICI Editor QICI Core:一套JavaScript游戏引擎类库(qc-core.js),基于开源免费的Phaser游戏引擎。 QICI Widget:一套JavaScript图形组件库(qc-widget.js),为编辑器提供丰富强大的通用组件。 QICI Editor:一套基于浏览器的跨平台集成式游戏编辑器,包含基于Node.JS的后台服务。 QICI Core可用于编程方式开发HTML5游戏,无需QICI Editor的支持。但对于界面布局稍微有点复杂度的游戏,如果没有QICI Editor这样所见即所得的可视化开发工具,很难进行快速开发和维护,采用QICI Editor美术和策划甚至都可以参与帮助游戏界面的构建。QICI Widget主要内部使用,为QICI Editor提供基础通用组件支持。 QICI Core是基于JavaScript游戏类库,QICI Widget是基于JavaScript的图形组件库,QICI Editor采用Node.JS进行资源文件IO处理,所以可以说青瓷引擎是全栈式的JavaScript游戏引擎青瓷引擎特点 游戏无需浏览器安装额外插件,适应性更广,更利于传播 重新定义了HTML5游戏开发工作流,开发、调试尽在浏览器内 面向组件式编程,支持组件热拔插,方便扩展维护 强大的可视化编辑功能,让设计不再是凭空想象 先进的UI界面布局规则,使得屏幕适配更加简单 为国内手机浏览器进行了优化,减少非标准适配的烦恼 高效的渲染底层,自适应WebGl和Canvas两种模式 丰富的底层核心功能,涵盖绝大部分游戏开发需求 不断丰富的插件库,让游戏开发更加便捷、简单青瓷引擎功能 基于浏览器的编辑器 所见即所得的实时调试功能 网络资源管理,支持预加载、动态加载 时间调度系统,可控制帧率,游戏速度等 自适应Web Audio和Audio Tag,适配性更高的声音管理功能 提供了表格、拉条、滚动视图等丰富的界面控件 提供了游戏HTML元素混合处理模式 提供基于Rect Tranform的UI布局套件 支持WebFont和BitmapFont等字体系统 优化文字对视网膜设备的适配 整合图集打包,帧动画编辑功能 高性能骨骼动画渲染 支持多种Filter着色器渲染 支持Excel数据导入功能 支持Tilemap的地图导入,并优化刷新性能 强大的可视化Tween曲线动画编辑功能 编辑器菜单和属性面板支持可自定义扩展功能 可扩展插件功能,提供物理、锁屏、微信接口和服务端通讯等内置插件 基于浏览器的编辑器,无需安装任何插件,开发、调试尽在浏览器内。 iPad iPhone 部分游戏示例(点击图片可体验游戏)《神奇六边形》(《神奇六边形》完整教程) 《蛇精病》    《跳跃的方块》 (《跳跃的方块》完整教程)        《2187》   Examples A wide range of source code examples for you to explore. Download all in one zip file.            标签:游戏引擎
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值