一、实验目标
1、学习使用快速启动模板创建小程序的方法;2、学习不使用模板手动创建小程序的方法。
二、实验步骤
1.项目创建
首先在文件夹中加入以下所需文件。
2.代码解析
以下着重介绍wxml中对各容器类型的引用方式及js文件中页面的实现逻辑。
选关卡主页面
<!--pages/index/index.wxml--> <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>
此部分代码实现了关卡选择页面的页面排布,同时实现了根据关卡数量更新显示相对应数目及对应关卡地图、关卡数目的功能。用微信小程序自带的wx:for='{{levels}}' wx:key='levels{{index}}'实现所有关卡的显示;用内嵌的bindtap='chooseLevel'设置在点击时前往chooseLevel函数执行页面跳转。
// pages/index/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 }) },
此部分js文件实现了主页面的页面逻辑,data中的levels包含了所有关卡对应的封面页,同时界定chooseLevel函数用于实现对应关卡页面的跳转,其利用的是微信小程序自带的navigateTo函数。
关卡页面
<!--pages/game/game.wxml--> <view class="container"> <view class="title">第{{level}}关</view> <canvas canvas-id='myCanvas'></canvas> <view class='btnBox'> <button type="warn" bind:tap='up'>⬆</button> <view> <button type="warn" bind:tap='left'>⬅</button> <button type="warn" bind:tap='down'>⬇</button> <button type="warn" bind:tap='right'>➡</button> </view> </view> <button type="warn" bind:tap='restartGame'>重新开始</button> </view>
此部分用于设置各个关卡页面的排布样式,利用<canvas>生成画布并给予其对应id名称。在button中定义type='warn'将按钮设置为红色,bingdtap实现点击后跳转对应函数执行。
var data = require("../../utils/data") 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(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(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 console.log(options.level) this.setData({ level: parseInt(level) + 1 }) this.ctx = wx.createCanvasContext('myCanvas') this.initMap(level) this.drawCanvas() },
此部分实现了游戏页面的信息数据初始化分别初始化地图格式、箱子数目及类型、主角所在位置。
initMap函数通过读取unils文件中的data.js读取对应关卡的地图格式、箱子数目及类型、主角所在位置。
drawCanvas初始化地图样式,设置箱子、小猪、石头和主角小鸟的样式,即完成了页面的UI排布。
up、down、left、right函数分别实现了上、下、左、右的行走及推动箱子。
isWin函数用于判断玩家是否成功将箱子推到小猪位置。
checkWin函数在调用isWin函数基础上实现与用户的交互输出游戏成功或失败。
三、程序运行结果
初始页面:
进入第二关后页面展示:
游戏通过后页面显示:
游戏进行重新开始后页面展示:
四、问题总结与体会
首先,由于微信小程序版本更新过快,在game.js的onLoad函数中我们使用wx.createCanvasContext(string)函数时会发现其可用版本低于2.9.0,而到目前最低可用版本为2.14.0,因此此处存在问题,但不影响使用。通过查阅Canvas文档发现可以将被弃用的wx.createCanvasContext(string)函数转为使用wx.createSelectQuery()进行context对象的获取。
其次,由于本人的一再粗心,竟然在<canvas></canvas>引用中错大canvas为convas从而导致画布无法正常生成,此为经常犯的错误,和上次将setData写作setDate一样为使用不熟练的问题,以后将更加注意。