一、实验目标
1、综合应用所学知识创建完整的拼图游戏项目;2、熟练掌握<canvas>组件。
二、实验步骤
列出实验的关键步骤、代码解析、截图。
一.创建模板并添加文件
下载images图像包并加入文件夹
创建games文件夹以存放游戏界面
二.页面设计
1.主页设计
index.wxml如下:
<!--index.wxml-->
<view class="container">
<!--标题-->
<view class="title">Level Selection</view>
<!--关卡列表-->
<view class="levelbox">
<view class='box'wx:for='{{levels}}'wx:key='levels{{index}}'bindtap='chooseLevel'data-level='{{item}}'>
<image src='/images/{{item}}'></image>
<text>Level-{{index+1}}</text>
</view>
</view>
</view>
index.wxss如下:
/**index.wxss**/
.levelbox{
width:100%;
}
.box{
width:50%;
float: left;
margin: 25rpx 0;
display: flex;
flex-direction: column;
align-items: center;
}
image{
width:260rpx;
height: 260rpx;
}
结果如图:
2.游戏界面设计
wxml如下:
<!--pages/game/game.wxml-->
<view class="container">
<!--提示图-->
<view class="title">hinter</view>
<image src='{{url}}'></image>
<!--游戏画布-->
<canvas canvas-id="myCanvas"bindtouchstart='touchBox'></canvas>
<!--重新开始按钮-->
<button type="warn"bindtap='restartGame'>Restart</button>
</view>
wxss如下:
/* pages/game/game.wxss */
image{
width:250rpx;
height:250rpx;
}
canvas{
border: 1rpx solid;
width: 300px;
height:300px;
}
结果如图:
三.逻辑设计
1.主页逻辑设计
首先录入图片信息
Page({
data: {
levels:[
'pic01.jpg',
'pic02.jpg',
'pic03.jpg',
'pic04.jpg',
'pic05.jpg',
'pic06.jpg'
]
},
})
接着添加循环选关功能与点击跳转功能
<!--关卡列表-->
<view class="levelbox">
<view class='box' wx:for='{{levels}}'wx:key='levels{{index}}'bindtap='chooseLevel'data-level='{{item}}'>
<image src='/images/{{item}}'></image>
<text>Level-{{index+1}}</text>
</view>
</view>
js文件中添加chooseLevel函数
chooseLevel:function(e){
let level=e.currentTarget.dataset.level
wx.navigateTo({
url: '../game/game?level='+level,
})
} ,
2.游戏页逻辑设计
(1)显示提示图
js代码如下:
onLoad(options) {
url='/images/'+options.level
this.setData({url:url})
},
wxml代码修改如下:
<view class="container">
<!--提示图-->
<view class="title">hinter</view>
<image src='{{url}}'></image>
...
</view>
运行结果如图:
(2)游戏主体逻辑
初始化拼图画面。传统做法是随机抽取画面中的任意两个方块,然后交换彼此位置,在进行足够多次数的交换后基本可以实现随机打乱的效果。但是这种方法有一个弊端,就是有时候会陷入无解的死局。因此可以考虑从空白方块的所在位置入手,每次随机让它和周围的邻近方块交换位置,这样可以通过方块反向移动回到最初始状态(确保本局有解),并且在交换足够多的次数后也可以实现随机打乱的效果。
js的Page部分中加入shuffle函数用于初始化图片
shuffle:function () {
num=[
['00','01','02'],
['10','11','12'],
['20','21','22']
]
var row=2
var col=2
for(var i=0;i<100;i++){
var direction=Math.round(Math.random()*3)
if(direction==0){
if(row!=0){
num[row][col]=num[row-1][col]
num[row-1][col]='22'
row-=1
}
}
else if(direction==1){
if(row!=2){
num[row][col]=num[row+1][col]
num[row+1][col]='22'
row+=1
}
}
else if(direction==2){
if(col!=0){
num[row][col]=num[row][col-1]
num[row][col-1]='22'
col-=1
}
}
else if(direction==3){
if(col!=2){
num[row][col]=num[row][col+1]
num[row][col+1]='22'
col+=1
}
}
}
},
上述代码表示使用for循环进行了100次打乱,开发者可以根据自己的需求更改循环次数。每次使用Math.random()方法从上下、左、右4个方向中随机产生一个方向,之后如果符合条件则交换空白方块和图片方块的位置。
然后在game.js中添加自定义函数drawCanvas,用于将打乱后的图片方块绘制到画布上。对应的js代码片段添加如下:
drawCanvas: function () {
let ctx=this.ctx
ctx.clearRect(0,0,300,300)
for(var i=0;i<3;i++){
for(var j=0;j<3;j++){
if(num[i][j]!='22'){
var row=parseInt(num[i][j]/10)
var col=num[i][j]%10
ctx.drawImage(url,col*w,row*w,w,w,j*w,i*w,w,w)
}
}
}
ctx.draw()
},
最后在game.js的onLoad函数中调用自定义函数shuffle和drawCanvas。对应的js代码片段添加如下:
onLoad(options) {
url='/images/'+options.level
this.setData({url:url})
this.ctx=wx.createCanvasContext('myCanvas')
this.shuffle()
this.drawCanvas()
},
移动被点击的方块。修改game.wxml页面中的画布组件(<canvas>),为其绑定触摸事件。wxml代码修改后如下:
<!--游戏画布-->
<canvas canvas-id="myCanvas"bindtouchstart='touchBox'></canvas>
在game.js文件添加自定义函数 touchBox,用于实现图片方块的移动,对应的js代码片段添加如下:
touchBox:function (e) {
if(this.data.isWin){
return
}
var x=e.changedTouches[0].x
var y=e.changedTouches[0].y
var row=parseInt(y/w)
var col=parseInt(x/w)
if(num[row][col]!='22'){
this.moveBox(row,col)
this.drawCanvas()
if(this.isWin()){
let ctx=this.ctx
ctx.drawImage(url,0,0)
ctx.setFillStyle('E63404')
ctx.setTextAlign('center')
ctx.setFontSize(60)
ctx.fillText('Victory',150,150)
ctx.draw()
}
}
},
要判断游戏成功首先在game.js文件中的data中添加初始数据 isWin,用于标记游戏成功与否。再编写isWin函数来判断是否游戏成功对应的js代码片段添加如下:
data: {
isWin:false
},
isWin:function () {
for(var i=0;i<3;i++){
for(var j=0;j<3;j++){
if(num[i][j]!=i*10+j){
return false
}
}
}
this.setData({isWin:true})
return true
},
要重新开始游戏则修改game.wxml代码,为“重新开始”按钮追加自定义函数的点击事件。wxml代码片段修改如下:
<!--重新开始按钮-->
<button type="warn"bindtap='restartGame'>Restart</button>
在game.js文件中添加 restartGame函数,用于重新开始游戏。对应的js代码片段添加如下:
restartGame:function () {
this.setData({isWin:false})
this.shuffle()
this,this.drawCanvas()
},
三、程序运行结果
列出程序的最终运行结果及截图。
运行结果如下
主页
游戏页
四、问题总结与体会
描述实验过程中所遇到的问题,以及是如何解决的。有哪些收获和体会,对于课程的安排有哪些建议。
实验中遇到最多的问题是打错了大小写,导致不能正确调用内容,我应该写一些就编译运行一些,一边写一遍检查,而不是写完再检查
通过本次实验我了解了canvas的用法,进一步提升了编写能力