IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> 拼图游戏-小程序游戏 -> 正文阅读

[移动开发]拼图游戏-小程序游戏

?

掌握<canvas>组件和绘图API

本项目一共需要两个页面:首页和游戏页面。首页用于呈现关卡菜单,点击对应难度的关卡后进入游戏画面。

首页功能需求:

(1)包含标题和关卡列表

(2)关卡至少要有6个关卡选项,每个关卡显示预览图片和第几关

(3)点击关卡列表可以打开对应的游戏界面

游戏页功能需求:

(1)游戏页面需要显示游戏提示图,游戏画面,“重新开始”按钮

(2) 每关游戏提示图显示对应的图片预览

(3)游戏画面随机将原图打乱为3x3的小方块,并且可移动被点击的方块。

(4)点击“重新开始”按钮可以重新随机打乱小方块并开始游戏

创建页面文件

需创建index首页页面和game游戏页面

页面设计

app.json

{
  "pages":[
    "pages/index/index"
  ],
  "window": {
    "navigationBarBackgroundColor": "#E64344",
    "navigationBarTitleText": "拼图游戏"
  }
}

app.wxss

/**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;
}

index.wxml

<!--index.wxml-->
<view class="container">
<!-- 标题 -->
<view class="title"> 游戏选关 </view>
<!-- 关卡列表 -->
<view class="levelBox">
  <view class="box">
    <image src="/images/p1.jpg"></image>
    <text>第一关</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;
}

游戏页面设计

游戏页面需要用户点击首页的关卡列表,然后在新窗口中打开该页面。游戏页面包括游戏提示图,游戏画面和“重新开始”按钮

由于暂时没有做点击跳转的逻辑设计,可以在开发工具顶端选择“普通编译”下的“添加编译模式”,并携带临时测试参数level=pi1.jpg


游戏页面设计

<!--pages/game/game.wxml-->

<view class="container">
<!-- 提示图区域 -->
<view class="title"> 提示图 </view>
    <image src="/images/p1.jpg"></image>
  <!-- 游戏画布 -->
  <canvas canvas-id="myCanvas"></canvas>

  <!-- 重新开始按钮 -->
  <button type="warn">重新开始</button>
</view>
/* pages/game/game.wxss */
/* 提示图样式 */
image{
  width: 250rpx;
  height: 250rpx;
}

/* 画布样式 */
canvas{
  border: 1rpx solid;
  widows: 300rpx;
  height: 300rpx;
}


逻辑实现

首页逻辑

首页功能主要是展示关卡列表,点击图片能跳转到游戏界面

关卡列表展示

在JS文件的data中录入关卡图片的数据信息。

index.js

 */
  data: {
    levels:[
      'p1.jpg',
      'p2.jpg',
      'p3.jpg',
      'p4.jpg',
      'p5.jpg',
      'p6.jpg'
    ]
  },

<view>组件添加wx:for属性循环显示关卡列表数据和图片

index.wxml

<!-- 关卡列表 -->
<view class="levelBox">
  <view class="box" wx:for="{{levels}}" wx:key="levels{{index}}">
    <image src="/images/{{item}}"></image>
    <text>第{{index+1}}关</text>
  </view>
</view>

点击跳转游戏页面

若需要用户点击图片即可实现跳转,需要首先为关卡列表项目添加点击事件

index.wxml

<!-- 关卡列表 -->
<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>

为关卡添加了自定义点击事件函数chooseLevel,并且使用data-level属性携带了关卡图片信息


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

游戏页逻辑

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

在游戏页接收关卡信息

Page({
  /**
   * 生命周期函数--监听页面加载
   */
  onLoad: function (options) {
    // 更新图片路径地址
    url='/images/'+options.level
    // 更新提示图的地址
    this.setData({urrl:url})
  },

})
<!--pages/game/game.wxml-->

<view class="container">
<!-- 提示图区域 -->
<view class="title"> 提示图 </view>
    <image src="{{url}}"></image>
  <!-- 游戏画布 -->
  <canvas canvas-id="myCanvas"></canvas>

  <!-- 重新开始按钮 -->
  <button type="warn">重新开始</button>
</view>

游戏逻辑实现

首先在game.js文件的顶端记录一些游戏初始数据信息

// pages/game/game.js
// 方块的初始位置
var num = [
  ['00','01','02'],
  ['10','11','12'],
  ['20','21','22']
]
// 方块的宽度
var w = 100
// 图片的初始地址
var url = '/images/p1.jpg'

Page({

  /**
   * 页面的初始数据
   */

初始化拼图画面

随机抽取画面中的任意两个方块,然后交换彼此位置,在进行足够多次数的交换之后基本可以实现随机打乱效果。

但有时会陷入死局

可以考虑从空白方块的所在位置入手,每次随机让它和周围的邻近方块交换位置,可以通过方块反向移动回到最初状态(确保本局有解),并且在交换足够多次数之后可以实现随机打乱效果

在game.js文件中添加shuffle函数,用于重新开始游戏


Page({

  // 自定义函数-随机打乱方块顺序
  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
        }
      }
    }
  },

  /**
   * 页面的初始数据
   */
  data: {

  },

每次使用Math.random()方法从上下左右4个方向中随机产生一个方向,之后如果符合条件则交换空白方块和图片方块位置

在game.js中添加自定义函数drawCanvas,用于打乱后的图片方块绘制到画布上

