移动软件开发实验四:拼图游戏

2023年夏季《移动软件开发》实验报告

本实验属于哪门课程?中国海洋大学23夏《移动软件开发》
实验名称?实验4:拼图游戏
博客地址?m0_63773979_-CSDN博客
Github仓库地址?XXXXXXX

(备注:将实验报告发布在博客、代码公开至 github 是 加分项,不是必须做的)

一、实验目标

1、综合应用所学知识创建完整的拼图游戏项目;2、熟练掌握<canvas>组件。

二、实验步骤

1.首先按照快速启动模板创建小程序的步骤得到一个小程序模板

 

2.创建页面文件并删除和修改其他文件

将app. json文件内 pages属性中的“pages/logs/logs”改成"pages/game/game", 按快捷键Ctrl+S保存当前修改后会在page文件夹下自动 game目录。

删除 utils文件夹及其内部所有内容。 删除 pages文件夹下的 logs目录及其内部所有内容。 删除 index. wxml和 index. wxss中的全部代码。 删除 index. js中的全部代码,并且输入关键词“page”找到第二个选项按回车键让其自动补全函数

删除 app. wxss中的全部代码。 删除 app. js中的全部代码,并且输入关键词“app”找到第一个选项按回车键让其自动补全函数

 

还需要创建一个images文件夹用于存放关卡图片

 

3.视图设计

(1)导航栏设计

在app.json中自定义导航栏标题和背景颜色,文件代码如下

"window":{
    "backgroundTextStyle":"light",
    "navigationBarBackgroundColor": "#E64340",
    "navigationBarTitleText": "拼图游戏",
    "navigationBarTextStyle":"white"
  },

上述代码可以更改所有页面的导航栏标题为“拼图游戏”、背景颜色为珊瑚红色,字体为白色

(2)页面设计:页面主要包括3个区域

1)公共样式设计:首先在app.wsxx中设置页面窗口和顶端标题的公共样式,代码如下:

.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代码如下:

<view class='container'>
<!--标题-->
<view class='title'>游戏选关</view>
<!--关卡列表-->
<view class='levelBox'>
<view class='box'>
<image src='/image/pic01.jpg'></image>
<text>第一关</text>
</view>
</view>
</view>

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页面了,设计完毕后再改回”普通编译“模式即可重新显示首页

计划使用如下组件:

<view>:整体容器和顶端标题

<image>:提示图

<canvas>:游戏画布

<button>:”重新开始''按钮

WXML代码如下:

<view class='container'>
<!--提示图区域-->
<view class='title'>提示图</view>
<image src='/images/pic01.jpg'></image>
<!--游戏画布-->
<canvas canvas-id='myCanvas'></canvas>
<!--“重新开始”按钮-->
<button type='warn'>重新开始</button>
</view>

WXSS代码如下:

image{
  width:250rpx;
  height:250rpx;
}
canvas{
  border:1rpx solid;
  width:300px;
  height:300px;
}

当前效果图如下

 

4.逻辑实现

(1)首页逻辑

首页主要有两个功能需要实现,一个是展示关卡列表,二是点击图片就能够跳转到游戏页面

1)关卡列表展示:在JS文件的data中录入关卡图片的数据信息,相关的JS代码如下

 data: {
    levels:[
      'pic01.jpg',
      'pic02.jpg',
      'pic03.jpg',
      'pic04.jpg',
      'pic05.jpg',
      'pic06.jpg'
    ]
},

接着为关卡对应的<view>组件添加wx:for属性循环显示关卡列表数据和图片,修改后的WXML代码如下:

<view class='box' wx:for='{{levels}}'wx:key='levels{{index}}'>
<image src='/image/{{item}}'></image>
<text>第{{index+1}}关</text>

效果图如下:

 

 

2)点击跳转游戏页面:若希望用户点击关卡图片即可实现跳转,首先需要为关卡列表项目添加点击事件,相关WXML代码片段修改如下:

<view class='box' wx:for='{{levels}}'wx:key='levels{{index}}'bindtap='chooseLevel'data-level='{{item}}'>

上述代码表示为关卡添加了自定义点击事件函数chooseLevel,并且使用了data--level属性携带了关卡图片信息,然后我们在对应的JS文件中添加该函数的相关内容,代码片段如下:

chooseLevel:function(e){
     let level=e.currentTarget.dataset.level
     wx.navigateTo({
       url:'../game/game?level='+level
     })
   },

现在已经可以点击跳转到游戏页面了,但是不能正确显示对应的游戏画面,仍需在game页面进行携带数据的接受处理才可以显示正确的游戏画面

