微信小游戏之三消(二)主要游戏控制方法

微信小游戏之三消(二)主要游戏控制方法_第1张图片

设计一个 game class。负责了游戏的核心控制逻辑,包括游戏状态管理、方块和道具的生成与效果处理,以及游戏的重新开始和复活流程。通过这些方法,脚本实现了游戏的基本玩法和用户交互。

主要游戏控制方法

  • gameStart():开始游戏,恢复所有方块状态,初始化分数管理器,设置地图。

  • mapSet(num):初始化地图,生成随机的方块布局。

  • checkNeedFall():检查是否需要下落的防抖方法。

  • onFall():方块下落的逻辑。

  • gameOver():游戏结束的逻辑,添加复活页面。

  • askRevive():处理复活请求,显示复活页面。

  • onReviveButton():复活按钮的点击事件。

  • showReviveSuccess():显示复活成功的页面。

  • onReviveCertainBtn():处理确定复活的按钮点击事件。

  • restart():重新开始游戏。

道具相关方法

  • onUserTouched(iid, jid, itemType, color, warning, pos):存储用户点击的方块信息,用于生成道具。

  • generatePropItem(type):根据类型生成道具。

  • checkGenerateProp(chain):检查并生成连锁道具效果。

  • onItem(type, color, pos):处理道具效果,如分数翻倍、炸弹消除等。

预制体实例化方法

  • generatePool():生成对象池,用于方块的实例化和回收。

  • instantiateBlock(self, data, parent, itemType, pos):实例化单个方块,初始化方块组件。

  • recoveryAllBlocks():回收所有方块节点,用于游戏重新开始或结束。

gameStart 方法是游戏开始时调用的核心逻辑,用于初始化游戏环境并启动游戏循环。以下是 gameStart 方法的逻辑分析:


/**
 * gameStart 方法用于启动游戏,初始化游戏环境和状态。
 */
gameStart() {
  // 回收所有方块,准备重新开始游戏
  this.recoveryAllBlocks().then(() => {
    // 初始化分数管理器
    this._score.init(this);
    
    // 初始化游戏地图,设置方块布局
    this.mapSet(this.rowNum).then((result) => {
      // 游戏状态改变,更新游戏状态为开始状态(状态1)
      this._status = 1;
    });
  });
},

详细步骤:

  • 回收方块 (recoveryAllBlocks): 将之前游戏中使用的所有方块回收到对象池,以便重新利用,减少实例化开销。

  • 初始化分数 (_score.init): 初始化或重置分数管理器,为新游戏开始做准备。

  • 设置地图 (mapSet): 创建一个新的地图,随机生成方块,并设置它们在地图上的位置。这个方法还负责设置特殊方块类型,如道具方块。

  • 异步等待: 由于 mapSet 是异步的,使用 then 来确保在地图准备好之后再继续。

  • 状态更新: 设置 _status 为 1,这通常会在游戏循环和用户界面中用来检查游戏是否已经开始。

mapSet 方法的目的是为游戏创建一个初始状态的地图,其中包括随机分布的方块和道具,为游戏开始做好准备。通过使用 PromisesetTimeout,它能够处理异步的动画延迟,确保方块以动画形式逐一出现在游戏地图上。

// mapSet 方法用于初始化游戏地图,设置方块的布局和类型
mapSet(num) {
  // 初始化地图为一个 num x num 的二维数组
  this.map = new Array();

  // 保存当前对象的引用
  let self = this;

  // 生成随机数来确定特殊方块的位置
  let a = Math.floor(Math.random() * num);
  let b = Math.floor(Math.random() * num);
  let c = Math.floor(1 + Math.random() * (num - 1)) - 1;
  // 确保 c 不等于 a,以便有区分的道具位置
  if (a == c) c++;
  let d = Math.floor(Math.random() * num);

  // 返回一个 Promise 对象,以便在地图设置完毕后执行异步操作
  return new Promise((resolve, reject) => {
    // 遍历地图的每一行
    for (let i = 0; i < num; i++) {
      // 初始化当前行的数组
      this.map[i] = new Array();
      // 遍历地图的每一列
      for (let j = 0; j < num; j++) {
        // 根据随机坐标确定方块的类型(0为普通方块,1和2为不同类型的道具方块)
        let itemType = (i == a && j == b) ? 1 : (i == c && j == d) ? 2 : 0;
        
        // 调用 instantiateBlock 方法来创建方块实例
        self.map[i][j] = self.instantiateBlock(self, {
          x: j, // 列位置
          y: i, // 行位置
          width: self.blockWidth, // 根据地图宽度计算的方块宽度
          startTime: (i + j + 1) * self._controller.config.json.startAnimationTime / num * 2 // 计算动画开始时间
        }, self.blocksContainer, itemType);
      }
    }

    // 初始化检查管理器,准备进行方块检查
    this.checkMgr.init(this);

    // 设置一个延迟,以便于所有方块动画完成后再执行检查
    setTimeout(() => {
      // 解析 Promise,表示地图设置完成
      resolve('200 OK');
      // 执行检查函数,检查方块布局和消除情况
      self.checkMgr.check(self);
    }, self._controller.config.json.startAnimationTime * num / 2);
  });
}

