利用Vue.js制作一个拼图华容道小游戏
作者:沐华 发布时间:2024-05-22 10:43:11
游戏介绍
先看看界面
这是一个拼图游戏,可以自选难度和自选闯关图片
游戏开始后根据不同难度,生成与所选主图 对应的 不同张数的 随机顺序的小图,然后只要把乱序的小图片还原成完整的图片就闯关成功
游戏区域有一个空白位置,可以用鼠标点击空白位相邻的图片完成替换,也就是移动,也可以用键盘上下左右操作
游戏好玩,可不要贪杯哦,学习也不能落下,不管什么游戏都一样
这个虽然用到的技术很一般很简单,多数还是普通的 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
}
来源:https://juejin.cn/post/7083375980403752968
猜你喜欢
- 问题:我在 Vue 中有一个 form 表单,用于上传博客帖子,它有标题、正文、描述、片段和图片等范围。所有的一切都是必需的。我在 Expr
- 我们可以通过mysql命令查看mysql的安装路径:# 以下两个sql任意一个可查询select @@basedir as basePath
- 为什么说浮点数缺乏精确性?在开始本文之前,让我们先来谈谈浮点数为什么缺乏精确性的问题,其实这不是Python的问题,而是实数的无限精度跟计算
- 一、gfile模块是什么 gfile模块定义在tensorflow/python/platform/gfile.py,但其源代码实现主要位于
- 1.散点图代码# This import registers the 3D projection, but is otherwise unu
- 之前在做数据分析的过程中,需要对数据进行实时的写入,比如对新生成的数据写入之前已经生成的txt或csv文件中。现在想想其实很简单,所以做一个
- 本文实例讲述了javascript设计模式 – 桥接模式原理与应用。分享给大家供大家参考,具体如下:介绍:如果软件系统中某个类存在两个或多个
- Python 包含6种数据类型,其中Number(数字)、String(字符串)、Tuple(元组)、List(列表)、Dictionary
- 不知不觉大半年没更新了...前面小二介绍过使用Typora+MinIO+Java代码打造舒适写作环境,然后有很多大佬啊,说用Java来实现简
- 根据我最近的一些实践以及在和一些读者进行关于HTML表格的使用问题沟通之后,决定写这篇文章。总的来说,我注意到由于误导性信息,他们对于tab
- 现在Go1.14都已经发布好些日子了,之前发的Go环境搭建教程早已过时,只是因为时间问题一直没来得及更新这次怀着愧疚的心情,在凌晨四点时,将
- import上一级目录的模块python中,import module会去sys.path搜索,sys.path是个列表,并且我们可以动态修
- detectres.asp<HTML><head><TITLE>asp教程之全能屏幕分辨率侦测</
- 废话不多说,估计只有我这个菜鸟废了2个小时才搞出来,主要是我想了太多方法来实现,最后都因为这因为那的原因失败了间接说明自己对可变与不可变类型
- 前言在所有编程语言中都涉及到大量的字符串操作,可见熟悉对字符串的操作是何等重要。本文通过示例详细介绍了Go语言实现字符串切片赋值的方法,感兴
- <html><head><title>过滤空格</title><SCRIPT LANG
- 1.1全部php生成结构1.2html中嵌套php总结如下:html和php混写规则:php代码必须包在<?php ?>html
- 前言在尝试将结构体序列化为 Json 时,你可能会遇到 “omitempty” 标记,本小记就来浅看
- 模型事件Laravel 模型事件允许你监听模型生命周期内的事件, 并且通过这个事件去做一些模型通用性的东西, 例如检查用户修改了那个字段,
- 一、var声明的变量会挂载在window上,而let和const声明的变量不会:var a = 100;console.log(a,wind