基于Vue3实现数字华容道游戏的示例代码

 更新时间:2022年04月19日 11:08:19   作者:vagg  
这篇文章主要为大家详细介绍了如何利用Vue编写一个数字华容道游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

前言

恰逢春之四月,天气忽热忽凉,遇游戏大赛,以笨拙之技,书一篇小文。

游戏规则:存在n*n的格子,需要将它们按数字顺序或图片顺序一一还原即可。

环境

主要环境:

vue3 version:3.2.4

vite version:2.5.0

vue-router version:4.0.14

注:这个游戏的路由使用的是自动路由插件

主要插件:

windicss version:3.5.1

预览地址

代码地址

运行如图:

思路

  • 搭建环境,下载依赖
  • 运行项目
  • 利用windicss主体兼容pc和移动端

姑且认为小于1024的是平板或者手机 lg(1024px)

App.vue

<div class="relative w-full h-full lg:(w-750px h-800px)">
    <route-view
</div>

主体Game.vue设置4个主体组件:GameTool.vue游戏工具栏(返回、开始和步数统计)、GameCnt.vue游戏主体、Tip.vue开局提示、GamePass.vue游戏通过

实现

GameCnt

布局

  • 先画出3*3的格子,这里有多种方法,笔者这里采取最简单的动态grid布局实现,后来因为css动画选取的是transform则不用gird布局了
  • 宽高获取,这里要获取,原因是使用了transform位移动画,则需要平移距离和宽高了
  • 设置lazyShow,让第一次渲染不会有transform动画
  • 隐藏最后一个,利用数组对象value值+css实现
  • 添加其他css(windicss不好实现的css)
// 定义行个数
const rowLen = 3
// 定义cnt宽高和item的宽高
const cntWidth = ref(0)
const cntHeight = ref(0)
const itemWidth = ref(0)
const itemHeight = ref(0)

// 定义数组
const lists = ref([])

lists.value = new Array(rowLen.value * rowLen.value).fill(1).map((item, index) => ({
    key: index, // 存储原序号
    value: item, // 1 代表不是空位
    moveIndex: index
  }))

// 设置最后一个为-1
  lists.value[lists.value.length - 1]['value'] = 0
  
//获取dom和渲染
onMounted(() => {
   // 获取cnt宽高和item的宽高
  getCntWidth()
  // 让第一次渲染不会有transform动画
  lazyShow.value = false
})
<div v-show="!lazyShow" v-for="(item, index ) in lists" class="box rounded-md  overflow-hidden absolute"
      :class="[item.value ? 'origin' : 'opacity-0']" @click="boxClick(item)" :style="{
        transform: `translate(${(item.moveIndex % rowLen) * (1 / rowLen) * cntWidth}px, ${parseInt(item.moveIndex / rowLen) * (1 / rowLen) * cntHeight}px) `, width: itemWidth + 'px', height: itemHeight + 'px'
      }">
    <p class="absolute z-10 text-light-100 left-1/2 top-1/2" :class="hasImg ? 'opacity-60' : ''"
        :style="{ 'font-size': (180 / rowLen) + 'px' }">{{ item.key + 1 }}</p>
</div>

点击元素的交换

核心代码:

// 是否在一行
  const isInline = parseInt(index / rowLen.value) === parseInt(emptyIndex / rowLen.value)
 
 // 在一行是否相邻
  Math.abs(emptyIndex - index) === 1
   
  // 不在一行是否是上下关系
  Math.abs(index - emptyIndex) === rowLen.value

点击元素上下左右的交换

先判断是否在一行,再判断是否相邻即可。

  • 先判断是否在一行
  • 在一行是否相邻或不在一行是否是上下关系
  • 看情况调用changeIndex
// 是否在一行
  if (isInline) {
    // 一行则判断是否左右相邻
    console.log('相差:' + (index - emptyIndex))
    // 是否相邻
    if (Math.abs(emptyIndex - index) === 1) {
      // 改变对应moveIndex
      changeIndex()
    } else {
      console.log('不相邻')
      return
    }
  } else {
    //  不是则判断是否上下相邻
    console.log('相差:' + (index - emptyIndex))
    // 是否上或者下
    if (Math.abs(index - emptyIndex) === rowLen.value) {
      // 改变对应moveIndex
      changeIndex()
    } else {
      console.log('不相邻')
      return
    }
  }
  
  // 声明改变的数组moveIndex的方法
  const changeIndex = () => {
    // 步数改变
    emit('stepChange');
    // 改变对应数组里的moveIndex 注意不是 index和 moveIndex
    ([lists.value[item.key].moveIndex, lists.value[emptyItem.key].moveIndex] = [emptyIndex, index]);
  }

判断游戏通过

这个地方很简单,主要判断数组对象每一个是否原序号key是否都相等于移动后的moveIndex

// 是否都成功
  const getIsAllOk = () => {
    // 
    return lists.value.some(item => item.moveIndex !== item.key)
  }
  // // 判断是否都成功了
  const flag = getIsAllOk()
  console.log(flag)
  if (!flag) {
    // alert('成功')
    gamePass()
  }

