2023年夏季《移动软件开发》实验报告
一、实验目标
1、综合应用所学知识创建完整的拼图游戏项目;2、熟练掌握canvas组件。
二、实验步骤
1.项目创建
本项目一共需要两个页面,即首页和游戏页面,其中,首页用于呈现关卡菜单,点击对应难度的关卡后进入游戏画面。
1.1首页功能需求
首页功能需求如下:(1) 首页需要包含标题和关卡列表。(2) 关卡至少要有 6 个关卡选项,每个关卡显示预览图片和第几关。(3) 点击关卡列表可以打开对应的游戏画面。
1.2游戏页功能需求
游戏页功能需求如下:(1)游戏页面需要显示游戏提示图、游戏画面和“重新开始”按钮。(2)每关游戏提示图显示对应的图片预览。(3)游戏画面随机将原图打乱为3×3的小方块,并且可移动被点击的方块。(4)点击“重新开始”按钮可以重新随机打乱小方块并开始游戏。
2.页面配置
2.1创建页面文件
2.2删除和修改文件
2.3创建其他文件
3.视图设计
3.1导航栏设计
"window": {
"backgroundTextStyle": "light",
"navigationBarBackgroundColor": "#E64340",
"navigationBarTitleText": "拼图游戏",
"navigationBarTextStyle": "white"
},
上述代码可以更改导航栏内背景色为珊瑚红色,字体为白色。
3.2页面设计
(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容器;
关卡列表:view容器,内部使用数组循环。
WXML(pages/index/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='{{item}}'>
<image src='/images/{{item}}'></image>
<text>第{{index+1}}关</text>
</view>
</view>
</view>
相关WXSS (pages/index/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;
}
(3)游戏页面设计:游戏页面需要用户点击首页的关卡列表,然后在新窗口中打开该页面口游戏页面包括游戏提示图、游戏画面和“重新开始”按钮。
由于暂时没有做点击跳转的逻辑设计,所以可以在开发工具顶端选择“普通编译”下的“添加编译模式”,并携带临时测试参数level=pic01.jpg,如图所示:
此时预览就可以直接显示game页面了,设计完毕后再改回“普通编译”模式即可重新显示首页。
4.逻辑实现
4.1首页逻辑
首页主要有两个功能需要实现,一是展示关卡列表,二是点击图片能够跳转到游戏页面。
index.js
Page({
/**
* 页面的初始数据
*/
data: {
levels:[
'pic01.jpg',
'pic02.jpg',
'pic03.jpg',
'pic04.jpg',
'pic05.jpg',
'pic06.jpg'
]
},
// 自定义函数-游戏选关
chooseLevel:function(e){
let level=e.currentTarget.dataset.level
wx.navigateTo({
url: '../game/game?level='+level
})
}
})
4.2游戏页逻辑
游戏页主要有两个功能需要实现,一是显示提示图;二是游戏逻辑实现。
game.js
//方块的初始位置
var num=[
['00','01','02'],
['10','11','12'],
['20','21','22']
]
//方块的宽度
var w=100
//图片的初始位置
var url='/images/pic01.jpg'
Page({
/**
* 页面的初始数据
*/
data: {
isWin:false
},
// 自定义函数-随机打乱方块顺序
shuffle:function(){
//先令所有方块回归初始位置
num=[
['00','01','02'],
['10','11','12'],
['20','21','22']
]
//记录当前空白方块的行和列
var row=2
var col=2
//打乱方块顺序100次
for(var i=0;i<100;i++){
//随机产生其中一个方向:上(0)下(1)左(2)右(3)
var direction=Math.round(Math.random()*3)
//上:0
if(direction==0){
if(row!=0){
num[row][col]=num[row-1][col]
num[row-1][col]='22'
row-=1
}
}
//下:1
else if(direction==1){
if(row!=2){
num[row][col]=num[row+1][col]
num[row+1][col]='22'
row+=1
}
}
//左:2
else if(direction==2){
if(col!=0){
num[row][col]=num[row][col-1]
num[row][col-1]='22'
col-=1
}
}
//右:3
else if(direction==3){
if(col!=2){
num[row][col]=num[row][col+1]
num[row][col+1]='22'
col+=1
}
}
}
},
// 自定义函数-绘制画布内容
drawCanvas:function(){
let ctx=this.ctx
//清空画布内容
ctx.clearRect(0,0,300,300)
//使用双重for循环绘制3*3的拼图
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()
},
//自定义函数-移动被点击的方块
moveBox:function(i,j){
//情况1:如果被点击的方块不在最上方,检查可否上移
if(i>0){
if(num[i-1][j]=='22'){
num[i-1][j]=num[i][j]
num[i][j]='22'
return
}
}
//情况2:如果被点击的方块不在最下方,检查可否下移
if(i<2){
if(num[i+1][j]=='22'){
num[i+1][j]=num[i][j]
num[i][j]='22'
return
}
}
//情况3:如果被点击的方块不在最左边,检查可否左移
if(j>0){
if(num[i][j-1]=='22'){
num[i][j-1]=num[i][j]
num[i][j]='22'
return
}
}
//情况4:如果被点击的方块不在最右边,检查可否右移
if(j<2){
if(num[i][j+1]=='22'){
num[i][j+1]=num[i][j]
num[i][j]='22'
return
}
}
},
//自定义函数-判断游戏是否成功
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
},
//自定义函数-监听点击方块事件
touchBox:function(e){
//如果游戏已经成功,不做任何操作
if(this.data.isWin){
//终止本函数
return
}
//获取被点击方块的坐标x和y
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('#E64340')
ctx.setTextAlign('center')
ctx.setFontSize(60)
ctx.fillText('游戏成功',150,150)
ctx.draw()
}
}
},
//自定义函数-重新开始游戏
restartGame:function(){
this.setData({isWin:false})
this.shuffle()
this.drawCanvas()
},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
//更新图片路径地址
url='/images/'+options.level
//更新提示图的地址
this.setData({url:url})
//创建画布上下文
this.ctx=wx.createCanvasContext('myCanvas')
//打乱方块顺序
this.shuffle()
//绘制画布内容
this.drawCanvas()
}
})
三、程序运行结果
首页界面:
选择第2关后的游戏页面:
游戏成功:
点击“重新开始”后,游戏重新开始:
四、问题总结与体会
通过此次实验,我学会了如何使用组件以及如何实现页面跳转,并对以往所学知识有了更深入的了解。