使用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使用vant中的checkbox实现全选功能
Nov 17 Vue.js
一篇超完整的Vue新手入门指导教程
Nov 18 Vue.js
vue组件中节流函数的失效的原因和解决方法
Dec 02 Vue.js
vue调用微信JSDK 扫一扫,相册等需要注意的事项
Jan 03 Vue.js
vue+vant 上传图片需要注意的地方
Jan 03 Vue.js
vue3弹出层V3Popup实例详解
Jan 04 Vue.js
vue watch监控对象的简单方法示例
Jan 07 Vue.js
VUE实现吸底按钮
Mar 04 Vue.js
一篇文章告诉你如何实现Vue前端分页和后端分页
Feb 18 Vue.js
vue使用echarts实现折线图
Mar 21 Vue.js
Vue中使用import进行路由懒加载的原理分析
Apr 01 Vue.js
vue 自定义组件添加原生事件
Apr 21 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修改session_id示例代码
2014/01/08 PHP
在SAE上搭建最新wordpress的方法
2014/12/21 PHP
CI操作cookie的方法分析(基于helper类库)
2016/03/28 PHP
PHP仿微信发红包领红包效果
2016/10/30 PHP
PHP实现的微信APP支付功能示例【基于TP5框架】
2019/09/16 PHP
[原创]网络复制内容时常用的正则+editplus
2006/11/30 Javascript
深入认识JavaScript中的函数
2007/01/22 Javascript
一个无限级XML绑定跨框架菜单(For IE)
2007/01/27 Javascript
仿迅雷焦点广告效果(JQuery版)
2008/11/19 Javascript
玩转方法:call和apply
2014/05/08 Javascript
jQuery中[attribute]选择器用法实例
2014/12/31 Javascript
基于jQuery Bar Indicator 插件实现进度条展示效果
2015/09/30 Javascript
JS实现网页上随机产生超链接地址的方法
2015/11/09 Javascript
Bootstrap每天必学之缩略图与警示窗
2015/11/29 Javascript
在js中实现邮箱格式的验证方法(推荐)
2016/10/24 Javascript
浅谈Angular.js中使用$watch监听模型变化
2017/01/10 Javascript
详解Vue中使用插槽(slot)、聚类插槽
2019/04/12 Javascript
antd-mobile ListView长列表的数据更新遇到的坑
2020/04/08 Javascript
简介JavaScript错误处理机制
2020/08/04 Javascript
vue路由分文件拆分管理详解
2020/08/13 Javascript
Javascript实现贪吃蛇小游戏(含详细注释)
2020/10/23 Javascript
Python 自动化表单提交实例代码
2017/06/08 Python
使用Python AIML搭建聊天机器人的方法示例
2018/07/09 Python
详解Numpy中的数组拼接、合并操作(concatenate, append, stack, hstack, vstack, r_, c_等)
2019/05/27 Python
django实现将修改好的新模型写入数据库
2020/03/31 Python
Python爬虫工具requests-html使用解析
2020/04/29 Python
Python实现简单猜数字游戏
2021/02/03 Python
python 获取域名到期时间的方法步骤
2021/02/10 Python
HTML5 Canvas实现平移/放缩/旋转deom示例(附截图)
2013/07/04 HTML / CSS
手摸手教你用canvas实现给图片添加平铺水印的实现
2019/08/20 HTML / CSS
Eyeko美国:屡获殊荣的睫毛膏、眼线笔和眉妆
2018/07/05 全球购物
Myprotein西班牙官网:欧洲第一大运动营养品牌
2020/02/24 全球购物
庆七一活动简报
2015/07/20 职场文书
食品安全主题班会
2015/08/13 职场文书
班干部竞选演讲稿(精选5篇)
2019/09/24 职场文书
nginx优化的六点方法
2021/03/31 Servers