html画布制作贪吃蛇小游戏

来源:互联网 发布:linux 目录别名 编辑:程序博客网 时间:2024/04/30 15:01

最终效果:


做贪吃蛇游戏需要Html5,部分Css美化,重要的是JavaScript的应用,因为我们主要是运用Html5的Canvas标签来打造游戏的,所以还是在JavaScript上的笔墨较多

首先搭建好框架:


<!DOCTYPE html><html><head><title>snake</title><style type="text/css">#canvas_frame{height:500px;width:500px;margin:auto;background:#444;border-radius:8px;box-shadow:0px 0px 15px #000;}canvas{background:#21F;margin:25px 25px;}#start_button{height:40px;width:150px;border:0px;background:#000;color:white;line-height:40px;font-size:15px;}</style></head><body><div id="canvas_frame"><canvas id="mycanvas" width="450" height="450"></canvas></div><section style="height:40px;width:100%;text-align:center;"><button id="start_button" onclick="moveSnake();">start</button></section><script type="text/javascript">/*javascript代码区*/</script></body></html>

然后在javascript代码区创建画布Dom对象:

var canvas = document.getElementById('mycanvas');var ctx = canvas.getContext('2d');

创建蛇对象:

var snake = {head : { x : 15 * 3, y : 0 },body : [{ x : 15 * 2, y : 0 },{ x : 15 * 1, y : 0 },{ x : 0, y : 0 }],speed : 100,direction: "right",};

注意点:蛇对象中的body是一个数组,数组内的元素是代表蛇每个节在画布上的X坐标和Y坐标,snake.body[0]为最靠近head的节,依此类推。。


描绘蛇:

function drawSnake(){ctx.clearRect( 0, 0, 450, 450 );var headImg = new Image();var headSrc = "./snake_head_min_" + snake.direction +".png";/*存贮蛇图片的位置,用于动态改变head的图片位置*/headImg.src= headSrc;ctx.drawImage(headImg, snake.head.x, snake.head.y );for( var i = 0; i <= snake.body.length - 1; i++){var cell = new Image();cell.src = "./snake_body_min.png";ctx.drawImage(cell, snake.body[i].x, snake.body[i].y );}}

注意点:

1.每次描绘蛇之前都需要将原有的图画清空------ ctx.clearRect( 0, 0, 450, 450);  clearRect()用法详见:HTML5 canvas clearRect() 方法;

2.这里我采用的不是填充矩形的方法来实现画蛇,而是采用描绘图像的方法: 用法详见:HTML 5 <canvas> 标签

1)创建图像:var Img = new Image();

2)图像位置:Img.src="./img.png";

3)开始描绘:ctx.drawImage( Img, 0, 0);后两个参数表示的是描绘图片的x坐标的y坐标;

在这里我采用了自己制作的图片,注意要调整图片的大小(为展示,此处显示大图):

             

body head

因为蛇头有方向:所以对于head我们有四张图片:



创建食物对象:

var food = {x : 300,y : 150,};


x , y 代表食物在画布的x坐标和y位置。


描绘食物:

function drawFood(){if(IsEat()){food.x = parseInt(Math.random() * 28) * 15;food.y = parseInt(Math.random() * 28) * 15;}var foodImg = new Image();foodImg.src="./apple_min.png";ctx.drawImage(foodImg, food.x, food.y );}

注意点:

1.关于获取随机数:Math.random();该函数返回一个区间为(0, 1 )的随机数;

2.此处我们将随机数乘以28以放大随机数的区间为(0, 28 ),总共的格子数为30 * 30 个 即450 / 15 = 30;

3.我们将其随机数的区间转化为整数:即1,2,3,4,。。。,27,

4.当food 被蛇吃的时候(snake.head的坐标与食物的坐标相同的时候),我们要随机在生成新的食物坐标,此处不考虑食物生成的坐标与蛇的身体有相同(食物生成在了蛇的body上)


判断食物是否被吃:

function IsEat(){if( snake.head.x == food.x && snake.head.y == food.y){snake.body[snake.body.length] = { x : 0, y : 0};return 1;}return 0;}

