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

一、实验目标

1、综合应用所学的知识创建完整的推箱子游戏;2、熟练掌握canvas和绘图 API。

二、实验步骤

1.创建项目

依次输入项目名称、选择目录、APPID等,注意选择不使用云服务。

2.修改添加与删除文件(及恢复文件初始化)

删除logs文件夹、utils文件夹,清空index.js、index.json、index.wxss、app.wxss文件中的内容,删除app.json文件中page属性里的"pages/logs/logs",以及上一行的逗号,新增game页面,新增imagesutils文件夹分别用于存放图片资源和公共JS文件。

3.编写文件

(1)编译导航栏

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

通过对window属性中内容进行修改,可以达到修改导航栏的作用。例如将原本白底黑字修改为蓝底白字,并修改文字内容。

(2)页面设计

1.首页:在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>

2.游戏:在game.wxml中编写代码

<view class = 'container'>
<!--关卡提示-->
<view class='title'>第{{level}}关</view>
<!--游戏画布-->
<view class="outer">
  <canvas canvas-id='myCanvas'></canvas>
</view>
​
<!--方向键-->
<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>

(3)页面元素的整理

1.全局样式:在app.wxss中编写代码

.container{
  height: 100vh;
  color: #E64340;
  font-weight: bold;
  display: flex;
  flex-direction: column;
  justify-content: space-evenly;
}
.title{
  font-size: 18pt;
  text-align: center;
}

2.首页:在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;
}
​
.title{
  text-align: center;
}

3.游戏:在game.wxss中编写代码。

/*游戏画布样式*/
canvas{
  border: 1rpx solid;
  width:320px;
  height:320px;
}
.outer{
  padding: 25px;
}
/*方向键按钮整体区域*/
.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;
}

(4)页面逻辑的实现

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]
}

2.首页逻辑:在index.js中 修改。

var data = require('../../utils/data.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.游戏逻辑:在game.js中编写代码。

// pages/game/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) {
          //返回false,表示游戏尚未成功
          return false
        }
      }
    }
    //返回 true, 表示游戏成功
    return true
  },
​
  /**
   *  自定义函数 -- 游戏成功处理
  */
  checkWin: function(){
    if (this.isWin()){
      wx.showModal({
        title:'恭喜',
        content:'游戏成功!',
        showCancel:false
      })
    }
  },
​
  /**
   * 生命周期函数--监听页面加载
   */
  onLoad:function(options) {
    let level=options.level
    this.setData({
      level:parseInt(level)+1
    })
    this.ctx=wx.createCanvasContext('myCanvas')
    this.initMap(level)
    this.drawCanvas()
  },
​
  restartGame:function(){
    this.initMap(this.data.level-1)
    this.drawCanvas()
  }
})

三、程序运行结果

运行结果如下:

                             

首页 
 游戏(未移动)

游戏(已移动)
游戏(已通关)

四、问题总结与体会

这次实验是最后一次实验,也是最复杂的实验。通过这次实验也令我收获了很多,首先第一次接触到微信小程序中画布的概念。同时,对于小程序中实现动态过程也有了一定的了解。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值