详细步骤:

  1. 初始化地图数组:创建一个二维数组 this.map 来存储游戏地图的布局。

  2. 定义局部变量:保存对当前类的引用,以便在匿名函数中使用。

  3. 随机生成位置:生成随机坐标点,用于确定特殊方块的初始位置。

  4. 返回 Promise:使 mapSet 方法支持异步操作,以便在地图初始化完成后执行其他任务。

  5. 遍历地图位置:通过两层嵌套循环遍历地图的每一行和每一列。

  6. 确定方块类型:根据随机生成的坐标点,为每个方块分配类型(普通或道具)。

  7. 实例化方块:为每个位置创建方块实例,设置其属性,并添加到游戏地图中。

  8. 初始化检查管理器:在所有方块生成后,准备进行方块的消除检查。

  9. 设置延迟执行:使用 setTimeout 延迟执行检查函数,确保方块动画完成后再进行检查。

  10. 解析 Promise:在延迟时间结束后,解析 Promise 并执行方块检查,完成地图的初始化。

checkNeedFall 方法实现了一个防抖机制,确保方块下落的逻辑不会过于频繁地被触发,从而提高游戏性能并优化用户体验

// checkNeedFall 方法用于检查是否需要执行方块的下落动作
checkNeedFall() {
  // 如果 checkNeedFallTimer 已经存在,说明之前的检查尚未完成,需要清除定时器
  if (this.checkNeedFallTimer) {
    clearTimeout(this.checkNeedFallTimer);
  }

  // 设置一个新的定时器,以实现防抖功能
  // 防抖逻辑:在一定时间间隔(例如300毫秒)内,即使多次触发也不会连续执行下落逻辑
  this.checkNeedFallTimer = setTimeout(() => {
    // 检查游戏状态是否允许方块下落(状态为5时允许)
    if (this._status == 5) {
      // 如果状态允许,将游戏状态更新为下落状态(状态4)
      this._status = 4;
      // 调用 onFall 方法执行方块下落的逻辑
      this.onFall();
    }
    // 设置定时器的时间间隔为 300 毫秒,以实现防抖效果
  }, 300 / 1
  // (cc.game.getFrameRate() / 60) // 这里被注释掉的代码可能是为了适应不同的帧率
  );
}

详细步骤:

  1. 清除已有定时器:如果 checkNeedFallTimer 已经设置,使用 clearTimeout 清除它,避免之前的延迟操作影响当前逻辑。

  2. 定义局部变量:this 关键字引用当前对象,用于访问类的属性和方法。

  3. 设置新定时器:使用 setTimeout 创建一个新的定时器,延迟执行下落检查逻辑。

  4. 防抖逻辑:定时器的延迟时间设置为 300 毫秒,这意味着在这段时间内,无论触发多少次 checkNeedFall 方法,onFall 方法都只会执行一次。

  5. 检查游戏状态:在定时器的回调函数中,检查 _status 是否等于 5,即是否处于可以下落的状态。

  6. 更新状态为下落:如果条件满足,将 _status 更新为 4,表示方块即将开始下落。

  7. 执行下落逻辑:调用 onFall 方法,执行方块下落的逻辑。

  8. 定时器时间间隔:定时器的时间间隔可以根据游戏的帧率进行调整,以确保不同设备上都能正常工作。

