微信小程序实验报告六

一、实验目标

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

二、实验步骤

1.准备工作

1.1 删除和修改文件

(1)删除utils文件夹及其内部所有内容。 (2) 删除pages 文件夹下的logs目录及其内部所有内容。 (3)删除index.wxml和index.wxss中的全部代码。 (4)删除index.js中的全部代码,并且输入关键词page 我到第二个选项按回车键让其自动补全函数

(5)删除app.wxss中的全部代码。 (6)删除app.js中的全部代码,并且输入关键词app找到第一个选项按回车键让其自动补全函数

(7)将app.json文件内pages属性中的“pages/logs/logs”改成“pages/game/game"。 (8)按快捷键Ctrl+S保存修改后会在pages文件夹下自动生成game目录。

1.2 建立image文件夹

新建一个文件夹,用来存放各个图标

游戏图片下载链接:https://gaopursuit.oss-cn-beijing.aliyuncs.com/course/mobileDev/boxgame_images.zip

1.3创建公共js文件data

右击utils文件夹,选择“新建”,输入data.js,创建完成后删去data.wxml文件,将app.json文件内pages属性中的“utils/data”删去

2.视图设计

2.1 导航栏设计

打开app.json,写入以下代码

"window": {
    "navigationBarTitleText":"推箱子游戏",
    "navigationBarBackgroundColor": "#E64340"
  },

2.2公共样式设计

在app.wxss写入如下代码

/*页面容器样式*/
.container {
  height: 100vh;
  color: #E64340;
  font-weight: bold;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: space-evenly;
}
  /*顶端标题样式*/
  .title {
  font-size: 18pt;
  }

2.3首页设计

首页设计包含两个部分:标题和关卡列表

在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>

level初始值设为0

关卡对应的<view>组件添加wx:for属性循环显示关卡列表数据和图片。

chooseLevel函数见下文

循环的key值是level的下标

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

2.4游戏页面设计

<!--pages/game/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>

bindtap会为每个方向键和restart绑定相关的函数,实现不同的事件。

函数代码见下文。

/*游戏画布样式*/
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;
  }

三、逻辑实现

3.1公共逻辑

在data.js中写入如下代码

//地图数据 map1~map4
//地图数据:1为墙、2为路、3为终点、4为箱子、5为人物、0为墙的外围
//关卡1
var map1 = [
  [0, 1, 1, 1, 1, 1, 0, 0],
  [0, 1, 2, 2, 1, 1, 1, 0],
  [0, 1, 5, 4, 2, 2, 1, 0],
  [1, 1, 1, 2, 1, 2, 1, 1],
  [1, 3, 1, 2, 1, 2, 2, 1],
  [1, 3, 4, 2, 2, 1, 2, 1],
  [1, 3, 2, 2, 2, 4, 2, 1],
  [1, 1, 1, 1, 1, 1, 1, 1]
]
  //关卡2
  var map2 = [
  [0, 0, 1, 1, 1, 0, 0, 0],
  [0, 0, 1, 3, 1, 0, 0, 0],
  [0, 0, 1, 2, 1, 1, 1, 1],
  [1, 1, 1, 4, 2, 4, 3, 1],
  [1, 3, 2, 4, 5, 1, 1, 1],
  [1, 1, 1, 1, 4, 1, 0, 0],
  [0, 0, 0, 1, 3, 1, 0, 0],
  [0, 0, 0, 1, 1, 1, 0, 0]
  ]
  //关卡3
  var map3 = [
  [0, 0, 1, 1, 1, 1, 0, 0],
  [0, 0, 1, 3, 3, 1, 0, 0],
  [0, 1, 1, 2, 3, 1, 1, 0],
  [0, 1, 2, 2, 4, 3, 1, 0],
  [1, 1, 2, 2, 5, 4, 1, 1],
  [1, 2, 2, 1, 4, 4, 2, 1],
  [1, 2, 2, 2, 2, 2, 2, 1],
  [1, 1, 1, 1, 1, 1, 1, 1]
  ]
  //关卡4
  var map4 = [
  [0, 1, 1, 1, 1, 1, 1, 0],
  [0, 1, 3, 2, 3, 3, 1, 0],
  [0, 1, 3, 2, 4, 3, 1, 0],
  [1, 1, 1, 2, 2, 4, 1, 1],
  [1, 2, 4, 2, 2, 4, 2, 1],
  [1, 2, 1, 4, 1, 1, 2, 1],
  [1, 2, 2, 2, 5, 2, 2, 1],
  [1, 1, 1, 1, 1, 1, 1, 1]
  ]
​
  module.exports={
    maps:[map1,map2,map3,map4]
  }

这里分别使用map1~map4代表4个不同关卡的地图数据,以二维数组的形式存放。 前地图均由8×8的方格组成,每个位置的数字代表对应的图标素材。

不要忘记在data.js中使用module.exports语句暴露数据出口,

数据是4个地图组成的数组

最后在game.js中引用公共js文件

var data=require('../../utils/data.js')

3.2首页逻辑

3.2.1关卡列表展示

在index.js中写入如下代码

初始数据:

//页面的初始数据
  data: {
    levels:[
      'level01.png',
      'level02.png',
      'level03.png',
      'level04.png'
    ]
  },

chooseLevel函数如下:

 //自定义函数 -- 游戏选关 
    chooseLevel: function(e) {
    let level = e.currentTarget.dataset.level
    wx.navigateTo( {
    url: '../game/game?level =' + level
    })
  },

3.2.2初始化地图数据

在game.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

3.3.3初始化游戏画面

在game.js中的代码如下

 //自定义函数 -- 初始化地图数据
  initMap: function(level) {
    //读取原始的游戏地图数据
    let mapData = data.maps[level]
    console.log(mapData)
    //使用双重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
        }
      }
    }
    },

上述代码首先从公共函数文件data.js中读取对应关卡的游戏地图数据,然后使用双重 for循环对每一块地图数据进行解析,并更新当前游戏的初始地图数据、箱子数据以及游戏主 角(小鸟)的所在位置。

drawCanvas:function(){
      let ctx = this.ctx 
      console.log(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()
      },

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

在game.js的onLoad函数中创建画布上下文

依次调用函数initMap和drawCanvas

3.3.4方向键逻辑实现

不同的方向都要一个函数,不同方向的函数逻辑实现大致相同,只需更改部分参数和值。为节省篇幅,只截取up和down的片段。

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() 
        }
      },

每次移动后,存储地图数据的数组会发生变动,所以需要重新绘制地图。

除此之外还要判断游戏是否成功通关。

3.3.5判断游戏成功

在game.js中写入如下代码

 //自定义函数 -- 判断游戏是否成功
      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) {
      //返回false,表示游戏尚未成功
      return false
      }
    }
  }     
      //返回true,表示游戏成功
      return true    
},

上述代码的判断逻辑是只要有一个箱子没有在终点位置就判断游戏尚未成功。 然后在game.js中添加自定义函数checkWin,要求一旦游戏成功就弹出提示对话框。

checkWin: function() {
  if (this. isWin()) {
  wx. showModal( {
  title:'恭喜',
  content:'游戏成功!',
  showCancel: false
  }) 
  }
},

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

四、程序运行结果

五、问题总结与体会

本次实验,在初始化游戏画面的时候老是出现错误,level值无法传输。后来发现是双重循环中j 被错写为i,导致循环出错。写代码一定要认真仔细,出现错误不要怕,根据错误的情况找到出错的部分,对症下药。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值