zoukankan      html  css  js  c++  java
  • JS开发HTML5游戏《神奇的六边形》(一)

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

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

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

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

    1. 功能分析

    2. 创建工程与场景

    3. 玩家分数管理

    4. 棋盘设计与实现

    5. 屏幕布局

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

    功能分析

    首先分析游戏的功能点、算法和数据,然后依此制订代码组织结构。如下图:

    主要功能点

    1. 棋盘的数据结构与绘制
    2. 3个形状的生成
    3. 形状拖拽填入棋盘
    4. 行消除判定与死亡判定
    5. 各种表现,例如消除动画、加分动画等

    代码结构

    将游戏逻辑(例如棋盘数据结构、死亡判定等)和界面逻辑分开,分别置于logic和ui界面。所有的UI界面交给UIManager脚本统一维护管理。

    二. 创建工程与场景

    创建工程Tetris和空的主场景Main,设置如下:

    本工程中,画布背景(background)设置为透明

    游戏入口与游戏初始化

    在Scripts目录下创建文件:Tetris.js。代码如下:

     1  /**
     2      * 游戏入口
     3      */
     4     window.Tetris = qc.Tetris = {
     5         // 所有的操作指令集合
     6         operation: {}
     7     };
     8 
     9     // 游戏逻辑初始化
    10     qc.initGame = function(game) {
    11         // 将游戏实例记录下来,便于访问
    12         Tetris.game = game;
    13 
    14         // 帧率显示为60帧(满帧)
    15         game.time.frameRate = 60;
    16     };

     设置此脚本为入口脚本:


    此脚本首先定义了名字空间,将全局的数据都记录在qc.Tetris。
    游戏入口中,记录了game的实例并将帧率限定为60帧(默认在手机下为30帧)


    三. 玩家分数管理

    1. 创建脚本:Scripts/logic/Score.js:

       1  /**
       2   * 维护分数信息
       3   */
       4  var Score = qc.Tetris.Score = function() {
       5      var self = this;
       6      self._current = 0;
       7      self._best = 0;
       8 
       9      // 将本地数据读取出来
      10      var game = qc.Tetris.game;
      11      var current = game.storage.get('current'),
      12          best = game.storage.get('best');
      13      if (current) self._current = current;    
      14      if (best) self._best = best;
      15  };
      16  Score.prototype = {};
      17  Score.prototype.constructor = Score;
      18 
      19  Object.defineProperties(Score.prototype, {
      20      current: {
      21          get: function() { return this._current; },
      22          set: function(v) {
      23              this._current = v;
      24              if (this.best < v) this.best = v;
      25          }
      26      },
      27 
      28      best: {
      29          get: function() { return this._best; },
      30          set: function(v) {
      31              this._best = v;
      32              var storage = qc.Tetris.game.storage;
      33              storage.set('best', v);
      34              storage.save();
      35          }
      36      }
      37  });

      Score类维护了两个数据:current(当前玩家的分数)、best(玩家的历史最高分)

    2. 实例化Score类
      打开Tetris.js脚本,在initGame方法中,加入代码:

       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  };
     

    四. 棋盘设计与实现

    棋盘为一边长为5的正六变形,为了方便计算,我们如下设定棋盘的坐标系(下文称为:格子逻辑坐标):

    原点在六边形中心点,半径为4。

    1. 修改Tetris.js文件,增加棋盘的配置信息:

       1  window.Tetris = qc.Tetris = {
       2      // 棋盘的大小(半径)
       3      SIZE: 4,
       4 
       5      // 棋盘中,每个格子的宽度和高度
       6      BLOCK_W: 61,
       7      BLOCK_H: 67,
       8 
       9      // 所有的操作指令集合
      10      operation: {}
      11  };

      棋盘格子的大小 = 格子图片的大小,后续导入资源后可以看到其大小为61*67。

    2. 在Scripts/logic下创建文件Board.js,维护棋盘的数据,代码如下:

       1  var Board = qc.Tetris.Board = function() {
       2      var self = this,
       3          size = qc.Tetris.SIZE,
       4          len = qc.Tetris.BLOCK_H;
       5 
       6      // 构建用来转换格子坐标的矩阵
       7      var m = self.m = new qc.Matrix();
       8      m.a = len;
       9      m.c = len / 2;
      10      m.d = len * (Math.sqrt(3) / 2);
      11 
      12      // 初始化棋盘数据
      13      self.data = {};
      14      for (var i = -size; i <= size; i++) {
      15          for (var j = -size; j <= size; j++) {
      16              // 这些格子落在六边形外,忽略掉
      17              if (i * j > 0 && Math.abs(i + j) > size) continue;
      18              if (i * j < 0 && (Math.abs(i) > size || Math.abs(j) > size)) continue;
      19 
      20              // 计算格子的坐标和对应屏幕上的偏移
      21              var pos = Tetris.makePos(i, j);
      22              var pt = self.toWorld(new qc.Point(i, j));
      23              self.data[pos] = {
      24                  value: 0,
      25                  x: pt.x,
      26                  y: pt.y
      27              };
      28          }
      29      }
      30  };
      31  Board.prototype = {};
      32  Board.prototype.constructor = Board;
      33 
      34  Object.defineProperties(Board.prototype, {
      35      /**
      36       * @property {boolean} die - 当前是否已经死亡了
      37       * @readonly
      38       */ 
      39      die: {
      40          get: function() {
      41              // TODO: 等待实现
      42          }
      43      }
      44  });
      45 
      46  /**
      47   * 清空棋盘
      48   */
      49  Board.prototype.clear = function() {
      50      for (var pos in this.data) {
      51          this.data[pos].value = 0;
      52      }
      53  };
      54 
      55  /**
      56   * 重新开始游戏
      57   */
      58  Board.prototype.restart = function() {
      59      this.clear();
      60  };
      61 
      62  // 判定形状可以放进来不
      63  // pos: 目标逻辑坐标
      64  // list: 形状的信息
      65  Board.prototype.checkPutIn = function(pos, list) {
      66      // TODO: 等待实现
      67  };
      68 
      69  // 把某个形状放进来
      70  Board.prototype.putIn = function(pos, list, value) {
      71      // TODO: 等待实现
      72  };
      73 
      74  // 根据格子的逻辑坐标,算出所在的屏幕坐标
      75  // distance: 两个格子中心点之间的距离
      76  Board.prototype.toWorld = function(p, distance) {
      77      if (!distance)
      78          return this.m.apply(p);
      79 
      80      var m = new qc.Matrix();
      81      m.a = distance;
      82      m.c = distance * 0.5;
      83      m.d = distance * (Math.sqrt(3) * 0.5);
      84      return m.apply(p);
      85  };
      86 
      87  // 根据格子的屏幕坐标,反算格子的逻辑坐标
      88  Board.prototype.toLocal = function(p) {
      89      return this.m.applyInverse(p);
      90  };
    3. 修改Tetris.js,在qc.initGame方法中,实例化本对象:

       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  };

      同时,在本文件中实现两个函数:makePos和readPos:

       1  // 构建坐标
       2  window.Tetris.makePos = function(x, y) {
       3      return x + '_' + y;
       4  };
       5 
       6  // 获取坐标
       7  window.Tetris.readPos = function(pos) {
       8      var arr = pos.split('_');
       9      return new qc.Point(arr[0]*1, arr[1]*1);
      10  };

    五. 屏幕布局

    在美术设计时,以640*960分辨率(iPhone4)进行设计,其他分辨率的屏幕需要自适应。如下图:




    • 整个界面分为标题栏(Top)、棋盘(Board)、3个形状(Shape)
      • Top:高度在iPhone4上为130。这里有两个信息:当前分数与历史最高分数
      • Board:棋盘,其大小为600*580
      • Shape:3个形状,大小为600*230,距离底部20
    • 自适应方案:
      • 以 640*960为基准,等比缩放,确保所有内容都能全部显示
      • 当分辨率比较瘦长时(即Height/Width > 960/640)时,Board和Shape保持和底部位置不变(方便单手操作)。Top高度自动增加
      • 当分辨率比较宽时(即Height/Width < 960/640)时,Board和Shape保持居中,两边留白

    导入资源

    1. 新建文件夹:Assets/atlas/ui@atlas,将以下文件拖入并打包图集(图片请在示例工程中查看)
      blue.png、cyan.png、gray.png、green.png、lightyellow.png、red.png、shadow.png、white.png、yellow.png
      darkblue.png、darkcyan.png、darkgreen.png、darklightyellow.png、darkred.png、darkyellow.png等,具体请参考示例工程
      格子在没有数据时,显示gray.png。其他形状的格子颜色,有6种(blue、cyan、green、lightyellow、yellow、red)

    2. 将以下文件拖入文件夹Assets/raw(raw目录下的资源都不会被打包,例如图片直接原样保留,适用于css样式表指定资源)
      blue.png、cyan.png、gray.png、green.png、lightyellow.png、red.png、yellow.png等,具体请参考示例工程,各图片的用途在后续中会说明。

    界面布局

          1. 创建UIRoot,并设置Reference Resolution(参考分辨率)为 640*960,Manual Type为Expand

             

             简单的理解:设置了以后,就可以认为屏幕的宽度>=640,高度>=960

    2. 创建棋盘。棋盘大部分情况下是“静态”的,只是在有新的形状放入时才会变化。如果棋盘的每个格子作为UIImage进行贴图,则每帧都需要重绘几十个格子图片,对渲染效率会有所影响。这里我们适用DOM方案,里面每个格子使用div进行绘制。因此创建一个DOM节点,设置其大小为:600*580,同时由于棋盘距离底部的位置固定,因此在布局上:水平居中、垂直距离底部250,自身中心点在底部中心位置。如下图:

    3. 添加一个Node节点,挂载3个形状。Node大小为 600*230,距离底部20。如下图:

    4. 创建DOM节点显示历史最高分(不常变化,因此不用UIText,使用Dom更高效)。本节点大小为200*60,距离屏幕右边20,顶部20:

    5. 创建DOM节点显示当前分(不常变化,因此不用UIText,使用Dom更高效)。本节点大小为200*80,水平居中,顶部顶部29:

     

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

  • 相关阅读:
    vbox安装增强功能,实现宿主机文件夹共享并浏览器访问
    linux镜像下载
    linux命令之sed
    关于MySQL数据库的备份方案
    linux防火墙使用以及配置
    Jenkins安装部署(二)
    Jenkins安装部署(一)
    Centos7在虚拟机中扩展磁盘空间
    CentOS 7系统根目录分区扩容
    Linux下的SVN服务器搭建
  • 原文地址:https://www.cnblogs.com/qici/p/4955963.html
Copyright © 2011-2022 走看看