信息发布→ 登录 注册 退出

利用Vue.js制作一个拼图华容道小游戏

发布时间:2026-01-11

点击量:
目录
  • 游戏介绍
  • 核心思路
  • 核心代码
    • html
    • games 类
    • 生成随机图片数量
    • 移动图片
    • 键盘事件
    • 拼图完成
  • 结语

    游戏介绍

    先看看界面

    这是一个拼图游戏,可以自选难度和自选闯关图片

    游戏开始后根据不同难度,生成与所选主图 对应的 不同张数的 随机顺序的小图,然后只要把乱序的小图片还原成完整的图片就闯关成功

    游戏区域有一个空白位置,可以用鼠标点击空白位相邻的图片完成替换,也就是移动,也可以用键盘上下左右操作

    游戏好玩,可不要贪杯哦,学习也不能落下,不管什么游戏都一样

    这个虽然用到的技术很一般很简单,多数还是普通的 JS,但是也花了不少时间,特别是图片。确定整体风格,找背景图、游戏框。也是前两天假期,喊我女朋友帮忙找图片,也找了很多图片让她帮忙参考,毕竟她的审美比我强,我就粗汉子

    核心思路

    • 游戏等级(level),比如初级,等级数值定为3,游戏界面就是三行三列,中级等级数值为4,游戏界面就是四行四列,即当前等级的平方,就是小格子总数量
    • 游戏开始后以格子总数量为最大值,来生成随机数的数组 randomData,初级如:[3,1,7,2,4,8,6,5,9],遍历生成小图片,最大数值为空白格子,就是9
    • 并根据当前等级生成拼图完成时的数据 finishData,初级如:123456789
    • 点击或键盘按键的时候将符合条件的,randomData 里的目标格子和空白格子对应的值,交换,然后自动更新视图,完成移动
    • 每走一步时,统计步数,并检查 randomData().join('') == finishData,相等即拼图完成

    核心代码

    注意看注释哦

    html

    以下就是拼图区域全部html,根据状态 isStart 控制是否是处于游戏状态

    <div class="stage">
      <div class="game-name" v-show="!isStart">华容道</div>
      <div class="content clearfix" v-show="isStart">
        <div
          v-for="item in randomData"
          :key="item"
          :class="`img${level}`"
          @click="handleMove(item)"
        >
          <el-image
            v-if="item != randomData.length"
            :src="getSmallImg(`${gameImg}/${level}/${item}.jpg`)"
          ></el-image>
        </div>
      </div>
    </div>

    getSmallImg 这个方法是用于动态引入图片的,毕竟不是 webpack,没有 require 那么方便

    // 获取当前游戏小图片
    export const getSmallImg = (path: string) => {
      return new URL(`../assets/images/${path}`, import.meta.url).href
    }

    games 类

    js 部分主要是封装了一个类,方便统一管理操作

    // 拼图类
    class Puzzle implements IPuzzle {
      isStart = false  // 游戏状态
      randomData: Array<number> = [] // 乱序的,对应当前游戏小图片张数的数组
      finishData = "" // 正序的,拼图完成时的排序,用来对比
      gameImg = ""  // 游戏主图
      level = 3 // 游戏等级
      step = 0 // 游戏步数
      constructor() {}
      // 初始化
      init({ gameImg, level }: IMode) {
        this.step = 0
        this.level = level
        this.gameImg = gameImg
        // 生成当前游戏随机数数组
        this.randomData = this.getRandomData()
        this.isStart = !this.isStart
        // 如果是开始游戏,就计算出拼图完成时的数据
        if (this.isStart) this.finishData = this.getFinishData()
      }
      // 移动图片
      move(idx: number) {}
      // 键盘事件
      onKeyDown(code: number){}
      // 检查是否拼图完成
      finish() {}
      // 生成小图片数量数组
      getRandomData(){}
    }

    生成随机图片数量

    就是在点击开始游戏的时候会执行 getRandomData,生成随机数数组,然后 DOM 部分就遍历这个生成的随机数数组,渲染切碎了的小图片

    // 生成小图片数量数组
    getRandomData() {
        // 随机数集合
        let randomArr = []
        // 根据游戏等级生成最大值,减1是因为最大值保留作空白位放最后
        let max = Math.pow(this.level, 2) - 1
        while (randomArr.length < max) {
          // 生成一个最大值范围内的随机数
          let random = Math.floor(Math.random() * max) + 1
          if (randomArr.indexOf(random) == -1) {
            // 没有重复的就添加
            randomArr.push(random)
          }
        }
        randomArr.push(max + 1) // 添加最大数字作为最后的空白位
        return randomArr // 如:[3, 1, 7, 2, 4, 8, 6, 5, 9]
    }

    移动图片

    接收一个参数,就是在遍历随机数数组 randomData 的时候,对应每个图片的值,鼠标点击的时候拿到这个值

    // 移动图片
    move(idx: number) {
        let level = this.level
        let target = this.randomData.indexOf(idx) // 当前点击位置下标
        let space = this.randomData.indexOf(Math.pow(level, 2)) // 空白位置下标
    
        // 过滤一下,不然空白位置在最左边时点击右边上一个数字时也能实现交换
        // 以及空白位置在最右边点击左边下一个数字时也能实现交换
        let condition =
          (space % level == 0 && target % level == level - 1) ||
          (space % level == level - 1 && target % level == 0)
          
        // 如果能交换
        if (!condition) {
          // 并且点击目标的,上或下或左或右是空白位,就交换位置
          if (
            target == space - level ||
            target == space + level ||
            target == space - 1 ||
            target == space + 1
          ) {
              this.change(space, target)
          }
        }
    }
    // 动起来
    change(space: number, target: number) {
        // 空白位置替换成目标位置
        this.randomData[space] = this.randomData[target]
        // 目标位置为最大值,实现交换
        this.randomData[target] = Math.pow(this.level, 2)
        // 步数
        this.step += 1
        // 检查是否完成
        this.finish()
    }

    键盘事件

    按下键盘上下左右的时候,判断空格位置对应你按的那个方向能不能移动,符合条件就替换

    // 键盘事件
    onKeydown(code: number) {
        let level = this.level
        // 目标位置下标
        let target
        // 空白位置下标
        let space = this.randomData.indexOf(Math.pow(level, 2))
        // 上下左右
        switch (code) {
          case 37:
            target = space + 1
            if (space % level == level - 1) return
            this.change(space, target)
            break
          case 38:
            target = space + level
            if (target > this.randomData.length - 1) return
            this.change(space, target)
            break
          case 39:
            target = space - 1
            if (space % level == 0) return
            this.change(space, target)
            break
          case 40:
            target = space - level
            if (target < 0) return
            this.change(space, target)
            break
        }
    }

    拼图完成

    思路是把当前乱序的 randomData 转为字符串,和正序的 finishData 作对比,如果一样了,就是拼图完成了

    // 检查是否拼图完成
    finish() {
        // 如:'312' == '123'
        if (this.randomData.join("") == this.finishData) {
          ElMessageBox.alert(`恭喜你,闯关成功,仅用${this.step}步`, "提示", {
            confirmButtonText: "OK",
            callback: (action: Action) => {
              this.randomData = []
              this.step = 0
              this.isStart = false
            },
          })
        }
    }
    // 根据不同难度生成拼图完成时的数据用来对比,判断是否完成
    // 比如初级难度就是:123456789
    getFinishData(): string {
        let str = ""
        for (let i = 1, len = Math.pow(this.level, 2); i <= len; i++) {
          str += i
        }
        return str
    }

    结语

    游戏体验地址(pc)

    开源地址

    以上就是利用Vue.js制作一个拼图华容道小游戏的详细内容,更多关于Vue.js拼图华容道的资料请关注其它相关文章!

    在线客服
    服务热线

    服务热线

    4008888355

    微信咨询
    二维码
    返回顶部
    ×二维码

    截屏,微信识别二维码

    打开微信

    微信号已复制,请打开微信添加咨询详情!