转载

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

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

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

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

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

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

6. 历史最高分显示

7. 当前分数显示

8. 绘制棋盘

9. 形状池设计与实现

10. 形状预制的实现

若要一次性查看所有文档,也可 点击这里 。

六. 历史最高分显示

对于DOM节点,其实就是个div,可以指定其样式,指定其样式表类名,也可以内嵌html元素。

  1. 在Scripts/ui下新建文件:BestScore.js,处理最高分数的显示逻辑,并将此逻辑脚本挂载到UIRoot/best节点上。

1 /**  2   * 绘制最高分数  3   */  4  var BestScore = qc.defineBehaviour('qc.tetris.BestScore', qc.Behaviour, function() {  5      var self = this;  6      self.runInEditor = true;  7  }, {  8  });  9  10  /** 11   * 初始化处理 12   */ 13  BestScore.prototype.awake = function() { 14      var self = this, div = self.gameObject.div; 15      div.className = 'score_best'; 16      self.setScore(qc.Tetris.score.current); 17  }; 18  19  /** 20   * 更新最新的高分 21   */ 22  BestScore.prototype.setScore = function(best) { 23      this.gameObject.div.innerHTML = 'Best: ' + best; 24  };

本脚本可以在编辑器下运行(方便在编辑状态下查看效果),首先设置DOM的样式表类名为score_best,然后获取最高分数并显示之。

2. 增加score_best样式表。打开Assets/css/style.css,添加样式表:

