使用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如何跨组件传递Slot的实现
Dec 14 Vue.js
vue实现图片裁剪后上传
Dec 16 Vue.js
vue中watch的用法汇总
Dec 28 Vue.js
Vue.extend 登录注册模态框的实现
Dec 29 Vue.js
vue中实现点击空白区域关闭弹窗的两种方法
Dec 30 Vue.js
Vue仿Bibibili首页的问题
Jan 21 Vue.js
vue3.0封装轮播图组件的步骤
Mar 04 Vue.js
vue-cropper组件实现图片切割上传
May 27 Vue.js
一篇文章告诉你如何实现Vue前端分页和后端分页
Feb 18 Vue.js
三种方式清除vue路由跳转router-link的历史记录
Apr 10 Vue.js
vue使用localStorage持久性存储实现评论列表
Apr 14 Vue.js
vue3不同环境下实现配置代理
May 25 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抓即时股票信息
2006/10/09 PHP
PHP基于双向链表与排序操作实现的会员排名功能示例
2017/12/26 PHP
php中错误处理操作实例分析
2019/08/23 PHP
javascript 命名空间以提高代码重用性
2008/11/13 Javascript
解析jquery获取父窗口的元素
2013/06/26 Javascript
js中top的作用深入剖析
2014/03/04 Javascript
深入理解JavaScript系列(38):设计模式之职责链模式详解
2015/03/04 Javascript
jquery+正则实现统一的表单验证
2015/09/20 Javascript
js操作数组函数实例小结
2015/12/10 Javascript
React.js入门学习第一篇
2016/03/30 Javascript
Nodejs全局安装和本地安装的不同之处
2016/07/04 NodeJs
vue 文件目录结构详解
2017/11/24 Javascript
nodejs实现的简单web服务器功能示例
2018/03/15 NodeJs
angularjs获取到My97DatePicker选中的值方法
2018/10/02 Javascript
cordova+vue+webapp使用html5获取地理位置的方法
2019/07/06 Javascript
微信小程序前端promise封装代码实例
2019/08/24 Javascript
React Hooks 实现和由来以及解决的问题详解
2020/01/17 Javascript
Vue生命周期activated之返回上一页不重新请求数据操作
2020/07/26 Javascript
linux服务器快速卸载安装node环境(简单上手)
2021/02/22 Javascript
Python内置函数dir详解
2015/04/14 Python
Python实现计算文件夹下.h和.cpp文件的总行数
2015/04/23 Python
python函数的5种参数详解
2017/02/24 Python
对Python w和w+权限的区别详解
2019/01/23 Python
Python实现语音识别和语音合成功能
2019/09/20 Python
浅谈python多线程和多线程变量共享问题介绍
2020/04/17 Python
使用python实现名片管理系统
2020/06/18 Python
基于第一个PhoneGap(cordova)的应用详解
2013/05/03 HTML / CSS
使用HTML5技术开发一个属于自己的超酷颜色选择器
2013/09/22 HTML / CSS
小程序瀑布流解决左右两边高度差距过大的问题
2019/02/20 HTML / CSS
行政办公员自我评价分享
2013/12/14 职场文书
四风问题自查报告剖析材料
2014/02/08 职场文书
田径运动会开幕式及主持词
2014/03/28 职场文书
奉献家乡演讲稿
2014/09/16 职场文书
2014年采购工作总结
2014/11/20 职场文书
2014年行政执法工作总结
2014/12/11 职场文书
《领导干部从政道德启示录》学习心得体会
2016/01/20 职场文书