贪吃蛇
今天给大家讲解怎样在画布里面完成贪吃蛇小游戏
首先我们先理一下思路:
蛇是在一个小方块里面运动的,由我们的键盘事件去控制方向,里面有随机产生的食物,而且食物不能出现在蛇的身上,蛇吃掉食物会慢慢变长,当蛇撞到了墙或者是自己的头碰到自己的身体也会死亡。
那我们新建一个画布,设置css样式黑色边框阴影并在页面中间部位显示:
<head>
<meta charset="utf-8">
<title></title>
<script src="https://cdn.bootcss.com/jquery/3.4.0/jquery.js"></script>
</head>
<style type="text/css">
/* 设置canvas画布的阴影 颜色为黑色 居中并且向下移动20px*/
canvas{
box-shadow: 0 0 10px 10px #000;
display: block;
margin: 20px auto;
}
</style>
<body>
<!-- 我们要操作的canvas -->
<canvas id="canvas" width="800" height="600"></canvas>
</body>
接下来我们就要用JS去实现它:
先绘制一个Draw的构造函数在里面判断浏览器是否支持canvas然后再做检测兼容、获取canvas的画笔,并在里面绘制蛇的初始图像及蛇吃的食物,做一个动画定时器,当蛇移动的时候将会清除它原来的旧图像,当蛇在运动的时候判断是否撞到了画布边框或者是自己的头碰到了自己的身体游戏都将结束,当蛇将食物吃掉会重新随机产生食物。
/**
[Draw description]canvas 绘图的构造函数
@param{[type]} canvas [description]
**/
function Draw(canvas){
this.canvas = canvas;// 这里通过Canvas获取canvas对象
/**
[check description]检测浏览器是否支持canvas
@return bool fals支持e 表示不支持 true表示
**/
this.check = function(){
//检测浏览器是否支持canvas
if(!this.canvas.getContext){
console.log('浏览器不支持canvas');
return false;//返回false
}else{
return true;//否则返回true
}
}
/**
[main description]canvas 绘图的主函数
@return{[type]} [description]
**/
this.main = function(){
//检测兼容
if(!this.check()){
console.log('浏览器不支持canvas');
return false;//返回false
}
//获取canvas绘图的上下文:画笔
Draw.prototype.xt = this.canvas.getContext('2d');
// var _this=this;
//绘制蛇的初始图像
var snake=new Snake(this);
snake.draw();
//随机产生食物
var food = randFood(snake);
food.draw();
//做一个动画的定时器
Draw.prototype.timer=setInterval(function(){
//清除旧的图像
Draw.prototype.xt.clearRect(0,0,this.canvas.width,this.canvas.height);
//改变蛇的位置
if(!snake.move()){
clearInterval(Draw.prototype.timer);
alert('游戏结束')
}
//重新绘制图像
snake.draw();
food.draw();
//是否吃到了食物
if(isRectHit(food,snake.head)){
Snake.prototype.isEatFood=true;
//重新随机产生食物
food=randFood(snake);
}
},200);
}
}
下一步添加蛇最开始默认的移动方向,这里我们设置为向右移动,定义一个蛇是否吃到了食物的方法,然后就是画蛇身,蛇头和蛇尾,并判断蛇尾的方向
//添加蛇默认的移动方向,右,公有的属性,任何地方能够修改访问,并且和实例共享
Snake.prototype.direction=1;
//定义一个是否吃到食物的标记
Snake.prototype.isEatFood=false;
//画蛇的方法
Snake.prototype.draw=function(){
//画蛇头
this.head.draw();
//画蛇身
for(var i=0;i<this.body.length;i++){
this.body[i].draw(); //判断当前尾部方向
}
}
接下来我们让蛇动起来:先检测蛇头与蛇身是否碰撞,再检测蛇是否撞到墙,给蛇加一个头添加到开始运动的地方并去掉一个尾巴。
//让蛇动起来
Snake.prototype.move=function(){
//检测蛇头与蛇身
for(var i=0;i<this.body.length;i++){
if(isRectHit(this.head,this.body[i])){
return false;
}
}
//检测碰撞到墙壁
if(this.head.x<40||this.head.y<40||
this.head.x>$('#canvas')[0].width-80||
this.head.y>$('#canvas')[0].height-80){
return false;
}
//蛇的 移动方式
//给身体加一个头
var rect=new Rect(this.head.x,this.head.y,40,40,'gray');//这个蛇头长40px,宽40Px,颜色为红色
//添加到身体开始的地方
this.body.splice(0,0,rect);
//去掉一个尾巴
if(Snake.prototype.isEatFood){
Snake.prototype.isEatFood=false;
// 如果吃到食物了就重新给位置,即末尾添加一节,即蛇变长
// 重新随机产生食物
}else{
this.body.pop();//如果没吃到末尾就砍掉一节,即蛇长度不变
}
switch(this.direction){
case 0:
this.head.y-=40//向上
break;
case 1:
this.head.x+=40;//向下
break;
case 2:
this.head.y+=40//向右
break;
case 3:
this.head.x-=40;//左
break;
}
return true;
}
下一步在画布里面产生随机食物:
//随机产生食物
function randFood(snake){
//是否在蛇身上
isInSnake = true;
while(isInSnake){
//产生两个位置 x,y
var x = getRandPosition(0,($('#canvas')[0].width-120)/40)*40;
var y = getRandPosition(0,($('#canvas')[0].height-120)/40)*40;
//创建食物矩形
var food = new Rect(x,y,40,40,'green');
isInSnake = false;
//判断这个位置是否在蛇上.
//是否是蛇头
if(isRectHit(food,snake.head)){
isInSnake = true;
continue;
}
//是否是蛇身
for(var i=0;i<snake.body.length;i++){
if(isRectHit(food,snake.body[i])){
isInSnake = true;
break;
}
}
}
return food;
}
//产生随机函数
function getRandPosition(min,max){
return Math.round(Math.random()*(max-min)+min);
}
下一步添加键盘监听事件:
//添加键盘监听
$(window).keydown(function(e){
switch(e.keyCode){
case 37://向右
if(Snake.prototype.direction==1){
return;
}
Snake.prototype.direction=3;
break;
//如果当前方向是向下的,不能改为向上
case 38:
if(Snake.prototype.direction==2){
return;
}
Snake.prototype.direction=0;
break;
case 39:
if(Snake.prototype.direction==3){
return;
}
Snake.prototype.direction=1;
break;
case 40:
if(Snake.prototype.direction==0){
return;
}
Snake.prototype.direction=2;
break;
}
})
然后构造对象方块:
//构造对象方块
function Rect(x,y,width,height,color){
this.x = x;//定义Rect的x坐标
this.y = y;//定义Rect的y坐标
this.width = width; //,宽
this.height = height;//,高
this.color = color;//颜色
}
/**
* [draw description] 画矩形
* @return
**/
//画方块的方法
Rect.prototype.draw = function(){
Draw.prototype.xt.beginPath();//画一条新的路径。
Draw.prototype.xt.fillStyle = this.color;//颜色
Draw.prototype.xt.fillRect(this.x,this.y,this.width,this.height);//起始位置
Draw.prototype.xt.strokeRect(this.x,this.y,this.width,this.height);//落点位置
}
下一步创建蛇的对象:
//创建蛇的对象
function Snake(obj){
//蛇头,,蛇头设成红色
this.head=new Rect(obj.canvas.width/2,obj.canvas.height/2-20,40,40,'red');
//蛇身
this.body=[];//表示多个身体
var x=this.head.x-40;//表示这个蛇身的x坐标=蛇头的x-40
var y=this.head.y;//表示这个蛇身=蛇头的y坐标
//循环创建身体
for(var i=0;i<3;i++){//画出3个方块,设置成灰色
var rect=new Rect(x,y,40,40,'gray');//创建新的身体,定义了x,y宽高颜色为灰色
this.body.push(rect);//将该函数添加到数组里面
x-=40;//x=x-40
}
}
下一步判断矩形是否重合:
//判断矩形是否重合
function isRectHit(rect1,rect2){
var R1_min_x = rect1.x;
var R2_min_x = rect2.x;
var R1_min_y = rect1.y;
var R2_min_y = rect2.y;
var R1_max_x = rect1.x+40;
var R2_max_x = rect2.x+40;
var R1_max_y = rect1.y+40;
var R2_max_y = rect2.y+40;
var min_x = Math.max(R1_min_x,R2_min_x);
var max_x = Math.min(R1_max_x,R2_max_x);
var min_y = Math.max(R1_min_y,R2_min_y);
var max_y = Math.min(R1_max_y,R2_max_y);
if(min_x<max_x && min_y<max_y){
return true;
}else{
return false;
}
}
最后创建绘图实例对象并调用:
var draw = new Draw($('#canvas')[0]);//创建一个绘图的实例对象
draw.main();//调用main绘制图像