一、实验目标
1、综合应用所学的知识创建完整的推箱子游戏。
2、熟练掌握canvas和绘图API。
二、实验步骤
2.1 项目准备
- 创建项目并创建游戏页面(将app.json文件内pages属性中的“pags/logs/logs改成“pages/game/game”,ctrl+S保存)。
- 删除utils和logs目录及其内部所有内容。
- 删除index.wxml、index.wxss和app.wxss全部代码。
- 删除index.js和app.js中全部代码。并分别输入page和app回车补全函数。
2.2 页面设计
- 在app.wxss中设置页面窗口和顶端标题的公共样式
- 顶端标题:view容器;关卡列表:view容器,内部使用数组循环。
- 效果如图所示,具体代码见2.4。
- 游戏页面设计view,整体容器和顶端标题;canvas,游戏画布。具体代码见2.4。
2.3 逻辑实现
2.3.1 公共逻辑和首页逻辑
功能实现:展示关卡列表
-
在utils/data.js中配置游戏地图的数据,使用module.exports语句暴露数据接口。
-
index.js中data 录入关卡图片的数据信息
-
关卡对应的view组件添加wx:for属性循环显示关卡列表数据和图片。
-
为关卡列表项目添加点击事件。利用bindtap绑定chooseLevel函数,并且使用data-level属性携带关卡图片下标信息。
-
效果如图所示,相关代码件2.4代码。
2.3.2 游戏页逻辑
功能实现:显示当前是第几关;游戏地图的绘制;4个方向键可以移动游戏主角;点击重新开始按钮可以是游戏页面还原为最初状态。
-
显示提示图。首页逻辑中已经实现页面跳转并携带关卡对应的图片信息,游戏页面需接收关卡信息,并显示对应的图片内容。此时从首页点击不同的关卡图片就可以实现跳转。
-
游戏逻辑实现。首先在game.js文件的顶端记录一些游戏初始数据信息。其后,初始化游戏画面。首先根据当前第几关读取对应游戏信息,并更新到初始游戏数据中。在game.js中添加initMap函数,用于初始化游戏地图数据;添加自定义函数drawCanvas,用于地图信息绘制到画布上;在onLoad函数中调用自定义函数initMap和drawCanvas。
-
绑定方向键。修改game.wxml页面中的4个方向键,为其绑定点击事件。在game.js文件添加自定义函数up,down,left,right,用于实现小鸟的移动。
-
在game.js文件中的data中添加自定义函数isWin,用于判断游戏成功与否。添加自定义函数checkWin,要求一旦游戏成功就弹出游戏提示对话框。
-
重新开始游戏,添加自定义restartGame函数,用于重新开始游戏。具体代码见2.4。
2.4 代码
2.4.1 html
<!--pages/index/index.wxml-->
<view class="container">
<view class="title">游戏选关</view>
<view class="levelBox">
<view class="box" wx:for="{{levels}}" wx:key="levels{{index}}" bind:tap="chooseLevel" data-level = '{{index}}'>
<image src="/images/{{item}}" mode=""/>
<text>第{{index+1}}关</text>
</view>
</view>
</view>
<!--pages/game/game.wxml-->
<view class="container">
<view class="title">游戏选关</view>
<view class="levelBox">
<view class="box" wx:for="{{levels}}" wx:key="levels{{index}}" bind:tap="chooseLevel" data-level = '{{index}}'>
<image src="/images/{{item}}" mode=""/>
<text>第{{index+1}}关</text>
</view>
</view>
</view>
2.4.2 css
/* pages/index/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;
}
/* pages/game/game.wxss */
canvas{
border: 1rpx solid;
width: 304px;
height: 304px;
}
.btnBox{
display: flex;
flex-direction: column;
align-items: center;
}
.btnBox view{
display: flex;
flex-direction: row;
}
.btnBox button{
height: 38px;
}
button{
margin: 10rpx;
}
2.4.3 js
// pages/index/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,
})
}
/**
* 系统默认函数省略
*/
})
// pages/game/game.js
var data = require('../../utils/data')
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 = 38
var row = 0
var col = 0
Page({
/**
* 页面的初始数据
*/
data: {
level:1,
ctx:"",
},
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()
},
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(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
})
}
},
restartGame:function(){
this.initMap(this.data.level - 1)
this.drawCanvas()
},
/**
* 生命周期函数--监听页面加载
*/
onLoad(options) {
let level = options.level
this.setData({
level:parseInt(level)+1
})
this.ctx = wx.createCanvasContext('myCanvas')
this.initMap(level)
this.drawCanvas()
}
/**
* 系统默认函数省略
*/
})
// utils/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]
}
三、程序运行结果
-
以第二关为例,进入第二关后,页面效果如下,使用方向按钮控制小鸟推动箱子。
-
箱子全部盖住小猪后,弹出游戏成功面板,效果如下所示。
- 如若像重开游戏,点击重新开始,刷新页面,效果如下。