贪吃蛇规则:
代码语言:javascript复制1、贪吃蛇碰到墙壁会结束游戏
2、头部碰到身体会结束游戏
3、吃到食物会增加长度
复制代码
分析:
代码语言:javascript复制需要一个棋盘、棋盘上会随机生成5个点(食物)、需要一个贪吃蛇、方向键控制贪吃蛇的移动方向。
最重要的是,贪吃蛇怎么移动?控制DOM移动,难度太大,因为贪吃蛇可以随意弯曲,不好计算。
如果用一个数组作为贪吃蛇,这个数组内包含棋盘上的某个些点,就让这些点变色。这样就比较容易。
可以让棋盘上的每个点都有一个有规律的坐标,
比如:
第一排第一个[0,0]、第二个[0,1].....[0,n];
第二排第一个[1,0]、第二个[1,1]......[1,n];
第n排第一个[n、0]、第二个[n、1]......[n、n];
贪吃蛇向上移动就让头部的x坐标-1、向下移动就让头部x坐标 1、向左就让y坐标-1、向右就让y坐标 1;
每次移动会在贪吃蛇数组内添加一个点(unshift)、会在末尾去掉一个点(pop);
遇到食物,就把食物所在的坐标添加到贪吃蛇数组内,贪吃蛇的长度就增加了;
判断贪吃蛇碰到墙壁或自己的身体,游戏就结束。
复制代码
代码: index.vue
代码语言:javascript复制<template>
<div class="wrap">
<div class="shade" v-show="over || !begin">
<div v-show="!begin" class="bigText">
<span>按方向键开始</span>
</div>
<div v-show="over" class="bigText">
<div v-show="over" class="text-align-center">游戏结束</div>
<br>
<br>
<span>按方向键重新开始</span>
</div>
</div>
<div class="text-align-center">得分:{{snake.length}}分</div>
<div class="grid">
<div
class="grid-item"
v-for="item,index in grid"
:class="{snake:snake.includes(item.value), randomPoint: randomPoint.includes(item.value), special: status, over: over}"
:key="index">
</div>
</div>
</div>
</template>
<script>
import { defineComponent, ref } from 'vue'
import { useGrid, genarateRandomPoint, interval } from './hooks/grid'
export default defineComponent({
setup() {
let speed = 500;
let [ grid, snake, derection, status, over, begin, { bindEvents, changeStatus } ] = useGrid();
bindEvents(e => {
console.log(begin.value, 'begin.value');
console.log(over.value, 'over.value');
if (!begin.value ) {
console.log('未开始');
// 若未开始,按方向键开始
begin.value = true;
changeSpeed(speed);// 初始速度 500
}
if( over.value ) {
over.value = false;
speed = 500;
snake.value = ['15,15'];
console.log('重新开始');
changeSpeed(speed);// 初始速度 500
return;
}
switch( e.keyCode ) {
case 37:
if (derection.value != 'right') {
derection.value = 'left';
}
break;
case 38:
if (derection.value != 'bottom') {
derection.value = 'top';
}
break;
case 39:
if (derection.value != 'left') {
derection.value = 'right';
}
break;
case 40:
if (derection.value != 'top') {
derection.value = 'bottom';
}
break;
default:
break;
}
console.log(derection.value, 'derection.value');
});
// 首次生成5个随机点
let randomPoint = ref(genarateRandomPoint(grid, snake, 5));
let { startInterval, stopInterval } = interval();
var changeSpeed = startInterval(() => {
console.log(snake.value[0], 'snake.value[0]');
let nextGrid = {
coordinate: snake.value[0].split(',').map(Number),
value: snake.value[0]
}
let addArray = [1, 1];
switch(derection.value){
case 'left':
console.log('left');
addArray = [0, -1];
break;
case 'right':
console.log('right');
addArray = [0, 1];
break;
case 'top':
console.log('top');
addArray = [-1, 0];
break;
case 'bottom':
console.log('bottom');
addArray = [1, 0];
break;
}
nextGrid.coordinate = [nextGrid.coordinate[0] addArray[0], nextGrid.coordinate[1] addArray[1]];
nextGrid.value = nextGrid.coordinate.join(',');
console.log(nextGrid, 'nextGrid');
if (nextGrid.coordinate[0] > 29 || nextGrid.coordinate[1] > 29 || nextGrid.coordinate[0] < 0 || nextGrid.coordinate[1] < 0) {
console.log('撞墙');
over.value = true;
stopInterval();
return;
} else if (snake.value.includes(nextGrid.value)) {
console.log('撞到自己');
over.value = true;
stopInterval();
return;
}
// 碰到食物
if (randomPoint.value.includes(nextGrid.value)) {
let newPoint = randomPoint.value.splice(randomPoint.value.indexOf(nextGrid.value),1)[0];
snake.value.unshift(newPoint);
changeStatus();
// 吃够5个涨一次速度
if (snake.value.length % 5 == 0) {
speed -= 100;
changeSpeed(speed)
}
if ( randomPoint.value.length < 1) {
randomPoint.value = randomPoint.value.concat(genarateRandomPoint(grid, snake, 5));
}
} else {
snake.value.pop();
snake.value.unshift(nextGrid.value);
}
});
return {
grid,
snake,
derection,
status,
over,
begin,
interval,
randomPoint
}
},
})
</script>
<style lang="scss" scoped>
@keyframes color{
0% {
background:black;
}
25% {
background:red;
}
50% {
background:orange;
}
75% {
background:blue;
}
100% {
background:black;
}
}
.text-align-center{
text-align: center;
font-weight: bold;
}
.wrap{
position: relative;
.shade{
position: absolute;
top:0;
left:0;
bottom: 0;
right:0;
z-index: 1;
background:rgba(#000, .6);
display: flex;
justify-content: center;
align-items: center;
.bigText{
color: white;
font-size: 30px;
letter-spacing: 3px;
font-weight: bold;
}
}
}
.grid{
margin:20px auto;
display: flex;
flex-wrap: wrap;
width:602px;
border-top:1px solid black;
border-left: 1px solid black;
.grid-item{
box-sizing: border-box;
flex-shrink: 0;
border-right:1px solid black;
border-bottom: 1px solid black;
width:20px;
height:20px;
&.snake{
background:black;
&.special{
animation: color .5s infinite;
}
&.over{
background:gray;
}
}
&.randomPoint{
background:green;
}
}
}
</style>
复制代码
hooks/grid.js
代码语言:javascript复制import { ref } from 'vue'
// 生成网格
export function useGrid(){
let grid = ref([]); // 网格
let snake = ref(['15,15']); // 贪吃蛇
let derection = ref('top'); // 方向
let status = ref(false); // 状态 如果是true 则是迟到食物或者加速
let over = ref(false); // game over
let begin = ref(false); // 开始状态
new Array(30).fill(1).forEach((xItem, x) => {
new Array(30).fill(1).forEach((yItem, y) => {
grid.value.push({
coordinate:[x, y],
value:`${x},${y}`
})
})
});
function bindEvents(cb){
document.addEventListener('keydown', e => {
cb(e)
})
}
function destroyEvents(){
document.removeEventListener('keydown');
}
// 改变状态
function changeStatus(){
status.value = true;
setTimeout(() => {
status.value = false;
},2000)
}
return [
grid,
snake,
derection,
status,
over,
begin,
{
bindEvents,
destroyEvents,
changeStatus
}
]
}
// 生成随机点
export function genarateRandomPoint (grid, nake, count) {
let arr = [];
let createNumberArray = (grid, nake) => {
let randomPoint = grid.value[Math.floor(Math.random() * 901)].value;
while(nake.value.includes(randomPoint.value)){
randomPoint = grid.value[Math.floor(Math.random() * 901)].value;
}
return randomPoint;
}
new Array(count).fill(1).forEach(() => {
arr.push(createNumberArray(grid, nake));
});
return arr;
}
// 计时器
export function interval(){
let timer = null;
function startInterval(cb){ // 回调函数 、 速度
return function(speed){
stopInterval();
timer = setInterval(() => {
cb()
}, speed);
}
}
function stopInterval(){
clearInterval(timer);
timer = null;
}
return {
startInterval,
stopInterval
}
}