手写一个简易版贪吃蛇,只是简易版,有bug很正常。
逻辑梳理:
1、画格子。固定xy(两个数组)长度,采用数组坐标[ [ { food:false,snake:false}, { }, { } ],[ ], ] 得到一个装有对象的二维数组。
2、点击开始游戏,使用随机数生成食物与小蛇。随机数最大值为当前xy的值。生成小蛇与食物即将对应坐标对象的food和snake属性改为true,且将当前坐标对象{ x:" ", y:" "} 存入单独的小蛇数组。
3、监听键盘按键。←↑→↓(键盘按钮code,左:37,上:38,右:39,下:40)。按下之后,将数组当前坐标的snake改为true。 小蛇数组第一个坐标对象永远为蛇头,且从小蛇数组
(3.1).如果蛇头撞到食物,重新生成食物
(3.2).否则蛇头未撞到食物,删除数组最后一个对象,且把对应坐标的小蛇点亮。
(3.3).撞到墙重新开始游戏
逻辑导图
4、代码
<template>
<div class="height100">
<div class="flex jc_c">
<div>
请输入行数: <input v-model="rows" placeholder="请输入每行个数" type="number" :max="30"
style="width: 200px;"></input>
请输入列数: <input v-model="columns" placeholder="请输入列数" type="number" :max="30"
style="width: 200px;"></input>
</div>
<div>
<button @click="start">开始</button>
</div>
</div>
<div class="big_div">
<div class="div_row" v-for="(row,rowIndex) in tableArr">
<div class="row_content" v-for="(data,$index) in row">
<div v-show="data.food" class="food_">食</div>
<div v-if="snakeArr.length>0" class="snke_" v-show="data.snake"
:class="{'snke_head':$index==snakeArr[0].x && rowIndex==snakeArr[0].y}">蛇</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
rows: 20,
columns: 20,
tableArr: [],
now: undefined, // 当前操作
snakeArr: [],
foodObj: {
x: "",
y: "",
},
interval: undefined
}
},
watch: {
columns() {
this.initTable();
},
rows() {
this.initTable();
},
},
mounted() {
this.initTable();
},
created() {
//当前页面监视键盘输入
document.onkeydown = e => {
//键盘按键判断:左箭头-37;上箭头-38;右箭头-39;下箭头-40
if (e && e.keyCode == 37 || e.keyCode == 38 || e.keyCode == 39 || e.keyCode == 40) {
clearInterval(this.interval);
this.now = e.keyCode;
this.snakeMove();
this.interval = setInterval(this.snakeMove, 500)
} else {
return;
}
}
},
methods: {
// 初始化生成表格
initTable() {
this.tableArr = [];
for (let a = 0; a < this.rows; a++) {
let rowArr = [];
for (let i = 0; i < this.columns; i++) {
let rowObj = {
snake: false,
food: false
};
rowArr.push(rowObj);
}
this.tableArr.push(rowArr);
}
},
start() {
this.initTable();
this.food();
this.snake();
},
// 生成食物
food() {
let XR = Math.round(Math.random() * this.rows);
let YR = Math.round(Math.random() * this.columns);
this.tableArr[YR][XR].food = true;
this.foodObj = {
x: XR,
y: YR
}
},
// 生成短小的蛇
snake() {
let XR = Math.round(Math.random() * (this.rows - 2) + 1);
let YR = Math.round(Math.random() * (this.columns - 2) + 1);
let newArr = [];
this.tableArr[YR][XR].snake = true;
newArr.push({
x: XR,
y: YR,
})
this.snakeArr = newArr;
},
// 小蛇蛇动起来
snakeMove() {
let [...newSnakeArr] = this.snakeArr; // 深拷贝避免数据混乱
let snakeObj = {};
if (this.now == 37) {
// 当前是否最边上格子
if (newSnakeArr[0].x == 0) {
alert("你gg了");
clearInterval(this.interval);
this.start();
return
}
snakeObj = {
x: newSnakeArr[0].x - 1,
y: newSnakeArr[0].y
}
}
if (this.now == 38) {
// 当前是否最边上格子
if (newSnakeArr[0].y == 0) {
alert("你gg了");
clearInterval(this.interval);
this.start();
return
}
snakeObj = {
x: newSnakeArr[0].x,
y: newSnakeArr[0].y - 1
}
}
if (this.now == 39) {
// 当前是否最边上格子
if (newSnakeArr[0].x == this.rows - 1) {
alert("你gg了");
clearInterval(this.interval);
this.start();
return
}
snakeObj = {
x: newSnakeArr[0].x + 1,
y: newSnakeArr[0].y
}
}
if (this.now == 40) {
// 当前是否最边上格子
if (newSnakeArr[0].y == this.columns - 1) {
alert("你gg了");
clearInterval(this.interval);
this.start();
return
}
snakeObj = {
x: newSnakeArr[0].x,
y: newSnakeArr[0].y + 1
}
}
this.snakeArr.unshift(snakeObj); //在头部添加跑起来的小蛇蛇
this.tableArr[snakeObj.y][snakeObj.x].snake = true; // 点亮跑起来的小蛇
// 当当前坐标与食物坐标重合,表示吃到了,重新生成食物
if (snakeObj.x == this.foodObj.x && snakeObj.y == this.foodObj.y) {
this.tableArr[snakeObj.y][snakeObj.x].food = false; //
this.food();
} else {
let deletedSnake = this.snakeArr.pop(); // 删除小蛇蛇最后一个,并返回被删除的对象
this.tableArr[deletedSnake.y][deletedSnake.x].snake = false; // 取消小蛇蛇最后一个格子
}
},
}
}
</script>
<style lang="less" scoped>
.width100 {
width: 100%;
}
.flex {
display: flex;
}
.jc_c {
justify-content: center;
}
.big_div {
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
.div_row {
font-size: 0;
overflow: hidden;
display: flex;
.row_content {
display: flex;
width: 24px;
height: 24px;
border: 1px solid rgba(230, 230, 230);
}
.snke_ {
background-color: blue;
width: 100%;
color: white;
display: flex;
align-items: center;
justify-content: center;
}
.snke_head {
background-color: red;
width: 100%;
}
.food_ {
background-color: aquamarine;
width: 100%;
color: white;
display: flex;
align-items: center;
justify-content: center;
}
}
}
</style>
5、效果视频
贪吃蛇