2023年夏季《移动软件开发》实验报告之实验6:推箱子游戏

2023年夏季《移动软件开发》实验报告

1、综合所学知识创建完整的推箱子游戏项目;能够在开发过程中熟练掌握真机预览、调试等操作。

二、实验步骤

列出实验的关键步骤、代码解析、截图。

1.项目创建和文件准备

下载素材图片并放入images文件夹中,创建game页面文件夹

image-20230905113733107

2.界面设计

2.1主页界面设计

index.wxss代码如下:

/* 关卡列表区域 */
.levelBox {
    width: 100%;
  }
  
  /* 单个关卡区域 */
  .box {
    width: 50%;
    float: left;
    margin: 20rpx 0;
    display: flex;
    flex-direction: column;
    align-items: center;
  }
  
  /* 选关图片 */
  image {
    width: 300rpx;
    height: 300rpx;
  }

index.wxml代码如下:

<view class='container'>
  <!-- 标题 -->
  <view class='title'>游戏选关</view>
  <!-- 关卡列表 -->
  <view class='levelBox'>
    <view class='box' wx:for='{{levels}}' wx:key='levels{{index}}' bind:tap='chooseLevel' data-level='{{index}}'>
      <image src='/images/{{item}}'></image>
      <text>第{{index+1}}关</text>
    </view>
  </view>
</view>

效果如图:

image-20230905125237238

2.2游戏界面设计

game.wxss代码如下:

/**game.wxss**/
/* 游戏画布样式 */
canvas {
    border: 1rpx solid;
    width: 320px;
    height: 320px;
  }
  /* 方向键按钮整体区域 */
  .btnBox {
    display: flex;
    flex-direction: column;
    align-items: center;
  }
  /* 方向键按钮第二行 */
  .btnBox view {
    display: flex;
    flex-direction: row;
  } 
  /* 所有方向键按钮 */
  .btnBox button {
    width: 90rpx;
    height: 90rpx;
  }
  /* 所有按钮样式 */
  button {
    margin: 10rpx;
  }

game.wxml代码如下:

<!--game.wxml-->
<view class='container'>
  <!-- 关卡提示 -->
  <view class='title'>第{{level}}关</view>
  <!-- 游戏画布 -->
  <canvas canvas-id='myCanvas'></canvas>
  <!-- 方向键 -->
  <view class='btnBox'>
    <button type='warn' bindtap='up'>↑</button>
    <view>
      <button type='warn' bindtap='left'>←</button>
      <button type='warn' bindtap='down'>↓</button>
      <button type='warn' bindtap='right'>→</button>
    </view>
  </view>
  <!-- 重新开始按钮 -->
  <button type='warn' bindtap='restartGame'>重新开始</button>
</view>

效果如图:

image-20230905125745764

3.逻辑设计

3.1主页逻辑

主页要展示缩略图和实现跳转功能

index.js代码如下:

Page({
    /**
     * 页面的初始数据
     */
    data: {
      levels: [
        'level01.png',
        'level02.png',
        'level03.png',
        'level04.png'
      ]
    },
    /**
     * 自定义函数--游戏选关
     */
    chooseLevel: function(e) {
      let level = e.currentTarget.dataset.level
      wx.navigateTo({
        url: '../game/game?level=' + level
      })
    },
  })
  

3.2游戏页逻辑

游戏逻辑部分要实现地图初始化,角色移动,复位功能

game.js代码如下:

//game.js
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
  },

  /**
   * 自定义函数--初始化地图数据
   */
  initMap: function(level) {
    // 读取原始的游戏地图数据
    let mapData = data.maps[level]
    //使用双重for循环记录地图数据
    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循环绘制8x8的地图
    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()
  },

  /**
   * 自定义函数--方向键:上
   */
  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.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.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.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.drawCanvas()
      //检查游戏是否成功
      this.checkWin()
    }
  },



  /**
   * 自定义函数--判断游戏成功
   */
  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
      })
    }
  },

  /**
   * 自定义函数--重新开始游戏
   */
  restartGame: function() {
    //初始化地图数据
    this.initMap(this.data.level - 1)
    //绘制画布内容
    this.drawCanvas()
  },

  /**
   * 生命周期函数--监听页面加载
   */
  onLoad: function(options) {
    //获取关卡
    let level= options.level
    //更新页面关卡标题
    this.setData({
      level: parseInt(level)+1
    })
    //创建画布上下文
    this.ctx = wx.createCanvasContext('myCanvas')
    //初始化地图数据
    this.initMap(level)
    //绘制画布内容
    this.drawCanvas()
  },

})

至此所有功能全部实现

三、程序运行结果

列出程序的最终运行结果及截图。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

四、问题总结与体会

描述实验过程中所遇到的问题,以及是如何解决的。有哪些收获和体会,对于课程的安排有哪些建议。

在设计游戏界面移动按钮时我遇到了边框异常的问题,后在q群中得知解决的方案就是删除app.json中的style:v2这一行代码,原因是渲染引擎不兼容,引起显示bug

下文
this.ctx = wx.createCanvasContext(‘myCanvas’)
//初始化地图数据
this.initMap(level)
//绘制画布内容
this.drawCanvas()
},

})


至此所有功能全部实现



## 三、程序运行结果

列出程序的最终运行结果及截图。

[外链图片转存中...(img-xLiu34q6-1693893008576)]

[外链图片转存中...(img-extFvcF9-1693893008577)]

[外链图片转存中...(img-ZuAZz9J3-1693893008578)]





## 四、问题总结与体会

描述实验过程中所遇到的问题,以及是如何解决的。有哪些收获和体会,对于课程的安排有哪些建议。

在设计游戏界面移动按钮时我遇到了边框异常的问题,后在q群中得知解决的方案就是删除app.json中的style:v2这一行代码,原因是渲染引擎不兼容,引起显示bug

通过本次实验我进一步掌握了小程序的编写
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值