game.js


  // 自定义画布函数
  drawCanvas:function(){
    let ctx = this.ctx
    // 清空画布
    ctx.clearRect(0,0,300,300)
    // 使用双重for循环绘制3x3的拼图
    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.

对应的game.js


  /**
   * 生命周期函数--监听页面加载
   */
  onLoad: function (options) {
    // 更新图片路径地址
    url='/images/'+options.level
    // 更新提示图的地址
    this.setData({urrl:url})
    // 创建画布上下文
    this.ctx = wx.createCanvasContext('myCanvas')
    // 打乱方块顺序
    this.shuffle()
    // 绘制画布内容
    this.drawCanvas()
  },

移动被点击的块

修改game.wxml页面中的画布组件<canvas>为其绑定触摸事件

 <!-- 游戏画布 -->
  <canvas canvas-id="myCanvas" bindtouchstart="touchBox"></canvas>

在game.js文件中添加自定义函数touchBox,用于实现图片方块的移动


  <!-- 游戏画布 -->
  <canvas canvas-id="myCanvas" bindtouchstart="touchBox"></canvas>

  // 自定义函数-监听点击方块事件
  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)
    }
  },

  /**
   * 自定义函数--移动方块
   */
  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
      }
    }

  },

判断游戏成功

首先在game.js文件的data中添加初始数据isWin,用于标记游戏成功与否。

 /**
   * 页面的初始数据
   */
  data: {
    isWin:false
  },

isWin为false表示游戏尚未成功,当成功时会重置为true.

在game.js文件中添加自定义函数isWin,用于判断游戏是否已经成功。


  //自定义函数 - 判断游戏是否成功
  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

  },
 // 自定义函数-监听点击方块事件
  touchBox:function(e){
    // 如果游戏成功,不做任何操作
    if(this.data.isWin){
      // 终止本函数
      return
    }

修改game.js的touchBox函数,要求被触发时追加对游戏成功状态的判断


  // 自定义函数-监听点击方块事件
  touchBox:function(e){
    // 如果游戏成功,不做任何操作
    if(this.data.isWin){
      // 终止本函数
      return
    }

    // 获取被点击方块的坐标x和y
      。。。略

    // 如果点击的不是空白位置
     。。。略
      // 重新绘制画布内容
      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()
      }
    }
  },

重新开始游戏

修改game.wxml代码,为“重新开始”按钮追加定义

<!-- 重新开始按钮 -->
  <button type="warn" bindtap="restartGame">重新开始</button>

在game.js文件中添加restartGame函数,用于重新开始游戏


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

完整代码:

app.json

{
  "pages":[
    "pages/index/index",
    "pages/game/game"
  ],
  "window": {
    "navigationBarBackgroundColor": "#E64344",
    "navigationBarTitleText": "拼图游戏"
  }
}

app.wxss

/**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;
}

首页代码展示:

index.wxml

<!--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>

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;
}

index.js

// index.js
// 获取应用实例
Page({

  /**
   * 页面的初始数据
   */
  data: {
    levels:[
      'p1.jpg',
      'p2.jpg',
      'p3.jpg',
      'p4.jpg',
      'p5.jpg',
      'p6.jpg'
    ]
  },

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

})

game.wxml

<!--pages/game/game.wxml-->

<view class="container">
<!-- 提示图区域 -->
<view class="title"> 提示图 </view>
    <image src="{{url}}"></image>
  <!-- 游戏画布 -->
  <canvas canvas-id="myCanvas" bindtouchstart="touchBox"></canvas>
  <!-- 重新开始按钮 -->
  <button type="warn" bindtap="restartGame">重新开始</button>
</view>

game.wxss

/* pages/game/game.wxss */
/* 提示图样式 */
image{
  width: 250rpx;
  height: 250rpx;
}

/* 画布样式 */
canvas{
  border: 1rpx solid;
  width: 300px;
  height: 300px;
}

game.js

// pages/game/game.js
// 方块的初始位置
var num = [
  ['00','01','02'],
  ['10','11','12'],
  ['20','21','22']
]
// 方块的宽度
var w = 100
// 图片的初始地址
var url = '/images/p1.jpg'

Page({
 /**
   * 页面的初始数据
   */
  data: {
    isWin:false
  },

  // 自定义画布函数
  drawCanvas:function(){
    let ctx = this.ctx
    // 清空画布
    ctx.clearRect(0,0,300,300)
    // 使用双重for循环绘制3x3的拼图
    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 =  parseInt(num[i][j]%10)
          //绘制方块
          ctx.drawImage(url,col*w,row*w,w,w,j*w,i*w,w,w)
        }
      }
    }
    ctx.draw()
  },

  // 自定义函数-随机打乱方块顺序
  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
        }
      }
    }
  },

 

  // 自定义函数-监听点击方块事件
  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
      }
    }
  },

  /**
   * 生命周期函数--监听页面加载
   */
  onLoad: function (options) {
    // 更新图片路径地址
    url='/images/'+options.level
    // 更新提示图的地址
    this.setData({url:url})
    // 创建画布上下文
    this.ctx = wx.createCanvasContext('myCanvas')
    // 打乱方块顺序
    this.shuffle()
    // 绘制画布内容
    this.drawCanvas()
  },
})

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2022-04-01 00:13:15  更:2022-04-01 00:13:21 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 19:28:42-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码