Vue.js拼图华容道
沐华 人气:0游戏介绍
先看看界面
这是一个拼图游戏,可以自选难度和自选闯关图片
游戏开始后根据不同难度,生成与所选主图 对应的 不同张数的 随机顺序的小图,然后只要把乱序的小图片还原成完整的图片就闯关成功
游戏区域有一个空白位置,可以用鼠标点击空白位相邻的图片完成替换,也就是移动,也可以用键盘上下左右操作
游戏好玩,可不要贪杯哦,学习也不能落下,不管什么游戏都一样
这个虽然用到的技术很一般很简单,多数还是普通的 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 }
结语
加载全部内容