绿色方块代表食物,红色代表蛇头,黄色代表蛇身
<template>
<div class="main">
<button @click="gameStart" class="startButtom">开始游戏</button>
<div class="canvas">
<div class="box" v-for="i in areaSize" :key="i" :id="i"/>
</div>
</div>
</template>
<script lang="ts">
import { nextTick,defineComponent,ref } from 'vue';
export default defineComponent({
name: 'App',
setup(){
let htmlDivElement
//贪吃蛇画布属性
const attributes={
//奇数
widthGrid:7,
//偶数 方便蛇初始化在地图中心
heightGrid:8
}
let areaSize=attributes.widthGrid*attributes.heightGrid
//贪吃蛇数组
let sankeArry:{body:number[],direction:number}={
body:[],
//0上 1左 2右
direction:0
}
//食物
let food:number
//画布初始化
function canvasInitialization(widthGrid:number,heightGrid:number):void {
htmlDivElement=document.getElementsByClassName('canvas')[0] as HTMLDivElement
htmlDivElement.style.display='grid'
htmlDivElement.style.gridTemplateColumns=`repeat(${widthGrid},20px)`
htmlDivElement.style.gridTemplateRows=`repeat(${heightGrid},20px)`
htmlDivElement.style.width=`${20*widthGrid}px`
htmlDivElement.style.height=`${20*heightGrid}px`
sankeInitialization(attributes.widthGrid,attributes.heightGrid)
foodInitialization(areaSize)
}
//贪吃蛇身体初始化
function sankeInitialization(widthGrid:number,heightGrid:number):void{
let sankeInitializationId:number
//蛇头
sankeInitializationId=((heightGrid-2)/2*widthGrid)+(Math.floor(widthGrid/2)+1)
sankeArry.body.push(sankeInitializationId)
//蛇尾
sankeInitializationId=((((heightGrid-2)/2)+1)*widthGrid)+(Math.floor(widthGrid/2)+1)
sankeArry.body.push(sankeInitializationId)
console.log(sankeArry.body)
}
//食物的初始化
function foodInitialization(areaSize:number) {
let control=1
food=Math.floor(Math.random()*areaSize+1)
while (control){
if (sankeArry.body.includes(food)){
food=Math.floor(Math.random()*areaSize)
}else {
control--
}
}
}
//蛇的绘制
function sankeDraw(sankeBody:number[]):void{
for (let i = 0;i<sankeBody.length;i++){
htmlDivElement=document.getElementById(`${sankeBody[i]}`) as HTMLDivElement
if (i===0){
htmlDivElement.style.backgroundColor='red'
}else{
htmlDivElement.style.backgroundColor='yellow'
}
}
}
//食物的绘制
function foodDraw() {
htmlDivElement=document.getElementById(food.toString()) as HTMLDivElement
htmlDivElement.style.backgroundColor='green'
}
//触碰食物
function touchFood(sankeTopId:number):boolean{
console.log(food)
if (sankeTopId===food){
foodInitialization(areaSize)
foodDraw()
return false
}
return true
}
//触碰蛇身 gameover
function touchBody(sankeNextTopId:number,sankebody:number[]):boolean {
console.log(sankeNextTopId)
console.log(sankebody)
if (sankebody.includes(sankeNextTopId)){
//控制定时器结束
stop=true
console.log('触碰到了身体')
alert('游戏结束,即将重开')
location.reload()
}
return true
}
//根据蛇头方向来改变sanke数组 只改变蛇头
function changeSankeArr(sankeArry:{body:number[],direction:number},widthGrid:number,heightGrid:number):{body:number[],direction:number}{
let sankeNextTopId:number
switch (sankeArry.direction) {
case 0:
//向上
if (sankeArry.body[0]<widthGrid){
//上边界
console.log('上边界')
sankeNextTopId=widthGrid*heightGrid-widthGrid+sankeArry.body[0]
if (touchBody(sankeNextTopId,sankeArry.body))
sankeArry.body.unshift(sankeNextTopId)
}else{
sankeNextTopId=sankeArry.body[0]-widthGrid
if (touchBody(sankeNextTopId,sankeArry.body))
sankeArry.body.unshift(sankeNextTopId)
}
if (touchFood(sankeArry.body[0]))
sankeArry.body=sankeArry.body.filter((item,index)=>{return index < sankeArry.body.length-1})
return sankeArry
case 1:
//向左
if (sankeArry.body[0]%widthGrid===1){
//左边界
console.log('左边界')
sankeNextTopId=sankeArry.body[0]+widthGrid-1
if (touchBody(sankeNextTopId,sankeArry.body))
sankeArry.body.unshift(sankeNextTopId)
}else{
sankeNextTopId=sankeArry.body[0]-1
if (touchBody(sankeNextTopId,sankeArry.body))
sankeArry.body.unshift(sankeNextTopId)
}
if (touchFood(sankeArry.body[0]))
sankeArry.body=sankeArry.body.filter((item,index)=>{return index < sankeArry.body.length-1})
return sankeArry
case 2:
//向下
if (sankeArry.body[0]<=(widthGrid*heightGrid)&&(sankeArry.body[0]>=(widthGrid*(heightGrid-1)+1))){
//下边界
console.log('下边界')
sankeNextTopId=widthGrid-widthGrid*heightGrid+sankeArry.body[0]
if (touchBody(sankeNextTopId,sankeArry.body))
sankeArry.body.unshift(sankeNextTopId)
}else{
sankeNextTopId=sankeArry.body[0]+widthGrid
if (touchBody(sankeNextTopId,sankeArry.body))
sankeArry.body.unshift(sankeNextTopId)
}
if (touchFood(sankeArry.body[0]))
sankeArry.body=sankeArry.body.filter((item,index)=>{return index < sankeArry.body.length-1})
return sankeArry
default:
if (!(sankeArry.body[0]%widthGrid)){
//右边界
console.log("右边界")
sankeNextTopId=sankeArry.body[0]-widthGrid+1
if (touchBody(sankeNextTopId,sankeArry.body))
sankeArry.body.unshift(sankeNextTopId)
}else {
sankeNextTopId=sankeArry.body[0]+1
if (touchBody(sankeNextTopId,sankeArry.body))
sankeArry.body.unshift(sankeNextTopId)
}
if (touchFood(sankeArry.body[0]))
sankeArry.body=sankeArry.body.filter((item,index)=>{return index < sankeArry.body.length-1})
//向右
return sankeArry
}
}
//蛇移动,还原画布,最后一位
function reductionCanves(sankeBody:number[]){
htmlDivElement=document.getElementById((sankeBody[sankeBody.length-1]).toString()) as HTMLDivElement
htmlDivElement.style.backgroundColor='black'
}
//游戏初始化
nextTick(()=>{
canvasInitialization(attributes.widthGrid,attributes.heightGrid)
sankeDraw(sankeArry.body)
foodDraw()
})
//系统自动前进 1.6s间隔
let reactionTime=0
let stop=false
function autoMove() {
if (stop===true){
return
}
let delay:number=1000+reactionTime
let timer=setTimeout(()=>{
reductionCanves(sankeArry.body)
sankeArry=changeSankeArr(sankeArry,attributes.widthGrid,attributes.heightGrid)
sankeDraw(sankeArry.body)
delay+=300
console.log(delay,`定时器时间`)
autoMove()
delay-=300
if (reactionTime!=0)
reactionTime=0
clearTimeout(timer)
},delay)
}
//点击开始
//计时器只运行一次
let workonly=true
function gameStart() {
console.log(sankeArry)
//聚焦
htmlDivElement=document.getElementsByClassName('canvas')[0] as HTMLDivElement
htmlDivElement.focus()
htmlDivElement=document.getElementsByClassName('startButtom')[0] as HTMLDivElement
htmlDivElement.style.pointerEvents='none'
document.onkeyup=function listenKey(event:any) {
if (workonly===true){
autoMove()
workonly=false
}
console.log(event)
let controlMath=sankeArry.body[0]-sankeArry.body[1]
console.log(controlMath)
//上 ArrowUp w
if (event.key==='w'||event.key==='ArrowUp'){
console.log('上')
if (controlMath!==attributes.widthGrid){
reductionCanves(sankeArry.body)
sankeArry.direction=0
sankeArry=changeSankeArr(sankeArry,attributes.widthGrid,attributes.heightGrid)
console.log(sankeArry.body)
sankeDraw(sankeArry.body)
}
}
//左 ArrowLeft a
if (event.key==='a'||event.key==='ArrowLeft'){
console.log('左')
if (controlMath!==1){
reductionCanves(sankeArry.body)
sankeArry.direction=1
sankeArry=changeSankeArr(sankeArry,attributes.widthGrid,attributes.heightGrid)
console.log(sankeArry.body)
sankeDraw(sankeArry.body)
}
}
//下 ArrowDown s
if (event.key==='s'||event.key==='ArrowDown'){
console.log('下')
if (controlMath!==-attributes.widthGrid){
reductionCanves(sankeArry.body)
sankeArry.direction=2
sankeArry=changeSankeArr(sankeArry,attributes.widthGrid,attributes.heightGrid)
console.log(sankeArry.body)
sankeDraw(sankeArry.body)
}
}
//右 ArrowRight d
if (event.key==='d'||event.key==='ArrowRight'){
console.log('右')
if (controlMath!==-1){
reductionCanves(sankeArry.body)
sankeArry.direction=3
sankeArry=changeSankeArr(sankeArry,attributes.widthGrid,attributes.heightGrid)
console.log(sankeArry.body)
sankeDraw(sankeArry.body)
}
}
}
}
return{
areaSize,gameStart
}
}
});
</script>
<style>
*{
margin: 0;
padding: 0;
}
.main{
width: 100%;
height: 100%;
}
.canvas{
background-color: black;
color: #40a9ff;
}
.box{
width: 19px;
height: 19px;
border: 1px solid #999999;
}
</style>