使用vue3重构拼图游戏的实现示例


Posted in Vue.js onJanuary 25, 2021

前言

花了两天时间,重构了项目中的一个拼图小游戏(又名数字华容道),为了方便使用抽离成了独立组件,效果如下:

使用vue3重构拼图游戏的实现示例

使用vue3重构拼图游戏的实现示例

线上体验

源码地址在文章最后哦!

主要重构点

原有拼图游戏是通过开源代码加以改造,使用的是 vue2 。在实际项目使用一切正常,但还是存在以下痛点

  • 源代码臃肿,暴露的配置项不足,特备是和项目现有逻辑结合时体现的更加明显
  • 生成的游戏可能出现无解情况,为了避免无解,只好写死几种情况然后随机生成
  • 源代码是vue2版本,不支持vue3

最后决定使用 vue3 重新实现拼图游戏,着重注意以下细节

  • 组件使用起来足够简单
  • 可以自定义游戏难度
  • 支持图片和数组两种模式

实现思路

无论是拼图片还是拼数字,其原理都是要把原本打乱的数组移动成有序状态。网上也有很多实现数字华容的的算法,算法主要需要解决的就是如何生成一组 随机且有解 的数组,有的人可能有疑问,数组华容道还有可能无解吗?

使用vue3重构拼图游戏的实现示例

如果生成的游戏像上面这样,那就是无解了。原理就像我们玩魔方一样,正常情况下不管我们打乱的多乱都可以还原,但是如果我们把 某几个块抠出来换换位置 ,那就可能还原不了了

网上也有很多算法可以避免生成无解的情况,但是写的都比较高深,加上自己阅读算法的能力有限,最后决定按照自己的思路实现。

我的思路其实比较简单,一句话总结就是逆向推理法,我们可以先从排列好的数组开始,然后随机的通过 移动 打乱其顺序,这样肯定可以保证生成的题目有解,同时可以根据打乱的步数来控制游戏的难度,真是个一举两得的idear。

源码实现

数据存放

首先我考虑的是使用一个一维数组来存放数据

let arr = [1,2,3,4,5,6,7,8,0] // 0 代表空白

但是这样会出现一个问题,就是移动的时候逻辑变的相当麻烦,因为一维数组只能记录数据并不能记录竖直方向的位置,这个时候我们自然就想到使用二维数组了,比如,当我们需要生成一个3*3的游戏时数据是这样的:

let arr [
  [1,2,3],
  [4,5,6],
  [7,8,0]
]

这样我们就可以通过下面来模拟x,y轴来表示每个数字的位置。比如0的位置是(2,2),6的位置是(1,2),如果我想移动6和0的位置,只需要把他们的坐标做调换即可。

移动函数

数字华容道最关键的交互就是用户点击那个块就移动哪个块,但是需要注意的是只有0附近的数组可以移动。下面我们先完成移动函数

function move(x, y, moveX, moveY) {
  const num = state.arr[x][y];
  state.arr[x][y] = state.arr[moveX][moveY];
  state.arr[moveX][moveY] = num;
 }

是不是很简单,其实就是把要移动的两个数的下标给交换下位置
有了移动函数,我们就可以实现上,下,左,右的移动了

// 上移动
 function moveTop(x, y) {
  if (x <= 0) return -1;
  //  开始交换位置
  const okx = x - 1;
  move(x, y, okx, y);
  return {
   x: okx,
   y,
  };
 }
 //下移动
 function moveDown(x, y) {
  if (x >= level - 1) return -1;
  const okx = x + 1;
  move(x, y, okx, y);
  return {
   x: okx,
   y,
  };
 }
 // 左移动

 function moveLeft(x, y) {
  if (y <= 0) return -1;
  const oky = y - 1;
  move(x, y, x, oky);
  return {
   x,
   y: oky,
  };
 }

 // 右移动
 function moveRight(x, y) {
  if (y >= level - 1) return -1;
  const oky = y + 1;
  move(x, y, x, oky);
  return {
   x,
   y: oky,
  };
 }

现在我们再实现一个判断移动方向的方法,如下所示:

