上一篇中我们介绍了关于Canvas的基础知识,用Canvas绘制各种图形和图片,在上一篇的基础上我们来做一个基于HTML5的坦克大战游戏,下面我们开始吧
一、用Canvas画出我们的坦克
我们设计的坦克结构如下图所示,如果有的朋友有更好的设计,希望分享和交流一下。
如上图所示,我们的坦克基本上是由三个矩形和一个圆形一个线段组成,每个部件的尺寸进行了标记,单位为px,下面我们用上一篇中讲到的知识来画出我们的坦克,注意:我们在画坦克的时候应该选择一个参考点,这里我们选择的是坦克的左上角,如图所示。
- <!DOCTYPE html>
- <html>
- <head>
- <meta charset="utf-8"/>
- </head>
- <body>
- <h1>html5-坦克大战</h1>
- <!--坦克大战的战场-->
- <canvas id="tankMap" width="400px" height="300px" style="background-color:black"></canvas>
- <script type="text/javascript">
- //得到画布
- var canvas1 = document.getElementById("tankMap");
- //定义一个位置变量
- var heroX = 80;
- var heroY = 80;
- //得到绘图上下文
- var cxt = canvas1.getContext("2d");
- //设置颜色
- cxt.fillStyle="#BA9658";
- //左边的矩形
- cxt.fillRect(heroX,heroY,5,30);
- //右边的矩形
- cxt.fillRect(heroX+17,heroY,5,30);
- //画中间的矩形
- cxt.fillRect(heroX+6,heroY+5,10,20);
- //画出坦克的盖子
- cxt.fillStyle="#FEF26E";
- cxt.arc(heroX+11,heroY+15,5,0,360,true);
- cxt.fill();
- //画出炮筒
- cxt.strokeStyle="#FEF26E";
- cxt.lineWidth=1.5;
- cxt.beginPath();
- cxt.moveTo(heroX+11,heroY+15);
- cxt.lineTo(heroX+11,heroY);
- cxt.closePath();
- cxt.stroke();
- </script>
- </body>
- </html>
二、怎么让坦克动起来?
在研究怎么让坦克动起来之前,我们先来研究一下怎么让一个小球通过键盘操作使其动起来。
首先我们给<body>标签添加一个监听函数
- <body onkeydown="test()">
- //现在按键盘上ASDW移动小球
- //说明:当我们按下一个键,实际上触发了一个onkeydown事件
- function test(){
- var code = event.keyCode; //键盘上字幕的ASCII码
- switch(code){
- case 87:
- ballY--;
- break;
- case 68:
- ballX++;
- break;
- case 83:
- ballY++;
- break;
- case 65:
- ballX--;
- break;
- }
- //重新绘制
- drawBall();
- }
我们可以在外部定义两个全局的变量分别表示x轴和y轴的坐标,然后通过改变ballX和ballY的值来改变小球的位置,我们用键盘的WDSA键来控制,这样出来的效果非常奇怪,如下图:
我们在绘制的时候没有将以前位置的小球擦除掉,在每次重新绘制前应该先擦除一下,下面将全部代码贴出来:
- <!DOCTYPE html>
- <html>
- <head>
- <meta charset="utf-8"/>
- </head>
- <!--当按键后,去调用test-->
- <body onkeydown="test()">
- <h1>小球上下左右移动</h1>
- <canvas id="test" width="400px" height="300px" style="background-color:black">
- </canvas>
- <script type="text/javascript">
- //得到画布
- var canvas1 = document.getElementById("test");
- //定义一个位置变量
- var ballX = 80;
- var ballY = 80;
- //得到绘图上下文
- var cxt = canvas1.getContext("2d");
- drawBall();
- function drawBall(){
- //画出一个红色的圆球
- cxt.beginPath(); //要注意闭合路径
- cxt.fillStyle="#FF0000";
- cxt.arc(ballX,ballY,10,0,360,true);
- cxt.closePath();
- cxt.fill();
- }
- //现在按键盘上ASDW移动小球
- //说明:当我们按下一个键,实际上触发了一个onkeydown事件
- function test(){
- var code = event.keyCode; //键盘上字幕的ASCII码
- switch(code){
- case 87:
- ballY--;
- break;
- case 68:
- ballX++;
- break;
- case 83:
- ballY++;
- break;
- case 65:
- ballX--;
- break;
- }
- //把画布清理
- cxt.clearRect(0,0,400,300);
- //重新绘制
- drawBall();
- }
- </script>
- </body>
- </html>
我们的坦克如果只是朝一个方向移动的话就非常容易了,只要将上面代码中的画小球改成画坦克就OK了,在让坦克移动之前我们首先应该考虑的是怎么让坦克绕着自己的中心朝各个方向转动的问题。好的,再将上面的图贴出来分析一下。
详细的计算过程我就不啰嗦了,想必大家的数学都很好,按照上图的比例计算好各个组件的坐标和位置,旋转后坦克画法如下:
- //设置颜色
- cxt.fillStyle="#BA9658";
- //上边的矩形
- cxt.fillRect(tank.x-4,tank.y+4,30,5);
- //下边的矩形
- cxt.fillRect(tank.x-4,tank.y+17+4,30,5);
- //画中间的矩形
- cxt.fillRect(tank.x+5-4,tank.y+6+4,20,10);
- //画出坦克的盖子
- cxt.fillStyle="#FEF26E";
- cxt.arc(tank.x+15-4,tank.y+11+4,5,0,360,true);
- cxt.fill();
- //画出炮筒
- cxt.strokeStyle="#FEF26E";
- cxt.lineWidth=1.5;
- cxt.beginPath();
- cxt.moveTo(tank.x+15-4,tank.y+11+4);
- if(tank.direct==1){ //只是炮筒的方向不同
- cxt.lineTo(tank.x+30-4,tank.y+11+4);
- }else{
- cxt.lineTo(tank.x-4,tank.y+11+4);
- }
- cxt.closePath();
- cxt.stroke();
- <!DOCTYPE html>
- <html>
- <head>
- <meta charset="utf-8"/>
- </head>
- <body onkeydown="getCommand();">
- <h1>html5-坦克大战</h1>
- <!--坦克大战的战场-->
- <canvas id="tankMap" width="400px" height="300px" style="background-color:black"></canvas>
- <script type="text/javascript">
- //定义一个Hero类(后面还要改进)
- //x表示坦克的横坐标
- //y表示纵坐标
- //direct表示方向
- function Hero(x,y,direct){
- this.x=x;
- this.y=y;
- this.speed=1;
- this.direct=direct;
- //上移
- this.moveUp=function(){
- this.y-=this.speed;
- this.direct=0;
- }
- //右移
- this.moveRight=function(){
- this.x+=this.speed;
- this.direct=1;
- }
- //下移
- this.moveDown=function(){
- this.y+=this.speed;
- this.direct=2;
- }
- //左移
- this.moveLeft=function(){
- this.x-=this.speed;
- this.direct=3;
- }
- }
- //得到画布
- var canvas1 = document.getElementById("tankMap");
- //得到绘图上下文
- var cxt = canvas1.getContext("2d");
- //我的tank
- //规定0向上、1向右、2向下、3向左
- var hero = new Hero(40,40,0);
- drawTank(hero);
- //绘制坦克
- function drawTank(tank){
- //考虑方向
- switch(tank.direct){
- case 0: //向上
- case 2: //向下
- //设置颜色
- cxt.fillStyle="#BA9658";
- //左边的矩形
- cxt.fillRect(tank.x,tank.y,5,30);
- //右边的矩形
- cxt.fillRect(tank.x+17,tank.y,5,30);
- //画中间的矩形
- cxt.fillRect(tank.x+6,tank.y+5,10,20);
- //画出坦克的盖子
- cxt.fillStyle="#FEF26E";
- cxt.arc(tank.x+11,tank.y+15,5,0,360,true);
- cxt.fill();
- //画出炮筒
- cxt.strokeStyle="#FEF26E";
- cxt.lineWidth=1.5;
- cxt.beginPath();
- cxt.moveTo(tank.x+11,tank.y+15);
- if(tank.direct==0){ //只是炮筒的方向不同
- cxt.lineTo(tank.x+11,tank.y);
- }else{
- cxt.lineTo(tank.x+11,tank.y+30);
- }
- cxt.closePath();
- cxt.stroke();
- break;
- case 1:
- case 3:
- //设置颜色
- cxt.fillStyle="#BA9658";
- //上边的矩形
- cxt.fillRect(tank.x-4,tank.y+4,30,5);
- //下边的矩形
- cxt.fillRect(tank.x-4,tank.y+17+4,30,5);
- //画中间的矩形
- cxt.fillRect(tank.x+5-4,tank.y+6+4,20,10);
- //画出坦克的盖子
- cxt.fillStyle="#FEF26E";
- cxt.arc(tank.x+15-4,tank.y+11+4,5,0,360,true);
- cxt.fill();
- //画出炮筒
- cxt.strokeStyle="#FEF26E";
- cxt.lineWidth=1.5;
- cxt.beginPath();
- cxt.moveTo(tank.x+15-4,tank.y+11+4);
- if(tank.direct==1){ //只是炮筒的方向不同
- cxt.lineTo(tank.x+30-4,tank.y+11+4);
- }else{
- cxt.lineTo(tank.x-4,tank.y+11+4);
- }
- cxt.closePath();
- cxt.stroke();
- break;
- }
- }
- //接收用户按键的函数
- function getCommand(){
- var code = event.keyCode; //键盘上字幕的ASCII码
- switch(code){
- case 87:
- hero.moveUp();
- break;
- case 68:
- hero.moveRight();
- break;
- case 83:
- hero.moveDown();
- break;
- case 65:
- hero.moveLeft();
- break;
- }
- //把画布清理
- cxt.clearRect(0,0,400,300);
- //重新绘制
- drawTank(hero);
- }
- </script>
- </body>
- </html>