本篇是该系列文章第三篇,其他文章请看下面帖子中的目录
http://blog.csdn.net/lufy_legend/article/details/8441677
进行该类型开发的第一个瓶颈,就是素材了,在此多谢网友yorhomwang提供了大量素材网址。
下面是本次开发的成果,大家先预览一下。
本次找到的素材都是gif类型的图片,想要在游戏里使用,需要将gif图片的每一帧动作取出来组成一张新的图片,我用flash制作了一个简单的转换工具,有需要的朋友请直接拿去用就行了,网址如下。
http://lufylegend.com/flash/demo/GifToPng
可以说,黄老将军已经被我凉在战场上有一段日子了,这些天已经无聊到了极点,拿着刀在战场了发疯似得砍着,跑着,咆哮着......
我是在不忍心看下去了,决心继续写几行代码,给他老人家添点乐趣。
首先,先让战场的地图移动起来,总不能怎么跑都在一个地方吧,定义一个变量。
var back_run = true;
当这个变量为true的时候,战场的背景地图是可以移动的,否则不可移动。
接着在Player.js的move函数里添加控制战场移动的代码,为什么在Player.js里,而不是在Character.js里呢?因为只有主人公黄老将军移动的时候,地图才会移动嘛,Character是父类,待会敌人也会继承自这个类。
Player.prototype.move = function (){
var self = this, mx = 0, my = 0;
if(keyCtrl[KEY.LEFT] && charaLayer.x + self.x > 0){
mx = -1;
}else if(keyCtrl[KEY.RIGHT] && charaLayer.x + self.x < LGlobal.width){
mx = 1;
}
if(keyCtrl[KEY.UP]){
my = -1;
}else if(keyCtrl[KEY.DOWN]){
my = 1;
}
self.mx = mx;
self.my = my;
if(self.action == ACTION.RUN){
mx *= 2;
my *= 2;
}else if(self.action == ACTION.HIT){
mx = 2*(self.direction == DIRECTION.RIGHT ? 1 : -1);
my = 0;
}
if(back_run && mx > 0 && charaLayer.x + self.x > LGlobal.width * 0.5){
var setX = mx*MOVE_STEP;
if(backLayer.data.x + setX + backLayer.data.width > backLayer.data.image.width){
back_run = false;
setX = backLayer.data.image.width - backLayer.data.width - backLayer.data.x;
}
charaLayer.x -= setX;
backLayer.data.setCoordinate(backLayer.data.x + setX,backLayer.data.y);
addEnemy();
}
self.callParent("move",arguments);
};
可以看到,当主人公移动的时候,地图坐标会向相反的方向增减,这样就实现了视觉上的地图移动,注意,里面有一行调用了addEnemy函数,这个函数是检测是否往战场上添加一个敌人。
下面看看怎么来添加一个敌人,我找到了孙尚香的几个素材,这个素材比较全,下面是其中的一张,不一一列出了。
下面增设一个Enemy.js类
function Enemy(list,speed){
var self = this;
base(this,Character,[list,speed]);
self.belong = "enemy";
self.hp = 100;
};
Enemy.prototype.onjump = function (){
var self = this;
self.callParent("onjump",arguments);
self.setLocation();
var index = self.anime.colIndex;
self.yArr = [0,-10,-20,-30,-40,-40,-30,-20,-10,0];
self.anime.y += self.yArr[index];
};
Enemy.prototype.onjump_attack = function (){
var self = this;
self.callParent("onjump_attack",arguments);
self.setLocation();
var index = self.anime.colIndex;
if(index >= self.yArr.length)return;
self.anime.y += self.yArr[index];
};
Enemy.prototype.setAction = function (action,direction){
var self = this,yArr = new Array();
if(action == ACTION.MOVE && self.action == ACTION.JUMP)return;
if(action == ACTION.JUMP_ATTACK){
var index = self.anime.colIndex,i;
for(i = index;i 0){
self.anime.y += self.yArr[0];
}
};
Enemy.prototype.overActionRun = function (lastAction,animeAction){
var self = this;
self.callParent("overActionRun",arguments);
keylock = false;
if(lastAction == ACTION.FALL){
if(self.direction == DIRECTION.LEFT){
self.x += 80;
}else{
self.x -= 80;
}
}
};
Enemy.prototype.move = function (){
var self = this, mx = 0, my = 0;
self.mx = mx;
self.my = my;
self.callParent("move",arguments);
};
这个类和Player.js是类似的,都继承自Character类,只是构造器我不在把每一个相关的数组传进去了,太麻烦了,而是传了一个数组list,里面有需要设定的所有参数。
当添加敌人的addEnemy()函数被调用的时候,我们不可能无限制的添加敌人,所以提前准备好,要添加的敌人,和什么时候添加。
var enemy_list = new Array(
{name:"sunji",x:800,y:350,when_x:300,back_run:false},
{name:"huangzhong",x:1200,y:280,when_x:800,back_run:true}
);
function addEnemy(){
if(enemy_list.length == 0)return;
if(enemy_list[0].when_x > hero.x)return;
var charadata = CharacterList[enemy_list[0].name]();
var enemy = new Enemy(charadata);
enemy.x = enemy_list[0].x;
enemy.y = enemy_list[0].y;
charaLayer.addChild(enemy);
enemy_list.shift();
}
我添加了一个enemy_list数组,它里面包含了什么时候添加敌人的when_x,和敌人出现的位置坐标,还有该人物出现后,地图是否停止移动等信息,当addEnemy函数被调用的时候,就通过when_x和主人公的位置来判断是否需要添加该敌人。
有了敌人,就要有战斗了,下面来说一说攻击与被攻击的判定。
攻击的判定,其实就是碰撞的检测,当然我们可以使用像素级碰撞,但是对于此类游戏来说,就有点大题小做了,而且效率实在太低,所以这里采用矩形碰撞的检测。
lufylegend.js引擎中有LGlobal.hitTest()函数,可以用来检测矩形是否发生碰撞,但是由于图片素材中有很多空白区域,直接采用此方法的话,误差有点太大了,所以我提前为人物的每一帧设定好需要检测的攻击范围和被攻击范围,看下面的CharacterList.js中的代码。
var CharacterList = {
huangzhong:function(){
//图片数据
var dataList = new Array();
dataList.push(new LBitmapData(imglist["player_stand"],0,0,106,77));
dataList.push(new LBitmapData(imglist["player_move"],0,0,115,85));
dataList.push(new LBitmapData(imglist["player_run"],0,0,125,87));
dataList.push(new LBitmapData(imglist["player_jump"],0,0,131,134));
dataList.push(new LBitmapData(imglist["player_attack"],0,0,242,143));
dataList.push(new LBitmapData(imglist["player_big_attack"],0,0,232,143));
dataList.push(new LBitmapData(imglist["player_jump_attack"],0,0,232,143));
dataList.push(new LBitmapData(imglist["player_hit"],0,0,161,88));
dataList.push(new LBitmapData(imglist["player_skill"],0,0,324,140));
dataList.push(new LBitmapData(imglist["player_big_skill"],0,0,441,166));
dataList.push(new LBitmapData(imglist["player_hert"],0,0,179,87));
dataList.push(new LBitmapData(imglist["player_fall"],0,0,298,157));
//图片分割数据
var coordinateList = new Array();
coordinateList.push(LGlobal.divideCoordinate(1272,77,1,12));
coordinateList.push(LGlobal.divideCoordinate(920,85,1,8));
coordinateList.push(LGlobal.divideCoordinate(750,87,1,6));
var jumpList = LGlobal.divideCoordinate(655,134,1,5);
coordinateList.push([[jumpList[0][0],jumpList[0][0],jumpList[0][1],jumpList[0][1],jumpList[0][2],jumpList[0][2],jumpList[0][3],jumpList[0][3],jumpList[0][4],jumpList[0][4]]]);
var attackList = LGlobal.divideCoordinate(484,143,1,2);
coordinateList.push([[attackList[0][0],attackList[0][1],attackList[0][1],attackList[0][1]]]);
var bigattackList = LGlobal.divideCoordinate(927,143,1,4);
coordinateList.push(bigattackList);
var jumpattackList = LGlobal.divideCoordinate(927,143,1,4);
coordinateList.push(jumpattackList);
coordinateList.push(LGlobal.divideCoordinate(966,88,1,6));
coordinateList.push(LGlobal.divideCoordinate(2268,140,1,7));
var bigskillList = LGlobal.divideCoordinate(2205,830,5,5);
coordinateList.push([[bigskillList[0][0],bigskillList[0][1],bigskillList[0][2],bigskillList[0][3],bigskillList[0][4]
,bigskillList[1][0],bigskillList[1][1],bigskillList[1][2],bigskillList[1][3],bigskillList[1][4]
,bigskillList[2][0],bigskillList[2][1],bigskillList[2][2],bigskillList[2][3],bigskillList[2][4]
,bigskillList[3][0],bigskillList[3][1],bigskillList[3][2],bigskillList[3][3],bigskillList[3][4]
,bigskillList[4][0],bigskillList[4][1],bigskillList[4][2],bigskillList[4][3],bigskillList[4][4]]]);
var hertList = LGlobal.divideCoordinate(358,87,1,2);
coordinateList.push([[hertList[0][0],hertList[0][0],hertList[0][1],hertList[0][1]]]);
var fallList = LGlobal.divideCoordinate(2682,157,1,9);
coordinateList.push([[fallList[0][0],fallList[0][1],fallList[0][2],fallList[0][3],fallList[0][4],fallList[0][5],fallList[0][6],fallList[0][6],fallList[0][6],fallList[0][7],fallList[0][7],fallList[0][6],fallList[0][6],fallList[0][7],fallList[0][8]]]);
//图片位置数据
var locationList = new Array();
locationList.push({x:0,y:0});
locationList.push({x:0,y:0});
locationList.push({x:0,y:0});
locationList.push({x:0,y:0});
locationList.push({x:20,y:20});
locationList.push({x:20,y:20});
locationList.push({x:20,y:20});
locationList.push({x:0,y:0});
locationList.push({x:100,y:0});
locationList.push({x:150,y:20});
locationList.push({x:5,y:0});
locationList.push({x:-30,y:10});
//被攻击范围
var hertList = [[[-30,-60,60,50],[-30,-60,60,50],[-30,-60,60,50],[-30,-60,60,50],[-30,-60,60,50],[-30,-60,60,50],[-30,-60,60,50],[-30,-60,60,50],[-30,-60,60,50],[-30,-60,60,50],[-30,-60,60,50],[-30,-60,60,50]],
[[-30,-70,50,60],[-30,-70,50,60],[-30,-70,50,60],[-30,-70,50,60],[-30,-70,50,60],[-30,-70,50,60],[-30,-70,50,60],[-30,-70,50,60]],
[[-30,-70,60,60],[-30,-70,60,60],[-30,-70,60,60],[-30,-70,60,60],[-30,-70,60,60],[-30,-70,60,60]],
[[-25,-70,50,60],[-25,-70,50,60],[-25,-70,50,60],[-25,-70,50,60],[-25,-70,50,60]],
[[-10,-60,30,60],[-10,-60,30,60],[-30,-60,30,60],[-30,-60,30,60]],
[[0,-60,40,60],[0,-60,40,60],[-20,-60,30,60],[-20,-60,30,60]],
[],
[[-20,-60,30,60],[-20,-60,30,60],[-20,-60,30,60],[-20,-60,30,60],[-20,-60,30,60],[-20,-60,30,60]],
[[0,-70,40,60],[0,-70,40,60]],
[],[],[]
];
//攻击范围
var attackList = [[],[],[],[],
[[0,0,0,0],[0,0,0,0],[-10,-70,115,60],[-10,-70,115,60]],
[[0,0,0,0],[0,0,0,0],[-10,-100,140,90],[-10,-100,140,90]],
[[0,0,0,0],[0,0,0,0],[-10,-130,115,60],[-10,-110,140,120]],
[[10,-70,30,70],[10,-70,30,70],[10,-70,30,70],[10,-70,30,70],[10,-70,30,70],[10,-70,30,70]],
[[0,0,0,0],[0,0,0,0],[-40,-70,80,60],[-60,-100,80,60],[20,-100,130,100],[20,-100,130,100]],
[[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0],
[50,-105,50,20],[60,-100,120,40],[60,-90,150,40],[50,-80,190,40],[50,-80,210,40],
[50,-75,310,60],[50,-75,310,60],[50,-75,310,60],[50,-75,310,80]],[],[]
];
return [dataList,coordinateList,locationList,hertList,attackList];
},
sunji:function(){
//图片数据
var dataList = new Array();
dataList.push(new LBitmapData(imglist["sunji_stand"],0,0,129,89));
dataList.push(new LBitmapData(imglist["sunji_move"],0,0,128,97));
dataList.push(new LBitmapData(imglist["sunji_run"],0,0,125,77));
dataList.push(new LBitmapData(imglist["sunji_jump"],0,0,131,134));
dataList.push(new LBitmapData(imglist["sunji_attack"],0,0,197,103));
dataList.push(new LBitmapData(imglist["sunji_big_attack"],0,0,198,103));
dataList.push(new LBitmapData(imglist["sunji_jump_attack"],0,0,182,143));
dataList.push(new LBitmapData(imglist["sunji_hit"],0,0,238,86));
dataList.push(new LBitmapData(imglist["sunji_skill"],0,0,215,102));
dataList.push(new LBitmapData(imglist["sunji_big_skill"],0,0,275,139));
dataList.push(new LBitmapData(imglist["sunji_hert"],0,0,131,79));
dataList.push(new LBitmapData(imglist["sunji_fall"],0,0,249,136));
//图片分割数据
var coordinateList = new Array();
coordinateList.push(LGlobal.divideCoordinate(1548,89,1,12));
coordinateList.push(LGlobal.divideCoordinate(640,97,1,5));
coordinateList.push(LGlobal.divideCoordinate(1000,77,1,8));
var jumpList = LGlobal.divideCoordinate(655,134,1,5);
coordinateList.push([[jumpList[0][0],jumpList[0][0],jumpList[0][1],jumpList[0][1],jumpList[0][2],jumpList[0][2],jumpList[0][3],jumpList[0][3],jumpList[0][4],jumpList[0][4]]]);
var attackList = LGlobal.divideCoordinate(394,103,1,2);
coordinateList.push([[attackList[0][0],attackList[0][1],attackList[0][1],attackList[0][1]]]);
var bigattackList = LGlobal.divideCoordinate(792,103,1,4);
coordinateList.push(bigattackList);
var jumpattackList = LGlobal.divideCoordinate(728,143,1,4);
coordinateList.push(jumpattackList);
coordinateList.push(LGlobal.divideCoordinate(1428,86,1,6));
coordinateList.push(LGlobal.divideCoordinate(2365,102,1,11));
var bigskillList = LGlobal.divideCoordinate(1650,695,5,6);
coordinateList.push([[bigskillList[0][0],bigskillList[0][1],bigskillList[0][2],bigskillList[0][3],bigskillList[0][4],bigskillList[0][5]
,bigskillList[1][0],bigskillList[1][1],bigskillList[1][2],bigskillList[1][3],bigskillList[1][4],bigskillList[1][5]
,bigskillList[2][0],bigskillList[2][1],bigskillList[2][2],bigskillList[2][3],bigskillList[2][4],bigskillList[2][5]
,bigskillList[3][0],bigskillList[3][1],bigskillList[3][2],bigskillList[3][3],bigskillList[3][4],bigskillList[3][5]
,bigskillList[4][0],bigskillList[4][1],bigskillList[4][2],bigskillList[4][3],bigskillList[4][4],bigskillList[4][5]]]);
var hertList = LGlobal.divideCoordinate(262,79,1,2);
coordinateList.push([[hertList[0][0],hertList[0][0],hertList[0][1],hertList[0][1]]]);
var fallList = LGlobal.divideCoordinate(1245,544,4,5);
coordinateList.push([[fallList[0][0],fallList[0][1],fallList[0][2],fallList[0][3],fallList[0][4],fallList[1][0],fallList[1][1],fallList[1][2],fallList[1][3],fallList[1][4],fallList[2][0],fallList[2][1],fallList[2][2],fallList[2][3],fallList[2][4],fallList[3][0],fallList[3][1],fallList[3][2],fallList[3][3],fallList[3][4]]]);
//图片位置数据
var locationList = new Array();
locationList.push({x:0,y:0});
locationList.push({x:0,y:0});
locationList.push({x:0,y:0});
locationList.push({x:0,y:0});
locationList.push({x:40,y:8});
locationList.push({x:20,y:0});
locationList.push({x:20,y:20});
locationList.push({x:0,y:0});
locationList.push({x:0,y:0});
locationList.push({x:70,y:10});
locationList.push({x:5,y:0});
locationList.push({x:-35,y:0});
//被攻击范围
var hertList = [[[-25,-70,60,60],[-25,-70,60,60],[-25,-70,60,60],[-25,-70,60,60],[-25,-70,60,60],[-25,-70,60,60],[-25,-70,60,60],[-25,-70,60,60],[-25,-70,60,60],[-25,-70,60,60],[-25,-70,60,60],[-25,-70,60,60]],
[[-25,-90,50,80],[-25,-90,50,80],[-25,-90,50,80],[-25,-90,50,80],[-25,-90,50,80],[-25,-90,50,80],[-25,-90,50,80],[-25,-90,50,80]],
[[-30,-60,70,40],[-30,-60,70,40],[-30,-60,70,40],[-30,-60,70,40],[-30,-60,70,40],[-30,-60,70,40]],
[[-25,-90,50,70],[-25,-90,50,70],[-25,-90,50,70],[-25,-90,50,70],[-25,-90,50,70]],
[[-20,-80,50,70],[-20,-80,50,70],[-10,-60,70,50],[-10,-60,70,50]],
[[-10,-80,50,60],[-10,-80,50,60],[-10,-80,50,60],[-10,-80,50,60]],
[[-30,-80,50,70],[-30,-80,50,70],[-30,-80,50,70],[-30,-80,50,70]],
[[-20,-70,60,60],[-20,-70,60,60],[-20,-70,60,60],[-20,-70,60,60],[-20,-70,60,60],[-20,-70,60,60]],
[[-10,-80,40,70],[-10,-80,40,70]],
[],[],[]
];
//攻击范围
var attackList = [[],[],[],[],
[[0,0,0,0],[0,0,0,0],[30,-70,75,60],[30,-70,75,60]],
[[0,0,0,0],[0,0,0,0],[20,-100,80,90],[20,-100,80,90]],
[[0,0,0,0],[0,0,0,0],[-10,-90,100,80],[-10,-90,100,80]],
[[10,-70,50,70],[10,-70,50,70],[10,-70,50,70],[10,-70,50,70],[10,-70,50,70],[10,-70,50,70]],
[[0,0,0,0],[0,0,0,0],[-30,-70,90,60],[-90,-70,130,60],[-100,-80,140,70],[-40,-80,140,70]],
[[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,-100,100,40],[0,-110,100,50],[0,-110,100,50],
[0,0,0,0],[20,-120,140,120],[20,-120,130,120],[-50,-120,160,120],[-60,-80,180,80],
[-20,-50,150,60],[-10,-60,150,60],[50,-60,90,60],[50,-75,150,70],[50,-75,150,70],
[50,-75,150,70],[50,-75,150,70]],[],[]
];
return [dataList,coordinateList,locationList,hertList,attackList];
}
}
这样一来,就直接通过这些提前设定好的范围来检测是否碰撞就可以了,这样的矩形碰撞如何检测呢?当然就用到了lufylegend.js引擎中的一个矩形类LRectangle,具体用法请参考官方的Api文档,本次用到的碰撞检测是intersects()函数,这个函数用来检测两个LRectangle对象是否重叠,即是否碰撞。
因为我方和地方都是可以攻击的,所以攻击的检测加载父类Character里,在Character类的onframe函数里添加下面代码。
if(self.action == ACTION.ATTACK || self.action == ACTION.BIG_ATTACK || self.action == ACTION.HIT ||
self.action == ACTION.JUMP_ATTACK || self.action == ACTION.SKILL || self.action == ACTION.BIG_SKILL){
for(key in charaLayer.childList){
chara = charaLayer.childList[key];
if(self.belong == chara.belong)continue;
self.checkAction(chara);
}
}
就是说,当前人物的动作处于攻击等动作的时候,并且是敌人的时候,进入攻击检测checkAction函数,checkAction函数如下。
Character.prototype.checkAction = function (chara){
var self = this;
var attack_rect = self.getAttackRect();
var hert_rect = chara.getHertRect();
if(!attack_rect || !hert_rect)return;
if(attack_rect.intersects(hert_rect) && Math.abs(self.y - chara.y) < 30){
if(self.action == ACTION.ATTACK){
chara.setAction(ACTION.HERT,chara.direction);
}else{
var dir = DIRECTION.RIGHT;
if(self.x < chara.x)dir = DIRECTION.LEFT;
chara.setAction(ACTION.FALL,dir);
}
}
}
getAttackRect函数和getHertRect函数分别返回当前的攻击和被攻击的范围LRectangle对象,然后通过intersects函数判断是否攻击到了对方,如果是普通攻击,则被攻击方变为被攻击状态,其他攻击方式的话,变为摔倒状态。
getAttackRect和getHertRect函数如下。
Character.prototype.getAttackRect = function(){
var self = this;
attackList = self.attackList[self.action];
if(self.anime.colIndex >= attackList.length)return false;
var rect = attackList[self.anime.colIndex];
var x = rect[0],y=rect[1],w=rect[2],h=rect[3];
if(x == 0 && y == 0 && w == 0 && h == 0)return false;
y += self.y;
if(self.direction == DIRECTION.LEFT){
x = self.x - x - w;
}else{
x = self.x +x;
}
return new LRectangle(x,y,w,h);
}
Character.prototype.getHertRect = function(){
var self = this;
var hertList = self.hertList[self.action];
if(self.anime.colIndex >= hertList.length)return false;
var rect = hertList[self.anime.colIndex];
var x = rect[0],y=rect[1],w=rect[2],h=rect[3];
if(x == 0 && y == 0 && w == 0 && h == 0)return false;
y += self.y;
if(self.direction == DIRECTION.LEFT){
x = self.x - x - w;
}else{
x = self.x +x;
}
return new LRectangle(x,y,w,h);
}
好了,剩下的敌人的AI和声效等部分,咱们留着以后再继续。现在,大家可以点击下面的测试连接,看看本次的成果了
http://lufy.netne.net/lufylegend-js/act03/index.html
黄老将军听说即将登场的是孙尚香后激动不已,那叫一个美啊,眼睛整个眯成了一个心形,大吼着,尚香啊,老夫等你几百年了。这是在令我大吃一惊,孙尚香不是刘备老婆吗,是这老家伙的主子啊,这真是太不像话了。可老将军在一旁兴奋的吼着,“靠!我会让你知道我暗恋她几百年吗?老夫绝对不会承认的。”,“如果当年我年轻个几十年,呸,我怎么会这么想,她毕竟是主公的老婆。”,“不对,主公也老了。啊,老夫可是忠臣,我是不会跟主公抢的。”,“老夫什么都没说。lufy,你给我听着,老夫什么都没说。”。我急忙说“啊啊,我什么都没听见啊……”
不过,这有什么用啊,这老家伙一上场,就开始往前跑,边跑边嘟囔“妞,给大爷摸一个……”。由于某种原因,这里省略1000字。
终于,孙尚香出现了,老黄忠一下子就扑了过去,刚伸手去摸了一把,就发现孙尚香被他打的满地跑,立马吼道“lufy,老夫要的是摸,不是砍啊”。
lufy:“哼哼,老色鬼,我岂能给你方便,让你得逞……”,另外他还不知道在前面,还给他准备了另一个黄忠,一个孙尚香,看他们怎么抢吧,哈哈。
唉,真是:
神箭威名数黄忠,斩将杀敌显神通。百年宝刀仍未老,一遇红颜梦成空。
现在给出本次源码下载,喜欢的可以看一下。
http://fsanguo.comoj.com/download.php?i=act03.rar
注意:该附件只包含本次文章源码,lufylegend.js引擎请到http://lufylegend.com/lufylegend进行下载。
转载请注明:转自lufy_legend的博客
欢迎继续关注我的博客
http://blog.csdn.net/lufy_legend