function shouldMove(x, y) {
  //  判断向哪移动
  const { emptyX, emptyY } = seekEmpty();
  if (x === emptyX && y !== emptyY && Math.abs(y - emptyY) === 1) {
   // 说明在一个水平线上 可能是左右移动
   if (y > emptyY) {
    moveLeft(x, y);
   } else {
    moveRight(x, y);
   }
  }
  if (y === emptyY && x !== emptyX && Math.abs(x - emptyX) === 1) {
   // 说明需要上下移动
   if (x > emptyX) {
    moveTop(x, y);
   } else {
    moveDown(x, y);
   }
  }
 }

if里面判断的意思是如果我们点击的块是空白快或者不是和空白快挨着的那个,那我们就不做任何处理

生成游戏面板

其实就是随机调用上移,下移,左移,右移函数,把数组打乱

// 随机打乱
 function moveInit(diffic) {
  state.arr = creatArr(level);
  const num = diffic ? diffic : state.diffec;
  const fns = [moveTop, moveDown, moveLeft, moveRight];
  let Index = null;
  let fn;
  for (let i = 0; i < num; i++) {
   Index = Math.floor(Math.random() * fns.length);
   //  moveConsole(Index);
   fn = fns[Index](startX, startY);
   if (fn != -1) {
    const { x, y } = fn;
    startX = x;
    startY = y;
   }
  }
 }

短短几个函数,就完成了核心逻辑,还有几个函数没有介绍到比如判断游戏完成,寻找空白块的位置,创建二维数组大家可自行阅读源码

使用vue3重构

以上逻辑貌似和vue3没什么关系,但是我们忽略了最重要的一点,就是 改变数组后,视图也就改变了 这不就是响应式吗,使用vue3后我们可以把关于游戏的所有逻辑放到一个js里面,大大减少了代码的耦合度

const { arr, shouldMove, moveInit } = useCreateGame(
 gamedata.level,
 gamedata.difficulty,
 gameEndCallback
);

可能有的人会有疑问?把所有逻辑抽离出来这不是很正常的操作吗?难道用vue2的时候都不能抽离了?
但是大家不要忘记了,我们的这个数组需要是响应式的,如果我们单独把逻辑抽离出来那我们在js文件里面改变数组还是响应式的吗

但当我们使用vue3的composition-api时就可以再js文件中声明一个响应式变量,且在组件中使用时它还是响应式的

export default function useCreateGame() {
//声明一个响应式变量
...
 const state = reactive({
  arr: [],
 });
...
 return {
 ...toRefs(state)
 ...
 }
 }
const { arr, shouldMove, moveInit } = useCreateGame(
 gamedata.level,
 gamedata.difficulty,
 gameEndCallback
);
// 这个时候 arr 还是响应式的

这正是composition-api强大所在,有了composition-api我们可以任意组装我们的逻辑代码了

在vue2 如果要维护一个响应式变量我们是不是就要使用vuex这种状态管理器了,这样就增加了代码的耦合度

关于vite2

现在vite已经到了vite2版本,并且官方还在飞快迭代中,使用vite2创建的项目默认是可以使用setup新特性的,比如我们可以这样写:

<template>
 <div>
  {{ name }}
 </div>
</template>

<script setup>
import { ref } from "vue";
const name = ref('"公众号码不停息"');
</script>

等价于这样写

<template>
 <div>
  {{ name }}
 </div>
</template>
<script>
import { ref } from "vue";
export default {
 setup() {
  const name = ref("公众号码不停息");
  return {
   name,
  };
 },
};
</script>

看着就简单了很多,并且在setup版本中vue又出了几个api,感兴趣的可以去官网看下,个人感觉还是挺香的。因为新语法还是实验性质的本次代码重构并未使用。

源码地址

源码地址:数字华容道拼图游戏 欢迎start?

最后

你可能感兴趣:

基于vue-router思考?实现一个简易版vue-router
基于webpack打包多页应用,对前端工程化的思考

