Robocode中一个高效雷达的学习记录
还记的刚接触到Robocode的兴奋,为Robocode比赛准备的艰辛,为写出的第一个机器人而高兴万分,为这个丰富的Robocode世界而震撼不已…
Robocode入门的门槛很低,但是要提高着实难度不小,这是我研究Robocode以来的一个不错的收获,作为告别Robocode的献礼,也为纪念我研究Robocode的日日夜夜留下点什么东西。
本雷达代码,提取自中国Robocode第一人,Wave技术的创始人iiley所写的Cigaret机器人中。
http://www.robochina.org,进入了解Robocode。
http://sourceforge.net/projects/robocode/files/ 下载Robocode
首先我们来复习Robocode世界中两个很重要的角度系统
注意,我的描述是用度为单位,代码中全使用弧度为单位。
第一, heading 角度系
如图所示,所谓heading角,即从Y轴出发,然后顺时针绕回Y轴的这么个角度区间,取值范围: [0,360]
第二, bearing角度系
所谓bearing 角,即从Y轴顺、逆时针出发,绕半圈回到Y轴所形成的两个角度区间,取值范围:顺时针[0,180) ;逆时针[0,-180]
好的,我们已近复习了两角度系,下面我们来学习这个非常高效的雷达。
首先给出代码:
public void onScannedRobot(ScannedRobotEvent e) { //注意 这里的计算都以弧度为单位 double absBearing=0d; //雷达转动角度 double radarTurnAngle=0d; //得到绝对角度差 absBearing=robocode.util.Utils.normalRelativeAngle(e.getBearingRadians()+getHeadingRadians()); //根据absBearing角算出Radar要调整的角度 radarTurnAngle=Math.sin(absBearing - getRadarHeadingRadians()); //转动雷达,注意是向右 setTurnRadarRightRadians(radarTurnAngle); } |
分析实例:
//得到绝对角度差 absBearing=robocode.util.Utils.normalRelativeAngle(e.getBearingRadians()+getHeadingRadians());
|
说明:
e.getBearingRadians(),如图中的∠FBC所示
是敌机(Enemy)与自己车头方向(你使用setAhead(正值)前进的方向即为车头方向,如BC箭头所示)所成的角,因为是以BC为Y轴的bearing角,所以这个角在这个例子中是个负值。
getHeadingRadians(),如图中∠ABC所示
是以自己的车头方向与屏幕垂直正上方为Y轴所成的heaing角。
absBearing=robocode.util.Utils.normalRelativeAngle(e.getBearingRadians()+getHeadingRadians());
所以absBearing角即为∠FBA,即自己与敌机的连线,与Y轴所成的bearing角,取值范围为[-180,180)。
//根据absBearing角算出Radar要调整的角度,进过sin运算,这个已经是个修正后的角度了radarTurnAngle=Math.sin(absBearing - getRadarHeadingRadians());
|
∠FBE=absBearing - getRadarHeadingRadians(),在这里计算出来为负值。即雷达需要转动的角度。
最后通过Math.sin(absBearing - getRadarHeadingRadians())进行角度修正得到最终值radarTurnAngle。这个修正很关键,原理可以参照sin曲线图
因为setTurnRadarRightRadians(radarTurnAngle)是向右旋转,所以若radarTurnAngle为负则雷达向左旋转。
总结:
有以上分析,我们不难得出雷达锁定目标所要转动的角度,由absBearing和e.getRadarHeading()(雷达的heading角)来决定.
radarTurnAngle=Math.sin(absBearing-getRadarHeadingRadians()); |
所以类似的,我们如果想让炮管、车身对准敌机,那么我们就就只要将e.getRadarHeading替换成e.getGunHeading()或e.getHeading()即可。
代码如下:
gunTurnAngle=Math.sin(absBearing-getGunHeadingRadians()); |
bodyTurnAngle=Math.sin(absBearing-getHeadingRadians()); |
应用实例:
所以我们可以写成这这样的一个机器人,你可以用它来对付Walls机器人
对,正如它的名字一样,它很疯!
import robocode.AdvancedRobot; import robocode.ScannedRobotEvent; /** * CrazyDog * @author lhx * */ public class CrazyDog extends AdvancedRobot { public void run(){ setAdjustGunForRobotTurn(true); setAdjustRadarForGunTurn(true); while(true){ turnRadarRightRadians(5); } } @Override public void onScannedRobot(ScannedRobotEvent e) { //注意 这里的计算都以弧度为单位 double absBearing=0d; //雷达转动角度 double radarTurnAngle=0d; double gunTurnAngle=0d; double bodyTurnAngle=0d; //得到绝对角度差 absBearing=robocode.util.Utils.normalRelativeAngle(e.getBearingRadians()+getHeadingRadians()); //根据absBearing角算出Radar要调整的角度 radarTurnAngle=Math.sin(absBearing - getRadarHeadingRadians()); gunTurnAngle=Math.sin(absBearing - getGunHeadingRadians()); bodyTurnAngle=Math.sin(absBearing - getHeadingRadians()); //转动雷达,注意是向右 setTurnRadarRightRadians(radarTurnAngle); //转动炮管 setTurnGunRightRadians(gunTurnAngle); //转动身体 setTurnRightRadians(bodyTurnAngle); //前进 setAhead(e.getDistance()); if(getGunHeat()<0.1)setFire(2); } } |