比如我点进第四关,但是显示的是第一关的游戏画面

(2)游戏页逻辑

游戏页主要有两个功能需要实现,一个是显示提示图,然后就是游戏逻辑实现

1)显示提示图:在首页逻辑中已经实现了页面跳转并携带了关卡对应的图片信息,现在需要实现在游戏界面接收关卡信息并显示对应的图片内容

相关JS代码如下:

onLoad: function(options) {
    url='/images/'+options.level
    this.setData({url:url})
  },

WXML代码如下:

<!--提示图区域-->
<view class='title'>提示图</view>
<image src='{{url}}'></image>

 

可以显示出正确的画面了

2)游戏逻辑实现

a.准备工作:首先在game.js文件的顶端记录一些游戏初始数据信息,对应的JS代码如下:

var num=[
  ['00','01','02'],
  ['10','11','12'],
  ['20','21','22']
]
var w=100
var url='/images/pic01.jpg'

b.初始化拼图画面,从空白方块的位置入手,每次随机让他和周围的邻近方块交换位置,这样可以通过方块反向移动回到最初状态(确保本局有解),并且在交换足够多的次数后也可以实现随机打乱的效果

在game.js文件中添加shuffle函数用于重新开始游戏,对应JS代码如下:

shuffle:function(e){
    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()方法从上下左右四个方向中随机产生一个方向,之后如果符合条件则交换空白方块和图片方块的位置

然后我们在game.js中添加一个自定义函数drawCanvas,用于将打乱后的图片方块绘制到画布上,对应的JS代码片段如下:

drawCanvas:function(e){
    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的inLoad函数中调用自定义函数shuffle和drawCanvas,对应的JS代码如下:

onLoad: function (options) {
    let url='/images/'+ options.level
    this.setData({url:url})
    this.ctx=wx.createCanvasContext('myCanvas')
    this.shuffle()
    this.drawCanvas()
  },

效果图如下:

 

 

c.移动被点击的方块,修改game.wxml页面中的画布组件,为其绑定触摸事件WXML代码修改后如下:

<canvas canvas-id="myCanvas" bindtouchstart="touchBox"></canvas>

在game.js文件添加自定义函数touchBox,用于实现图片方块的移动,对应的JS代码如下:

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) //将坐标除于小方块的宽度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(50) //调节字的大小
        ctx.fillText('游戏成功',150,150)
        ctx.draw()
      }
    }
  },
 
  //自定义函数 - 判断游戏是否成功
  isWin:function(){
    // 使用双重for循环遍历整个数组
    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})
    // 返回i真,游戏成功
    return true
  },
  // 自定义函数-重新开始游戏
  restartGame:function(){
    // 更新游戏成功状态
    this.setData({isWin:false})
    // 打乱方块顺序
    this.shuffle()
    //绘制画布内容
    this.drawCanvas()
 
  },
  /**
   * 自定义函数--移动方块
   */
  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
      }
    }
  },

效果图如下:

d.判断游戏成功

首先在game.js文件中的data中添加初始数据isWin,用于标记游戏成功与否,对应的JS代码片段如下:

data: {
    isWin:false
  },

在上述代码中isWin为false表示游戏尚未成功,当成功时会重置为true,然后在game.js文件中添加自定义函数isWin,用于判断游戏是否已经成功,对应JS代码如下:

isWin:function(){
    // 使用双重for循环遍历整个数组
    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})
    // 返回i真,游戏成功
    return true
  },

然后修改game.js中的touchBox函数,要求被触发时追加对游戏成功状态的判断,对应JS代码片段如下:

if(this.data.isWin){
      // 终止本函数
      returntouchBox: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) //将坐标除于小方块的宽度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(50) //调节字的大小
        ctx.fillText('游戏成功',150,150)
        ctx.draw()
      }
    }
  },

 

 

e.重新开始游戏

修改game.wxml代码,为“重新开始”按钮追加自定义函数的点击事件,WXML代码片段修改如下:

<button type="warn" bindtap="restartGame">重新开始</button>

在game.js文件中添加restartGame函数,用于重新开始游戏,对应的JS代码如下:

restartGame:function(){
    // 更新游戏成功状态
    this.setData({isWin:false})
    // 打乱方块顺序
    this.shuffle()
    //绘制画布内容
    this.drawCanvas()
  },

三、程序运行结果

 

 

四、问题总结与体会

在实验过程中出现了很多小问题,因为代码量太大而导致经常出现代码上的一些小错误,还有就是在<canvas>的使用上略微有些不熟练,通过此次实验,学会了拼图小游戏的做法,还有一

些函数的用法以及熟悉了<canvas>的用法

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值