到此这篇关于使用vue3重构拼图游戏的实现示例的文章就介绍到这了,更多相关vue3重构拼图内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Vue.js 相关文章推荐
浅析VUE防抖与节流
Nov 24 Vue.js
vue element-ul实现展开和收起功能的实例代码
Nov 25 Vue.js
vue-cli4.0多环境配置变量与模式详解
Dec 30 Vue.js
详解为什么Vue中的v-if和v-for不建议一起用
Jan 13 Vue.js
基于VUE实现简单的学生信息管理系统
Jan 13 Vue.js
Vue包大小优化的实现(从1.72M到94K)
Feb 18 Vue.js
基于vue-simple-uploader封装文件分片上传、秒传及断点续传的全局上传插件功能
Feb 23 Vue.js
vue-cli4.5.x快速搭建项目
May 30 Vue.js
vue整合百度地图显示指定地点信息
Apr 06 Vue.js
vue 实现弹窗关闭后刷新效果
Apr 08 Vue.js
vue实现Toast组件轻提示
Apr 10 Vue.js
vue实现input输入模糊查询的三种方式
Aug 14 Vue.js
vue 计算属性和侦听器的使用小结
Jan 25 #Vue.js
vue keep-alive的简单总结
Jan 25 #Vue.js
vue form表单post请求结合Servlet实现文件上传功能
Jan 22 #Vue.js
Vue 集成 PDF.js 实现 PDF 预览和添加水印的步骤
Jan 22 #Vue.js
Vue仿Bibibili首页的问题
Jan 21 #Vue.js
如何在vue 中使用柱状图 并自修改配置
Jan 21 #Vue.js
Vue看了就会的8个小技巧
Jan 21 #Vue.js
You might like
php中将图片gif,jpg或mysql longblob或blob字段值转换成16进制字符串
2011/08/23 PHP
Yii2创建表单(ActiveForm)方法详解
2016/07/23 PHP
PHP中快速生成随机密码的几种方式
2017/04/17 PHP
html+js实现简单的计算器代码(加减乘除)
2016/07/12 Javascript
JS清除字符串中重复值的实现方法
2016/08/03 Javascript
vue.js实现请求数据的方法示例
2017/02/07 Javascript
Vue.js实现简单动态数据处理
2017/02/13 Javascript
jQuery为DOM动态追加事件的方法
2017/02/16 Javascript
为JQuery EasyUI 表单组件增加焦点切换功能的方法
2017/04/13 jQuery
浅谈Angular 中何时取消订阅
2017/11/22 Javascript
vue集成百度UEditor富文本编辑器使用教程
2018/09/21 Javascript
基于vue实现移动端圆形旋钮插件效果
2018/11/28 Javascript
js实现图片跟随鼠标移动效果
2019/10/16 Javascript
[01:01:41]DOTA2-DPC中国联赛 正赛 PSG.LGD vs Magma BO3 第二场 1月31日
2021/03/11 DOTA
python 不关闭控制台的实现方法
2011/10/23 Python
python web.py开发httpserver解决跨域问题实例解析
2018/02/12 Python
linux下python使用sendmail发送邮件
2018/05/22 Python
Django框架多表查询实例分析
2018/07/04 Python
pytorch制作自己的LMDB数据操作示例
2019/12/18 Python
浅谈HTML5新增及移除的元素
2016/06/27 HTML / CSS
推荐WEB开发者最佳HTML5和CSS3代码生成器
2015/11/24 HTML / CSS
携程英文网站:Trip.com
2017/02/07 全球购物
学生自我鉴定范文
2013/10/04 职场文书
毕业生求职简历的自我评价
2013/10/07 职场文书
最新个人职业生涯规划书
2014/01/22 职场文书
酒店值班经理的工作职责范本
2014/02/18 职场文书
幼儿教师国培感言
2014/02/19 职场文书
2014年公务员退休工资改革方案
2014/10/01 职场文书
践行党的群众路线心得体会
2014/11/05 职场文书
环境建议书
2015/02/04 职场文书
英文导游词
2015/02/13 职场文书
2015年保险公司工作总结
2015/04/24 职场文书
培训后的感想
2015/08/07 职场文书
MySQL中utf8mb4排序规则示例
2021/08/02 MySQL
mongodb的安装和开机自启动详细讲解
2021/08/02 MongoDB
td 内容自动换行 table表格td设置宽度后文字太多自动换行
2022/12/24 HTML / CSS