2024年夏季《移动软件开发》实验报告——实验六:推箱子游戏

小程序功能

  • 首页呈现关卡菜单,玩家可以自由选择4个游戏关卡
  • 游戏关卡页面可以通过点击上下左右4个按钮实现小鸟的移动
  • 在游戏关卡页面游戏成功后会弹出提示框,并且可以选择重新开始游戏

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

一、实验目标

1、综合所学知识创建完整的推箱子游戏;

2、能够在开发过程中熟练掌握真机预览、调试等操作。

二、实验步骤

1.创建项目并配置页面文件
  • pages文件夹中创建indexgame两个页面
  • 新建imagesutils文件夹, 分别存储游戏图片素材和和公共data.js文件

效果如下:

在这里插入图片描述

2.导航栏设计
  • windows属性中自定义导航栏效果,设置背景色为珊瑚红色、字体为白色

app.json文件的代码如下:

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

效果如下:

在这里插入图片描述

3.首页设计

(1)公共样式设计

  • 设置页面容器和顶端标题的公共样式

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)首页设计

  • 使用<view>组件设置顶端标题
  • 使用数组循环显示关卡列表

index.wxml文件代码如下:

<view class="container">
  <!--标题-->
  <view class="title">游戏选关</view>
  <!--关卡列表-->
  <view class='levelBox'>
    <view class="box">
    <image src="/images/level01.png" />
    <text>第1关</text>
</view>
  </view>
</view>

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

效果如下:

在这里插入图片描述

4.游戏页设计
  • 游戏页面包括游戏关卡标题、游戏画面、方向键和重新开始按钮

game.wxml文件代码如下:

<!--game.wxml-->
<view class='container'>
  <!-- 关卡提示 -->
  <view class="title">第1关</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'>重新开始</button>
</view>

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

效果如下:

在这里插入图片描述

5.公共逻辑
  • data.js文件中配置游戏地图数据,需要存放4个二维数组(代表4个不关卡的地图数据)
  • 接着在data.js文件中使用module.exports语句暴露数据接口
  • 最后在game.js文件顶端引用公共JS文件

data.js文件代码如下:

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

game.js文件引用代码如下:

var data = require('../../utils/data.js')
6.首页逻辑

(1)展示关卡列表

  • data.js文件中添加关卡图片的数据信息,并在index.wxml文件中显示出来

index.js文件代码如下:

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

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}}" />
    <text>第{{index+1}}关</text>
</view>
  </view>
</view>

效果如下:

在这里插入图片描述

(2)点击跳转游戏页面

  • 首先在index.wxml文件中为关卡列表项目添加点击事件
  • index.js文件中添加chooseLevel函数

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}}" />
    <text>第{{index+1}}关</text>
</view>
  </view>
</view>

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
    })
  },
})
7.游戏页逻辑

(1)显示当前第几关

  • 在游戏页面接收关卡信息,并显示对应的图片内容

game.js文件代码如下:

Page({
  /**
   * 页面的初始数据
   */
  data: {
    level: 1
  },

  // 生命周期函数
  onLoad:function(options) {
    let level=options.level
    this.setData({
      level:parseInt(level)+1
    })
  },
})

效果如下:

在这里插入图片描述

(2)游戏逻辑实现

  • 首先在game.js文件中添加游戏初始数据信息
  • 初始化游戏页面
    • game.js文件中添加initMap函数,初始化游戏地图数据
    • game.js中添加drawCanvas函数,将地图信息会绘制到画布上
    • game.js文件的onLoad函数中创建画布上下文,并调用initMap函数和drawCanvas函数

game.js文件代码如下:

// pages/game/game.js
var data = require('../../utils/data.js')
var level 
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循环绘制8*8地图
    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(options) {
    let level=options.level
    this.setData({
      level:parseInt(level)+1
    })
    this.ctx=wx.createCanvasContext('myCanvas')
    this.initMap(level)
    this.drawCanvas()
  },
})

效果如下:

在这里插入图片描述

(3)方向键逻辑实现

  • game.wxml文件中的4个方向键绑定点击事件
  • game.js文件中添加updownleftright函数,实现小鸟上下左右4个方向的移动

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>

game.js文件代码如下:

 // 方向键
  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()
    }
  },

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

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

效果如下:

(移动前)

在这里插入图片描述

(移动后)

在这里插入图片描述

8.判断游戏成功
  • game.js文件中添加isWin函数,判断游戏是否已经成功
  • 然后在game.js中添加checkWin函数,游戏成功就弹出提示框
  • 最后在game.js的4个方向函数中添加判断游戏是否成功的函数,以up函数为例,其余三个函数均相同

isWin函数代码如下:

 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函数代码如下:

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

up函数添加代码如下:

 //检查游戏是否成功
 this.checkWin()

效果如下:

在这里插入图片描述

9.重新开始游戏
  • game.wxml中给“重新开始”按钮添加点击事件,并在game.js文件中添加restartGame函数

game.wxml文件代码如下:

 <!-- 重新开始按钮 -->
  <button type='warn' bindtap='restartGame'>重新开始</button>

game.js文件中restartGame函数代码如下:

  restartGame:function(){
    this.initMap(this.data.level-1)
    this.drawCanvas()
  },

效果如下:

(重新开始前)

在这里插入图片描述

(重新开始后)

在这里插入图片描述

三、程序运行结果

(首页)

在这里插入图片描述

(选择关卡后)

在这里插入图片描述

(小鸟移动页面)

在这里插入图片描述

(重新开始页面)

在这里插入图片描述

(成功页面)

在这里插入图片描述

四、问题总结与体会

在游戏设计过程中,我学会了如何分析问题、制定解决方案,提高了自己的逻辑思维能力;本次实验让我在短时间内掌握了推箱子游戏小程序的开发过程,提高了自己的编程实践能力。在今后的学习和工作中,我会继续努力,不断积累经验,为成为一名优秀的程序员而努力。

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值