在此之前,建议安装最新版火狐浏览器或者Chrome,编辑器可以Dreamweaver,或者记事本也可以,如果有更专业的编辑则更好,只要具备这些条件,那么一切都已经准好了,我们可以开始神奇的html5之旅了!
首先,我们建立一个基本的html5页面
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>DEMO</title></head> <body> <canvas id="scene" width="800" height="600"></canvas> </body> </html>
对比XHTML,它的头部申明变短了,不需要加入那长长的一串URL地址了,而且meta标签的申明也简化了!这 里我们就建立了一个基本的html5页面,使用UTF-8编码!而且我们还使用了一个canvas标签!html5通过canvas提供了相关图形处理接 口,我们通过它就可以处理各种各样的图形了,在canvas中我们可以绘制各种图形,比如矩形,圆行,直线,曲线等,同时出可以绘制各种现有图片!
下面的例子,我将在canvas(下称为画布)上绘制一张小图片(精灵)(在这里,我假定大家已经知道了帧与Sprite(精灵)的概念!如果对这两个概念不了解的自行查询)!
var ctx = document.getElementById("scene").getContext("2d"); var img = new Image(); img.onload=function(){ ctx.drawImage(img,0,0,75,70,0,0,75,70); } img.src="dragon.gif";显示结果:
我们成功在画布上画出一个精灵,第一行通行getContext("2d")获得了一个CanvasRenderingContext2D对 象,然后创建了一个Image对象,并在Image加载完成的事件中,使用drawImage方法将我们的精灵绘制到了画布上!
看起来很简单,好像也没有什么激动人心的,是的,只是一张小小的图片,不过一切复杂的事物不都是加简单的东西组成的吗?我们先来看一下drawImage方法的相关参数:
drawImage有多个参数的重载!最多为九个,下面以以九个参数为例解释下各个参数的作用:drawImage(image,sx,sy,sw,sh,dx,dy,dw,dh)
参数 |
参数 |
说明 |
参数1 |
image |
图片 |
参数2 |
sx |
图片裁剪的X位置 |
参数3 |
sy |
图片裁剪的Y位置 |
参数4 |
sw |
裁剪的宽度 |
参数5 |
sh |
裁剪的高度 |
参数6 |
dx |
画布的X位置 |
参数7 |
dy |
画布的Y位置 |
参数8 |
dw |
绘制到画布上的宽 |
参数9 |
dh |
绘制到画布上的高 |
所有方法如下:
void drawImage(in HTMLImageElement image, in float dx, in float dy, optional in float dw, in float dh); void drawImage(in HTMLImageElement image, in float sx, in float sy, in float sw, in float sh, in float dx, in float dy, in float dw, in float dh); void drawImage(in HTMLCanvasElement image, in float dx, in float dy, optional in float dw, in float dh); void drawImage(in HTMLCanvasElement image, in float sx, in float sy, in float sw, in float sh, in float dx, in float dy, in float dw, in float dh); void drawImage(in HTMLVideoElement image, in float dx, in float dy, optional in float dw, in float dh); void drawImage(in HTMLVideoElement image, in float sx, in float sy, in float sw, in float sh, in float dx, in float dy, in float dw, in float dh);
利用CanvasRenderingContext2D对象还可以进行像素级的操作,这个我将会在后期讲到,目前只要利用drawImage方法就可以做出很多有趣的东西来了!
下面我们来做一个会动的精灵!其实每个动画,都是由一张一张的图片(帧)快速切换而得到的!下面,我们将利用这个原理,每隔一定时间,从下面的图片上截取一张小图片绘制到画布上,形成动画,让小红龙扇动翅膀!
首先要用到一张大图:
var ctx = document.getElementById("scene").getContext("2d"); var img = new Image(); var x =0; img.onload=function(){ setInterval(function(){ if(x>=9){ x=0; }else{ x++; } ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height); ctx.drawImage(img,x * 75,0,75,70,n,0,75,70); },50) }
img.src="dragon.gif";
在这里,使用了定时器,每隔50毫秒就会在图片截取一张75 * 70像素大小的小图并绘制出来,且每次向右移75像素,直到到最右端时重新从0开始,不停循环!小红龙就开始不停扇动翅膀了!
好,翅膀开始扇动起来,我们的小红龙也要展翅高翔了,下面,我就让小红龙在我们的控制下开始飞行!
drawImage方法的九个参数中,第一个参数是绘制对象,可以是图片,也可以是canvas,第二到五个参数是图片的裁剪参数,控制裁剪的位置与大小,第六 至九个参数控制绘制到画布的位置与大小!我们只要更改图片在画面的位置就可以让小红龙“飞行”起来了!即动态更改第6,第7个数值即可!
不过先别急,在这处理这个过程前,还有涉及到一个方向的问题,在2D游戏中,一般主流有四个方向或者八个方向两种(横版的是二个方向的,最近也比较流行),我这里将以八个方向为例,演示如何控制小红龙的飞行!
为了方便控制,我先定义一个对象字面量!
var Directions={
North:6,
NorthEast:7,
East:0,
SouthEast:1,
South:2,
SouthWest:3,
West:4,
NorthWest:5
};
我在这里用0-7 来代表东南西北等八个方向!这里哪个方向代表哪个数字是有一定规律的,细心的朋友可能发现了,在素材图中,每一行均代表了一个方向!Directions 中每个方向的值对应每行的索引值,比如第一行,红龙的朝向为东,则Directions.East=0,第二行为东南,则 Directions.SouthEast=1,依此类推!
然后定义一个对象来保存精灵的当前位置,一个对象来保存精灵当前朝向!
var currentPoint = {"X":0,"Y":0};
var direction=0;
然后可以通过onclick事件来处理精灵的移动!另外,我通过canvas的onmousemove事件来获取当前的鼠标点击坐标,完整代码如下
var ctx = document.getElementById("scene").getContext("2d"); var ctxW = document.getElementById("scene").width;//画布宽 var ctxH = document.getElementById("scene").height;//画面高 var currentPoint = {"X":0,"Y":0};//精灵当前位置 var mousePoint = {"X":0,"Y":0};//鼠标相对位置 var direction=0;//当前朝向 var Directions={ North:6, NorthEast:7, East:0, SouthEast:1, South:2, SouthWest:3, West:4, NorthWest:5 }; var timer;//定时器 //获取鼠标相对坐标 document.getElementById("scene").onmousemove=function(e){ e = e || window.event; if(e.pageX || e.pageY){ mousePoint.X=parseInt(e.pageX); mousePoint.Y = parseInt(e.pageY); }else{ mousePoint.X=parseInt(e.clientX + document.body.scrollLeft - document.body.clientLeft); mousePoint.Y=parseInt(e.clientY + document.body.scrollTop - document.body.clientTop); } var boundingClient=document.getElementById("scene").getBoundingClientRect(); mousePoint.X-=parseInt(boundingClient.left+document.documentElement.scrollLeft); mousePoint.Y-=parseInt(boundingClient.top+document.documentElement.scrollTop); }; //获取两个坐标点的距离 function GetDistance(x,y){ return Math.sqrt(Math.pow((x.X - y.X), 2) + Math.pow((x.Y - y.Y), 2)); }; //获取精灵朝向 function GetDirection(current,target){ var n = (target.Y - current.Y) / (target.X - current.X); if (Math.abs(n) >= Math.tan(Math.PI * 3 / 8) && target.Y <= current.Y) { return Directions.North; } else if (Math.abs(n) > Math.tan(Math.PI / 8) && Math.abs(n) < Math.tan(Math.PI * 3 / 8) && target.X > current.X && target.Y < current.Y) { return Directions.NorthEast; } else if (Math.abs(n) <= Math.tan(Math.PI / 8) && target.X >= current.X) { return Directions.East; } else if (Math.abs(n) > Math.tan(Math.PI / 8) && Math.abs(n) < Math.tan(Math.PI * 3 / 8) && target.X > current.X && target.Y > current.Y) { return Directions.SouthEast; } else if (Math.abs(n) >= Math.tan(Math.PI * 3 / 8) && target.Y >= current.Y) { return Directions.South; } else if (Math.abs(n) > Math.tan(Math.PI / 8) && Math.abs(n) < Math.tan(Math.PI * 3 / 8) && target.X < current.X && target.Y > current.Y) { return Directions.SouthWest; } else if (Math.abs(n) <= Math.tan(Math.PI / 8) && target.X <= current.X) { return Directions.West; } else if (Math.abs(n) > Math.tan(Math.PI / 8) && Math.abs(n) < Math.tan(Math.PI * 3 / 8) && target.X < current.X && target.Y < current.Y) { return Directions.NorthWest; } else { return 0; } }; //判断精灵是否到达指定坐标 function RatherPoint(p1,p2){ switch(direction){ case Directions.North: return p1.Y<=p2.Y; case Directions.NorthEast: return p1.X>=p2.X||p1.Y<=p2.Y; case Directions.East: return p1.X>=p2.X; case Directions.SouthEast: return p1.X>=p2.X||p1.Y>=p2.Y; case Directions.South: return p1.Y>=p2.Y; case Directions.SouthWest: return p1.X<=p2.X||p1.Y>=p2.Y; case Directions.West: return p1.X<=p2.X; case Directions.NorthWest: return p1.X<=p2.X || p1.Y<=p2.Y; }; return true; }; //获取每次移动步长 function GetMovePoint(toPoint){ var m=0,n=0,t=1; var speed=10;//移动速度 switch(direction){ case Directions.North: m=0; n=-speed; break; case Directions.NorthEast: t = GetDistance(currentPoint,toPoint); m=speed * (toPoint.X-currentPoint.X)/t; n=-speed * (currentPoint.Y - toPoint.Y)/t; break; case Directions.East: m=speed; n=0; break; case Directions.SouthEast://alert("Directions.SouthEast"+toPoint.X); t = GetDistance(currentPoint,toPoint);//alert(t); m=speed * (toPoint.X-currentPoint.X)/t; n=speed * (toPoint.Y-currentPoint.Y)/t; break; case Directions.South: m=0; n=speed; break; case Directions.SouthWest: t = GetDistance(currentPoint,toPoint); m=-speed * (currentPoint.X-toPoint.X)/t; n=speed * (toPoint.Y-currentPoint.Y)/t; break; case Directions.West: m=-speed; n=0; break; case Directions.NorthWest: t = GetDistance(currentPoint,toPoint); m=-speed * (currentPoint.X-toPoint.X)/t; n=-speed * (currentPoint.Y-toPoint.Y)/t; break; }; return {"X":m,"Y":n}; } //鼠标点击事件 document.getElementById("scene").onclick=function(){ clearInterval(timer);//清除定时器 var tp = {"X":mousePoint.X,"Y":mousePoint.Y};//鼠标点击坐标,引用值不能直接用mousePoint,不然当鼠标在点击后移动时,目的坐标会变更 direction = GetDirection(currentPoint,tp);//设置精灵朝向 var movePoint = GetMovePoint(tp);//获取移动步长 timer=setInterval(function(){//判断是否到达目标 if(!RatherPoint(currentPoint,tp)){ currentPoint.X+=movePoint.X; currentPoint.Y+=movePoint.Y; //碰撞检测 if(currentPoint.X>ctxW){ currentPoint=ctxW; clearInterval(timer); } if(currentPoint.X<0){ currentPoint=0; clearInterval(timer); } if(currentPoint.Y>ctxH){ currentPoint=ctxH; clearInterval(timer); } if(currentPoint.Y<0){ currentPoint=0; clearInterval(timer); } }else{ clearInterval(timer); } },100); } var index=0; var img = new Image(); img.onload=function(){ setInterval(function(){ if(index>=9){ index=0; }else{ index++; } ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height); ctx.drawImage(img,index * 75,direction * 70 ,75,70,currentPoint.X,currentPoint.Y,75,70); },50); } img.src="dragon.gif";
GetDistance, GetDirection这两个方法参考了深蓝的右手的相关博文,有兴趣的朋友可以去看下他写的Silverlight游戏开发系列教程,地址是:http://www.cnblogs.com/alamiye010
演示地址:http://www.jiniannet.com/html5
本文同步发表于博客园
原创作品,转载请注明作者:翅膀的初衷 出自:http://www.jiniannet.com
注:原域名iis0已弃用,启用新域名www.jiniannet.com