注:这个gamePass需要在defineEmits里注册

打乱数组

这个地方很有点麻烦,存在无解的情况,暂时没想到更好的实现方法,这里使用的是排序打乱

// 打乱数据
const mixData = () => {
  const arr = new Array(rowLen.value * rowLen.value).fill(0).map((item, index) => index)
  // console.log(arr)
  arr.sort(() => {
    return Math.random() > 0.5 ? -1 : 1
  })
  arr.forEach((item, index) => {
    lists.value[index].moveIndex = item
  })

  // 如果直接是成功的则重新来一次排序
  const flag = getIsAllOk()
  if (!flag) {
    // alert('成功')
    mixData()
  }
}

注:有想法可以沟通下,一起提升!

动态格子和宽高

const params = route.query
// 定义行个数
rowLen.value = +params.num || 3;

// 重新获取item宽高
cnt.value && getCntWidth()

图片华容道

图片使用定位。然后超出截取即可展示出效果

<img v-if="hasImg" class="absolute" :src="Default" alt=""
        :style="{ width: cntWidth + 'px', maxWidth: cntWidth + 'px', height: cntHeight + 'px', left: -(item.key % rowLen) * (1 / rowLen) * cntWidth + 'px', top: -parseInt(item.key / rowLen) * (1 / rowLen) * cntHeight + 'px' }">
  
 // 是否渲染图片
  hasImg.value = params.hasImg === '1' ? true : false;

GameTool

左侧是返回按钮,右侧是重新开始按钮,中间是移动步数

移动步数后中间会调整为移动多少次

注:图标从iconfont找的

GamePass

  • 先布局全屏遮罩
  • 设置中间div样式
  • 设置通过成功提示和步数提示即可

GameTip

这个组件就是开局的提示组件

Menu

这个组件就是菜单页 设置了两种入口

最后

GameCnt 可以写一些测试代码,方便测试下通关后的情况

GameCnt 的块级效果优化过,否则只有颜色,不太好看

GamePass 还有优化空间,例如图片通过可以有不同效果啊等等

整体难度不高,可以练习下vue3,以及游戏思维

到此这篇关于基于Vue3实现数字华容道游戏的示例代码的文章就介绍到这了,更多相关Vue数字华容道内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 深度剖析 Vue3 在浏览器的运行原理

    深度剖析 Vue3 在浏览器的运行原理

    这篇文章主要介绍了深度剖析Vue3在浏览器的运行原理,文章通过围绕主题展开相关详细介绍,具有一定的参考价值,需要的小伙伴可以参考一下
    2022-09-09
  • vscode中vue-cli项目es-lint的配置方法

    vscode中vue-cli项目es-lint的配置方法

    本文主要介绍vscode中 vue项目es-lint的配置方法,非常不错,具有一定的参考借鉴价值,需要的的朋友参考下吧
    2018-07-07
  • vue中$nexttick,$set,$forceupdate的区别

    vue中$nexttick,$set,$forceupdate的区别

    本文主要介绍了vue中$nexttick,$set,$forceupdate的区别,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-07-07
  • 前端Vue项目部署到服务器的全过程以及踩坑记录

    前端Vue项目部署到服务器的全过程以及踩坑记录

    使用Vue做前后端分离项目时,通常前端是单独部署,用户访问的也是前端项目地址,因此前端开发人员很有必要熟悉一下项目部署的流程,下面这篇文章主要给大家介绍了关于前端Vue项目部署到服务器的全过程以及踩坑记录的相关资料,需要的朋友可以参考下
    2023-05-05
  • Django与Vue语法的冲突问题完美解决方法

    Django与Vue语法的冲突问题完美解决方法

    这篇文章主要介绍了Django与Vue语法的冲突问题完美解决方法,本文给大家分享了两种解决方法,需要的朋友参考下吧
    2017-12-12
  • vue项目中created()被调用多次的踩坑实战

    vue项目中created()被调用多次的踩坑实战

    在vue项目中我在created中调用了两次get数据请求,所以下面这篇文章主要给大家介绍了关于vue项目中created()被调用多次的踩坑实战,需要的朋友可以参考下
    2023-03-03
  • vue中手机号,邮箱正则验证以及60s发送验证码的实例

    vue中手机号,邮箱正则验证以及60s发送验证码的实例

    下面小编就为大家分享一篇vue中手机号,邮箱正则验证以及60s发送验证码的实例,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-03-03
  • vue中form表单禁用专用组件介绍

    vue中form表单禁用专用组件介绍

    这篇文章主要介绍了vue中form表单禁用专用组件,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-01-01
  • vue动态组件之:is在组件中的使用场景

    vue动态组件之:is在组件中的使用场景

    这篇文章主要介绍了vue动态组件之:is在组件中的使用场景,本文结合示例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-07-07
  • Vue之创建项目及目录方式

    Vue之创建项目及目录方式

    这篇文章主要介绍了Vue之创建项目及目录方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-11-11

最新评论