2024年夏季《移动软件开发》实验报告
一、实验目标
二、实验步骤
1.预先准备
本次实验所要使用的图片素材下载链接如下
https://gaopursuit.oss-cn-beijing.aliyuncs.com/course/mobileDev/boxgame_images.zip
解压后将images文件夹替换到新建的项目中的images文件夹相应位置即可
2.创建微信小程序项目以及内部文件修改配置
使用微信开发者工具创建一个新项目,并进行如下操作:
(1)删除utils文件夹及其内部所有内容。
(2)删除 pages文件夹下的 logs目录及其内部所有内容。
(3)删除index. wxml和 index. wxss中的全部代码。
(4)删除 index. js中的全部代码,并且输入关键词“page”找到第二个选项按回车键让其自动补全函数。
(5)删除app. wxss中的全部代码。
(6)删除 app.js 中的全部代码,并且输入关键词“app”找到第一个选项按回车键让其自动补全函数。
(7)添加一个新文件夹,命名为images,用下载的文件夹替换其内容。
(8)添加一个新文件夹,命名为images,在内部新建一个data.js文件。
3.初始化配置
(1)导航栏设计
在app.json中添加代码如下:
{
"pages": [
"pages/index/index",
"pages/game/game"
],
"window": {
"navigationBarTextStyle": "white",
"navigationBarBackgroundColor": "#e64340",
"navigationBarTitleText": "推箱子游戏"
}
}
在app.WXSS添加代码如下:
/**app.wxss**/
.container {
height: 100vh;
color:#e64340;
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-evenly;
font-weight: bold;
}
.text{
font-size: 18pt;
}
4.页面设计
(1)首页设计
index.WXML代码片段修改如下:
<view class="container">
<!--标题-->
<view class="title">游戏选关</view>
<!--关卡列表-->
<view class="levelBox">
<view class="box"wx:for="{{levels}}"wx:key="index"bindtap="chooseLevel"data-level="{{index}}">
<image src='/images/{{item}}'></image>
<text>第{{index+1}}关</text>
</view>
</view>
</view>
index.WXSS修改如下:
/*关卡列表*/
.levelBox{
width: 100%;
}
/*单个关卡*/
.title{
font-size: 50rpx;
}
.box{
width: 50%;
float:left;
margin: 20rpx 0;
display: flex;
flex-direction: column;
align-items: center;
}
/*选关图片*/
image{
width: 300rpx;
height: 300rpx;
}
效果如图
(2)游戏页面设计
同时对game.WXML对数据进行初始化如下:
<!--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>
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.逻辑实现
(1)首先在每个文件夹的js中最上方添加如下代码引用存在utils里面的数据和函数
var data=require('../../utils/data.js')
(2)初始化utils/data
首先先初始化四张地图
将utils/data.js文件添加代码如下:
//地图数据: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],
]
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],
}
(3)首页逻辑
将index.js文件添加代码如下:
Page({ //将之前images中的地图图片导入出来,用于页面的展示
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,
})
},
})
(4)游戏页面逻辑
在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,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,0,0,0,0,0,0,0,0],
]
var w = 40
var row = 0
var col = 0
Page({
/**
* 页面的初始数据
*/
data: {
level:1
},
initMap:function(level){ //对地图数据运用两层for循环进行赋值
let mapData = data.maps[level]
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]!=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-1]!=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+1]!=1&&box[row][col+2]!=4){
box[row][col+2]=4
box[row][col+1]=0
col=col+1
}
}
}
this.drawCanvas()
this.checkWin()
}
},
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()
},
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,
success (res) {
if (res.confirm) {
wx.redirectTo({ //点击确定后跳转回关卡页
url: '../index/index',
})
}
}
})
}
},
})
三、程序运行结果
四、问题总结与体会
在本次实验中按照实验方案进行微信小程序推箱子小游戏的制作,在实验过程中遇见的主要问题在于还是微信更新后Canvas接口函数无法调用,这里我调整了工具的版本为2.20.3.才能够调用接口
通过本次实验能够让我在开发过程中熟练掌握绘图相关API和游戏设计判读逻辑过程, 为我后期的项目的逻辑判读编写提供了经验,收获颇丰。