摘自:
Robocode教程7——雷达锁定
在这次教程中,我们要写这样一个代码,它将让敌人逃不出我们的眼睛。雷达锁定是一个高效战斗机器人的基础,因为robot只有执行onScannedRobot方法,我们才能够获取敌人的信息,而onScannedRobot方法只有在我们的雷达扫描到敌人之后才会被调用,当然,调用的过程是自动的。雷达是以机器人为圆心的一条射线,为了更直观,我们最好打开雷达图形显示,方法是:进入robocode,打开Options-> Preferences->view options,勾选Visible Scan Arcs还记得我们的Enemy类吗?它在我们的这个机器人中有着至关重要的作用。所以如果不太熟悉class Enemy的话还是先去看看吧。在Enemy类中有一个direction变量,它的值为:direction = bearingRadian + me.getHeadingRadians();
如这张图所示,弄懂了direction变量,雷达锁定就很简单了。雷达的扫描实际上是一条线,当扫描线扫描到目标时,触发onScannedRobot事件,更新当前数据,包括direction。当程序执行到onScannedRobot内的代码时,雷达扫描线的角度getRadarHeadingRadians()已经和direction有所偏离。为了锁定目标,我们可以把雷达往反方向扫描。因为雷达旋转很快,而且getRadarHeadingRadians()和direction的偏移量不大,机器人是有一定大小的。于是扫描线在目标身上来回扫动,实现了雷达锁定。public void onScannedRobot(ScannedRobotEvent e) { enemy.update(e,this); double Offset = rectify( enemy.direction -getRadarHeadingRadians() ); setTurnRadarRightRadians( Offset * 1.5); }这是我们的onScannedRobot方法,enemy.updata(e,this);是调用我们的enemy对象里面的方法,更新敌人信息,当然,忘了一点,在这之前,我们需要生成一个enemy对象,具体方法为:Enemy enemy = new Enemy();这里我们还要解释一下rectify方法,它的作用是对角度进行修正,因为direction减去我们雷达的朝向,有可能会大于180度或者小于-180度,比如当大于180度时,我们所需要转动的角度并不需要那么大,只需方向转一个角度就可以了。这个rectify方法很简单,当在后面应用很多。它的代码为: public double rectify ( double angle ) { if ( angle < -Math.PI ) angle += 2*Math.PI; if ( angle > Math.PI ) angle -= 2*Math.PI; return angle; }在代码中,enemy.direction -getRadarHeadingRadians()是雷达所要旋转的偏移量。假设之前雷达顺时针扫描,那么enemy.direction略小于getRadarHeadingRadians(),为负。经rectify()方法修正后即为需要转动的值。然后用setTurnRadarRightRadians旋转雷达,旋转度数为偏移的1.5倍,因为RadarOffset为负,故反方向扫描,保证无论目标如何移动,扫描线始终在目标身上。上面的1.5可以改成2,3等数。当你在Options中打开了Visible Scan Arcs选项后,就可以看到绿色的扇形,倍数为1.5的时候,类似一条线,而倍数为2,3的时候就可以看到像是一个扇形。另外我们还要说一下另外两段代码: setAdjustGunForRobotTurn( true ); setAdjustRadarForGunTurn( true );它们的作用是使雷达、大炮、车身运动独立,具体参考API手册。到这里我们雷达扫描的代码就完成了,运行试试我们的“观察者号”吧!!
附:观察者号完整代码:package cm; import java.awt.*;import robocode.*; public class ObserverRobo extends AdvancedRobot { Enemy enemy = new Enemy(); public static double PI = Math.PI; public void run() { setAdjustGunForRobotTurn( true ); setAdjustRadarForGunTurn( true ); this.setColors(Color.red, Color.blue, Color.yellow, Color.black, Color.green); while(true){ if(enemy.name == null){ setTurnRadarRightRadians(2*PI); execute(); } else{ execute(); } } } public void onScannedRobot(ScannedRobotEvent e) { enemy.update(e,this); double Offset = rectify( enemy.direction - getRadarHeadingRadians() ); setTurnRadarRightRadians( Offset * 1.5); } //角度修正方法,重要 public double rectify ( double angle ) { if ( angle < -Math.PI ) angle += 2*Math.PI; if ( angle > Math.PI ) angle -= 2*Math.PI; return angle; } public class Enemy { public double x,y; public String name = null; public double headingRadian = 0.0D; public double bearingRadian = 0.0D; public double distance = 1000D; public double direction = 0.0D; public double velocity = 0.0D; public double prevHeadingRadian = 0.0D; public double energy = 100.0D; public void update(ScannedRobotEvent e,AdvancedRobot me){ name = e.getName(); headingRadian = e.getHeadingRadians(); bearingRadian = e.getBearingRadians(); this.energy = e.getEnergy(); this.velocity = e.getVelocity(); this.distance = e.getDistance(); direction = bearingRadian + me.getHeadingRadians(); x = me.getX() + Math.sin( direction ) * distance; y= me.getY() + Math.cos( direction ) * distance; } }}