html5 Game开发系列文章之 二 精灵(下)

  昨天在家装了IE9,感觉不错,界面终于清爽了,跑HTML5也还不错!期待IE10正式版!

  上一节我简单了介绍了HTML5 canvas 中的 drawImage方法,并绘制了一条扇动翅膀的小红龙,那么,今天我想让小龙在我的控制下飞行起来!

  首先我们再回顾下drawImage的九个参数,第一个参数是绘制对象,可以是图片,也可以是canvas,第二到五个参数是图片的裁剪参数,控制裁剪的位置与大小,第六至九个参数控制绘制到画布的位置与大小!到这里,估计大家都知道该怎么做了,只要更改图片在画面的位置就可以让小红龙“飞行”起来了!

  不过先别急,在这处理这个过程前,还有涉及到一个方向的问题,在2D游戏中,一般主流有四个方向或者八个方向两种(横版的是二个方向的,最近也比较流行),我这里将以八个方向为例,演示如何控制小红龙的飞行!

  为了方便控制,我先定义一个枚举对象,嗯,不过JS中不存在枚举对象,没关系,JS是一种十分自由的语言,我发现我越来越喜欢它了,我定义一个对象字面量!

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="1.jpg";

 

  

  GetDistance, GetDirection这两个方法其实我是直接从深蓝的博客中的copy过来的,有兴趣的朋友可以去看下他写的Silverlight游戏开发系列教程,写得非常好,地址是:http://www.cnblogs.com/alamiye010

  其实HTML5除了安全性能上面外,有一些效果处理起来还是相当方便的!大家玩魔兽时,对山丘之王的天神下凡应该都有印象,小矮人大吼一声,身子迅速变大,威风凛凛,其实用HTML5来做的话,非常简单的,其实就是图片缩放效果而已!

  不废话,直接上代码:

var ctx = document.getElementById("scene").getContext("2d");
var index=0;
var img = new Image();
var size = 1;
var timer;
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,0 ,75,70,20,20,parseInt(75*size),parseInt(70*size));
},50);
}
function BieShen(){
size = 1;
timer=setInterval(function(){
size+=0.1;//设定每次增大10%
if(size>2){
size=2;
clearInterval(timer);
}
},50);
}
img.src="1.jpg";

 

  到这里,一个基本的精灵就已经出现了!不过如果用来做游戏的话,这样零散的代码是很痛苦的,下一节,我将介绍如果封装这些代码!

  本节代码源码下载地址https://files.cnblogs.com/hnvvv/html5_Game_L1_2.zip (注:变身效果也在里面,图片是直接以base64的字符串直接保存在HTML中,下载后直接用火狐,Chrome,IE9都可以运行)

  演示地址http://www.jiniannet.com/html5/ (注:里面的代码比文章里面的要新一些,已经完成了基本的精灵,地图等,会不定时修改,每篇文章的源代码直接在文章后附出,不单独出现在演示地址中)

  目录地址http://www.cnblogs.com/hnvvv/archive/2012/01/09/2317336.html

  

  欢迎大家回复你的意见,比如哪些东西需要详细介绍,哪些东西可以简写,代码有更好的实现方法等等,我会一一改进的!

posted @ 2012-01-14 09:45  翅膀的初衷  阅读(1602)  评论(6编辑  收藏  举报