注意点:

1.此处用了if判断语句,且判断的表达式需满足 蛇的头的坐标与食物的坐标相同(x坐标和y坐标);

2.为了在描绘食物的方法(drawFood();)里更好的判断,我们设置返回值 1 代表被吃,0代表未被吃;

3.食物被吃之后应该生成一个新的节(此处默认生成的节懂得x坐标和y坐标都为0(这个不要紧)在蛇移动的时候会自动改变该值)

snake.body[snake.body.length] = { x : 0, y : 0};


开始重头大戏----移动蛇:

首先移动蛇我们需要的是:不断地描绘图像,并且不断的更新蛇的头的身体各节的坐标:

代码上:

function moveSnake(){for( var i = snake.body.length - 1; i > 0 ; i-- ){snake.body[i].x = snake.body[i - 1].x;snake.body[i].y = snake.body[i - 1].y;}snake.body[0].x = snake.head.x;snake.body[0].y = snake.head.y;switch( snake.direction ){case "right":{snake.head.x = snake.head.x + 15;break;} case "left":{snake.head.x = snake.head.x - 15;break;}case "up":{snake.head.y = snake.head.y - 15;break;}case "down":{snake.head.y = snake.head.y + 15;break;}}drawSnake();drawFood();IsGameover();setTimeout( 'moveSnake()', snake.speed );}

注意点:

1.为了达到更新蛇的头和蛇的身体各节坐标的目标,我们的想法应该是:较后的节继承较前的节的坐标;所以就有for循环:

for( var i = snake.body.length - 1; i > 0 ; i-- ){snake.body[i].x = snake.body[i - 1].x;snake.body[i].y = snake.body[i - 1].y;}snake.body[0].x = snake.head.x;snake.body[0].y = snake.head.y;
最靠近头的节将继承头的坐标。

2.针对头的坐标更新我们根据蛇的方向(snake.direction)来进行判断:

switch( snake.direction ){}

3.在移动蛇的时候,我们需要不断的画蛇,不断的画食物,不断的判断是否结束游戏,并且我们需要不断的调用自己这个函数;

更新时间我们用setTimeout();用法详见:HTML DOM setTimeout() 方法


判断GameOver:

判断游戏结束有两个标准:

1.碰壁,游戏结束

2.吃着自己,游戏结束


代码上:

function IsGameover(){if(snake.head.x == game.width && snake.direction == 'right'){alert("GameOver!");}if(snake.head.x == -15 && snake.direction == 'left'){alert("GameOver!");}if(snake.head.y == game.height  && snake.direction == 'down'){alert("GameOver!");}if(snake.head.y == -15 && snake.direction == 'up'){alert("GameOver!");}for( var i = 0; i < snake.body.length; i++ ){if( snake.head.x == snake.body[i].x && snake.head.y == snake.body[i].y){alert("GameOver!");}}}

注意点:

1.四个if判断语句用于判断碰壁:!!满足条件为 坐标 和 蛇的移动方向(例如 蛇的head的x坐标为0,方向向上  =》 碰壁)

2.for循环语句:对每个body的节判断其坐标是否与head的坐标重合(重合即代表 蛇头吃到自己的身体了)


监听键盘输入:

document.onkeydown = function(e){var code = e.keyCode;switch(code){case 38:{if( snake.direction != 'down'){snake.direction='up';}break;}case 39:{if( snake.direction != 'left'){snake.direction='right';}break;}case 40:{if( snake.direction != 'up'){snake.direction='down';}break;}case 37:{if( snake.direction != 'right'){snake.direction='left';}break;}default:break;}}

注意点:

1.html Dom document对象的onkeydown事件后的函数需要引入参数(e)

2.对该事件(event)的键盘值(keyCode)进行判断然后改变蛇的方向--snake.direction;


该游戏的制作就完成了,当然我们也可以把它可以做的更好。


最后上完整代码:

