html5 MMORPG Game研究 一 精灵
在此之前,建议安装最新版火狐浏览器或者Chrome,编辑器可以Dreamweaver,或者记事本也可以,如果有更专业的编辑则更好,只要具备这些条件,那么一切都已经准好了,我们可以开始神奇的html5之旅了!
首先,我们建立一个基本的html5页面
::: cnblogs_code
对比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