中北大学2010届毕业设计说明书
Random random=new Random(System.currentTimeMillis()); return (Math.abs(random.nextInt())%4)*50;
只是需要乘以每秒会刷新的屏幕的次数。这样就相当于允许在某一个方向运行0~3秒钟的时间。
开始 是否已死Y N N 是否刚出现 Y 是否碰撞 N 前进 Y 可否开炮 N 开炮 可否前N Y 换向、取随机移动步数、随机开炮倒数记结束 图4.6 敌方坦克运行流程图
开始 是否出界 Y Y 是否击中物体N 将可以消除的障碍物消除 N N 玩家的子弹吗 Y 是否与任何敌Y 人的子弹碰撞 N 子弹抵消 是否击中任Y 何敌人 N 消除敌人 敌人的子N 弹吗? Y 是否与玩家Y 的子弹碰撞 N 子弹抵消 是否击中玩Y 家 N 消除玩家 结束 图4.7 子弹运行的主要功能流程图
第 21 页 共30 页
中北大学2010届毕业设计说明书
每个敌人还需要拥有一个内部的所有敌人的数组元素。这样,它们才可以自动检测自己是否与同伴发生了碰撞,以便采取躲避、转向等行动。
collidesWithOtherTank()将检测是否与其他坦克(包括敌人和玩家)。一个循环将依据敌人的序号查找5次。if(i==number)break ;语句将避免检测到自己,永远返回真。
collidesInOtherTank()虽与上面的函数很相似,但仍有一些细微不同,那就是不需要在检测前设置被检测方的矩形区域。因为不需要进行预先检测。此函数用来检测是否在刚出现时就与其他坦克发生碰撞的。如果一出现,出口就被堵死,显然,不能永远不出现,那就应采取其他的办法,否则两辆坦克将因为都处在碰撞状态中而无法移出。在运行的线程中,需在每前进的一步骤中循环做下列事件:
如果坦克已死亡,立刻退出。(由boolean值destroyed决定)。
如果不是刚出现(由isBeginner决定),判断是否与将其他坦克发生碰撞,就向当前方向前进一步骤,否则,将需要循环检测的当前随机步数减少为原先的2/3(为了加速离开的时间)。如果刚出现,就直接走一步,具体如何行走将在go()函数中决定,并且此go()与UserSprite中的有所区别。
当随机发炮数减少到0时,就进行发炮的动作。发炮后应立即重新赋值给随机发炮数,以便重新倒数计算。
当所有的步骤走完后,因为需要转动方向,于是,调用一次随机取得方向的函数再次获值。其他的随机值也应当重置。
在go()函数中首先检测是否正处于碰撞状态中,如果不是,就需要取消Beginner的状态,因为不需要Beginner这样的特殊身份,让别的坦克不检测了。
在运行在某个方向上,当确定为canPass时,应再检测是否为Beginner。如果是,就不应该受到其他坦克的影响而直接改变坐标,但若不是,就应当远地不动。 相关代码如下:
public void go(int direction) //method for tank to go forward {
if(!collidesInOtherTank()) isBeginner=false; switch (direction) {
case UP: {
第 22 页 共30 页
中北大学2010届毕业设计说明书
if (currentDirection == UP) {
if (canPass(UP)) {
if(isBeginner) y--;
else if (!collidesWithOtherTank()) y--; } } else {
setTransform(transformDirection[0]); currentDirection = UP; }
break ; }
case DOWN: {
if (currentDirection == DOWN) {
if (canPass(DOWN)) {
if(isBeginner) y++;
else if (!collidesWithOtherTank()) y++; } }
else {
setTransform(transformDirection[2]); currentDirection = DOWN; }
break ; }
case RIGHT: {
if (currentDirection == RIGHT) {
if (canPass(RIGHT)) {
if(isBeginner) x++;
else if (!collidesWithOtherTank())
第 23 页共30 页
中北大学2010届毕业设计说明书
x++; } }
else {
setTransform(transformDirection[1]); currentDirection = RIGHT; }
break ; }
case LEFT: {
if (currentDirection == LEFT) {
if (canPass(LEFT)) {
if(isBeginner) x--;
else if (!collidesWithOtherTank()) x--; } } else {
setTransform(transformDirection[3]); currentDirection = LEFT; }
break ; } }
setRefPixelPosition(x, y); }
4.6 子弹的运行和控制
子弹继承了Runnable,运行在独立的线程中。它拥有一个很重要的变量,isFromEnemy。它标识了该子弹是属于玩家的,还是敌人的,这样可以控制子弹在脱离坦克管束后的运行状态中的行为。其主要功能流程图见图4.7。
checkHit(int x,int y)调用了getTileIndex(x,y)获取当前子弹击中的是什么障碍物,如果返回了false就表示没有击中任何东西。当击中了需要作出反映的物体时,就分别采取措施:击中草时,由于没有定义相关函数,就不会有任何反映,会重合在草上正常通过;击中砖块时,将产生爆炸,调用setCell将当前块置为空,并产生爆炸效果。爆炸效果由tileExplode(x,y)根据需要爆炸的坐标点生成,其中将一个
第 24 页 共30 页
中北大学2010届毕业设计说明书
Sprite图片在界面上闪现150毫秒。爆炸效果需要将图片insert进第0层,这样才不至于被其他景物所覆盖,爆炸结束后layerManager会自动相应调整。击中钢筋时,将只产生爆炸效果。
setShootCheck(EnemySprite enemySprite[]);setUserSprite(UserSprite
userSprite);
setEnemySprite(EnemySprite enemySprite)
都是将相关的坦克传入到子弹类里来,以便确认来源或攻击目标。
相关代码如下:
private boolean checkHit(int x,int y) //check what tile the bullet had hit and what to do {
boolean hit=false;
int index=getTileIndex(x,y);
if(index==2) //if it is wall,eliminate it. {
tiledLayer.setCell(x / 8, y / 8, 0); tileExplode(x, y);
hit=true; // if the bullet hit a wall, it does hit something. }
else if(index==5) //if it is steel,ignore it but explode. {
tileExplode(x,y);
hit=true; // if the bullet hit a steel pan,it does hit something,too. } // hit any other things will be considered hit nothing(eg.grass,river);
else if((index==3)||(index==4)||(index==7)||(index==8)) {
layerManager.remove(this); // the bullet should disappear immediately
isEnd=true;
while(userSprite.getLife()>0) userSprite.die();
//die many times until no lives left. } return hit; }
子弹运行中,将用collidesWith(tiledLayer,true)测试是否碰撞上了地图。如果为真,就继续检测碰撞上了什么样的物体。这将针对四个不同的方向分别以象素级检测。如果击中了某样物体,那么checkHit自然会处理,子弹的生命周期结束,以
第 25 页 共30 页