观察现象
被连续击中、经常撞墙、路线太固定,都是可分析的战场信号。
Lecture 03 · Movement, Coordinates, and Evasion
用 Coordinate(坐标)、Angle(角度)与 Event(事件)理解战场,并写出更不容易被预测的移动策略。
前两课我们让坦克会动、会看、会开火;这一课开始训练策略判断:为什么被打中,为什么撞墙,下一步怎么改。
被连续击中、经常撞墙、路线太固定,都是可分析的战场信号。
把现象对应到移动距离、转向角度、循环与事件处理器。
一次只改一个机制,测试后再判断是否真的改善。
认识 Robocode Tank Royale 的坐标系统:左下角是 (0, 0)。
使用 Loop(循环)与随机变化,让移动不再像固定路线一样容易预测。
在受击或撞墙时触发反应,把危险变成策略调整机会。
复习扫描与火力规则,观察上一版 Bot 的弱点。
讲解坐标、角度、边界与撞墙。
教师示范:受击反应、撞墙反应、随机走位。
学生实作、对战测试、Debug 与保存版本。
(0, 0) 在战场左下角。x 越大越靠右,y 越大越靠上。@Override
public void run() {
while (isRunning()) {
double myX = getX();
double myY = getY();
double myDirection = getDirection();
forward(100);
turnGunLeft(360);
}
}
今天不要求大家做复杂数学;重点是知道代码可以读取当前位置,并用它辅助判断。
记住几条规则,就能解释坦克为什么“转不动”、为什么撞墙很痛:
10 − 0.75 × |速度|:开得越快,每回合能转的角度越小。
|速度| / 2 − 1:速度越高,撞墙越痛。
想灵活转向躲避,就别一直全速直线冲;接近墙时先放慢,能少受伤,也更难被对手预测。
参考: Robocode Physics
如果坦克永远前进 100、后退 100、再转同样角度,对手很容易预测下一步位置。策略优化的第一步,是减少固定规律。
@Override
public void run() {
while (isRunning()) {
if (Math.random() < 0.5) {
turnLeft(35);
} else {
turnRight(35);
}
forward(120);
turnGunLeft(360);
}
}
Math.random() 会产生 0 到 1 之间的小数,用来制造简单的不确定性。
@Override
public void onHitByBullet(HitByBulletEvent e) {
turnRight(90);
forward(120);
}
被打中代表当前路线可能被敌人瞄准。立刻转向并移动,能降低继续被命中的机会。
与其随便转 90 度,不如转到与子弹来向垂直的方向,向侧面移动,让对手更难再次命中:
e.getBullet().getDirection():打中我们的子弹的飞行方向。calcBearing(方向):把一个绝对方向换算成相对车身的角度(助手方法)。
90 - bearing:转到与子弹垂直的方向。@Override
public void onHitByBullet(HitByBulletEvent e) {
double bearing = calcBearing(e.getBullet().getDirection());
turnRight(90 - bearing);
forward(100);
}
这正是模板里 MyFirstBot 被击中时使用的躲避方式。
@Override
public void onHitWall(HitWallEvent e) {
back(80);
turnRight(90);
}
到目前为止我们用的都是阻塞 (blocking) 指令:
forward(100) 会一直等到走完,才执行下一行。
想同时移动并转向,可改用
set 系列 + go():
setForward(10000);
setTurnLeft(90);
go(); // 一起执行:边走边转
模板里的 SpinBot、Crazy 就是这样实现边走边转的。
onHitByBullet(...),观察受击后是否更快离开原位置。onHitWall(...) 和随机转向,观察生存时间是否改善。每次只加入一个机制,才能知道改善来自哪里。
onHitByBullet(...) 的受击反应。onHitWall(...) 的撞墙反应。如果靠近战场边缘,就减少前进距离或增加转向角度。
double margin = 100;
double moveDistance = 120;
// 离任何一道墙太近,就少走一点
if (getX() < margin || getY() < margin
|| getX() > getArenaWidth() - margin
|| getY() > getArenaHeight() - margin) {
moveDistance = 60;
}
forward(moveDistance);
用 getArenaWidth()、getArenaHeight() 判断四面墙,比只看
(0, 0) 那个角更可靠。
HitByBulletEvent 与
HitWallEvent 都来自 events package(事件包)。
可拍照或打印;实作时填写自己的一行记录。
| 现象 | 可能原因 | 小步修正 |
|---|---|---|
| 例:连续被击中 | 例:路线太固定 | 例:加入 onHitByBullet 转向 |
模板仓库的 BrokenWallBot 在撞墙后没有正确后退(故意写错)。用 5
分钟集体读代码,找出 onHitWall(...) 的问题。
参考: 学生代码模板
建议 commit message:Add evasion and wall handling。课后延伸:把最有效的一项移动改进写进 commit message,让 Git 历史成为坦克进化记录。
趣味 Java 编程启蒙班
© 2026 by
Eng Zer Jun
is licensed under
Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International