Robocode Lesson: Basic Scanning

In this lesson, we describe the basics of how the scanning works.

Robot Senses

We'll begin this lesson by discussing your robot's senses. It has only a few.

Sense of Touch

Your robot knows when it's:

  1. hit a wall (onHitWall),
  2. been hit by a bullet (onHitByBullet),
  3. or hit another robot (onHitRobot).

All of these methods pass you events that give you information about what you touched. (See the links to the on-line docs, above.)

Sense of Sight

Your robot knows when it's seen another robot, but only if it scans it (onScannedRobot).

Scan events are arguably the most important of all events. Scan events give you information about the other robots on the battlefield. (Some robots put 90+% of their code in the onScannedRobot method.) The only way scan events can be generated (practically speaking) is if you move your radar. (If an enemy robot wanders in front of your radar it will generate a scan event, but you should really take a more proactive stance.)

Also, remember in Battlefield Basics, the scanner is the fastest moving part of your robot, so don't be stingy about moving it.

If you want to, you can make the robots' scan arcs visible by selecting Options Menu -> Preferences -> View Options Tab and click on the "Visible Scan Arcs" checkbox. This is handy when debugging. Another handy debugging aid: you can pause / unpause the program by hitting the 'Alt' key.

Other Senses

Your robot also knows when he's died (onDeath), when another robot has died (onRobotDeath), or when he's won the round (onWin -- this is where you write the code for your victory dance. Side note: if you want to test your victory dance, you can start the round with just one bot: yours).

Your robot also is aware of his bullets and knows when a bullet has hit an opponent (onBulletHit), when a bullet hits a wall (onBulletMissed), when a bullet hits another bullet (onBulletHitBullet).

Building A Better Robot

Serial Movements with The Robot Class

You want to find other robots to kill. To do that, you need to scan for other robots. The simplest approach to scanning is to just turn the radar around and around. Your run method could look something like this:

public void run() {
	setAdjustRadarForRobotTurn(true);
	while (true) {
		turnRadarRight(360);
	}
}   

(Note that we call setAdjustRadarForRobotTurn(true) so as to have radar movement independent from gun movement.)

Indeed, our beloved BearingBot from last week did exactly that: he rotates his radar and moves closer to whoever he scans.

You may have noticed that BearingBot has a large defect that you can see if you match him up against an opponent that moves a lot (like, say, Crazy). He scans an opponent, then moves to where he saw him, and by the time he gets there, the opponent has moved away.

Compound Movements with the AdvancedRobot Class

It would be great if we could do more than one thing at once (scan AND turn AND fire). Thankfully, the powers that be have provided us with a means to accomplish this: The AdvancedRobot base class, which allows us to make non-blocking calls to move the robot and then executes them all as a compound action. Crazy and SpinBot (and oddly enough SittingDuck) are all examples of advanced robots.

To change your robot to an advanced robot, just change your class declaration from:

class MyRobot extends Robot {
	...
to
class MyRobot extends AdvancedRobot {
	...
Now you're inheriting from AdvancedRobot rather than Robot; now you can use the set* methods provided by the AdvancedRobot class. (We will discuss more about inheritance later.)

Sample robot: AdvancedBearingBot - A great improvement over 'BearingBot', because he can do compound movements.

Sample robot: AdvancedTracker - This is a modification of the 'Tracker' sample robot. Per the source code for Tracker, notice how much he improves when you turn him into an AdvancedRobot.

Important Note: If you make a robot derived from AdvancedRobot, you must call the execute() method to perform all the queued-up actions. If you forget to do that, your bot will become disabled. You can click on your bot's button on the right to see the error message from the system.

But AdvancedBearingBot has another large defect which you can see if you match him up against more than one opponent: he goes driving all over the battlefield chasing one robot after another and doesn't get a lot accomplished. This is because his radar keeps scanning robots, and he chases every one he scans. In short, he lacks focus.

Locking Onto an Enemy

Narrow Beam

We can easily lock onto our opponent by constantly turning the radar toward him whenever we scan him. Intuatively, you might think of doing something with the scanned robot's bearing like so:

    public void onScannedRobot(ScannedRobotEvent e) {
		// Lock on to our target (I hope...)
		 setTurnRadarRight(e.getBearing());
		 ...

There's a problem with this, though: the ScannedRobotEvent gives us a bearing to the scanned robot but it is relative to our tank's position, not our radar's position. How do we resolve this little quandry?

Easy: we find the difference between our tank heading (getHeading()) and our radar heading (getRadarHeading()) and add the bearing to the scanned robot (e.getBearing()), like so:

    public void onScannedRobot(ScannedRobotEvent e) {
		// Lock on to our target (this time for sure)
		setTurnRadarRight(getHeading() - getRadarHeading() + e.getBearing());
		...

Sample robot: NarrowBeam - Uses the above source to lock onto an opponent and nail him. Match him up against as many opponents as you want.

Oscillating (or "Wobbling") the Radar

An alternative technique is to oscillate your radar. Every time you see an opponent, you whipsaw the radar back so as to focus on one robot and continuously generate scan events. This is an improvement over the narrow beam because you are a little more aware of nearby robots.

To make this work, you need a variable that keeps track of which direction to turn the radar, it will only ever have values of 1 and -1, so it can be small. You can declare it in your robot like so:

class MyRobot extends AdvancedRobot {
	private byte scanDirection = 1;
	...
The run method can look just like the one above, but in the onScannedRobot method you do the following:
public void onScannedRobot(ScannedRobotEvent e) {
	...
	scanDirection *= -1; // changes value from 1 to -1
	setTurnRadarRight(360 * scanDirection);
	...
Flipping the value of scanDirection creates the oscillating effect.

Sample robot: Oscillator - wobbles his radar to keep track of his opponent. Note that while he tends to track an enemy, he'll chase others that are nearby, too.

Homework: Add scanning to your bot

For your homework today, follow the above notes to:

  1. Convert your robot from a Robot to an AdvancedRobot
  2. Add some scanning code, either the Narrow Beam or Oscillating technique