射击
你可以用很多方法杀死敌人。你可以通过刀剑、枪或者其他的东西。让我们来看看我们怎样向敌人射击(使用shift键射击)。
当我说到“子弹”的时候,我的意思是那些从英雄处飞出来的、看起来要去杀死敌人的东西。它可以是球、箭头、冰激凌、企鹅等等。
首先,我们还是应该考虑一下,射击应该是怎样的过程,子弹是怎样运动。一旦shift键被按下,首先,子弹对象、子弹剪辑被创建,子弹剪辑的位置应该是英雄所在的位置。而且子弹应该朝英雄面对的方向运动。如果子弹遇到墙或者敌人,它应该自动消失。如果它碰到的是敌人,那么敌人也要消失。
子弹的速度应当比英雄的速度大,除非你准备让英雄可以用某种方式阻挡飞行的子弹。通常那些傻乎乎的敌人不会看到飞行的子弹,但是你也可以创建会躲避子弹的敌人。你也可以做一些能朝英雄射击的敌人。
准备射击
画一个子弹的mc,然后做一个linkage,ID是bullet,以便用AS复制到舞台中。子弹MC中的图像应该居中对齐。
让我们声明一下子弹对象:
game.Bullet= function () {}; game.Bullet.prototype.speed=5; game.Bullet.prototype.dirx=0; game.Bullet.prototype.diry=-1; game.Bullet.prototype.width=2; game.Bullet.prototype.height=2;
子弹每步移动的距离是5,高度和宽度都是2象素,这已经足够杀死敌人了。
dirx/diry属性确定了子弹移动的方向。实际上我们还是通过moveChar函数移动子弹。如果dirx=1,子弹向右移动,diry=-1则向上移动。我可以从英雄(或敌人)对象中得到方向参数,设定dirx/diry的值,但是在游戏刚开始的时候,英雄还没有移动,这时候玩家如果要射击,就用上面这个默认的方向(dirx=0,diry=-1,朝上移动)。
给game对象添加两个新的属性:
game={tileW:30, tileH:30, currentMap:1, bulletcounter:0}; game.bullets= new Array();
bulletcounter属性用来记录子弹的数目,以便我们给新产生的子弹取不重复的名称。游戏里第一发子弹名称是bullet0,然后是bullet1、bullet2……最多是bullet100,接下来返回到bullet0。我们可以让数目无限增长,但是谁也不能保证到最后会发生什么。
game.bullets数组用来放置舞台上的子弹对象。一开始的时候它是一个空的数组。
然后给角色对象加上一个shootspeed属性,设置每次发弹的最小时间间隔:
char={xtile:2, ytile:1, speed:4, shootspeed:1000};
更高的shootspeed值代表更长的间隔、更慢的射击速度,单位是毫秒。
敌人死亡后,我们还要把他们从game对象中删除。改变buildMap函数的创建敌人的部分:
game.currentEnemies = []; for (var i = 0; i<enemies.length; ++i) { var name = "enemy"+i; game[name]= new game["Enemy"+enemies[i][0]]; game[name].id=i; game.currentEnemies.push(game[name]);
然后在enemyBrain函数中,把这句:
var name = "enemy"+i; 换成 :var name = "enemy"+game.currentEnemies[i].id;
我通过currentEnemies数组来放置舞台上活动的敌人。一旦敌人被杀死,我们就会把它从currentEnemies数组中删除。新的属性“id”帮助我们找到敌人在enemies数组中的位置。
在detectKeys函数检查完按键后添加代码:
if (Key.isDown(Key.SHIFT) and getTimer()>ob.lastshot+ob.shootspeed) { _root.shoot(ob); }
如果SHIFT键被按下,而且时间间隔足够长,调用shoot函数。
在moveChar函数的开头添加两行代码,用来保存当前对象的方向:
ob.dirx=dirx; ob.diry=diry;
我们可以用这个来指定子弹运行的方向。
开枪
为了成功的让子弹按照我们预定的想法飞行,我们要写一个新的函数shoot:
function shoot (ob) { ob.lastshot=getTimer(); game.bulletcounter++; if (game.bulletcounter>100) { game.bulletcounter=0; } var name = "bullet"+game.bulletcounter; game[name]= new game.Bullet; game[name].id=game.bulletcounter; game.bullets.push(game[name]); if (ob.dirx or ob.diry) { game[name].dirx= ob.dirx; game[name].diry= ob.diry; } game[name].xtile= ob.xtile; game[name].ytile= ob.ytile; game.clip.attachMovie("bullet", name, 10100+game.bulletcounter); game[name].clip=game.clip[name]; game[name].x = (ob.x+game[name].dirx*ob.width); game[name].y = (ob.y+game[name].diry*ob.height); game.clip[name]._x = game[name].x; game.clip[name]._y = game[name].y; }
首先我们传递了一个obj对象给函数。如果开枪的是英雄,这个obj就是英雄;如果是敌人射击,obj就是敌人对象。
我们通过getTimer()函数把当前的时间保存到lastshot属性中。
接着给game.bulletcounter属性增加1,如果它大于100,我们就让他回到0。
现在用bulletcounter产生一个新的子弹名字,创建一个子弹对象,然后把这个数字存到该对象中,把这个对象的地址放入game.bullets数组中。
下面的if判断用来检测角色对象是否移动过(dirx/diry有值),如果是,则把这两个方向属性传递给新建的子弹对象。否则子弹会有默认的运行方向。
为了让子弹从角色处出现,我们把角色的xtile和ytile属性复制给子弹对象。
代码的最后部分创建了新的子弹剪辑,计算坐标,最后显示到该位置。有趣的地方在于如何计算子弹的象素坐标:
game[name].x = (ob.x+game[name].dirx*ob.width);
首先我们得到角色的位置(ob.x),这是角色的中心坐标。通常子弹并不是从角色的正中心发出,我们给他加上了角色的宽度。这个地方的巧妙之处在于乘了子弹的dirx属性,dirx取-1,0,1都能适合。当dirx为0的时候,子弹的x坐标就是角色的中心,不过这时候子弹是竖直运动的,出现在角色的正上方或正下方。
杀死敌人!
在detectKeys函数的结尾添加一行,调用一个新的函数来移动子弹,并且检查是不是打到了什么东西。
_root.moveBullets();
moveBullets函数:
function moveBullets () { for (var i = 0; i<game.bullets.length; ++i) { var ob=game.bullets[i]; getMyCorners (ob.x+ob.speed*ob.dirx, ob.y+ob.speed*ob.diry, ob); if (ob.downleft and ob.upleft and ob.downright and ob.upright) { moveChar(ob, ob.dirx, ob.diry); } else { ob.clip.removeMovieClip(); delete game["bullet"+game.bullets[i].id]; game.bullets.splice(i,1); } for (var j = 0; j<game.currentEnemies.length; ++j) { var name = "enemy"+game.currentEnemies[j].id; var obenemy = game[name]; var xdist = ob.x - obenemy.x; var ydist = ob.y - obenemy.y; if (Math.sqrt(xdist*xdist+ydist*ydist) < ob.width+obenemy.width) { obenemy.clip.removeMovieClip(); delete game["enemy"+game.currentEnemies[j].id]; game.currentEnemies.splice(j,1); ob.clip.removeMovieClip(); delete game["bullet"+game.bullets[i].id]; game.bullets.splice(i,1); } } } }
这个函数通过循环来操作放在bullets数组中的每一个子弹对象。
使用getMyCorners函数我们得知子弹下一步是不是打在了障碍物上。如果不是,我们就调用moveChar函数移动子弹。
如果子弹确实击中了障碍物,我们就要删除它了。有3样事情要做:+ 删除子弹mc (使用removeMovieClip)+ 删除子弹对象 (使用delete函数)+ 从子弹数组中删除当前的子弹
尽管我们可以只删除子弹mc而留下子弹对象,这样做不会有大问题。因为子弹mc已经不存在,对它的所有的操作不能被执行。但是这样做会降低效率,子弹数组越来越大,而且里面全是垃圾数据。
当移动了子弹而且子弹没有撞上障碍物,我们开始检查它是不是击中了敌人。循环currentEnemies数组,计算出子弹和敌人的距离。如果他们离得太近,我们就删除他们——子弹和敌人都消失。
如果你要永久清楚这个被杀的敌人(当你再一次进入这个房间的时候,它不会再出现),在这里再添加一行:myEnemies[game.currentMap][obenemy.id]=0;
你也可以让射击变得更加丰富多彩:
+限制子弹的总数 。你可以设置一个变量,每次创建一个子弹,变量就减1,只有这个变量值大于0才能创建对象。+限制舞台上只有1颗子弹 。当子弹数组长度>0时不创建子弹。+让敌人也能发弹 。让敌人射击也很容易做到,方法和他们改变移动方向一样。+创建不同的武器 。你可以声明多种子弹模板,规定不同的伤害值,你可以得到更强的武器,更快的杀死敌人。
玩的开心 :-)
下载上例的源文件
在侧视图中射击:
下载本例的源文件
出处:蓝色理想
责任编辑:qhwa
上一页 更多关于敌人的东西 下一页 拾取物品
◎进入论坛Flash专栏 版块参加讨论