用原生canvas做个贪吃蛇
通过观察贪吃蛇,发现可以通过把蛇身上最后一个元素,移动到头部位置来实现蠕动,新的位置通过当前的头部坐标和当前的方向判断。所以要实现很简单的。
蛇的身体通过若干矩形绘制,所以要有个数组来存储矩形开始绘制的坐标和颜色等信息,监听按键来改变当前的方向。生成的果子也是随机的,不在蛇身上就可以了。
下面是实现后的贪吃蛇:
没有做碰撞检测,撞墙了或者吃到自己了也不会挂。可能跑到地图外去,就很难找回了( ̄▽ ̄)/
v-dragable是我自定义的指令,要去掉的。蛇身上的属性并没有做处理,理论上要重新赋一遍值。
当然如果有环形链表实现起来就要简单很多。之所以会有白色的轨迹是因为尾部被移开的元素被白色填充,看起来就像白色的轨迹,也是个特效吧(^_^)☆
<template>
<div class='snake_cnt' :style="{'width':width||'480px'}" v-dragable>
<div class='head clear-float'>snake<span class='el-icon-close icon' @click="close"></span></div>
<div class="main">
<canvas ref="mainCav" :height="cavHeight" :width="cavWidth"></canvas>
</div>
<div>分数:{{score}}</div>
<div>
<el-button size="small" @click="startGame">开始</el-button>
<el-button size="small" @click="pauseGame">停止</el-button>
</div>
</div>
</template>
<script>
export default {
name:'greedy-snake',
comments:{
},
props: ['width'],
data() {
return {
cavWidth:720,
cavHeight:200,
scale:5,//比例
snake:[{x:0,y:0,color:"green"},{x:5,y:0,color:"green"}],//蛇的组成数组
score:0,//得分
speed:200,//蛇移动的间隔ms
ctx:null,
direction:"right",
handleMove:null,//定时器句柄
food:[],//理论来说只有一个食物,需要多个要改代码
}
},mounted() {
this.ctx=this.$refs.mainCav.getContext("2d");
console.log(this.ctx);
},methods: {
close(){
this.$emit("execTrans",{fnc:"closeDialog",param:['showSnake']})
},startGame(){//开始游戏
let that=this;
this.drawSnake();
this.initFood();
document.addEventListener("keydown",function(event){
console.log(event);
if([37,38,39,40].indexOf(event.keyCode)!=-1 && that.handleMove){//有效按键,并且游戏运行按键事件触发
that.direction=["left","up","right","down"][event.keyCode-37];console.log(that.direction)
that.drawSnake();
}
});
},drawSnake(){
let that=this;clearInterval(this.handleMove);
this.handleMove=setInterval(()=>{
that.ctx.save();
let ele={...[...that.snake].pop()};
if(that.direction=="up"){
ele.y-=that.scale;
}
if(that.direction=="down"){
ele.y+=that.scale;
}
if(that.direction=="right"){
ele.x+=that.scale;
}
if(that.direction=="left"){
ele.x-=that.scale;
}
that.snake.push(ele);//头部,通过原头部和方向判断新头部的位置
let oldele=that.snake.shift();
if(that.food.some((item)=>item.x==ele.x&&item.y==ele.y)){//吃到食物了没有
that.snake.unshift({
x:oldele.x,
y:oldele.y,
color:"green"
});//后面插入一个元素
that.score+=10;//吃掉加10分
that.initFood();//吃掉后新增食物
}
//边界限制未设置
that.ctx.fillStyle="white";
that.ctx.fillRect(oldele.x,oldele.y,5,5);console.log(that.snake,oldele);
that.ctx.restore();
that.snake.forEach(item => {
that.ctx.save();
that.ctx.fillStyle=item.color;
// that.ctx.translate(item.x,item.y);
that.ctx.fillRect(item.x,item.y,5,5);
that.ctx.restore();
});
},that.speed);
},pauseGame(){
clearInterval(this.handleMove);
},initFood(){//初始化食物
let pos={},that=this;
function getPos(){
pos.x=Math.ceil((Math.random()*that.cavWidth)/5)*5;
pos.y=Math.ceil((Math.random()*that.cavHeight)/5)*5;
that.snake.some((item)=>item.x==pos.x&&item.y==pos.y) && getPos();
}
getPos();//获取随机的坐标,但不能在蛇身上
this.ctx.save();
that.ctx.fillStyle="red";
that.ctx.fillRect(pos.x,pos.y,5,5);
that.ctx.restore();//绘制小红点食物
that.food.push(pos);
}
},
}
还是工作太闲了,别被老板发现才好 (=´ω`=)