愚蠢的敌人
我们的英雄已经很完美了,但是他很无聊,唯一能做的只是来回走。我们需要别的东西。不是食物,不是饮料,也不是美女,我们需要的是——一些敌人。敌人就像加在汤里的盐,缺了它,一切都索然无味。好的游戏中会有聪明的敌人,但是我们从一些最笨的敌人开始做起。他们所做的仅仅是来回走,顺便检测是不是碰上英雄了。
到目前为止,我们已经有了两类对象:英雄和方块。英雄由玩家操纵,方块不会运动。敌人应该类似英雄,唯一不同的是,我们不能操作他们移动,我们将会赋予他们一定的智能。我们将要做两种不同的敌人,第一种上下走,第二种会左右走。他们都会在撞到墙上后回头继续走。(真够笨的:)
在你开始构造你的超级复杂的敌人之前,再想想一些东西。许多游戏实际上没有用到敌人,有的虽然用到了,也不是很聪明。Flash并不是非常强大,如果你的游戏中有100个敌人,他们都聪明地使用A*算法跟踪英雄,我真的怀疑是否有这么强大的机器能运行。如果可以的话,最好让一些敌人愚蠢些,一些聪明些,结果玩家可能就会忽略了他们的差别。另外,我们都想要比别人聪明,所以就让玩家感觉这种乐趣好了 :)
准备敌人
同创建英雄一样,创建一个剪辑放置敌人(如果忘了怎么做,在回头看看)。他们也有4帧,分别是左、上、下、右的动画。同样的,他们也要导出为“enemy1”和“enemy2”(在库面板中设置linkage)。现在我们添加一个enemies数组:
myEnemies = [ [0], [[1, 6, 1]], [[2, 1, 3]] ];
看得出来,我们在map1放了1个敌人。 [1,6,1]:第一个1代表敌人的类型(hoho~我们有好多中敌人得) 6,1是他开始的位置。创建地图的时候,我们会把他放到x=6,y=1的方块上。同理在map2中也有一个敌人,但是类型是2,位置是1,3。你可在一个地图中放置多个敌人,但是千万记住,不要把他们嵌到墙里面!记得要放在一个可通行的方块上面。
让我们声明一些敌人的模板:
game.Enemyp1= function () {}; game.Enemyp1.prototype.xMove=0; game.Enemyp1.prototype.yMove=1; game.Enemyp1.prototype.speed=2;
game.Enemyp2= function () {}; game.Enemyp2.prototype.xMove=1; game.Enemyp2.prototype.yMove=0; game.Enemyp2.prototype.speed=2;
他们的代码看起来很相似,但是他们动作就不一样了。Enemyp1会上下走,因为他的yMove属性是1;但是Enemyp2只会水平移动。你可以设置xMove/yMove属性为1或-1或0。不过请不要同时把这两个属性都设置成非零值,除非你希望敌人能走对角线。
你也可以把xMove和yMove都设置成0,这样的敌人没有移动的能力,也许你会用到。
speed属性声明了敌人移动的速度。不同的敌人可以有不同的速度。
摆放敌人
在buildMap函数中,介于创建门和创建英雄的代码之间,加入如下代码:
var enemies = myEnemies[game.currentMap]; game.currentEnemies = enemies.length; for (var i = 0; i<game.currentEnemies; ++i) { var name = "enemy"+i; game[name]= new game["Enemyp"+enemies[i][0]]; game.clip.attachMovie("enemy"+enemies[i][0], name, 10001+i); game[name].clip=game.clip[name]; game[name].xtile = enemies[i][1]; game[name].ytile = enemies[i][2]; game[name].width = game.clip[name]._width/2; game[name].height = game.clip[name]._height/2; game[name].x = (game[name].xtile *game.tileW)+game.tileW/2; game[name].y = (game[name].ytile *game.tileH)+game.tileH/2; game[name].clip._x = game[name].x; game[name].clip._y = game[name].y; }
这段代码什么意思?首先我们得到当前地图的敌人数组,转存为enemies数组,然后把敌人的个数传给currentEnemies,接着遍历敌人数组,把他们都安置好。 (记住,虽然这里只用到了一个敌人,但是可以有更多的)
变量name的值是新创建的敌人的名字,“enemy0”,“enemy1”,“enemy2”……依次类推。然后我们从相应的模板(刚刚声明过)创建新的对象:
game[name]= new game["Enemy"+enemies[i][0]]; 从敌人数组(enemies[i])的第一个元素(enemies[i][0])得到敌人的类型,比如是1,然后通过enemyp1模板创建一个敌人。
下面的几行是取得坐标,然后把敌人放置到该处。ok,这就是buildMap函数该变动的地方。
但是,你也许会大声喊出来,但是他还不会动!好吧,我们就让他动起来
移动敌人
同人一样,敌人也需要脑子,我们就写个enemyBrain函数好了:
function enemyBrain () { for (var i = 0; i<game.currentEnemies; ++i) { var name = "enemy"+i; var ob = game[name]; getMyCorners (ob.x+ob.speed*ob.xMove, ob.y+ob.speed*ob.yMove, ob); if (ob.downleft and ob.upleft and ob.downright and ob.upright) { moveChar(ob, ob.xMove, ob.yMove); } else { ob.xMove = -ob.xMove; ob.yMove = -ob.yMove; } var xdist = ob.x - char.x; var ydist = ob.y - char.y; if (Math.sqrt(xdist*xdist+ydist*ydist) < ob.width+char.width) { removeMovieClip(_root.tiles); _root.gotoAndPlay(1); } }
}
正如你所看到的,我们又要遍历数组了。我们把enemies数组的每个元素存到ob,当i等于0的时候,ob就是enemy0。
然后我们调用getCorners函数,检查敌人是不是碰到了障碍物,如果upleft、downleft、upright、downright都是true,则说明可以行走。我们就可以放心的调用moveChar函数,同时传递xMove、yMove给moveChar函数。我们以前用moveChar都是移动英雄的,现在移动敌人也没有任何区别,我说过,我们可以重复使用许多函数的。
如果英雄碰到了障碍物,我们就让xMove和yMove都取相反数,比如原来xMove是1,就取-1,这样敌人就会掉头移动。如果yMove原来是0,那么相反数还是0,没有影响。
最后一部分检测英雄和敌人的距离,看是不是碰到了一起,如果是,oh,game over。当然,游戏不可能这么简单的结束掉,你可以减少英雄的生命值或者做别的处理,这些都由你自己完成。我们使用的计算距离的公式用的是“勾股定理”,如果你需要精确到象素级别的接触,你应该用hitTest,但是这里没有必要这么精确。别离敌人太近,否则你会死掉的。:-)
我们需要不停的调用这个函数,所以在detectKeys函数中加入:
_root.enemyBrain();
这就是一个敌人,很愚蠢的敌人。接下来我们要做更聪明的敌人,他们象人一样四处巡逻,碰到障碍物后会改变方向继续巡逻。hoho,继续吧~
下载本例的源文件
出处:蓝色理想
责任编辑:qhwa
上一页 梯子 下一页 更多关于敌人的东西
◎进入论坛Flash专栏 版块参加讨论