关于前端:用Vuejs写一个命令行贪吃蛇游戏

前言

大家好,我是webfansplz.本文要分享的是如何应用Vue.js实现一个命令行贪吃蛇游戏(temir-snake-game).对于贪吃蛇游戏想必大家都不生疏了,应用Vue.js实现一个Web版的贪吃蛇游戏仿佛没什么难度,那如果是命令行版的呢?是不是你会对它的实现原理感兴趣呢?让咱们开始吧!

装置

npm install temir-snake-game -g

开始游戏

在终端窗口运行temir-sg.

对于Windows零碎,举荐应用hyper终端进行体验.

将Vue渲染到命令行界面

应用Vue.js实现命令行贪吃蛇游戏,首先意味着咱们要将Vue.js渲染到命令行界面,能力开始具体的游戏实现.咱们常常用Vue.js来编写Web利用,然而Vue的能力却不仅仅局限于此,它的舞台也不只有浏览器.Vue3领有杰出的跨平台能力,咱们能够通过createRenderer API创立一个自定义渲染器,通过创立宿主环境中对应的Node和Element,并对元素进行增删改查操作.

得益于Vue3杰出的跨平台能力,我实现了Temir,一个用Vue组件来编写命令行界面利用的工具.开发者只须要应用Vue就能够编写命令行利用,不须要任何额定的学习老本.顺便值得一提的是,它还反对HMR~

对于Temir就不在这里进行具体的介绍了,有趣味的童鞋能够上Github查看介绍或者看应用Vue.js编写命令行界面这篇文章.

贪吃蛇游戏实现

有了Temir,咱们就具备了应用Vue.js编写命令行游戏的条件,接下来咱们来看看游戏的具体实现:

实现拆解

首先咱们对游戏实现进行一下简略的拆解,从元素+逻辑的维度来看,能够简略分为几局部:

元素初始化

竞技台

蛇的匍匐与食物的生成都须要依赖坐标,最简略的坐标其实只须要一个索引值.因而竞技台的组成也很简略,就是由很多个小盒子(这里以⬛示意)组成,每一个盒子对应一个坐标(索引),咱们要做的是一个28*28的竞技台,因而它的索引汇合就是(0~783).

const basic = 28
const backgroundIcon = '⬛'
const arena = ref<string[]>([])

function initArena() {
 arena.value = Array.from({ length: basic * basic }, () => backgroundIcon)
} 

后面咱们提到了坐标的概念,蛇身的组成就是一串有法则的坐标.

const snakeIcon = '🟧'
// 坐标(索引)30,29 长度为2的蛇身
const snakeBody = ref([30, 29])
食物

食物的生成其实也就是随机一个坐标(索引),只不过要留神的是,咱们须要避开蛇身自身的坐标.

const foodIcon = '🍗'
// 食物坐标
const foodCoord = ref(77)

// 生成食物
function generateFood() {
  const food = Math.floor(Math.random() * basic * basic)
  // 与蛇身抵触,从新生成
  if (snakeBody.value.includes(food)) {
    generateFood()
    return
  }
  foodCoord.value = food
}

初始化后的元素长这样 👇 :

蛇的匍匐

蛇的匍匐逻辑有两个根底元素,方向 + 步数.后面咱们提到了竞技台的组成是一个28*28的行列式构造,那么对于方向和步数的映射,就比拟清晰了:

const map = {
 left: -1,
 right: 1,
 top: -28,
 bottom: 28
}

有了两个根本元素,咱们就能够得出咱们每一次匍匐的下一个坐标.咱们只须要在每次匍匐的时候往蛇头增加对应的坐标,并移除蛇尾所在的坐标就能够达到蛇匍匐的成果.


function move() {
  const h = snakeBody.value[0]
  // 计算下一次匍匐坐标,并增加至蛇头
  head.value = h + direction.value
  snakeBody.value.unshift(head.value)

  // 吃到食物,从新生成
  if (head.value === foodCoord.value) {
    generateFood()
  }
  // 只有在未吃到食物的时候,才须要移除蛇尾
  else { snakeBody.value.pop() }
}

越界逻辑

贪吃蛇的游戏完结规定判断就是匍匐时蛇头越界(这里的界线指的是超出竞技台的范畴)或者碰到蛇身.

function isOutOfRange(h: number) {
    // 1. 蛇头碰到蛇身
  return snakeBody.value.indexOf(h, 1) > 0
    // 2. 蛇头超出竞技台上方
    || h < 0
    // 3. 蛇头超出竞技台下方
    || h > basic * basic - 1
    // 4. 蛇头超出竞技台右方
    || (direction.value === 1 && h % basic === 0)
    // 5. 蛇头超出竞技台左方
    || (direction.value === -1 && h % basic === basic - 1)
}

方向管制

贪吃蛇游戏外围的操作逻辑在于操纵蛇的方向进行食物的捕获.所以咱们须要做的就是捕获用户方向键的输出进行方向的切换.Temir提供了useInput函数监听用户的输出.

import { useInput } from '@temir/core'
useInput(onKeyBoard, { isActive: true })

function onKeyBoard(_, keys) {
  const { upArrow, downArrow, leftArrow, rightArrow } = keys
  const d = {
    [+leftArrow]: -1,
    [+rightArrow]: 1,
    [+upArrow]: -basic,
    [+downArrow]: basic,
  }[1] ?? direction.value
  direction.value = (snakeBody.value[1] - snakeBody.value[0] === d) ? direction.value : d
}

UI绘制

对于UI的绘制与出现Temir提供了一些Vue组件,咱们只须要像构建Flexbox布局那样构建终端UI:

<script lang="ts" setup>
import { computed } from 'vue'
import { TBox, TText } from '@temir/core'
import { useGame } from './composables'
import Header from './components/Header.vue'
import Home from './components/Home.vue'
import Game from './components/Game.vue'
import GameOver from './components/GameOver.vue'
import Exit from './components/Exit.vue'
const { playStatus } = useGame()
const activeComponent = computed(() => {
  return {
    unplayed: Home,
    playing: Game,
    over: GameOver,
    exit: Exit,
  }[playStatus.value]
})
</script>

<template>
  <TBox
    :width="100"
    justify-content="center"
    align-items="center"
    flex-direction="column"
    border-style="double"
  >
    <Header />
    <component :is="activeComponent" />
  </TBox>
</template>

到这里,贪吃蛇的实现就完结了,对具体实现感兴趣的能够戳源码查看.

演示

结语

如果我的文章和我的项目对你有所启发和帮忙,请给一个star反对作者 ✌!

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理