onFall 方法实现了方块下落的逻辑,包括处理空格、生成新方块、执行下落动画,以及在适当的时候更新游戏状态


// onFall 方法用于处理方块下落的逻辑
onFall() {
  // 检查是否可以生成道具,并在完成后继续执行下落逻辑
  this.checkGenerateProp(this._score.chain).then(() => {
    let self = this; // 保存当前对象的引用
    let canFall = 0; // 用于记录连续空格的数量

    // 从每一列的最下面开始往上判断,是否有空格
    for (let j = this.rowNum - 1; j >= 0; j--) {
      canFall = 0; // 重置连续空格计数器

      // 从底部开始向上遍历每一列的方块
      for (let i = this.rowNum - 1; i >= 0; i--) {
        // 如果当前位置的方块状态为已消失(状态2),则进行下落处理
        if (this.map[i][j].getComponent('cell')._status == 2) {
          // 将消失的方块回收到对象池中
          this.blockPool.put(this.map[i][j]);
          // 更新地图数组,标记当前位置为空
          this.map[i][j] = null;
          canFall++; // 增加连续空格计数
        } else {
          // 如果上方有连续空格,则让当前方块下落
          if (canFall != 0) {
            // 交换当前方块与上方空格的方块
            this.map[i + canFall][j] = this.map[i][j];
            this.map[i][j] = null;
            // 让上方的方块下落
            this.map[i + canFall][j].getComponent('cell').playFallAction(canFall, {
              x: j,
              y: i + canFall,
            });
          }
        }
      }

      // 如果当前列有连续空格,生成新方块并让它们下落
      for (var k = 0; k < canFall; k++) {
        // 在地图数组中放置新方块的位置
        this.map[k][j] = this.instantiateBlock(this, {
          x: j,
          y: k,
          width: this.blockWidth,
          startTime: null
        }, this.blocksContainer, '', {
          x: j,
          y: -canFall + k
        });
        // 让新生成的方块执行下落动作
        this.map[k][j].getComponent('cell').playFallAction(canFall, null);
      }
    }

    // 在所有下落动作完成后,设置一个延迟,再次检查游戏状态
    setTimeout(() => {
      // 初始化检查管理器,准备进行方块检查
      this.checkMgr.init(this);
      // 执行检查函数,检查方块布局和消除情况
      this.checkMgr.check(this);
      // 更新游戏状态为可玩
      this._status = 1;
    }, 250); // 设置延迟时间,以便于动画效果完成后再执行检查
  });
}

详细步骤:

  1. 检查生成道具:调用 checkGenerateProp 方法检查是否可以生成道具,并等待其完成后继续。

  2. 保存引用:保存当前对象的引用,以便在匿名函数中使用。

  3. 初始化空格计数器:canFall 用于记录连续的空格数量。

  4. 遍历列:从地图的最底部开始,向上遍历每一列。

  5. 重置空格计数器:在遍历每一列时重置 canFall

  6. 遍历行:在每一列内部,从底部向上遍历每一行。

  7. 方块下落处理:

    • 如果当前方块已经消失(状态为2),则将其回收并标记地图数组中相应位置为空。

    • 如果上方有空格,让当前方块下落。

  8. 生成新方块:如果有连续空格,生成新方块并让它们下落。

  9. 执行下落动作:调用 playFallAction 方法让方块执行下落动画。

  10. 设置延迟:在所有下落动作完成后,使用 setTimeout 设置延迟。

  11. 再次检查状态:延迟结束后,初始化检查管理器并执行检查函数,更新游戏状态。

更多详细代码逻辑请看:微信小游戏之三消(二)主要游戏控制方法代码逻辑分享 (qq.com)icon-default.png?t=N7T8https://mp.weixin.qq.com/s?__biz=MzI0NTE3ODY5Mg==&mid=2247483770&idx=1&sn=721d6cb02baf8d2345870e924598e094&chksm=e953c951de24404768866f4c01a3e97f4cda185fe4f4a1cba84c8b98fc76303de832f66c3ebb&token=1281952290&lang=zh_CN#rd

你可能感兴趣的:(微信小游戏开发,游戏开发,游戏,微信小程序)