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

近期出现一款魔性的消除类HTML5游戏《神奇的六边形》,今天我们一起来看看如何通过开源免费的青瓷引擎(www.zuoyouxi.com)来实现这款游戏。

点击这里可进入游戏体验)

因内容太多,为方便大家阅读,所以分成部分来讲解。

本文为第六部分,主要包括:

15. 消除行

十五. 消除行

以下的行是可以被消除的:

  

逻辑实现

1. 打开Scripts/logic/board.js,将上述3类型的行建立数据结构:

var Board = qc.Tetris.Board = function() {
     // 省略一堆代码
     ...
 
     // 左斜的9条线,指明起始点坐标
     self.xyLines = [
         [0, -4],
         [1, -4],
         [2, -4],
         [3, -4],
         [4, -4],
 
         [4, -3],
         [4, -2],
         [4, -1],
         [4, 0]
     ];
 
     // 横向9条线,指明起始点坐标和长度
     self.yLines = [
         [0, -4, 5],
         [-1, -3, 6],
         [-2, -2, 7],
         [-3, -1, 8],
         [-4, 0, 9],
         [-4, 1, 8],
         [-4, 2, 7],
         [-4, 3, 6],
         [-4, 4, 5]
     ];
 
     // 右斜9条线,指明起始点坐标和长度
     self.xLines = [
         [-4, 0, 5],
         [-3, -1, 6],
         [-2, -2, 7],
         [-1, -3, 8],
         [0, -4, 9],
         [1, -4, 8],
         [2, -4, 7],
         [3, -4, 6],
         [4, -4, 5]
     ];
 };

 

 

2. 实现putIn接口:

 Board.prototype.putIn = function(pos, list, value) {
     var self = this;
     var pt = qc.Tetris.readPos(pos),
         x = pt.x,
         y = pt.y;
 
     for (var i = 0; i < list.length; i++) {
         var x0 = x + list[i][0],
             y0 = y + list[i][1];
 
         // 这个点应该是空的
         var block = self.data[qc.Tetris.makePos(x0, y0)];
         block.value = value;
     }
 };

 

3. 实现clearLine接口,干掉一行数据:

// 干掉一行
 Board.prototype.clearLine = function(pts) {
     var self = this;
     pts.forEach(function(pos) {
         self.data[pos].value = 0;
     });
 };

 

4. 实现getFullLines接口,将所有可以消除的行返回:

// 取得可以消除的行
 Board.prototype.getFullLines = function() {
     var self = this,
         lines = [];
 
     // 横向9条线
     var pts = self.yLines;
     for (var i = 0; i < pts.length; i++) {
         var start = pts[i], end = [start[0] + start[2] - 1, start[1]];
         var ok = true;
         for (var x = start[0], y = start[1]; x <= end[0];) {
             var pos = qc.Tetris.makePos(x, y);
             if (self.data[pos].value === 0) {
                 // 不符合,不能消除
                 ok = false; break;
             }
 
             // 下一个点
             x++;
         }
         if (ok) {
             // 这条线可以消除,添加进来
             lines.push('y' + qc.Tetris.makePos(start[0], start[1]));
         }
     }
 
     // 右斜9条线
     var pts = self.xLines;
     for (var i = 0; i < pts.length; i++) {
         var start = pts[i], end = [start[0], start[1] + start[2] - 1];
         var ok = true;
         for (var x = start[0], y = start[1]; y <= end[1];) {
             var pos = qc.Tetris.makePos(x, y);
             if (self.data[pos].value === 0) {
                 // 不符合,不能消除
                 ok = false; break;
             }
 
             // 下一个点
             y++;
         }
         if (ok) {
             // 这条线可以消除,添加进来
             lines.push('x' + qc.Tetris.makePos(start[0], start[1]));
         }
     }
 
     // 左斜的9条线
     var pts = self.xyLines;
     for (var i = 0; i < pts.length; i++) {
         var start = pts[i], end = [start[1], start[0]];
         var ok = true;
         for (var x = start[0], y = start[1]; true;) {
             var pos = qc.Tetris.makePos(x, y);
             if (self.data[pos].value === 0) {
                 // 不符合,不能消除
                 ok = false; break;
             }
 
             // 下一个点
             if (end[0] > start[0]) {
                 x++, y--;
                 if (x > end[0]) break;
             }
             else {
                 x--, y++;
                 if (x < end[0]) break;
             }
         }
         if (ok) {
             // 这条线可以消除,添加进来
             lines.push('xy' + qc.Tetris.makePos(start[0], start[1]));
         }
     }
 
     return lines;
 };

界面实现

预先将所有的行创建出来,当行被删除时直接显示出来做动画表现。以下流程中,我们首先创建一个格子的预制,再创建一个行的预置。

1. 在board节点下,创建Image对象,设置属性如下图:

2.将新创建的block节点拖入Assets/prefab目录,创建预制。然后从场景中删除。

3. 在board节点下,创建Node对象,设置属性如下图:

4. 为节点挂载TweenAlpha动画组件,消失时需要淡出:

  • 透明度从1变化到0

  • 耗时0.5秒

  • 变化的曲线是:先平缓的做变化,然后在快速变化为0

  • 图片中from和to值设置反了,请手工设置下from=1,to=0

5. 在Scripts/ui下创建脚本Line.js,控制行的绘制和表现:

/**
  * 消除一行的表现界面
  */
 var LineUI = qc.defineBehaviour('qc.tetris.LineUI', qc.Behaviour, function() {
     var self = this;
 
     // 描述行的信息
     self.flag = 'xy';
     self.x = 0;
     self.y = 0;
 }, {
     blockPrefab: qc.Serializer.PREFAB
 });
 
 Object.defineProperties(LineUI.prototype, {
     /**
      * 取得行标记
      */
     key: {
         get: function() {
             return this.flag + qc.Tetris.makePos(this.x, this.y);
         }
     },
 
     /**
      * 取得本行的格子数量
      */
     count: {
         get: function() {
             return this.gameObject.children.length;
         }
     }
 });
 
 /**
  * 初始化行
  */
 LineUI.prototype.init = function(flag, start, end) {
     var self = this;
     self.flag = flag;
     self.x = start[0];
     self.y = start[1];
 
     // 创建一个格子
     var createBlock = function(pos) {
         var block = self.game.add.clone(self.blockPrefab, self.gameObject);
         block.frame = 'white.png';
         block.anchoredX = qc.Tetris.board.data[pos].x;
         block.anchoredY = qc.Tetris.board.data[pos].y;
         block.name = pos;
         return block;
     };
 
     switch (flag) {
     case 'xy':
         for (var x = self.x, y = self.y; true;) {
             createBlock(qc.Tetris.makePos(x, y));
 
             // 下一个点
             if (end[0] > start[0]) {
                 x++, y--;
                 if (x > end[0]) break;
             }
             else {
                 x--, y++;
                 if (x < end[0]) break;
             }
         }
         break;
 
     case 'y':
         for (var x = start[0], y = start[1]; x <= end[0];) {
             createBlock(qc.Tetris.makePos(x, y));
             x++;
         }
         break;
 
     case 'x':
         for (var x = start[0], y = start[1]; y <= end[1];) {
             createBlock(qc.Tetris.makePos(x, y));
             y++;
         }
     }
 
     // 初始时隐藏掉
     self.gameObject.name = self.key;
     self.gameObject.visible = false;
 };
 
 /**
  * 播放消失的动画
  */
 LineUI.prototype.playDisappear = function(index) {
     var self = this,
         o = self.gameObject,
         ta = self.getScript('qc.TweenAlpha');
 
     o.visible = true;
     o.alpha = 1;
 
     ta.delay = 0;
     ta.resetToBeginning();
     ta.onFinished.addOnce(function() {
         // 隐藏掉
         o.visible = false;
     });
     ta.playForward();
 };
  • flag和x、y属性描述了行的信息(左斜行、水平行还是右斜行,起始点的坐标)

6. 将此脚本挂载到Line节点,并设置blockPrefab为第一步骤创建的格子预置:

7. 将line拖进Assets/prefab目录,创建预制。然后从场景中删除。

8. 在Scripts/ui创建脚本KillLineEffect.js,处理行消失表现的逻辑

/**
  * 行消除的动画表现
  */
 var KillLineEffect = qc.defineBehaviour('qc.tetris.KillLineEffect', qc.Behaviour, function() {
     var self = this;
 
     /**
      * 所有的行
      */
     self.lines = {};
 
     /**
      * 两行之间的播放延迟
      */
     self.delay = 300;
 }, {
     delay: qc.Serializer.NUMBER,
     linePrefab: qc.Serializer.PREFAB
 });
 
 /**
  * 初始化:将用于表现的行全部创建出来放着
  */
 KillLineEffect.prototype.awake = function() {
     var self = this;
 
     // 创建用于消除表现的格子行
     var createLine = function(flag, start, end) {
         var ob = self.game.add.clone(self.linePrefab, self.gameObject);
         var line = ob.getScript('qc.tetris.LineUI');
         line.init(flag, start, end);
         self.lines[line.key] = line;
     };
     var pts = qc.Tetris.board.xyLines;
     for (var i = 0; i < pts.length; i++) {
         var start = pts[i], end = [start[1], start[0]];
         createLine('xy', start, end);
     }
 
     var pts = qc.Tetris.board.yLines;
     for (var i = 0; i < pts.length; i++) {
         var start = pts[i], end = [start[0] + start[2] - 1, start[1]];
         createLine('y', start, end);
 
     }
     var pts = qc.Tetris.board.xLines;
     for (var i = 0; i < pts.length; i++) {
         var start = pts[i], end = [start[0], start[1] + start[2] - 1];
         createLine('x', start, end);
     }
 };
 
 KillLineEffect.prototype.find = function(flag) {
     return this.lines[flag];
 };
 
 KillLineEffect.prototype.play = function(index, flag, score) {
     var self = this;
     var line = self.find(flag);
     var delay = index * self.delay;
 
     var playFunc = function() {
         // 冒出分数
         var children = line.gameObject.children;
         var pos = children[Math.round(children.length/2) - 1].name;
         self.getScript('qc.tetris.FlyScore').play(pos, score);
 
         // 消失动画
         line.playDisappear();
     };
     if (delay <= 0) {
         playFunc();
     }
     else {
         self.game.timer.add(delay, playFunc);
     }
 };

 

  • 在脚本初始化时,将所有行的数据构建出来,并隐藏掉

  • delay表示在多行消失时,其动画的间隔时间

  • 在动画表现时,有分数表现,FlyScore下一章再补充

9. 将KillLineEffect挂载到board节点(棋盘),并设置linePrefab:

10. 运行工程,就可以看到这些“行”了:

11. 选中UIRoot节点,设置UIManager的Kill Line Effect Node属性(board节点,因为board挂载了KillLineEffect脚本):

 

下一篇:JS开发HTML5游戏《神奇的六边形》(五)

下一篇:JS开发HTML5游戏《神奇的六边形》(七)



转载于:https://my.oschina.net/u/2510595/blog/531621

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值