微信小程序--推箱子小游戏

新建项目

新建一个空的微信小程序项目。

配置文件
  1. 在pages页面下配置home、game相关页面文件;

  2. 在app.js、app.json和app.wxss文件中进行全局配置;

  3. 新建images文件夹,在文件夹下导入所需图片素材;

  4. 在utils文件夹下的data.js文件夹中配置关卡数据。

功能分析
基础功能:

(1) 首页需要包含标题和关卡列表。 (2) 关卡至少要有4个关卡选项,每个关卡显示预览图片和第几关。 (3) 点击关卡列表可以打开对应的游戏画面。

添加功能:

(1) 为每个关卡添加倒计时功能,限时60秒,超时后若没有通关则提醒用户选择继续游戏或者重新开始。

(2) 为每个关卡添加步数记录功能,每移动一步步数加1。

(3) 为全局添加背景音乐。

(4) 为每个关卡添加撤回功能,用户可以撤回每一步,撤回时计时不暂停,步数不增加。

(5) 为全局添加背景,进一步优化界面。

页面设计与实现
首页
  1. 使用view、image和text标签实现首页标题和关卡列表展示及点击跳转功能:

    <view class='container'>
      <view class='title'>游戏选关</view>
      <view class='levelBox'>
        <view class='box' wx:for='{{levels}}' wx:key='levels{{index}}' bindtap='chooseLevel' data-level='{{index}}'>
          <image src='/images/{{item}}'></image>
          <text>第 {{index+1}} 关</text>
        </view>
      </view>
    </view>

    对应JavaScript函数实现功能:

    Page({
      data: {
        levels: [
          '../../images/level01.png',
          '../../images/level02.png',
          '../../images/level03.png',
          '../../images/level04.png'
        ]
      },
      chooseLevel: function(e) {
        let level = e.currentTarget.dataset.level
        wx.navigateTo({
          url: '../game/game?level=' + level
        })
      },

关卡页面
  1. 使用view,image和text标签实现新闻内容的显示。

  <image id="lb" src="../../images/喇叭.png"></image>
  <view class='title'>第 {{level}} 关</view>
  <view class="container2">  
    <view class="timer">还剩 {{timeLeft}} 秒</view>  
    <text class="walk">步数: {{steps}}</text>
  </view> 
 onLoad: function(options) {
    //获取关卡
    const backgroundAudioManager = wx.getBackgroundAudioManager();  
    backgroundAudioManager.src = '../../music/back.mp3';
    backgroundAudioManager.play();  
  
    //监听背景音频播放结束事件  
    backgroundAudioManager.onEnded(() => {  
      console.log('背景音乐播放结束');  
    });  
  
    //监听背景音频播放错误事件  
    backgroundAudioManager.onError((res) => {  
      console.error('背景音乐播放出错', res.errMsg);  
    });  
    let level= options.level
    //更新页面关卡标题
    this.setData({
      level: parseInt(level) + 1
    })
    //创建画布上下文
    this.ctx = wx.createCanvasContext('myCanvas')
    //初始化地图数据
    this.initMap(level)
    //绘制画布内容
    this.drawCanvas(),
    // 开始倒计时  
    this.startTimer(); 
  },
  startTimer: function() {    
    let timeLeft = this.data.timeLeft;    
    let timerId = setInterval(() => {    
      if (timeLeft > 0) { 
        timeLeft--;    
        this.setData({    
          timeLeft: timeLeft    
        });    
      } else {  // 当timeLeft不大于0时,停止倒计时  
        this.timeOut();    
      }    
    }, 1000);    
    // 将timerId保存到页面的data中,以便可以在其他地方访问它  
    this.setData({  
      timerId: timerId  
    });  
  },   
  timeOut: function() {  
    clearInterval(this.data.timerId);  
    wx.showModal({  
      title: '超时',  
      content: '时间耗尽,您没有过关!是否重新开始?',  
      success: (res) => {  
        if (res.confirm) {  
          this.restartGame();  
        } else if (res.cancel) {  
          console.log('用户点击取消');  
        }  
      }  
    });  
  }, 
  1. 使用canvas标签实现游戏画布可视化功能。

  <canvas canvas-id='myCanvas'></canvas>

通过addFavorites和addFavorites函数,结合if判断语句和isAddsc的状态实现收藏和取消收藏功能。

var data = require('../../utils/data.js')
var map = [
  [0, 0, 0, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0, 0, 0]
]
var box = [
  [0, 0, 0, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0, 0, 0]
]
var w = 40
var row = 0
var col = 0
​
Page({
  data: {
    level: 1,
    timeLeft: 60, // 初始倒计时60秒  
    steps: 0,
    history: [],
  },
  updateSteps: function() {  
    this.setData({  
      steps: this.data.steps + 1  
    });  
  }, 
​
  initMap: function(level) {
    let mapData = data.maps[level]
    for (var i = 0; i < 8; i++) {
      for (var j = 0; j < 8; j++) {
        box[i][j] = 0
        map[i][j] = mapData[i][j]
​
        if (mapData[i][j] == 4) {
          box[i][j] = 4
          map[i][j] = 2
        } else if (mapData[i][j] == 5) {
          map[i][j] = 2
          //记录小鸟的当前行和列
          row = i
          col = j
        }
      }
    }
  },
​
  drawCanvas: function() {
    let ctx = this.ctx
    //清空画布
    ctx.clearRect(0, 0, 320, 320)
    for (var i = 0; i < 8; i++) {
      for (var j = 0; j < 8; j++) {
        let img = 'ice'
        if (map[i][j] == 1) {
          img = 'stone'
        } else if (map[i][j] == 3) {
          img = 'pig'
        }
​
        //绘制地图
        ctx.drawImage('/images/icons/' + img + '.png', j * w, i * w, w, w)
​
        if (box[i][j] == 4) {
          //叠加绘制箱子
          ctx.drawImage('/images/icons/box.png', j * w, i * w, w, w)
        }
      }
    }
​
    //叠加绘制小鸟
    ctx.drawImage('/images/icons/bird.png', col * w, row * w, w, w)
​
    ctx.draw()
  },
​
  1. 使用button组件实现移动功能。

<view class='btnBox'>
    <button type='warn' bindtap='up'>↑</button>
    <view>
      <button type='warn' bindtap='left'>←</button>
      <view class="noUse"> </view>
      <button type='warn' bindtap='down'>↓</button>
      <view class="noUse"> </view>
      <button type='warn' bindtap='right'>→</button>
    </view>
  </view>
up: function() {
    //如果不在最顶端才考虑上移
    if (row > 0) {
      //如果上方不是墙或箱子,可以移动小鸟
      if (map[row - 1][col] != 1 && box[row - 1][col] != 4) {
        //更新当前小鸟坐标
        row = row - 1
      }
      //如果上方是箱子
      else if (box[row - 1][col] == 4) {
        //如果箱子不在最顶端才能考虑推动
        if (row - 1 > 0) {
          //如果箱子上方不是墙或箱子
          if (map[row - 2][col] != 1 && box[row - 2][col] != 4) {
            box[row - 2][col] = 4
            box[row - 1][col] = 0
            //更新当前小鸟坐标
            row = row - 1
          }
        }
      }
      this.updateSteps();
      this.saveState();
      //重新绘制地图
      this.drawCanvas()
      //检查游戏是否成功
      this.checkWin()
    }
  },
​
  down: function() {
    //如果不在最底端才考虑下移
    if (row < 7) {
      //如果下方不是墙或箱子,可以移动小鸟
      if (map[row + 1][col] != 1 && box[row + 1][col] != 4) {
        //更新当前小鸟坐标
        row = row + 1
      }
      //如果下方是箱子
      else if (box[row + 1][col] == 4) {
        //如果箱子不在最底端才能考虑推动
        if (row + 1 < 7) {
          //如果箱子下方不是墙或箱子
          if (map[row + 2][col] != 1 && box[row + 2][col] != 4) {
            box[row + 2][col] = 4
            box[row + 1][col] = 0
            //更新当前小鸟坐标
            row = row + 1
          }
        }
      }
      this.updateSteps();
      this.saveState();
      //重新绘制地图
      this.drawCanvas()
      //检查游戏是否成功
      this.checkWin()
    }
  },
  left: function() {
    //如果不在最左侧才考虑左移
    if (col > 0) {
      //如果左侧不是墙或箱子,可以移动小鸟
      if (map[row][col - 1] != 1 && box[row][col - 1] != 4) {
        //更新当前小鸟坐标
        col = col - 1
      }
      //如果左侧是箱子
      else if (box[row][col - 1] == 4) {
        //如果箱子不在最左侧才能考虑推动
        if (col - 1 > 0) {
          //如果箱子左侧不是墙或箱子
          if (map[row][col - 2] != 1 && box[row][col - 2] != 4) {
            box[row][col - 2] = 4
            box[row][col - 1] = 0
            //更新当前小鸟坐标
            col = col - 1
          }
        }
      }
      this.updateSteps();
      this.saveState();
      //重新绘制地图
      this.drawCanvas()
      //检查游戏是否成功
      this.checkWin()
    }
​
​
  },
​
  right: function() {
    //如果不在最右侧才考虑右移
    if (col < 7) {
      //如果右侧不是墙或箱子,可以移动小鸟
      if (map[row][col + 1] != 1 && box[row][col + 1] != 4) {
        //更新当前小鸟坐标
        col = col + 1
      }
      //如果右侧是箱子
      else if (box[row][col + 1] == 4) {
        //如果箱子不在最右侧才能考虑推动
        if (col + 1 < 7) {
          //如果箱子右侧不是墙或箱子
          if (map[row][col + 2] != 1 && box[row][col + 2] != 4) {
            box[row][col + 2] = 4
            box[row][col + 1] = 0
            //更新当前小鸟坐标
            col = col + 1
          }
        }
      }
      this.updateSteps();
      this.saveState();
      //重新绘制地图
      this.drawCanvas()
      //检查游戏是否成功
      this.checkWin()
    }
  },
​
  1. 使用button组件实现重新开始和撤回功能。

  <button type='warn' bindtap='restartGame'>重新开始</button>
  <button bindtap="undo">撤回</button> 
restartGame: function() {
    this.setData({  
      timeLeft: 60, // 假设初始时间为60秒  
      // 重置其他游戏状态...  
    }); 
    //初始化地图数据
    this.initMap(this.data.level - 1)
    //绘制画布内容
    this.drawCanvas();
    this.startTimer();  
  },
saveState: function() {  
    // 假设 getState 是一个函数,返回当前游戏状态的对象  
    let state = this.getState();  
    // 将当前状态添加到历史记录中  
    this.data.history.push(state);  
    // 更新当前步骤  
    this.setData({  
      currentStep: this.data.history.length - 1  
    });  
  },  
    
  // 获取当前游戏状态  
getState: function() {  
    return {  
      map: JSON.parse(JSON.stringify(map)),  // 深拷贝地图  
      box: JSON.parse(JSON.stringify(box)),  // 深拷贝箱子  
      row: row,  
      col: col  
    };  
  },
  1. 检测游戏是否结束。

  isWin: function() {
    //使用双重for循环遍历整个数组
    for (var i = 0; i < 8; i++) {
      for (var j = 0; j < 8; j++) {
        //如果有箱子没在终点
        if (box[i][j] == 4 && map[i][j] != 3) {
          //返回假,游戏尚未成功
          return false
        }
      }
    }
    //返回真,游戏成功
    return true
  },
​
  checkWin: function() {
    if (this.isWin()) {
      wx.showModal({
        title: '恭喜',
        content: '游戏成功!',
        showCancel: false
      })
    }
  },

效果:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值