1 .score_best { 2      font-weight: 60; 3      font-size:30px; 4      color: #ffffff; text-align: right; 5  }

3.刷新下页面,查看效果:

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

4. 注意:更改样式表目前需要刷新页面才能看到效果。

七. 当前分数显示

1. 在Scripts/ui下新建文件:CurrentScore.js,处理当前分的显示逻辑,并将此逻辑脚本挂载到UIRoot/score节点上。

1 /**  2   * 绘制当前分数  3   */  4  var CurrentScore = qc.defineBehaviour('qc.tetris.CurrentScore', qc.Behaviour, function() {  5      var self = this;  6      self.runInEditor = true;  7  }, {  8  });  9  10  /** 11   * 初始化处理 12   */ 13  CurrentScore.prototype.awake = function() { 14      var self = this, div = self.gameObject.div; 15  16      div.className = 'score_current'; 17      self.setScore(qc.Tetris.score.current); 18  }; 19  20  /** 21   * 更新最新的分数 22   */ 23  CurrentScore.prototype.setScore = function(best) { 24      this.gameObject.div.innerHTML = '' + qc.Tetris.score.current; 25  };

本脚本可以在编辑器下运行(方便在编辑状态下查看效果),首先设置DOM的样式表类名为score_current,然后获取当前分数并显示之。

2.增加score_current样式表。打开Assets/css/style.css,添加样式表:

1 .score_current{ 2      color: #ffffff; 3      font-weight: 100; 4      font-size:50px; 5      text-align: center; 6  }

3.刷新下页面,查看效果

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

八. 绘制棋盘

DOM的层次

DOM节点可以绘制在最底层(当工程背景设置为非透明时,将不可见),也可以绘制在最上层(在所有精灵、UIImage等节点之上)。本棋盘放在最底层,因为棋盘上面还需要拖拽形状、显示可放入指示等。方法是:选中board节点,在Inspector中设置Pos=BACK:

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

开始绘制棋盘

    1. 棋盘中的每个格子都作为一个div元素,采用绝对定位。格子可能表现为7种图片形式(空时为灰色,其他为形状的对应颜色),这7种图片通过不同的样式类来区分。

    2. 打开Assets/css/style.css,加入如下几个样式表:

1 .board { width: 61px; height: 67px; position: absolute; background-repeat: no-repeat; }  2  .board_gray {  3      background-image: url("../raw/gray.png");  4  }  5  .board_blue {  6      background-image: url("../raw/blue.png");  7  }  8  .board_cyan {  9      background-image: url("../raw/cyan.png"); 10  } 11  .board_green { 12      background-image: url("../raw/green.png"); 13  } 14  .board_lightyellow { 15      background-image: url("../raw/lightyellow.png"); 16  } 17  .board_red { 18      background-image: url("../raw/red.png"); 19  } 20  .board_yellow { 21      background-image: url("../raw/yellow.png"); 22  }

这些样式表指明了棋盘格子中的图片

3. 编辑Tetris.js,加入IMAGES常量,指明在不同的值下面格子所使用的className

1 window.Tetris = qc.Tetris = {  2      // 棋盘的大小(半径)  3      SIZE: 4,  4   5      // 棋盘中,每个格子的宽度和高度  6      BLOCK_W: 61,  7      BLOCK_H: 67,  8   9      // 所有的格子图片 10      IMAGES: [ 11          'gray',        // 0 12          'blue',        // 1 13          'cyan',        // 2 14          'green',       // 3 15          'lightyellow', // 4 16          'red',         // 5 17          'yellow'       // 6 18      ], 19  20      // 所有的操作指令集合 21      operation: {} 22  };

4. 在Scripts/ui下创建脚本BoardUI.js,负责棋盘的绘制逻辑:

1 var s = qc.Serializer;  2   3  /**  4   * 管理棋盘的数据并绘制棋盘  5   */  6  var BoardUI = qc.defineBehaviour('qc.tetris.BoardUI', qc.Behaviour, function() {  7      var self = this;  8   9      /** 10       * 棋盘的棋子元素 11       */ 12      self.pieces = {}; 13  14      // 本脚本在编辑模式下可以运行 15      self.runInEditor = true; 16  }, { 17      linePrefab: s.PREFAB 18  }); 19  20  /** 21   * 初始化处理 22   */ 23  BoardUI.prototype.awake = function() { 24      var self = this; 25      self.reset(); 26  27      // 立刻重绘制下 28      self.redraw(); 29  30      // 设置游戏画布的背景色 31      self.gameObject.div.parentNode.style.background = '#1F1E1E'; 32  33      // 缓存图片,防止在图片切换过程中出现卡顿 34      if (self.game.device.editor) return; 35      qc.Tetris.IMAGES.forEach(function(c) { 36          var div = document.createElement('div'); 37          div.className = 'board board_' + c; 38          div.style.left = '-2000px'; 39          div.style.left = '-2000px'; 40          self.gameObject.div.appendChild(div); 41      }); 42  }; 43  44  /** 45   * 重绘棋盘 46   * @private 47   */ 48  BoardUI.prototype.redraw = function() { 49      var self = this; 50  51      // 绘制背景 52      self.drawBackground(); 53  }; 54  55  /** 56   * 绘制棋盘背景 57   */ 58  BoardUI.prototype.drawBackground = function() { 59      var self = this; 60  61      for (var pos in self.pieces) { 62          var div = self.pieces[pos]; 63          div.className = 'board board_' + qc.Tetris.IMAGES[qc.Tetris.board.data[pos].value]; 64      } 65  }; 66  67  /** 68   * 初始化棋盘 69   */ 70  BoardUI.prototype.reset = function() { 71      var self = this, o = self.gameObject; 72  73      // 构建棋盘数据 74      if (o.children.length === 0) { 75          for (var pos in qc.Tetris.board.data) { 76              var info = qc.Tetris.board.data[pos]; 77              var div = self.pieces[pos] = document.createElement('div'); 78              div.className = 'board board_' + qc.Tetris.IMAGES[info.value]; 79              div.style.left = Math.round(info.x + (o.width - qc.Tetris.BLOCK_W) / 2) + 'px'; 80              div.style.top = Math.round(info.y + (o.height - qc.Tetris.BLOCK_H) / 2) + 'px'; 81              o.div.appendChild(div); 82          } 83      } 84      else { 85          o.children.forEach(function(child) { 86              self.pieces[child.name] = child; 87          }); 88      } 89  };

本脚本运行在编辑模式下,这样就可以实时看到棋盘。对本脚本做一些解释:

  • 属性pieces存放了下面所有的div元素(显示格子),key为其逻辑坐标
  • 初始化时,会将底下的所有格子创建出来,并设置上合适的位置(由于在Board.js中计算坐标时,是以棋盘中心为原点;但格子div是以棋盘的左上角为原点,因此代码中做了换算)
  • redraw方法中,以格子的值获取对应的className,对应的设置到格子div就可以了
  • 工程设置的背景是为透明的,因此在初始化时,顺便将游戏背景的颜色设置为:1F1E1E(最底层div的background-color属性)
  • 另外,初始时我们把所有格子的图片都加载进来(方法是创建个屏幕内不可见的div),这样在className切换过程中,就可以直接从本地缓存读取图片,避免加载图片影响体验

5. 将此脚本挂载到board节点上,保存场景并刷新页面,就可以看到效果了:

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

九. 形状池设计与实现

1. 本游戏中,总共有23种形状,每种类型的形状,其颜色是不同的。在Scripts/logic下创建脚本Shapes.js,负责各种形状的配置、抽取等。

1 var Shapes = qc.Tetris.Shapes = {  2      // 所有可能的形状  3      tiles: [  4          // 1个点的  5          {  6              value: 1,  7              list: [[[0, 0]]]  8          },  9  10          { 11              value: 2, 12              list: [ 13                  [[1, -1], [0, 0], [1, 0], [0, 1]], 14                  [[0, 0],  [1, 0], [-1, 1], [0, 1]], 15                  [[0, 0], [1, 0], [0, 1], [1, 1]] 16              ] 17          }, { 18              value: 3, 19              list: [ 20                  [[0, -1], [0, 0], [0, 1], [0, 2]], 21                  [[0, 0], [1, -1], [-1, 1], [-2, 2]], 22                  [[-1, 0], [0, 0], [1, 0], [2, 0]] 23              ] 24          }, { 25              value: 4, 26              list: [ 27                  [[0, 0], [0, 1], [0, -1], [-1, 0]], 28                  [[0, 0], [0, -1], [1, -1], [-1, 1]], 29                  [[0, 0], [0, 1], [0, -1], [1, 0]], 30                  [[0, 0], [1, 0], [-1, 0], [1, -1]], 31                  [[0, 0], [1, 0], [-1, 0], [-1, 1]] 32              ] 33          }, { 34              value: 5, 35              list: [ 36                  [[0, 0], [0, 1], [0, -1], [1, -1]], 37                  [[0, 0], [1, -1], [-1, 1], [-1, 0]], 38                  [[0, 0], [1, -1], [-1, 1], [1, 0]], 39                  [[0, 0], [1, 0], [-1, 0], [0, -1]], 40                  [[0, 0], [1, 0], [-1, 0], [0, 1]] 41              ] 42          }, { 43              value: 6, 44              list: [ 45                  [[0, -1], [-1, 0], [-1, 1], [0, 1]], 46                  [[-1, 0], [0, -1], [1, -1], [1, 0]], 47                  [[0, -1], [1, -1], [1, 0], [0, 1]], 48                  [[-1, 1], [0, 1], [1, 0], [1, -1]], 49                  [[-1, 0], [-1, 1], [0, -1], [1, -1]], 50                  [[-1, 0], [-1, 1], [0, 1], [1, 0]] 51              ] 52          } 53      ], 54  55      /** 56       * 重新开始的逻辑 57       */ 58      restart: function() { 59          qc.Tetris.Shapes.pool = []; 60          for (var i = 0; i < 3; i++) { 61              qc.Tetris.Shapes.pool.push(qc.Tetris.Shapes.random()); 62          } 63      }, 64  65      /** 66       * 随机抽取一个形状 67       */ 68      random: function() { 69          // 先抽取分类 70          var math = qc.Tetris.game.math; 71          var shapes = Shapes.tiles; 72          var shape = shapes[math.random(0, shapes.length - 1)]; 73  74          // 再抽子类 75          var list = shape.list[math.random(0, shape.list.length - 1)]; 76          return { 77              color: shape.color, 78              value: shape.value, 79              list: list 80          }; 81      }, 82  83      /** 84       * 当前的pool数据 85       */ 86      pool: [] 87  };

代码说明如下:

    • value指明了格子应该使用哪个图片
    • list包含了多个形状,形状由数组组成,每个元素指明了逻辑坐标
    • pool属性存储了当前屏幕上3个形状的数据信息
  1. 修改Tetris.js的qc.initGame方法,最后面添加3个形状的初始化逻辑:

1  qc.initGame = function(game) {  2      // 将游戏实例记录下来,便于访问  3      Tetris.game = game;  4   5      // 帧率显示为60帧(满帧)  6      game.time.frameRate = 60;  7   8      // 初始化分数信息  9      Tetris.score = new qc.Tetris.Score(); 10  11      // 构建棋盘对象 12      Tetris.board = new qc.Tetris.Board(); 13  14      // 3个形状 15      qc.Tetris.Shapes.restart(); 16  };

十. 形状预制的实现

本章节我们进行形状的绘制实现,如下图:

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

1. 在UIRoot/pool节点下,创建一空的Node节点,设置如下图

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

  • 定位在父亲的中心点
  • 大小为200*100
  • pivot设置为:(0.5, 0.5)
  • 本对象需要可以交互(需要被拖放),勾选Interactive。并设置碰撞盒类型为Rectangle(正方形),按图示设置大小(碰撞盒大小会比节点实际大小更大)

2.在Scripts/ui创建文件BlocksUI.js

1 /**  2   * 绘制一个形状  3   */  4  var BlocksUI = qc.defineBehaviour('qc.tetris.BlocksUI', qc.Behaviour, function() {  5      var self = this;  6   7      // 格子的预置,一个形状下有多个格子  8      self.blockPrefab = null;  9  10      // 下属所有的格子 11      self._blocks = {}; 12  }, { 13      blockPrefab: qc.Serializer.PREFAB 14  }); 15  16  Object.defineProperties(BlocksUI.prototype, { 17      /** 18       * 关联的数据 19       */ 20      data: { 21          get: function() { return this._data; }, 22          set: function(v) { 23              this._data = v; 24              this.redraw(); 25          } 26      }, 27  28      /** 29       * 第几个? 30       */ 31      index: { 32          get: function() { 33              return this.gameObject.parent.getChildIndex(this.gameObject); 34          } 35      } 36  }); 37  38  /** 39   * 初始化 40   */ 41  BlocksUI.prototype.awake = function() { 42      // 点击时的偏移量 43      var self = this; 44      self.offsetY = self.game.device.desktop ? 0 : 50; 45  }; 46  47  /** 48   * 重新绘制区块 49   */ 50  BlocksUI.prototype.redraw = function() { 51      var self = this; 52      var frame = qc.Tetris.IMAGES[self.data.value]; 53      self.data.list.forEach(function(pos) { 54          var x = pos[0], y = pos[1]; 55          var block = self.game.add.clone(self.blockPrefab, self.gameObject); 56          block.find('block').frame = frame + '.png'; 57          block.name = x + '_' + y; 58          self._blocks[qc.Tetris.makePos(x, y)] = block; 59      }); 60      self.reset(); 61  }; 62  63  /** 64   * 重设区块大小和排列下属格子的位置 65   */ 66  BlocksUI.prototype.reset = function() { 67      var self = this, o = self.gameObject; 68      for (var pos in self._blocks) { 69          var p = qc.Tetris.readPos(pos); 70          var pt = qc.Tetris.board.toWorld(p, qc.Tetris.POOL_DISTANCE_NORMAL); 71          var block = self._blocks[pos]; 72          block.anchoredX = pt.x; 73          block.anchoredY = pt.y; 74      } 75  };
  • 本脚本根据形状的数据,动态创建出格子并显示出来
  • blockPrefab为格子的预置,后续步骤创建
  • 形状的大小会比棋盘中显示小,因此计算格子的屏幕坐标时,指明了常量:qc.Tetris.POOL_DISTANCE_NORMAL
  • 在初始化时,设置了非PC模式下需要做偏移为50。(在手机上拖拽时方式被手指完全挡住,从而看不清形状)

3. 修改Tetris.js,加入POOL_DISTANCE_NORMAL配置:

1  window.Tetris = qc.Tetris = {  2      // 棋盘的大小(半径)  3      SIZE: 4,  4   5      // 棋盘中,每个格子的宽度和高度  6      BLOCK_W: 61,  7      BLOCK_H: 67,  8   9      // 没有点击时,格子之间的距离 10      POOL_DISTANCE_NORMAL: 45, 11  12      ...

4.在上述Blocks节点下,创建空的节点Node,名字修改为block2,属性为:

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

5. 在block2节点下,创建Image节点,名字修改为shadow,属性设置如下:

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

  • 相对于父亲居中显示
  • pivot=(0.5, 0.5)
  • 大小为60*65
  • 使用ui图集

6. 在block2节点下,创建Image节点,名字修改为block,属性设置如下:

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

    • 相对于父亲居中显示
    • pivot=(0.5, 0.5)
    • 大小为40*45
    • 使用ui图集
      至此,你的场景应该是:

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

7. 将block2节点拖入到目录Assets/prefab,创建预置。然后将节点从场景中删除。

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

8. 将BlocksUI.js挂载到Blocks节点,并设置blockPrefab的值为上步骤创建的预制。设置完成后,将此节点拖入Assets/prefab目录,创建预置。

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

9. 至此,形状的预置创建完毕了

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

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

正文到此结束
Loading...