Head-On Targeting
Origins
Head-On Targeting is the simplest targeting method, documented by the RoboWiki community as the baseline all other targeting systems aim to beat.
Head-on targeting means aiming directly at where the enemy was when it was last scanned. It does not try to predict where the enemy will be when the bullet arrives.
This makes it easy to implement and great for learning, but it becomes less accurate as distance increases or when the enemy moves sideways.
When does it work well?
Head-on targeting tends to do okay when:
- The enemy is close (bullets arrive quickly).
- The enemy is moving straight toward or away from the bot.
- The enemy often pauses (common in sample / beginner bots).
- There are multiple enemies close to or behind the target enemy—the probability of hitting an enemy increases. If the bullet misses the target, another enemy behind or near the target might get hit instead.
It tends to miss when:
- The enemy is far away.
- The enemy moves mostly sideways relative to the bot.
- The enemy frequently changes its direction.
- A smart enemy predicts where the bullet will go and dodges accordingly.
A useful mindset: head-on targeting is the “baseline” that more advanced targeting (linear, circular, GuessFactor, …) tries to beat.
What information is needed?
To aim at a point, two things are needed:
- The enemy’s position
(enemyX, enemyY). - The direction from the bot to that position (an angle / heading for the gun).
Getting (enemyX, enemyY) differs by platform:
- Classic Robocode: a scan provides bearing + distance, so the enemy coordinates must be computed.
- Robocode Tank Royale: a scan event (
ScannedBotEvent) provides the enemy coordinates directly (x,y).
From scan to enemy position (classic Robocode)
Classic Robocode scan events provide a relative bearing: the angle from the bot’s heading to the enemy. Combine that with the bot’s heading to get an absolute bearing.
absoluteBearing = myHeading + relativeBearing
enemyX = myX + sin(toRadians(absoluteBearing)) * distance
enemyY = myY + cos(toRadians(absoluteBearing)) * distanceDefinitions:
myX,myY: the bot's position.myHeading: the bot's heading (in degrees here).relativeBearing: fromScannedRobotEvent(in degrees).distance: fromScannedRobotEvent.
Note
sin is used for X and cos for Y in classic Robocode because 0° points up (North) and angles increase clockwise. The trig functions need radians, so convert degrees using toRadians(). See Coordinate Systems & Angles.
Aiming the gun at that point
Once a last-known enemy position is available, the gun should be turned to point at it.
Aiming is basically "what is the angle from (myX, myY) to (enemyX, enemyY)?"
- In classic Robocode, typical code computes a gun turn angle and uses
setTurnGunRight(...). - In Tank Royale, the API offers helpers like
calcHeadingTo(x, y)that returns the heading to a point.
Illustration: The bot aims its gun directly at the enemy's last scanned position. However, the enemy bot has already moved to a new position*
Minimal examples
Keep it small
The examples below focus on the “head-on” idea only: compute (or read) the enemy position, turn the gun, and fire. More advanced bots usually also decouple radar from gun/body and choose firepower based on distance and energy.
Classic Robocode (Java)
// Inside onScannedRobot(ScannedRobotEvent e):
double absBearing = getHeading() + e.getBearing();
double enemyX = getX() + Math.sin(Math.toRadians(absBearing)) * e.getDistance();
double enemyY = getY() + Math.cos(Math.toRadians(absBearing)) * e.getDistance();
// Aim gun at the enemy's last scanned position
// (Use Robocode's normalRelativeAngle to pick the shortest turn direction.)
double gunAbsHeading = Math.toDegrees(Math.atan2(enemyX - getX(), enemyY - getY()));
double gunTurn = robocode.util.Utils.normalRelativeAngle(gunAbsHeading - getGunHeading());
setTurnGunRight(gunTurn);
// Fire when roughly aligned
if(Math.
abs(getGunTurnRemaining()) < 2){
setFire(1.5);
}Robocode Tank Royale (Java)
In Tank Royale, ScannedBotEvent includes the enemy position, so "head-on" targeting is mostly just turning the gun to that point.
// Tank Royale Java (conceptual): inside onScannedBot(ScannedBotEvent e)
// e.getX() and e.getY() are the enemy's coordinates on the battlefield
double gunHeadingToEnemy = calcHeadingTo(e.getX(), e.getY());
// Turn the gun the shortest way toward the target heading
// (Method names can vary slightly by base class / language binding.)
double gunTurn = normalizeRelativeAngle(gunHeadingToEnemy - getGunHeading());
setTurnGunRight(gunTurn);
if(Math.
abs(getGunTurnRemaining()) < 2){
setFire(1.5);
}Platform notes (classic vs. Tank Royale)
- Scan data is history on both platforms. Even “instant” head-on targeting aims at slightly old information.
- Angles differ:
- Classic Robocode: angles increase clockwise from North, degrees or radians.
- Tank Royale: angles increase counterclockwise from East, degrees only.
- Enemy coordinates:
- Classic Robocode: compute
enemyX,enemyYfrom bearing + distance. - Tank Royale: use
e.getX(),e.getY()from the scan event.
- Classic Robocode: compute
Tips & common mistakes
- Forgetting shortest-turn normalization: Without it, the gun might rotate almost a full circle instead of a few degrees.
- Forgetting to convert for trig functions (classic Robocode):
getHeading()andgetBearing()return degrees, butMath.sin()andMath.cos()need radians—useMath.toRadians()to convert. - Assuming head-on will work at long range: bullets take time to travel; prediction methods exist for a reason.
- Not scanning often enough: head-on targeting gets worse quickly if the last scan is several turns old. Radar strategy matters.
Further Reading
- Head-On Targeting — RoboWiki (classic Robocode)