<!DOCTYPE html><html><head><title>snake</title><style type="text/css">#canvas_frame{height:500px;width:500px;margin:auto;background:#444;border-radius:8px;box-shadow:0px 0px 15px #000;}canvas{background:#21F;margin:25px 25px;}#start_button{height:40px;width:150px;border:0px;background:#000;color:white;line-height:40px;font-size:15px;}</style></head><body><div id="canvas_frame"><canvas id="mycanvas" width="450" height="450"></canvas></div><section style="height:40px;width:100%;text-align:center;"><button id="start_button" onclick = "moveSnake();">start</button></section><script type="text/javascript">var canvas = document.getElementById('mycanvas');var ctx = canvas.getContext('2d');/*//画格子 ctx.strokeStyle = 'white';for( var i = 1; i <= 30; i++ ){ctx.beginPath();ctx.moveTo( 15 * i, 0 );ctx.lineTo( 15 * i, 450 );ctx.closePath();ctx.stroke();}for( var i = 1; i <= 30; i++ ){ctx.beginPath();ctx.moveTo( 0, 15 * i );ctx.lineTo( 450, 15 * i );ctx.closePath();ctx.stroke();}*///创建游戏对象var game = {width : 450,height : 450,};//创建一条蛇var snake = {head : { x : 15 * 3, y : 0 },body : [{ x : 15 * 2, y : 0 },{ x : 15 * 1, y : 0 },{ x : 0, y : 0 }],length : 4,speed : 100,direction: "right",};//创建食物var food = {x : 300,y : 150,color : "green",};//描绘蛇function drawSnake(){ctx.clearRect( 0, 0, 450, 450 );var headImg = new Image();var headSrc = "./snake_head_min_" + snake.direction +".png";headImg.src= headSrc;ctx.drawImage(headImg, snake.head.x, snake.head.y );for( var i = 0; i <= snake.body.length - 1; i++){var cell = new Image();cell.src = "./snake_body_min.png";ctx.drawImage(cell, snake.body[i].x, snake.body[i].y );}}//描绘食物function drawFood(){if(IsEat()){food.x = parseInt(Math.random() * 28) * 15;food.y = parseInt(Math.random() * 28) * 15;}var foodImg = new Image();foodImg.src="./apple_min.png";ctx.drawImage(foodImg, food.x, food.y );}//移动蛇function moveSnake(){for( var i = snake.body.length - 1; i > 0 ; i-- ){snake.body[i].x = snake.body[i - 1].x;snake.body[i].y = snake.body[i - 1].y;}snake.body[0].x = snake.head.x;snake.body[0].y = snake.head.y;switch( snake.direction ){case "right":{snake.head.x = snake.head.x + 15;break;} case "left":{snake.head.x = snake.head.x - 15;break;}case "up":{snake.head.y = snake.head.y - 15;break;}case "down":{snake.head.y = snake.head.y + 15;break;}}drawSnake();drawFood();IsGameover();setTimeout( 'moveSnake()', snake.speed );}//判断游戏结束function IsGameover(){if(snake.head.x == game.width && snake.direction == 'right'){alert("GameOver!");}if(snake.head.x == -15 && snake.direction == 'left'){alert("GameOver!");}if(snake.head.y == game.height  && snake.direction == 'down'){alert("GameOver!");}if(snake.head.y == -15 && snake.direction == 'up'){alert("GameOver!");}for( var i = 0; i < snake.body.length; i++ ){if( snake.head.x == snake.body[i].x && snake.head.y == snake.body[i].y){alert("GameOver!");}}}//监听键盘输入document.onkeydown = function(e){var code = e.keyCode;switch(code){case 38:{if( snake.direction != 'down'){snake.direction='up';}break;}case 39:{if( snake.direction != 'left'){snake.direction='right';}break;}case 40:{if( snake.direction != 'up'){snake.direction='down';}break;}case 37:{if( snake.direction != 'right'){snake.direction='left';}break;}default:break;}}//判断是否吃了食物function IsEat(){if( snake.head.x == food.x && snake.head.y == food.y){snake.body[snake.body.length] = { x : 0, y : 0};return 1;}return 0;}</script></body></html>


图片资源:

     

本文中的超链接指向W3school