博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
JS开发HTML5游戏《神奇的六边形》(三)
阅读量:5141 次
发布时间:2019-06-13

本文共 22468 字,大约阅读时间需要 74 分钟。

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

(点击图片可进入游戏体验)

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

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

11.显示出3个形状

12.形状的拖放处理

13.形状放入棋盘的实现

14.界面管理

15.消除行

若要一次性查看所有文档,也可。

 

十一. 显示出3个形状

1. 在Scripts/ui创建文件:Pool.js,绘制3个形状。

1  var s = qc.Serializer; 2  3  /** 4   * 3个形状的绘制 5   */ 6  var Pool = qc.defineBehaviour('qc.tetris.Pool', qc.Behaviour, function() { 7      var self = this; 8  9      /**10       * 形状的预置11       */ 12      self.blocksPrefab = null;13 14      /**15       * 记录下面3个形状的实例16       */17      self.shapes = [];18  }, {19      blocksPrefab: s.PREFAB20  });21 22  /**23   * 初始化处理24   */25  Pool.prototype.awake = function() {26      var self = this;27      self.redraw();28  };29 30  /**31   * 绘制3个形状32   */33  Pool.prototype.redraw = function() {34      var self = this;35 36      // 先干掉旧的形状数据37      for (var i = 0; i < self.shapes.length; i++) {38          self.shapes[i].destroy();39      }40      self.shapes = [];41 42      // 创建3个新的形状43      for (i = 0; i < 3; i++) {44          self.add(i);45      }46      self.resize();47  };48 49  /**50   * 调整位置51   */52  Pool.prototype.resize = function() {53      var self = this, o = self.gameObject;54 55      // 计算X方向的偏移56      var offset = o.width * (0.5 - 0.165);57      for (var i = 0; i < 3; i++) {58          var child = self.shapes[i];59          if (!child) return;60          child.anchoredX = offset * (i - 1);61          child.anchoredY = 0;62      }63  };64 65  /**66   * 添加一个形状67   */68  Pool.prototype.add = function(index) {69      var self = this;70 71      var o = self.game.add.clone(self.blocksPrefab, self.gameObject);72      var c = o.getScript('qc.tetris.BlocksUI');73      c.data = qc.Tetris.Shapes.pool[index];74      self.shapes[index] = o;75  };76 77  /**78   * 删除一个形状79   */80  Pool.prototype.remove = function(index) {81      var o = this.shapes[index];82      o.destroyImmediately();83      this.shapes.splice(index, 1);84  };

整个代码逻辑比较简单,根据3个形状的数据进行绘制。请参考注释进行理解。

 

2. 将此脚本挂载到UIRoot/pool节点,关联blocksPrefab属性:

3. 运行测试下效果,3个形状正确显示了:

 

十二. 形状的拖放处理

形状在被按下时,需要变大,如果是手机上需要向上做一定的位置偏移。拖拽时形状应该跟着鼠标或手指进行移动。

修改脚本Scripts/ui/BlocksUI.js,添加如下代码:

1. 修改reset函数,增加放大区块的逻辑:

1 BlocksUI.prototype.reset = function(fixToBoard) { 2      var self = this, o = self.gameObject; 3      for (var pos in self._blocks) { 4          var p = qc.Tetris.readPos(pos); 5          var pt = qc.Tetris.board.toWorld(p, fixToBoard ? qc.Tetris.BLOCK_H : qc.Tetris.POOL_DISTANCE_NORMAL); 6          var block = self._blocks[pos]; 7          block.anchoredX = pt.x; 8          block.anchoredY = pt.y; 9 10          var scale = fixToBoard ? 1.13 : 1;11          block.find('shadow').scaleX = scale;12          block.find('shadow').scaleY = scale;13          block.find('block').scaleX = scale;14          block.find('block').scaleY = scale;15      }16  };

2. 添加按下的逻辑处理,放大区块:

1 /** 2   * 鼠标按下:放大区块 3   */ 4  BlocksUI.prototype.onDown = function(e) { 5      var self = this, o = self.gameObject; 6      self.drop = false; 7      self.reset(true); 8  9      // 在手机下,需要往上做点偏移10      o.y -= self.offsetY;11  };
  • drop标记当前区块是否被放到棋盘了,刚开始按下清理下环境
  • 按下时需要向上做偏移offsetY

3. 添加鼠标松开或触摸结束的处理,还原区块的位置和大小:

1 /**2   * 鼠标松开:重置区块大小3   */4  BlocksUI.prototype.onUp = function() {5      var self = this;6      self.reset();7  };

 

4. 添加开始拖拽的处理:

1 /** 2   * 拖拽开始 3   */ 4  BlocksUI.prototype.onDragStart = function(e) { 5      var self = this; 6      self.drop = false; 7      self.drag = true; 8      self.lastPos = ''; 9      self.game.input.nativeMode = true;10      self.reset(true);11 12      self.game.log.trace('Start drag:{0}', self.index);13 14      // 复制出可放入标记15      var ob = self.flagBlocks = self.game.add.clone(self.gameObject, qc.Tetris.boardUI.gameObject);16      ob.children.forEach(function(block) {17          block.find('shadow').visible = false;18          var b = block.find('block');19          b.width = qc.Tetris.BLOCK_W;20          b.height = qc.Tetris.BLOCK_H;21          b.scaleX = 1;22          b.scaleY = 1;23          b.frame = 'dark' + b.frame;24      });25      ob.scaleX = 1;26      ob.scaleY = 1;27      ob.interactive = false;28      self.hideFlag();29  };
  • 初始时,标记正在拖拽(drag = true),并且没有被放下(drop = false)
  • 当拖拽到棋盘时,需要实时指示是否可以放下本形状。拖拽开始先清理下最近一次检测的逻辑坐标点(last = '')
  • 设置输入模式nativeMode = true。确保输入事件能被实时处理(默认情况下延后一帧处理,运行效率比较高),本游戏对拖拽的实时响应比较重要。
  • 拖拽开始时,放大并偏移形状(和鼠标按下的逻辑一样)
  • 后续的逻辑:另外复制出本形状,并隐藏掉。这个形状在后续拖拽中,会在棋盘显示出来以指示当前是否可以放入。这个指示的格子图片,使用暗色的图片。

5. 添加拖拽的处理,每帧都会进行调度:

1  /** 2   * 拖拽中 3   */ 4  BlocksUI.prototype.onDrag = function(e) { 5      var self = this, 6          o = self.gameObject; 7      if (self.drag) { 8          // 改变节点的目标位置 9          var p = o.getWorldPosition();10          p.x += e.source.deltaX;11          p.y += e.source.deltaY;12          var lp = o.parent.toLocal(p);13          o.x = lp.x;14          o.y = lp.y;15 16          // 计算当前对应棋盘中心点的偏移17          var board = qc.Tetris.boardUI.gameObject;18          p = board.toLocal(p);19          p.y += board.height * 0.5;20 21          // 反算出对应的归一化坐标22          var xy = qc.Tetris.board.toLocal(p);23          var x = Math.round(xy.x),24              y = Math.round(xy.y),25              pos = qc.Tetris.makePos(x, y);26          if (self.lastPos !== pos) {27              self.lastPos = pos;28              if (qc.Tetris.board.data[pos] &&29                  qc.Tetris.board.checkPutIn(pos, self.data.list)) {30                  self.showFlag(pos);31              }32              else {33                  self.hideFlag();34              }35          }36      }37  };

 

  • 在拖拽的事件e中,会指明本帧到上一帧的移动偏移量(屏幕坐标),本形状加上屏幕坐标偏移,这样就移动起来了
  • 然后计算本形状的中心点,对应到棋盘的逻辑坐标。并检查目标是否可以放入,如果可以就需要显示指示
  • 最近一次检测的逻辑坐标需要记录下来,防止每帧都对同一逻辑坐标检查是否可以放入(白耗CPU)

6. 打开脚本Scripts/logic/Board.js,实现checkPutIn方法:

1 Board.prototype.checkPutIn = function(pos, list) { 2      var self = this; 3      var pt = qc.Tetris.readPos(pos), 4          x = pt.x, 5          y = pt.y; 6  7      for (var i = 0; i < list.length; i++) { 8          var x0 = x + list[i][0], 9              y0 = y + list[i][1];10 11          // 这个点应该是空的12          var block = self.data[qc.Tetris.makePos(x0, y0)];13          if (!block) return false;14          if (block.value !== 0) return false;15      }16      return true;17  };

 

7. 继续打开Scripts/ui/Blocks.js,继续实现拖拽结束的逻辑:

1  /** 2   * 拖拽结束 3   */ 4  BlocksUI.prototype.onDragEnd = function(e) { 5      var self = this, 6          o = self.gameObject; 7      self.drag = false; 8  9      if (self.flagBlocks.visible && self.lastPos) {10          // 放到这个位置中去11          self.drop = true;12          qc.Tetris.operation.putIn(self.index, self.lastPos, self.data);13      }14      else {15          self.reset();16          o.parent.getScript('qc.tetris.Pool').resize();17      }18 19      // 显示标记可以干掉了20      self.flagBlocks.destroy();21      delete self.flagBlocks;22  };23 24  /**25   * 隐藏指示标记26   */27  BlocksUI.prototype.hideFlag = function() {28      this.flagBlocks.visible = false;29  };30 31  /**32   * 显示指示标记33   */34  BlocksUI.prototype.showFlag = function(pos) {35      this.flagBlocks.visible = true;36      var pt = qc.Tetris.board.data[pos];37      this.flagBlocks.anchoredX = pt.x;38      this.flagBlocks.anchoredY = pt.y;39  };

 

  • 拖拽结束后,需要判定形状是否被放入目标节点
  • 如果可以放入,则调用指令:qc.Tetris.operation.putIn(下步骤实现)
  • 如果不能放入,则需要将位置和大小等还原
  • 最后,指示对象需要被析构

8. 在Scripts/operation创建文件PutIn.js,实现放入形状指令:

1 /**2   * 请求放入指定格子,如果成功放入返回true,否则返回false3   */4  qc.Tetris.operation.putIn = function(index, pos) {5      // TODO: 逻辑待实现6  };

 

9. 在Blocks.js中,我们使用到了棋盘对象:qc.Tetris.boardUI.gameObject,但目前这个值(BoardUI)尚未被赋值。

打开BoardUI.js,在构造函数中加入代码赋值:

1 var BoardUI = qc.defineBehaviour('qc.tetris.BoardUI', qc.Behaviour, function() { 2      var self = this; 3  4      // 登记下本对象 5      qc.Tetris.boardUI = self; 6  7      /** 8       * 棋盘的棋子元素 9       */10      self.pieces = {};11 12      ...

 

10. 运行测试下,形状可以随意拖拽了,并且可以反弹回原来位置。不过还无法放入(因为PutIn我们还没实现),请继续后面教程。

十三. 形状放入棋盘的实现

处理流程如下图:

打开文件Scripts/operation/PutIn.js,实现上述代码:

1 /**  2      * 请求放入指定格子,如果成功放入返回true,否则返回false  3      */  4     qc.Tetris.operation.putIn = function(index, pos) {  5         var shape = qc.Tetris.Shapes.pool[index],  6             board = qc.Tetris.board,  7             ui = qc.Tetris.game.ui,  8             log = qc.Tetris.game.log;  9         log.trace('尝试将({0})放入({1})', index, pos); 10  11         if (!board.checkPutIn(pos, shape.list)) { 12             // 禁止放入 13             return false; 14         } 15         log.trace('放入格子:({0})', pos); 16  17         // 更新棋盘信息 18         board.putIn(pos, shape.list, shape.value); 19  20         // 计算可以消除的行,并同时消除掉 21         var lines = board.getFullLines(); 22         lines.forEach(function(flag) { 23             var children = ui.killLineEffect.find(flag).gameObject.children; 24             var pts = []; 25             children.forEach(function(child) { pts.push(child.name); }) 26             board.clearLine(pts); 27         }); 28  29         // 计算分数明细,并添加之 30         var scoreDetail = qc.Tetris.operation.calcScore(lines); 31         qc.Tetris.score.current += scoreDetail.total; 32  33         // 替换为新的形状 34         qc.Tetris.Shapes.pool.splice(index, 1); 35         qc.Tetris.Shapes.pool.push(qc.Tetris.Shapes.random()); 36  37         // 重新绘制棋盘 38         ui.board.redraw(); 39  40         // 行消除与分数增加的动画表现 41         if (lines.length > 0) { 42             for (var i = 0; i < lines.length; i++) { 43                 ui.killLineEffect.play(i, lines[i], scoreDetail.lines[i]); 44             } 45         } 46         else { 47             ui.board.getScript('qc.tetris.FlyScore').play(pos, scoreDetail.total); 48         } 49  50         // 当前分数的动画表现 51         ui.currentScore.setScore(); 52  53         // 形状飞入的动画表现,并将旧的形状删除掉 54         ui.pool.remove(index); 55         ui.pool.add(2); 56         ui.pool.flyIn(index); 57  58         // 死亡检测 59         if (board.die) { 60             // 延迟显示死亡界面 61             log.trace('Game Over!'); 62             qc.Tetris.game.timer.add(3000, function() { 63                 ui.onDie(); 64             }); 65         } 66  67         // 放入成功了 68         return true; 69     }; 70  71     /** 72      * 计算分数明细 73      * total: 总分数 74      * lines: [各行的分数] 75      */ 76     qc.Tetris.operation.calcScore = function(lines) { 77         var scores = { 78             total: 40, 79             lines: [] 80         }; 81         if (lines.length < 1) return scores; 82  83         // 计算加成 84         var append = Math.max(0, lines.length - 1 * 10); 85  86         for (var i = 0; i < lines.length; i++) { 87             var flag = lines[i]; 88  89             var line = qc.Tetris.game.ui.killLineEffect.find(flag); 90             var len = line.gameObject.children.length; 91             scores.lines[i] = len * 20 + append * len; 92             scores.total += scores.lines[i]; 93  94             // 40合并到第一行去做表现 95             if (i === 0) { 96                 scores.lines[i] += 40; 97             } 98         } 99 100         return scores;101     };
  • calcScore方法为计算分数的逻辑
  • 代码中出现了qc.Tetris.game.ui(即UIManager),在下文中陆续实现
  • 另外,本逻辑中加入了一些动画表现,在下文中也陆续实现之
  • 先大致理解下处理流程,细节可以后续章节中逐一理解

十四. 界面管理

1. 在Scripts/ui新建UIManager.js:

1 /** 2   * 负责管理所有的游戏界面 3   */ 4  var UIManager = qc.defineBehaviour('qc.tetris.UIManager', qc.Behaviour, function() { 5      var self = this; 6      self.game.ui = self; 7  8      self.runInEditor = true; 9  }, {10      bestScoreNode: qc.Serializer.NODE,11      currentScoreNode: qc.Serializer.NODE,12      boardNode: qc.Serializer.NODE,13      poolNode: qc.Serializer.NODE,14      killLineEffectNode: qc.Serializer.NODE,15 16      uiRoot: qc.Serializer.NODE,17      gameOverPrefab: qc.Serializer.PREFAB18  });19 20  /**21   * 初始化管理22   */23  UIManager.prototype.awake = function() {24      var self = this;25 26      /**27       * bestScore: BestScore组件28       */29      if (self.bestScoreNode)30          self.bestScore = self.bestScoreNode.getScript('qc.tetris.BestScore');31 32      /**33       * currentScore: CurrentScore组件34       */35      if (self.currentScoreNode)36          self.currentScore = self.currentScoreNode.getScript('qc.tetris.CurrentScore');37 38      /**39       * board: 棋盘绘制组件40       */41      if (self.boardNode)42          self.board = self.boardNode.getScript('qc.tetris.BoardUI');43 44      /**45       * pool: 3个形状的方块46       */47      if (self.poolNode)48          self.pool = self.poolNode.getScript('qc.tetris.Pool');49 50      /**51       * killLineEffect: 方块消除的动画组件52       */53      if (self.killLineEffectNode)54          self.killLineEffect = self.killLineEffectNode.getScript('qc.tetris.KillLineEffect');55  };56 57  /**58   * 游戏重新开始的界面处理59   */60  UIManager.prototype.restart = function() {61      var self = this;62 63      // 重新生成3个新的形状64      self.pool.redraw();65 66      // 棋盘重绘制67      self.board.redraw();68 69      // 重绘当前分数70      self.currentScore.setScore();71  };72 73  /**74   * 死亡的处理75   */76  UIManager.prototype.onDie = function() {77      // 显示失败页面78      this.game.add.clone(this.gameOverPrefab, this.uiRoot);79  };
  • UIManager引用了几个界面逻辑,其中KillLineEffect脚本下章节再实现
  • 同时,加入了死亡处理接口、重新开始游戏接口,具体的逻辑在后续章节中逐一实现

2. 将脚本挂载到UIRoot,并关联各属性:

部分属性先留空

 

十五. 消除行

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

  

逻辑实现

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

1 var Board = qc.Tetris.Board = function() { 2      // 省略一堆代码 3      ... 4  5      // 左斜的9条线,指明起始点坐标 6      self.xyLines = [ 7          [0, -4], 8          [1, -4], 9          [2, -4],10          [3, -4],11          [4, -4],12 13          [4, -3],14          [4, -2],15          [4, -1],16          [4, 0]17      ];18 19      // 横向9条线,指明起始点坐标和长度20      self.yLines = [21          [0, -4, 5],22          [-1, -3, 6],23          [-2, -2, 7],24          [-3, -1, 8],25          [-4, 0, 9],26          [-4, 1, 8],27          [-4, 2, 7],28          [-4, 3, 6],29          [-4, 4, 5]30      ];31 32      // 右斜9条线,指明起始点坐标和长度33      self.xLines = [34          [-4, 0, 5],35          [-3, -1, 6],36          [-2, -2, 7],37          [-1, -3, 8],38          [0, -4, 9],39          [1, -4, 8],40          [2, -4, 7],41          [3, -4, 6],42          [4, -4, 5]43      ];44  };

 

 

2. 实现putIn接口:

1 Board.prototype.putIn = function(pos, list, value) { 2      var self = this; 3      var pt = qc.Tetris.readPos(pos), 4          x = pt.x, 5          y = pt.y; 6  7      for (var i = 0; i < list.length; i++) { 8          var x0 = x + list[i][0], 9              y0 = y + list[i][1];10 11          // 这个点应该是空的12          var block = self.data[qc.Tetris.makePos(x0, y0)];13          block.value = value;14      }15  };

 

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

1 // 干掉一行2  Board.prototype.clearLine = function(pts) {3      var self = this;4      pts.forEach(function(pos) {5          self.data[pos].value = 0;6      });7  };

 

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

1 // 取得可以消除的行 2  Board.prototype.getFullLines = function() { 3      var self = this, 4          lines = []; 5  6      // 横向9条线 7      var pts = self.yLines; 8      for (var i = 0; i < pts.length; i++) { 9          var start = pts[i], end = [start[0] + start[2] - 1, start[1]];10          var ok = true;11          for (var x = start[0], y = start[1]; x <= end[0];) {12              var pos = qc.Tetris.makePos(x, y);13              if (self.data[pos].value === 0) {14                  // 不符合,不能消除15                  ok = false; break;16              }17 18              // 下一个点19              x++;20          }21          if (ok) {22              // 这条线可以消除,添加进来23              lines.push('y' + qc.Tetris.makePos(start[0], start[1]));24          }25      }26 27      // 右斜9条线28      var pts = self.xLines;29      for (var i = 0; i < pts.length; i++) {30          var start = pts[i], end = [start[0], start[1] + start[2] - 1];31          var ok = true;32          for (var x = start[0], y = start[1]; y <= end[1];) {33              var pos = qc.Tetris.makePos(x, y);34              if (self.data[pos].value === 0) {35                  // 不符合,不能消除36                  ok = false; break;37              }38 39              // 下一个点40              y++;41          }42          if (ok) {43              // 这条线可以消除,添加进来44              lines.push('x' + qc.Tetris.makePos(start[0], start[1]));45          }46      }47 48      // 左斜的9条线49      var pts = self.xyLines;50      for (var i = 0; i < pts.length; i++) {51          var start = pts[i], end = [start[1], start[0]];52          var ok = true;53          for (var x = start[0], y = start[1]; true;) {54              var pos = qc.Tetris.makePos(x, y);55              if (self.data[pos].value === 0) {56                  // 不符合,不能消除57                  ok = false; break;58              }59 60              // 下一个点61              if (end[0] > start[0]) {62                  x++, y--;63                  if (x > end[0]) break;64              }65              else {66                  x--, y++;67                  if (x < end[0]) break;68              }69          }70          if (ok) {71              // 这条线可以消除,添加进来72              lines.push('xy' + qc.Tetris.makePos(start[0], start[1]));73          }74      }75 76      return lines;77  };

界面实现

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

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,控制行的绘制和表现:

1 /**  2   * 消除一行的表现界面  3   */  4  var LineUI = qc.defineBehaviour('qc.tetris.LineUI', qc.Behaviour, function() {  5      var self = this;  6   7      // 描述行的信息  8      self.flag = 'xy';  9      self.x = 0; 10      self.y = 0; 11  }, { 12      blockPrefab: qc.Serializer.PREFAB 13  }); 14  15  Object.defineProperties(LineUI.prototype, { 16      /** 17       * 取得行标记 18       */ 19      key: { 20          get: function() { 21              return this.flag + qc.Tetris.makePos(this.x, this.y); 22          } 23      }, 24  25      /** 26       * 取得本行的格子数量 27       */ 28      count: { 29          get: function() { 30              return this.gameObject.children.length; 31          } 32      } 33  }); 34  35  /** 36   * 初始化行 37   */ 38  LineUI.prototype.init = function(flag, start, end) { 39      var self = this; 40      self.flag = flag; 41      self.x = start[0]; 42      self.y = start[1]; 43  44      // 创建一个格子 45      var createBlock = function(pos) { 46          var block = self.game.add.clone(self.blockPrefab, self.gameObject); 47          block.frame = 'white.png'; 48          block.anchoredX = qc.Tetris.board.data[pos].x; 49          block.anchoredY = qc.Tetris.board.data[pos].y; 50          block.name = pos; 51          return block; 52      }; 53  54      switch (flag) { 55      case 'xy': 56          for (var x = self.x, y = self.y; true;) { 57              createBlock(qc.Tetris.makePos(x, y)); 58  59              // 下一个点 60              if (end[0] > start[0]) { 61                  x++, y--; 62                  if (x > end[0]) break; 63              } 64              else { 65                  x--, y++; 66                  if (x < end[0]) break; 67              } 68          } 69          break; 70  71      case 'y': 72          for (var x = start[0], y = start[1]; x <= end[0];) { 73              createBlock(qc.Tetris.makePos(x, y)); 74              x++; 75          } 76          break; 77  78      case 'x': 79          for (var x = start[0], y = start[1]; y <= end[1];) { 80              createBlock(qc.Tetris.makePos(x, y)); 81              y++; 82          } 83      } 84  85      // 初始时隐藏掉 86      self.gameObject.name = self.key; 87      self.gameObject.visible = false; 88  }; 89  90  /** 91   * 播放消失的动画 92   */ 93  LineUI.prototype.playDisappear = function(index) { 94      var self = this, 95          o = self.gameObject, 96          ta = self.getScript('qc.TweenAlpha'); 97  98      o.visible = true; 99      o.alpha = 1;100 101      ta.delay = 0;102      ta.resetToBeginning();103      ta.onFinished.addOnce(function() {104          // 隐藏掉105          o.visible = false;106      });107      ta.playForward();108  };
  • flag和x、y属性描述了行的信息(左斜行、水平行还是右斜行,起始点的坐标)

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

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

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

1 /** 2   * 行消除的动画表现 3   */ 4  var KillLineEffect = qc.defineBehaviour('qc.tetris.KillLineEffect', qc.Behaviour, function() { 5      var self = this; 6  7      /** 8       * 所有的行 9       */10      self.lines = {};11 12      /**13       * 两行之间的播放延迟14       */15      self.delay = 300;16  }, {17      delay: qc.Serializer.NUMBER,18      linePrefab: qc.Serializer.PREFAB19  });20 21  /**22   * 初始化:将用于表现的行全部创建出来放着23   */24  KillLineEffect.prototype.awake = function() {25      var self = this;26 27      // 创建用于消除表现的格子行28      var createLine = function(flag, start, end) {29          var ob = self.game.add.clone(self.linePrefab, self.gameObject);30          var line = ob.getScript('qc.tetris.LineUI');31          line.init(flag, start, end);32          self.lines[line.key] = line;33      };34      var pts = qc.Tetris.board.xyLines;35      for (var i = 0; i < pts.length; i++) {36          var start = pts[i], end = [start[1], start[0]];37          createLine('xy', start, end);38      }39 40      var pts = qc.Tetris.board.yLines;41      for (var i = 0; i < pts.length; i++) {42          var start = pts[i], end = [start[0] + start[2] - 1, start[1]];43          createLine('y', start, end);44 45      }46      var pts = qc.Tetris.board.xLines;47      for (var i = 0; i < pts.length; i++) {48          var start = pts[i], end = [start[0], start[1] + start[2] - 1];49          createLine('x', start, end);50      }51  };52 53  KillLineEffect.prototype.find = function(flag) {54      return this.lines[flag];55  };56 57  KillLineEffect.prototype.play = function(index, flag, score) {58      var self = this;59      var line = self.find(flag);60      var delay = index * self.delay;61 62      var playFunc = function() {63          // 冒出分数64          var children = line.gameObject.children;65          var pos = children[Math.round(children.length/2) - 1].name;66          self.getScript('qc.tetris.FlyScore').play(pos, score);67 68          // 消失动画69          line.playDisappear();70      };71      if (delay <= 0) {72          playFunc();73      }74      else {75          self.game.timer.add(delay, playFunc);76      }77  };

 

  • 在脚本初始化时,将所有行的数据构建出来,并隐藏掉
  • delay表示在多行消失时,其动画的间隔时间
  • 在动画表现时,有分数表现,FlyScore下一章再补充

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

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

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

 

 

转载于:https://www.cnblogs.com/qici/p/4956345.html

你可能感兴趣的文章
转 Silverlight开发历程—(画刷与着色之线性渐变画刷)
查看>>
SQL语法(3)
查看>>
在js在添版本号
查看>>
sublime3
查看>>
Exception Type: IntegrityError 数据完整性错误
查看>>
Nuget:Newtonsoft.Json
查看>>
【luogu4185】 [USACO18JAN]MooTube [并查集]
查看>>
手机号脱敏处理
查看>>
CI控制器调用内部方法并载入相应模板的做法
查看>>
Hdu - 1002 - A + B Problem II
查看>>
HDU - 2609 - How many
查看>>
每天CookBook之Python-003
查看>>
每天CookBook之Python-004
查看>>
Android设置Gmail邮箱
查看>>
StringBuffer的用法
查看>>
js编写时间选择框
查看>>
PHP压缩文件操作
查看>>
Java数据结构和算法(四)--链表
查看>>
JIRA
查看>>
小技巧——直接在目录中输入cmd然后就打开cmd命令窗口
查看>>