一、程序运行结果
二、实验目标
1、综合应用所学的知识创建完整的推箱子游戏;2、熟练掌握 和绘图 API。
3、自己设计额外功能:计分
三、实验步骤
1.创建项目,修改app.json中的pages:
{
"pages": [
"pages/index/index",
"pages/game/game"
],
ctrl+s保存即可
2.删除模板中自带的多余的代码
3.创建images文件夹,右键在资源文件中打开,复制粘贴图片素材(https://gaopursuit.oss-cn-beijing.aliyuncs.com/course/mobileDev/boxgame_images.zip)
创建utils文件夹,新建data.js文件
4.导航栏设计:
在app.json中:
"window": {
"navigationBarTextStyle": "black",
"navigationBarTitleText": "推箱子",
"navigationBarBackgroundColor": "#E64340"
},
5.公共页面与首页设计:
在app.wxss中:
/**app.wxss**/
.container {
height: 100vh;
color:#E64340;
font-weight: bold;
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-between;
}
在index.wxml中设计首页布局:
<view class="container">
<view class="title">游戏选关</view>
<view class="levelBox">
<view class="box">
<image src="/images/level01.png"></image>
</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;
}
编译并运行:
6.游戏页面设计:
由于暂时没有做跳转至游戏页面的逻辑,于是我们可以调整编译模式,从“普通编译”转为“添加编译模式”,调整启动页面和启动参数如下:
设计游戏页面布局:
在game.wxml中:
<!--pages/game/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>
在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;
}
编译运行如下:
7.公共逻辑实现:
在utils.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中引用公共js文件,代码 为:
var data= require('../../utils/data.js')
8.首页逻辑实现:
展示关卡列表:在index.js中:
data: {
levels:[
'level01.png',
'level02.png',
'level03.png',
'level04.png',
]
},
在idnex.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="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>
在js文件中实现函数:
chooseLevel:function(e){
let level=e.currentTarget.dataset.level
wx.navigateTo({
url:'../game/game?level='+level
})
},
在game.js中接受图片信息:
data: {
level:1
},
/**
* 生命周期函数--监听页面加载
*/
onLoad:function(options) {
let level=options.level
this.setData({
level:parseInt(level)+1
})
},
在wxml中修改布局,设计关卡提示:
<!--pages/game/game.wxml-->
<view class='container'>
<!--关卡提示-->
<view class='title'>第{{level}}关</view>
<!--游戏画布-->
编译运行结果如下:
9.游戏逻辑实现:
在game.js中保存一些初始数据,设计初始化函数,绘制地图函数,并在onload函数中调用:
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
},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function(options) {
let level=options.level
console.log('Received level:', level);
this.setData({
level:parseInt(level)+1
})
this.ctx=wx.createCanvasContext('myCanvas')
this.initMap(this.data.level-1)
this.drawCanvas()
},
initMap:function(level) {
let mapData = data.maps[level];
if (!mapData || !Array.isArray(mapData) || mapData.length < 8 || !Array.isArray(mapData[0])) {
console.error('Invalid map data for level:', level);
return;
}
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()
},
编译运行结果如下:
10.方向键逻辑实现:
在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>
</view>
在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()
}
},
11.游戏胜负检验逻辑:
在js文件中设计检验函数并在上下左右四个函数中调用(这里只写了up函数的例子):
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
})
}
},
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()
}
},
12.重新开始功能的逻辑实现:
在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>
在js中实现逻辑:
restartGame:function(){
this.initMap(this.data.level - 1)
this.drawCanvas()
},
OK,到这里功能就全部实现完了
四、问题总结与体会
通过本次实验,我受益匪浅,切身体会了一个游戏制作过程的各种逻辑交互以及画面的修改绘制,还有各个页面的美化与布局,大大提高了我的动手能力。即便是一个简单的推箱子,想要实现也需要莫大的努力,今后我更应该努力提高自己。
额外功能,我增加了计数功能,实时记录玩家的得分状况,下面是部分代码示例:
Page({
/**
* 页面的初始数据
*/
data: {
level: 1,
score: 0
},
// 更新分数函数
updateScore: function() {
let score = 0;
for (let i = 0; i < 8; i++) {
for (let j = 0; j < 8; j++) {
if (box[i][j] == 4 && map[i][j] == 3) {
score += 10;
}
}
}
if (score > 100) score = 100; // 确保得分不会超过100
this.setData({
score: score
});
this.updateScoreDisplay();
},
updateScoreDisplay: function() {
this.setData({
scoreText: `您的得分:${this.data.score}`
});
},
/**
* 生命周期函数--监听页面加载
*/