一、实验目标
1.综合所学知识创建完整的推箱子游戏;
2.能够在开发过程中熟练掌握真机预览、调试等操作。
二、实验步骤
1.创建项目,选择JS基础模板。
2.页面配置。
(1)创建页面文件:
将app.json文件pages属性中的pages/logs/logs删除;
在app.json文件pages属性中追加pages/game/game;
保存修改后,会在pages文件夹下自动生成game目录。
(2)删除和修改文件:
删除utils文件夹中的所有内容;
删除pages文件夹下的logs目录及其内部所有内容;
删除index.wxml和index.wxss中的全部代码;
删除index.js中的全部代码,并且输入关键词“page”找到Page选项按回车让其自动补全函数;
删除app.wxss中的全部代码;
删除app.js中的全部代码,并且输入关键词“app”找到App选项按回车让其自动补全函数。
(3)创建其他文件:
创建images文件夹,然后在文件管理器中找到它并将小游戏需要用到的图片素材保存进去;
创建utils文件夹,在其中新建data.js。
配置完成的文件目录如下:
3.导航栏设计。
将导航栏背景改为珊瑚红色,字体改为白色,app.json中代码如下:
"window": {
"navigationBarTitleText": "推箱子游戏",
"navigationBarBackgroundColor": "#E64340"
},
效果如图:
4.页面设计。
(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"></image>
<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;
}
效果如图:
(3)游戏页面设计:
首先在顶端工具栏中找到“普通编译”下拉选项,选择“添加编译模式”,然后追加对于game页面的直接浏览效果,并携带临时测试参数level=0,如下图所示:
然后使用view组件设计整体容器和顶端标题,使用canvas组件设计游戏画布,使用button组件设计4个方向键和1个“重新开始”按钮。
game.wxml中的相关代码如下:
<view class='container'>
<view class='title'>第1关</view>
<canvas canvas-id='myCanvas'></canvas>
<view class ='btnBox'>
<button type='warn'>↑</button><view>
<button type='warn'>←</button>
<button type='warn'>↓</button>
<button type='warn'>→</button>
</view>
</view>
<button type='warn'>重新开始</button>
</view>
game.wxss中的相关代码如下:
canvas {
border:Irpx 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)公共逻辑:
在utils/data.js中配置游戏地图数据,并在末尾使用module.exports语句暴露数据出口,代码如下:
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顶端引用公共js文件,代码如下:
var data=require('../../utils/data.js')
(2)首页逻辑:
在index.js的data中录入关卡图片的数据信息,相关代码如下:
data: {
levels:[
'level01.png',
'level02.png',
'level03.png',
'level04.png'
]
},
然后为关卡对应的view组件添加wx:for属性循环显示关卡列表数据和图片。index.wxml中相关代码如下:
<view class='container'>
<view class='title'>游戏选关</view>
<view class='levelBox'>
<view class='box' wx:for="{{levels}}" wx:key="levels{{index}}">
<image src="/images/{{item}}"></image>
<text>第{{index+1}}关</text>
</view>
</view>
</view>
效果如图:
接下来为关卡列表项目添加点击事件实现跳转功能,index.wxml中相关代码如下:
<view class='box' wx:for="{{levels}}" wx:key="levels{{index}}"bindtap='chooseLevel'data-level='{{index}}'>
在对应的index.js中添加chooseLevel函数,代码如下:
chooseLevel:function(e){
let level=e.currentTarget.dataset.level
wx.navigateTo({
url:'../game/game?level='+level
})
},
(3)游戏页逻辑:
首先在游戏页面接收关卡信息,game.js中相关代码如下:
onLoad:function(options) {
let level=options.level
this.setData({
level:parseInt(level)+1
})
},
修改game.wxml中相关代码如下:
<view class='title'>第{{level}}关</view>
此时从首页点击第2关即可成功跳转进入,效果如图:
接下来进行游戏逻辑的实现。
首先在game.js的顶端记录一些游戏初始数据信息。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
然后在game.js中添加initMap函数,用于初始化游戏地图数据;添加drawCanvas函数,用于将地图信息绘制到画布上。最后在onLoad函数中创建画布上下文,并依次调用自定义函数initMap和drawCanvas。game.js中相关代码如下:
initMap:function(level){
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()
},
onLoad:function(options) {
let level=options.level
this.setData({
level:parseInt(level)+1
})
this.ctx=wx.createCanvasContext('myCanvas')
this.initMap(level)
this.drawCanvas()
},
效果如图:
接下来进行方向键逻辑的实现。
首先修改game.wxml中的4个方向键button,为其绑定点击事件。修改后的game.wxml中相关代码如下:
<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>
然后在game.js中添加自定义函数up、down、left和right,分别用于实现小鸟在上、下、左、右4个方向的移动。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.drawCanvas()
}
},
效果如图:
接下来在game.js中添加自定义函数isWin,用于判断游戏是否已经成功;添加自定义函数checkWin,要求一旦游戏成功就弹出提示对话框。game.js中相关代码如下:
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
})
}
},
并且在game.js的4个方向键函数中追加关于游戏成功判断的函数,以up函数为例,对应的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()
this.checkWin()
}
},
最后在game.wxml中为“重新开始”按钮追加点击事件。game.wxml中相关代码如下:
<button type='warn'bindtap='restartGame'>重新开始</button>
同时在game.js中添加restartGame函数,用于重新开始游戏。game.js中相关代码如下:
restartGame:function(){
this.initMap(this.data.level-1)
this.drawCanvas()
},
至此整个推箱子小游戏已制作完成。
三、程序运行结果
首页(选关页):
点击第1关进入游戏页:
点击方向键进行移动:
点击重新开始:
成功通关后: