Canvas实现贪吃蛇小游戏
我们常常在网页上制作的小游戏都是通过Canvas实现的,虽然我们也可以使用DOM来实现,但是这样会更加的节约资源。
我们书写这个小游戏的目的主要是为了适应js中关于面向对象的设计模式,由于js的面向对象有些特殊所以更加应该引起我们的注意。
其实网上已经有很多关于贪吃蛇这样小游戏的教学,每个人都有每个人的实现方法,也都有所不同,在这其中最需要学习的是面向对象的思维方式,那么下面我直接讲代码粘贴在下面,代码之中有很多注解能够帮助大家理解一些细节的地方。
简单的讲一下代码的思路:因为是对canvas画图小游戏的实现所以我们将最大最外层的构造函数取名为Draw,Drew中接收一个参数是dom的canvas元素,Drew包含两个私有方法是check和main,check主要用于判断用于运行的浏览器是否支持Canvas,main里面主要用于调用其他所有的方法。
我们创建一个用于画图的一个构造函数Rect,并给Rect设置一个公有方法drew用于绘画,创建另一个构造函数snack创建对象画出蛇头和蛇身,创建一个randFood用于随机创建出食物,当然还有很多的关于蛇对象snake的很多公有方法,例如是否吃到食物和方向等。
其实下面的方法还有很多没有完善的地方,有些方法没有加入到构造函数里面,还有一些缺陷,大家借鉴的时候可以稍作修改。
像这样这么多函数放在一起是非常难看的,如果使用模块化以后,那么面向对象的代码就会变的更加完善,更加的容易维护和修改。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<style type="text/css">
canvas{
margin: 10px auto;
display: block;
box-shadow: 0 0 10px #000;
}
</style>
<script src="http://cdn.bootcss.com/jquery/3.4.0/jquery.js" type="text/javascript" charset="utf-8"></script>
</head>
<body>
<canvas id="canvas" width="800" height="600"></canvas>
</body>
<script type="text/javascript">
$(function(){
/**
* [Draw description] canvas 绘图的构造函数
* @param {[type]} canvas [description]
* */
function Draw(canvas){ //绘图的构造函数
this.canvas = canvas;
/**
* [check description]检测浏览器是否支持canvas
* @return bool false 表示不支持 true 表示支持
* */
this.check = function(){//检测浏览器是否支持canvas
if(!this.canvas.getContext){
return false;//返回false
}
else{
return true;//返回true
}
}
/**
* [main description]canvas 绘图的主函数
* @return {[type]}[description]
* */
this.main = function(){//检测兼容性
if(!this.check()){
console.log('浏览器不支持');//显示浏览器不支持
return false //返回false
}
Draw.prototype.xt = this.canvas.getContext('2d');//用2维样式显示
//......
//绘制蛇的初始图形
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);
}
},150)
}
}
function Rect(x,y,width,height,color){//创建
this.x = x;//x 矩形的起始点x坐标
this.y = y;//y 矩形的起始点y坐标
this.width = width;//width 矩形的宽
this.height = height;//height 矩形的高
this.color = color;//color 矩形的颜色
}
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坐标
var y = this.head.y;//身体的y坐标
for(var i =0;i<3;i++){//循环创建身体
var rect = new Rect(x,y,40,40,'gray');//在身体坐标处创建宽高为40的方块
this.body.push(rect);//把创建出来的方块放入身体
x-=40;//新创建的方块的横坐标往后移动40
}
}
//添加蛇默认的移动方向是向右的,公有的属性,任何的地方能够修改访问,
//并且和实例共享
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(item in this.body){
if(isRectHit(this.head,this.body[item])){
return false;
}
}
//蛇头与墙的碰撞检测
if(this.head.x < 40|| this.head.y < 40 || this.head.x > $('#canvas')[0].width-40-40 || this.head.y > $('#canvas')[0].height-40-40){
return false;
}
//给身体加一个头
var rect = new Rect(this.head.x,this.head.y,40,40,'gray');
//添加到身体开始的地方
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;
}
//添加键盘监听
$(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 randFood(snake){
//是否在蛇身上
isInSnake = true;
//产生两个位置,x,y
while(isInSnake){
var x = getRandPosition(0,($('#canvas')[0].width-40)/40)*40;
var y = getRandPosition(0,($('#canvas')[0].height-40)/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);
}
//判断矩形是否重合
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绘制图像
var rect1= new Rect(0,0,40,40);
var rect2= new Rect(41,0,40,40);
})
</script>
</html>
希望能给大家带来帮助
如有错误请评论指出,将及时修改