Difference between revisions of "PluggableRobot/Source"

From Robowiki
Jump to navigation Jump to search
m (Added summary)
m (Using <syntaxhighlight>.)
 
(5 intermediate revisions by 4 users not shown)
Line 1: Line 1:
 
Below is the source for [[PluggableRobot]]. Pillage to your heart's content. PluggableRobot is released under the [[RWLPCL|RoboWiki Limited Public Code License]].
 
Below is the source for [[PluggableRobot]]. Pillage to your heart's content. PluggableRobot is released under the [[RWLPCL|RoboWiki Limited Public Code License]].
 
+
== Canvas.java ==
== Component.java ==
+
<syntaxhighlight><nowiki>
<pre><nowiki>
 
 
/*
 
/*
 
  * PluggableRobot, by Robert J. Walker
 
  * PluggableRobot, by Robert J. Walker
  * Home page: http://robowiki.net/cgi-bin/robowiki?PluggableRobot
+
  * Home page: http://robowiki.net/w/index.php?title=PluggableRobot
  * This software is made available under the RoboWiki Limited Public Code License (RWLPCL). The full
+
  * This software is made available under the RoboWiki Limited Public Code
* text of the license may be found at http://robowiki.net/cgi-bin/robowiki?RWLPCL.
+
* License (RWLPCL). The full text of the license may be found at:
 +
* http://robowiki.net/w/index.php?title=RWLPCL
 
  */
 
  */
 
package rjw.pluggablerobot;
 
package rjw.pluggablerobot;
 +
 +
import java.awt.*;
 +
import java.awt.geom.Point2D;
 +
 +
import robocode.AdvancedRobot;
  
 
/**
 
/**
  * Components encapsulate the main combat behavior of the robot into pluggable modules. Any code
+
  * A convenience wrapper around Graphics2D which provides the following
  * that actually sets an action for the robot (moving, turning, rotating the turret or radar, etc.)
+
* features:
  * should be done in the go() method. Components should NEVER call any blocking methods;
+
*
  * PluggableRobot will call execute() automatically when all components have had a chance to act.
+
  * - Accepts doubles for many arguments which are ints in Graphics2D
 +
* - getCenter(), getHeight() and getWidth()
 +
  * - drawCircle(), fillCircle()
 +
  *  
 
  * @author Robert J. Walker
 
  * @author Robert J. Walker
 
  */
 
  */
public interface Component {
+
public class Canvas {
 +
private Graphics2D _g;
 +
private double _width;
 +
private double _height;
 +
private Point2D.Double _center;
 +
 
 +
Canvas(AdvancedRobot bot) {
 +
_g = bot.getGraphics();
 +
_width = bot.getBattleFieldWidth();
 +
_height = bot.getBattleFieldHeight();
 +
_center = new Point2D.Double(_width / 2, _height / 2);
 +
}
 +
 
 +
/**
 +
* @see java awt.Graphics2D.clearRect(int, int, int, int)
 +
*/
 +
public void clearRect(double x, double y, double width, double height) {
 +
_g.clearRect(i(x), i(y), i(width), i(height));
 +
}
 +
 
 
/**
 
/**
* Asks this Component to execute any actions that it wants to take this turn. PluggableRobot
+
* @see java awt.Graphics2D.clip(java.awt.Shape)
* will call this method once per turn for each registered Component. Don't put any blocking
 
* calls in here; PluggableRobot will call execute() for you automatically after calling go() on
 
* each Component.
 
 
*/
 
*/
public abstract void go();
+
public void clip(Shape shape) {
}
+
_g.clip(shape);
</nowiki></pre>
+
}
  
== EventListener.java ==
+
/**
<pre><nowiki>
+
* @see java awt.Graphics2D.clipRect(int, int, int, int)
/*
+
*/
* PluggableRobot, by Robert J. Walker
+
public void clipRect(double x, double y, double width, double height) {
* Home page: http://robowiki.net/cgi-bin/robowiki?PluggableRobot
+
_g.clipRect(i(x), i(y), i(width), i(height));
* This software is made available under the RoboWiki Limited Public Code License (RWLPCL). The full
+
}
* text of the license may be found at http://robowiki.net/cgi-bin/robowiki?RWLPCL.
 
*/
 
package rjw.pluggablerobot;
 
  
import java.awt.Graphics2D;
+
/**
import java.awt.geom.Point2D;
+
* @see java awt.Graphics2D.copyArea(int, int, int, int, int, int)
import java.util.ArrayList;
+
*/
 +
public void copyArea(double x, double y, double width, double height,
 +
double dx, double dy) {
 +
_g.copyArea(i(x), i(y), i(width), i(height), i(dx), i(dy));
 +
}
  
import robocode.*;
+
/**
 +
* @see java awt.Graphics2D.draw(java.awt.Shape)
 +
*/
 +
public void draw(Shape shape) {
 +
_g.draw(shape);
 +
}
  
/**
+
/**
* A pluggable listener and strategy architecture for a robot.
+
* @see java awt.Graphics2D.drawArc(int, int, int, int, int, int)
* http://robowiki.net/cgi-bin/robowiki?PluggableRobot
+
*/
* @author Robert J. Walker
+
public void drawArc(double x, double y, double width, double height,
*/
+
double startAngle, double arcAngle) {
public abstract class PluggableRobot extends AdvancedRobot {
+
_g.drawArc(i(x), i(y), i(width), i(height), i(startAngle), i(arcAngle));
private static boolean _battleInitialized = false;
+
}
private static Hud _hud;
 
  
private ListenerDelegate _listenerDelegate;
+
/**
private ArrayList<Component> _components;
+
* Convenience method for drawing a circle, given the center coordinates and
private ArrayList<Hud.Painter> _painters;
+
* radius.
private Point2D.Double _center;
+
*/
 +
public void drawCircle(double x, double y, double r) {
 +
int d = i(r * 2);
 +
_g.drawOval(i(x - r), i(y - r), d, d);
 +
}
  
 
/**
 
/**
* Sets up the ListenerDelegate and the Component and Painter lists.
+
* @see java awt.Graphics2D.drawLine(int, int, int, int)
 
*/
 
*/
protected PluggableRobot() {
+
public void drawLine(double x1, double y1, double x2, double y2) {
_listenerDelegate = new ListenerDelegate();
+
_g.drawLine(i(x1), i(y1), i(x2), i(y2));
_components = new ArrayList<Component>();
 
_painters = new ArrayList<Hud.Painter>();
 
 
}
 
}
  
 
/**
 
/**
* Set up the robot, then continuously collect events and invoke components.
+
* @see java awt.Graphics2D.drawOval(int, int, int, int)
 
*/
 
*/
@Override
+
public void drawOval(double x, double y, double width, double height) {
public final void run() {
+
_g.drawOval(i(x), i(y), i(width), i(height));
// Initialize battle (at start of first round only)
+
}
if(!_battleInitialized) {
 
_hud = new Hud(this);
 
initializeBattle();
 
_battleInitialized = true;
 
}
 
  
// Register custom event test() hook for event manager
+
/**
addCustomEvent(new Condition("eventManager") {
+
* @see java awt.Graphics2D.drawRect(int, int, int, int)
public boolean test() {
+
*/
PluggableRobot.this.handleEvents();
+
public void drawRect(double x, double y, double width, double height) {
return false;
+
_g.drawRect(i(x), i(y), i(width), i(height));
}
+
}
});
 
  
// Round is starting
+
/**
initializeRound();
+
* @see java awt.Graphics2D.drawRoundRect(int, int, int, int, int, int)
 +
*/
 +
public void drawRoundRect(double x, double y, double width, double height,
 +
double arcWidth, double arcHeight) {
 +
_g.drawRoundRect(i(x), i(y), i(width), i(height), i(arcWidth),
 +
i(arcHeight));
 +
}
  
// Main loop
+
/**
while(true) {
+
* @see java awt.Graphics2D.drawString(String, float, float)
for(Component component : _components) {
+
*/
component.go();
+
public void drawString(String str, double x, double y) {
}
+
_g.drawString(str, (float) x, (float) y);
 +
}
  
execute();
+
/**
}
+
* @see java awt.Graphics2D.fill(java.awt.Shape)
 +
*/
 +
public void fill(Shape shape) {
 +
_g.fill(shape);
 
}
 
}
  
 
/**
 
/**
* This method will be called at the beginning of a battle. Robots can override this method to
+
* @see java awt.Graphics2D.fillArc(int, int, int, int, int, int)
* initialize their properties. This is a good place to initialize static properties or set your
 
* tank color.
 
 
*/
 
*/
protected void initializeBattle() {
+
public void fillArc(double x, double y, double width, double height,
// Default implementation does nothing
+
double startAngle, double arcAngle) {
 +
_g.fillArc(i(x), i(y), i(width), i(height), i(startAngle), i(arcAngle));
 
}
 
}
  
 
/**
 
/**
* This method will be called at the beginning of each round. Robots can override this method to
+
* Convenience method for filling a circle, given the center coordinates and
* initialize their properties. This is a good place to set up non-static properties and
+
* radius.
* register listeners, painters and components.
 
 
*/
 
*/
protected void initializeRound() {
+
public void fillCircle(double x, double y, double r) {
// Default implementation does nothing
+
int d = i(r * 2);
 +
_g.fillOval(i(x - r), i(y - r), d, d);
 
}
 
}
  
 
/**
 
/**
* Called before events get processed each tick. The default implementation does nothing.
+
* @see java awt.Graphics2D.fillOval(int, int, int, int)
 
*/
 
*/
public void onBeforeEventsProcessed() {
+
public void fillOval(double x, double y, double width, double height) {
// Do nothing
+
_g.fillOval(i(x), i(y), i(width), i(height));
 
}
 
}
  
 
/**
 
/**
* Returns a Point2D.Double object representing the center of the battlefield.
+
* @see java awt.Graphics2D.fillRect(int, int, int, int)
 
*/
 
*/
public Point2D.Double getCenter() {
+
public void fillRect(double x, double y, double width, double height) {  
if(_center == null) {
+
_g.fillRect(i(x), i(y), i(width), i(height));
_center = new Point2D.Double(getBattleFieldWidth() / 2, getBattleFieldHeight() / 2);  
+
}
}
 
  
return _center;
+
/**
 +
* @see java awt.Graphics2D.fillRoundRect(int, int, int, int, int, int)
 +
*/
 +
public void fillRoundRect(double x, double y, double width, double height,
 +
double arcWidth, double arcHeight) {
 +
_g.fillRoundRect(i(x), i(y), i(width), i(height), i(arcWidth),
 +
i(arcHeight));
 
}
 
}
  
 +
/**
 +
* @see java awt.Graphics2D.getBackground()
 +
*/
 +
public Color getBackground() {
 +
return _g.getBackground();
 +
}
  
 
/**
 
/**
* Registers the given EventListener, which will cause it to receive notifications of the events
+
* Returns a Point2D located at the center of the canvas.
* indicated by the listener interfaces it implements.
 
 
*/
 
*/
protected void registerListener(EventListener listener) {
+
public Point2D.Double getCenter() {
_listenerDelegate.register(listener);
+
return _center;
 
}
 
}
  
 
/**
 
/**
* Reigsters the given Component, which will give it the opportunity to act each turn.
+
* @see java awt.Graphics2D.getClip()
 
*/
 
*/
protected void registerComponent(Component component) {
+
public Shape getClip() {
_components.add(component);
+
return _g.getClip();
 
}
 
}
  
 
/**
 
/**
* Reigsters the given Painter, which will give it the opportunity to draw on the HUD each turn.
+
* @see java awt.Graphics2D.getClipBounds()
 
*/
 
*/
protected void registerPainter(Hud.Painter painter) {
+
public Rectangle getClipBounds() {
_painters.add(painter);
+
return _g.getClipBounds();
 
}
 
}
  
 
/**
 
/**
* Hand out notifications to the Painters.
+
* @see java awt.Graphics2D.getClipBounds(java.awt.Rectangle)
 
*/
 
*/
@Override
+
public Rectangle getClipBounds(Rectangle r) {
public final void onPaint(Graphics2D g) {
+
return _g.getClipBounds(r);
_hud.setContext(g); // Inject the graphics context into the Hud
+
}
  
for(Hud.Painter painter : _painters) {
+
/**
painter.paint(_hud, getTime());
+
* @see java awt.Graphics2D.getColor()
}
+
*/
 +
public Color getColor() {
 +
return _g.getColor();
 +
}
  
_hud.setContext(null); // Clear the injected graphics context
+
/**
 +
* @see java awt.Graphics2D.getDeviceConfiguration()
 +
*/
 +
public GraphicsConfiguration getDeviceConfiguration() {
 +
return _g.getDeviceConfiguration();
 
}
 
}
  
 
/**
 
/**
* Process all the events in the queue.
+
* Returns a reference to the actual Graphics2D object wrapped by the
 +
* Canvas.
 
*/
 
*/
private void handleEvents() {
+
public Graphics2D getGraphics() {
onBeforeEventsProcessed();
+
return _g;
_listenerDelegate.processEvents(getAllEvents());
 
clearAllEvents();
 
 
}
 
}
  
// Since we have our own event manager, we want to prevent overrides of the Robocode event
+
/**
// methods, so we'll make them final.
+
* Returns the canvas's height.
 +
*/
 +
public double getHeight() {
 +
return _height;
 +
}
  
@Override
+
/**
public final void onCustomEvent(CustomEvent event) {
+
* @see java awt.Graphics2D.getPaint()
 +
*/
 +
public Paint getPaint() {
 +
return _g.getPaint();
 
}
 
}
  
@Override
+
/**
public final void onDeath(DeathEvent event) {
+
* @see java awt.Graphics2D.getStroke()
 +
*/
 +
public Stroke getStroke() {
 +
return _g.getStroke();
 
}
 
}
  
@Override
+
/**
public final void onSkippedTurn(SkippedTurnEvent event) {
+
* Returns the canvas's width.
 +
*/
 +
public double getWidth() {
 +
return _width;
 
}
 
}
  
@Override
+
/**
public final void onBulletHit(BulletHitEvent event) {
+
* @see java awt.Graphics2D.hit(java.awt.Rectangle, java.awt.Shape, boolean)
 +
*/
 +
public boolean hit(Rectangle rect, Shape s, boolean onStroke) {
 +
return _g.hit(rect, s, onStroke);
 
}
 
}
  
@Override
+
/**
public final void onBulletHitBullet(BulletHitBulletEvent event) {
+
* @see java awt.Graphics2D.hitClip(int, int, int, int)
 +
*/
 +
public boolean hitClip(double x, double y, double width, double height) {
 +
return _g.hitClip(i(x), i(y), i(width), i(height));
 
}
 
}
  
@Override
+
/**
public final void onBulletMissed(BulletMissedEvent event) {
+
* @see java awt.Graphics2D.setBackground(java.awt.Color)
 +
*/
 +
public void setBackground(Color color) {
 +
_g.setBackground(color);
 
}
 
}
  
@Override
+
/**
public final void onHitByBullet(HitByBulletEvent event) {
+
* @see java awt.Graphics2D.setClip(int, int, int, int)
 +
*/
 +
public void setClip(double x, double y, double width, double height) {
 +
_g.setClip(i(x), i(y), i(width), i(height));
 
}
 
}
  
@Override
+
/**
public final void onHitRobot(HitRobotEvent event) {
+
* @see java awt.Graphics2D.setClip(java.awt.Shape)
 +
*/
 +
public void setClip(Shape clip) {
 +
_g.setClip(clip);
 
}
 
}
  
@Override
+
/**
public final void onHitWall(HitWallEvent event) {
+
* @see java awt.Graphics2D.setColor(java.awt.Color)
 +
*/
 +
public void setColor(Color c) {
 +
_g.setColor(c);
 
}
 
}
  
@Override
+
/**
public final void onRobotDeath(RobotDeathEvent event) {
+
* @see java awt.Graphics2D.setPaint(java.awt.Paint)
 +
*/
 +
public void setPaint(Paint paint) {
 +
_g.setPaint(paint);
 
}
 
}
  
@Override
+
/**
public final void onScannedRobot(ScannedRobotEvent event) {
+
* @see java awt.Graphics2D.setStroke(java.awt.Stroke)
 +
*/
 +
public void setStroke(Stroke stroke) {
 +
_g.setStroke(stroke);
 
}
 
}
  
@Override
+
/**
public final void onWin(WinEvent event) {
+
* Rounds a double to the nearest integer and returns it as an int.
 +
*/
 +
private static int i(double d) {
 +
return (int) Math.round(d);
 
}
 
}
 
}
 
}
</nowiki></pre>
+
</nowiki></syntaxhighlight>
  
== Hud.java ==
+
== Component.java ==
<pre><nowiki>
+
<syntaxhighlight><nowiki>
 
/*
 
/*
 
  * PluggableRobot, by Robert J. Walker
 
  * PluggableRobot, by Robert J. Walker
  * Home page: http://robowiki.net/cgi-bin/robowiki?PluggableRobot
+
  * Home page: http://robowiki.net/w/index.php?title=PluggableRobot
  * This software is made available under the RoboWiki Limited Public Code License (RWLPCL). The full
+
  * This software is made available under the RoboWiki Limited Public Code
* text of the license may be found at http://robowiki.net/cgi-bin/robowiki?RWLPCL.
+
* License (RWLPCL). The full text of the license may be found at:
 +
* http://robowiki.net/w/index.php?title=RWLPCL
 
  */
 
  */
 
package rjw.pluggablerobot;
 
package rjw.pluggablerobot;
  
 +
/**
 +
* Components encapsulate the main combat behavior of the robot into pluggable
 +
* modules. Any code that actually sets an action for the robot (moving,
 +
* turning, rotating the turret or radar, etc.) should be done in the go()
 +
* method. Components should NEVER call any blocking methods; PluggableRobot
 +
* will call execute() automatically when all components have had a chance to
 +
* act.
 +
* @author Robert J. Walker
 +
*/
 +
public interface Component {
 +
/**
 +
* Asks this Component to execute any actions that it wants to take this
 +
* turn. PluggableRobot will call this method once per turn for each
 +
* registered Component. Don't put any blocking calls in here;
 +
* PluggableRobot will call execute() for you automatically after calling
 +
* go() on each Component.
 +
*/
 +
public abstract void go();
 +
}
 +
</nowiki></syntaxhighlight>
  
import java.awt.Graphics2D;
+
== EventListener.java ==
import java.awt.Paint;
+
<syntaxhighlight><nowiki>
 +
/*
 +
* PluggableRobot, by Robert J. Walker
 +
* Home page: http://robowiki.net/w/index.php?title=PluggableRobot
 +
* This software is made available under the RoboWiki Limited Public Code
 +
* License (RWLPCL). The full text of the license may be found at:
 +
* http://robowiki.net/w/index.php?title=RWLPCL
 +
*/
 +
package rjw.pluggablerobot;
  
import robocode.Robot;
+
import robocode.*;
  
 
/**
 
/**
  * Facilitates drawing graphics on the arena by automatically converting between values used in
+
  * Event listener interfaces. Objects that wish to be notified of events must
  * calculations to values used for drawing. The graphics context (Graphics2D) is injected into the
+
  * extend one or more of these subinterfaces and register themselves with
  * Hud just before it is handed to Painters, then removed afterward.
+
  * PluggableRobot at the start of the round via the registerListener() method.
 
  * @author Robert J. Walker
 
  * @author Robert J. Walker
 
  */
 
  */
public class Hud {
+
public interface EventListener {
/**
+
public interface BattleEnded extends EventListener {
* Objects which implement this interface can be passed to PluggableRobot.registerPainter(), and
+
/**
* will get their paint() methods called when it's time to draw the HUD.
+
* Called by the ListenerDelegate when the battle ends.
*/
+
*/
public interface Painter {
+
public void notifyBattleEnded(BattleEndedEvent event);
 +
}
 +
 
 +
public interface BulletHitBullet extends EventListener {
 +
/**
 +
* Called by the ListenerDelegate when a bullet fired by your robot has
 +
* hit another bullet.
 +
*/
 +
public void notifyBulletHitBullet(BulletHitBulletEvent event);
 +
}
 +
 
 +
public interface BulletHit extends EventListener {
 +
/**
 +
* Called by the ListenerDelegate when a bullet fired by your robot has
 +
* hit another robot.
 +
*/
 +
public void notifyBulletHit(BulletHitEvent event);
 +
}
 +
 
 +
public interface BulletMissed extends EventListener {
 +
/**
 +
* Called by the ListenerDelegate when a bullet fired by your robot has
 +
* hit a wall.
 +
*/
 +
public void notifyBulletMissed(BulletMissedEvent event);
 +
}
 +
 
 +
public interface Death extends EventListener {
 +
/**
 +
* Called by the ListenerDelegate when your robot has been destroyed.
 +
*/
 +
public void notifyDeath(DeathEvent event);
 +
}
 +
 
 +
public interface HitByBullet extends EventListener {
 
/**
 
/**
* This method will be called by PluggableRobot when it's time for this object to draw.
+
* Called by the ListenerDelegate when your robot has been hit by an
 +
* enemy bullet.
 
*/
 
*/
public void paint(Hud hud, long tick);
+
public void notifyHitByBullet(HitByBulletEvent event);
 
}
 
}
  
private Graphics2D _g;
+
public interface HitRobot extends EventListener {
 +
/**
 +
* Called by the ListenerDelegate when your robot has collided with
 +
* another robot.
 +
*/
 +
public void notifyHitRobot(HitRobotEvent event);
 +
}
  
public double _w;
+
public interface HitWall extends EventListener {
public double _h;
+
/**
 +
* Called by the ListenerDelegate when your robot has collided with a
 +
* wall.
 +
*/
 +
public void notifyHitWall(HitWallEvent event);
 +
}
  
/**
+
public interface RobotDeath extends EventListener {
* Creates a new Hud object.
+
/**
*/
+
* Called by the ListenerDelegate when an enemy robot has been
public Hud(Robot bot) {
+
* destroyed.
_w = bot.getBattleFieldWidth();
+
*/
_h = bot.getBattleFieldHeight();
+
public void notifyRobotDeath(RobotDeathEvent event);
 
}
 
}
  
/**
+
public interface ScannedRobot extends EventListener {
* Draws a point at the given coordinates.
+
/**
*/
+
* Called by the ListenerDelegate when your radar has swept over an
public void drawPoint(double x, double y) {
+
* enemy robot.
int x0 = i(x);
+
*/
int y0 = i(y);
+
public void notifyScannedRobot(ScannedRobotEvent event);
_g.drawLine(x0, y0, x0, y0);
 
 
}
 
}
  
/**
+
public interface SkippedTurn extends EventListener {
* Draws a line between the two indicated points.
+
/**
*/
+
* Called by the ListenerDelegate when your robot has skipped a turn.
public void drawLine(double x1, double y1, double x2, double y2) {
+
*/
_g.drawLine(i(x1), i(y1), i(x2), i(y2));
+
public void notifySkippedTurn(SkippedTurnEvent event);
 
}
 
}
  
/**
+
public interface Status extends EventListener {
* Draws a circle with the given center point and radius.
+
/**
*/
+
* Called by the ListenerDelegate every turn with a robot status update.
public void drawCircle(double x, double y, double r) {
+
*/
int d = i(r * 2);
+
public void notifyStatus(StatusEvent event);
_g.drawOval(i(x - r), i(y - r), d, d);
 
 
}
 
}
  
public void drawArc(double x, double y, double r, double start, double extend) {
+
public interface Win extends EventListener {
int d = i(r * 2);
+
/**
_g.drawArc(i(x - r), i(y - r), d, d, i(Math2.radToDeg(start)), i(Math2.radToDeg(extend)));
+
* Called by the ListenerDelegate when all robots besides yours have
 +
* been destroyed.
 +
*/
 +
public void notifyWin(WinEvent event);
 
}
 
}
 +
 +
 +
// Internal event listeners
  
 
/**
 
/**
* Draws a rectangle with the given position and dimensions.
+
* An EventListener used only by the Hud to inform it of KeyPressedEvents
 +
* so that it handle requests to toggle layers.
 
*/
 
*/
public void drawRect(double x, double y, double w, double h) {
+
interface _KeyPressed extends EventListener {
_g.drawRect(i(x), i(y), i(w), i(h));
+
/**
 +
* Notifies the Hud that a key was pressed.
 +
*/
 +
public void notifyKeyPressed(KeyPressedEvent event);
 
}
 
}
  
 
/**
 
/**
* Draws a filled rectangle with the given position and dimensions.
+
* An EventListener used only by the ListenerDelegate to inform it of
 +
* PaintEvents. The ListenerDelegate registers with itself as being
 +
* interested in this event. This is the connection point for
 +
* PluggableRobot's debug graphics harness.
 
*/
 
*/
public void drawFilledRect(double x, double y, double w, double h) {
+
interface _Paint extends EventListener {
_g.fillRect(i(x), i(y), i(w), i(h));
+
/**
 +
* Notifies the ListenerDelegate that a PaintEvent has been received.
 +
*/
 +
public void notifyPaint(PaintEvent event);
 +
}
 +
}
 +
</nowiki></syntaxhighlight>
 +
 
 +
== Hud.java ==
 +
<syntaxhighlight><nowiki>
 +
/*
 +
* PluggableRobot, by Robert J. Walker
 +
* Home page: http://robowiki.net/w/index.php?title=PluggableRobot
 +
* This software is made available under the RoboWiki Limited Public Code
 +
* License (RWLPCL). The full text of the license may be found at:
 +
* http://robowiki.net/w/index.php?title=RWLPCL
 +
*/
 +
package rjw.pluggablerobot;
 +
 
 +
import java.util.ArrayList;
 +
 
 +
import rjw.pluggablerobot.EventListener._KeyPressed;
 +
import robocode.AdvancedRobot;
 +
import robocode.KeyPressedEvent;
 +
 
 +
/**
 +
* The Hud is responsible for drawing debug graphics. The Hud has multiple
 +
* layers, each of which can be enabled or disabled independently through a key
 +
* binding. Any object which is interested in contributing to the Hud must
 +
* register itself with PluggableRobot, declaring which layer it wishes to paint
 +
* on. Layers are painted in the order in which they were declared, and
 +
* individual painters are invoked in the order that they were registered for
 +
* that layer.
 +
*
 +
* Concept based on previous work by Nfwu and David Alves:
 +
* http://robowiki.net/w/index.php?title=User:Nfwu/Painter
 +
*
 +
* @author Robert J. Walker
 +
*/
 +
public class Hud implements _KeyPressed {
 +
private Canvas _canvas;
 +
private ArrayList<Layer> _layers = new ArrayList<Layer>();
 +
 
 +
public Hud(AdvancedRobot bot) {
 +
_canvas = new Canvas(bot);
 
}
 
}
  
 
/**
 
/**
* Draws a left-aligned String at the given position.
+
* Constructs a new Layer with the given name and bound to the indicated
 +
* key. The enabled argument determines whether or not the layer should
 +
* be on or off by default.
 
*/
 
*/
public void drawString(String s, double x, double y) {
+
public void createLayer(int key, String name, boolean enabled) {
_g.drawString(s, i(x), i(y));
+
Layer layer = new Layer(key, name, enabled);
 +
_layers.add(layer);
 
}
 
}
  
 
/**
 
/**
* Draws a right-aligned String at the given position.
+
* Registers a painter with the layer bound to the given key.
 
*/
 
*/
public void drawStringRight(String s, double x, double y) {
+
public void registerPainter(int key, Painter painter) {
_g.drawString(s, i(x) - _g.getFontMetrics().stringWidth(s), i(y));
+
for (Layer layer : _layers) {
 +
if (layer.getKey() == key) {
 +
layer.addPainter(painter);
 +
return;
 +
}
 +
}
 +
 
 +
throw new IllegalArgumentException("No layer bound to that key!");
 
}
 
}
  
 
/**
 
/**
* Sets the Hud's current drawing paint.
+
* Notifes the Hud that a key was pressed, and toggles the corresponding
 +
* layer, if it exists.
 
*/
 
*/
public void setPaint(Paint c) {
+
@Override
_g.setPaint(c);
+
public void notifyKeyPressed(KeyPressedEvent event) {
 +
Layer layer = getLayer(event.getSourceEvent().getKeyCode());
 +
 +
if (layer != null) {
 +
layer.toggle();
 +
}
 
}
 
}
  
 
/**
 
/**
* Returns the width of the battlefield. This is useful in situations where you don't have
+
* Called by PluggableRobot when it's time to paint the Hud.
* access to the robot object.
 
 
*/
 
*/
public double getWidth() {
+
void paint(long tick) {
return _w;
+
for (Layer layer : _layers) {
 +
layer.paint(_canvas, tick);
 +
}
 
}
 
}
  
 
/**
 
/**
* Returns the height of the battlefield. This is useful in situations where you don't have
+
* Returns the layer bound to the given key.
* access to the robot object.
 
 
*/
 
*/
public double getHeight() {
+
private Layer getLayer(int key) {
return _h;
+
for (Layer layer : _layers) {
 +
if (layer.getKey() == key) {
 +
return layer;
 +
}
 +
}
 +
 
 +
return null;
 
}
 
}
 +
  
 
/**
 
/**
* Allows PluggableRobot to inject the graphics context into the Hud.
+
* Objects which implement the Painter interface and are registered
 +
* PluggableRobot will get their paint() methods called when it is time for
 +
* them to paint. Note that any one object that implements Painter may only
 +
* paint on one layer of the Hud.
 
*/
 
*/
public void setContext(Graphics2D g) {
+
public interface Painter {
_g = g;
+
/**
 +
* Notifies the Painter that it's time to paint, and provides it with a
 +
* Canvas object to paint with.
 +
*/
 +
public void paint(Canvas canvas, long tick);
 
}
 
}
  
 
/**
 
/**
* Rounds the given double value to the nearest int.
+
* A single Hud layer, responsible for painting itself by calling the
 +
* Painters that which to paint on it.  
 
*/
 
*/
private int i(double val) {
+
private static class Layer {
return (int) Math.round(val);
+
private int _key;
 +
private String _name;
 +
private boolean _enabled;
 +
private ArrayList<Painter> _painters = new ArrayList<Painter>();
 +
 
 +
/**
 +
* Constructs a new Layer with the given name and bound to the indicated
 +
* key. The enabled argument determines whether or not the layer should
 +
* be on or off by default.
 +
*/
 +
Layer(int key, String name, boolean enabled) {
 +
_key = key;
 +
_name = name;
 +
_enabled = enabled;
 +
}
 +
 
 +
/**
 +
* Returns the key to which this Layer is bound.
 +
*/
 +
int getKey() {
 +
return _key;
 +
}
 +
 
 +
/**
 +
* Returns this Layer's name.
 +
*/
 +
String getName() {
 +
return _name;
 +
}
 +
 
 +
/**
 +
* Adds a new Painter to this Layer.
 +
*/
 +
void addPainter(Painter painter) {
 +
_painters.add(painter);
 +
}
 +
 
 +
/**
 +
* Returns whether or not this Layer is enabled.
 +
*/
 +
boolean isEnabled() {
 +
return _enabled;
 +
}
 +
 
 +
/**
 +
* Toggles this Layer between being enabled and disabled.
 +
*/
 +
void toggle() {
 +
_enabled = !_enabled;
 +
}
 +
 
 +
/**
 +
* Notifies the Painter that it's time to paint, and provides it with a
 +
* Canvas object to paint with.
 +
*/
 +
void paint(Canvas canvas, long tick) {
 +
if (!_enabled) {
 +
return;
 +
}
 +
 
 +
for (Painter painter : _painters) {
 +
painter.paint(canvas, tick);
 +
}
 +
}
 
}
 
}
 
}
 
}
</nowiki></pre>
+
</nowiki></syntaxhighlight>
  
 
== ListenerDelegate.java ==
 
== ListenerDelegate.java ==
<pre><nowiki>
+
<syntaxhighlight><nowiki>
 
/*
 
/*
 
  * PluggableRobot, by Robert J. Walker
 
  * PluggableRobot, by Robert J. Walker
  * Home page: http://robowiki.net/cgi-bin/robowiki?PluggableRobot
+
  * Home page: http://robowiki.net/w/index.php?title=PluggableRobot
  * This software is made available under the RoboWiki Limited Public Code License (RWLPCL). The full
+
  * This software is made available under the RoboWiki Limited Public Code
* text of the license may be found at http://robowiki.net/cgi-bin/robowiki?RWLPCL.
+
* License (RWLPCL). The full text of the license may be found at:
 +
* http://robowiki.net/w/index.php?title=RWLPCL
 
  */
 
  */
 
package rjw.pluggablerobot;
 
package rjw.pluggablerobot;
Line 394: Line 709:
  
 
/**
 
/**
  * Class that manages all the event listeners for a PluggableRobot and delegates events to the
+
  * Class that manages all the event listeners for a PluggableRobot and delegates
* appropriate EventListeners. Unlike the default Robocode behavior, events are doled out first by
+
* events to the appropriate EventListeners. Unlike the default Robocode
* listener (first registered, first notified), then by the order of the listener interfaces
+
* behavior, events are doled out first by listener (first registered, first
  * declared on the listener implementation. So a class with a declaration like this:
+
* notified), then by the order of the listener interfaces declared on the
  *     public class MyClass implements ScannedRobotListener, EventListener.Death
+
  * listener implementation. This allows each component to get notified of events
  * ...will get notified of the ScannedRobotEvent *before* the DeathEvent!
+
  * in any order it likes, regardless of event priorities or the order used by
 +
* other components.
 +
  *  
 +
* PaintEvents are handled differently; they are captured and held until all
 +
* EventListeners have been notified and Components have acted, so that as much
 +
* information as possible is available for debug painting.
 +
*  
 
  * @author Robert J. Walker
 
  * @author Robert J. Walker
 
  */
 
  */
public class ListenerDelegate {
+
public class ListenerDelegate implements EventListener._Paint {
private ArrayList<EventListener> _listeners = new ArrayList<EventListener>();
+
private static HashMap<Class, Invoker> _invokers;
private static HashMap<Class<? extends EventListener>, ListenerInvoker> _invokers;
 
  
// Build the invoker map, allowing us to look up invokers by listener class
+
// Build the invoker map, so we can look up invokers by listener class
 
static {
 
static {
_invokers = new HashMap<Class<? extends EventListener>, ListenerInvoker>();
+
_invokers = new HashMap<Class, Invoker>();
_invokers.put(EventListener.Death.class,
+
 
new ListenerInvoker<EventListener.Death, DeathEvent>() {
+
// interal paint event listener
protected Class<DeathEvent> eventClass() { return DeathEvent.class; }
+
_invokers.put(_Paint.class, new Invoker() {
protected void invokeListener(EventListener.Death listener, DeathEvent event) {
+
protected boolean consumesEvent(Event event) {
listener.notifyDeath(event);
+
return event instanceof PaintEvent;
}
+
}
}
+
 
);
+
protected void invoke(EventListener listener, Event event) {
_invokers.put(EventListener.Win.class,
+
((_Paint) listener).notifyPaint((PaintEvent) event);
new ListenerInvoker<EventListener.Win, WinEvent>() {
+
}
protected Class<WinEvent> eventClass() { return WinEvent.class; }
+
});
protected void invokeListener(EventListener.Win listener, WinEvent event) {
+
 
listener.notifyWin(event);
+
// interal key pressed event listener
}
+
_invokers.put(_KeyPressed.class, new Invoker() {
}
+
protected boolean consumesEvent(Event event) {
);
+
return event instanceof KeyPressedEvent;
_invokers.put(EventListener.SkippedTurn.class,
+
}
new ListenerInvoker<EventListener.SkippedTurn, SkippedTurnEvent>() {
+
 
protected Class<SkippedTurnEvent> eventClass() { return SkippedTurnEvent.class; }
+
protected void invoke(EventListener listener, Event event) {
protected void invokeListener(EventListener.SkippedTurn listener, SkippedTurnEvent event) {
+
((_KeyPressed) listener).notifyKeyPressed(
listener.notifySkippedTurn(event);
+
(KeyPressedEvent) event
}
+
);
}
+
}
);
+
});
_invokers.put(EventListener.ScannedRobot.class,
+
 
new ListenerInvoker<EventListener.ScannedRobot, ScannedRobotEvent>() {
+
// battle ended
protected Class<ScannedRobotEvent> eventClass() { return ScannedRobotEvent.class; }
+
_invokers.put(EventListener.BattleEnded.class, new Invoker() {
protected void invokeListener(EventListener.ScannedRobot listener, ScannedRobotEvent event) {
+
protected boolean consumesEvent(Event event) {
listener.notifyScannedRobot(event);
+
return event instanceof BattleEndedEvent;
}
+
}
}
+
 
);
+
protected void invoke(EventListener listener, Event event) {
_invokers.put(EventListener.HitByBullet.class,
+
((EventListener.BattleEnded) listener).notifyBattleEnded(
new ListenerInvoker<EventListener.HitByBullet, HitByBulletEvent>() {
+
(BattleEndedEvent) event
protected Class<HitByBulletEvent> eventClass() { return HitByBulletEvent.class; }
+
);
protected void invokeListener(EventListener.HitByBullet listener, HitByBulletEvent event) {
+
}
listener.notifyHitByBullet(event);
+
});
}
+
 
}
+
// bullet hit
);
+
_invokers.put(EventListener.BulletHit.class, new Invoker() {
_invokers.put(EventListener.BulletHit.class,
+
protected boolean consumesEvent(Event event) {
new ListenerInvoker<EventListener.BulletHit, BulletHitEvent>() {
+
return event instanceof BulletHitEvent;
protected Class<BulletHitEvent> eventClass() { return BulletHitEvent.class; }
+
}
protected void invokeListener(EventListener.BulletHit listener, BulletHitEvent event) {
+
 
listener.notifyBulletHit(event);
+
protected void invoke(EventListener listener, Event event) {
}
+
((EventListener.BulletHit) listener).notifyBulletHit(
}
+
(BulletHitEvent) event
);
+
);
_invokers.put(EventListener.BulletHitBullet.class,
+
}
new ListenerInvoker<EventListener.BulletHitBullet, BulletHitBulletEvent>() {
+
});
protected Class<BulletHitBulletEvent> eventClass() { return BulletHitBulletEvent.class; }
+
 
protected void invokeListener(EventListener.BulletHitBullet listener, BulletHitBulletEvent event) {
+
// bullet hit bullet
listener.notifyBulletHitBullet(event);
+
_invokers.put(EventListener.BulletHitBullet.class, new Invoker() {
}
+
protected boolean consumesEvent(Event event) {
}
+
return event instanceof BulletHitBulletEvent;
);
+
}
_invokers.put(EventListener.BulletMissed.class,
+
 
new ListenerInvoker<EventListener.BulletMissed, BulletMissedEvent>() {
+
protected void invoke(EventListener listener, Event event) {
protected Class<BulletMissedEvent> eventClass() { return BulletMissedEvent.class; }
+
((EventListener.BulletHitBullet) listener)
protected void invokeListener(EventListener.BulletMissed listener, BulletMissedEvent event) {
+
.notifyBulletHitBullet((BulletHitBulletEvent) event);
listener.notifyBulletMissed(event);
+
}
}
+
});
}
+
 
);
+
// bullet missed
_invokers.put(EventListener.HitRobot.class,
+
_invokers.put(EventListener.BulletMissed.class, new Invoker() {
new ListenerInvoker<EventListener.HitRobot, HitRobotEvent>() {
+
protected boolean consumesEvent(Event event) {
protected Class<HitRobotEvent> eventClass() { return HitRobotEvent.class; }
+
return event instanceof BulletMissedEvent;
protected void invokeListener(EventListener.HitRobot listener, HitRobotEvent event) {
+
}
listener.notifyHitRobot(event);
+
 
}
+
protected void invoke(EventListener listener, Event event) {
}
+
((EventListener.BulletMissed) listener).notifyBulletMissed(
);
+
(BulletMissedEvent) event
_invokers.put(EventListener.HitWall.class,
+
);
new ListenerInvoker<EventListener.HitWall, HitWallEvent>() {
+
}
protected Class<HitWallEvent> eventClass() { return HitWallEvent.class; }
+
});
protected void invokeListener(EventListener.HitWall listener, HitWallEvent event) {
+
 
listener.notifyHitWall(event);
+
// death
}
+
_invokers.put(EventListener.Death.class, new Invoker() {
}
+
protected boolean consumesEvent(Event event) {
);
+
return event instanceof DeathEvent;
_invokers.put(EventListener.RobotDeath.class,
+
}
new ListenerInvoker<EventListener.RobotDeath, RobotDeathEvent>() {
+
 
protected Class<RobotDeathEvent> eventClass() { return RobotDeathEvent.class; }
+
protected void invoke(EventListener listener, Event event) {
protected void invokeListener(EventListener.RobotDeath listener, RobotDeathEvent event) {
+
((EventListener.Death) listener).notifyDeath(
listener.notifyRobotDeath(event);
+
(DeathEvent) event
}
+
);
}
+
}
);
+
});
 +
 
 +
// hit by bullet
 +
_invokers.put(EventListener.HitByBullet.class, new Invoker() {
 +
protected boolean consumesEvent(Event event) {
 +
return event instanceof HitByBulletEvent;
 +
}
 +
 
 +
protected void invoke(EventListener listener, Event event) {
 +
((EventListener.HitByBullet) listener).notifyHitByBullet(
 +
(HitByBulletEvent) event
 +
);
 +
}
 +
});
 +
 
 +
// hit robot
 +
_invokers.put(EventListener.HitRobot.class, new Invoker() {
 +
protected boolean consumesEvent(Event event) {
 +
return event instanceof HitRobotEvent;
 +
}
 +
 
 +
protected void invoke(EventListener listener, Event event) {
 +
((EventListener.HitRobot) listener).notifyHitRobot(
 +
(HitRobotEvent) event
 +
);
 +
}
 +
});
 +
 
 +
// hit wall
 +
_invokers.put(EventListener.HitWall.class, new Invoker() {
 +
protected boolean consumesEvent(Event event) {
 +
return event instanceof HitWallEvent;
 +
}
 +
 
 +
protected void invoke(EventListener listener, Event event) {
 +
((EventListener.HitWall) listener).notifyHitWall(
 +
(HitWallEvent) event
 +
);
 +
}
 +
});
 +
 
 +
// robot death
 +
_invokers.put(EventListener.RobotDeath.class, new Invoker() {
 +
protected boolean consumesEvent(Event event) {
 +
return event instanceof RobotDeathEvent;
 +
}
 +
 
 +
protected void invoke(EventListener listener, Event event) {
 +
((EventListener.RobotDeath) listener).notifyRobotDeath(
 +
(RobotDeathEvent) event
 +
);
 +
}
 +
});
 +
 
 +
// scanned robot
 +
_invokers.put(EventListener.ScannedRobot.class, new Invoker() {
 +
protected boolean consumesEvent(Event event) {
 +
return event instanceof ScannedRobotEvent;
 +
}
 +
 
 +
protected void invoke(EventListener listener, Event event) {
 +
((EventListener.ScannedRobot) listener).notifyScannedRobot(
 +
(ScannedRobotEvent) event
 +
);
 +
}
 +
});
 +
 
 +
// skipped turn
 +
_invokers.put(EventListener.SkippedTurn.class, new Invoker() {
 +
protected boolean consumesEvent(Event event) {
 +
return event instanceof SkippedTurnEvent;
 +
}
 +
 
 +
protected void invoke(EventListener listener, Event event) {
 +
((EventListener.SkippedTurn) listener).notifySkippedTurn(
 +
(SkippedTurnEvent) event
 +
);
 +
}
 +
});
 +
 
 +
// status
 +
_invokers.put(EventListener.Status.class, new Invoker() {
 +
protected boolean consumesEvent(Event event) {
 +
return event instanceof StatusEvent;
 +
}
 +
 
 +
protected void invoke(EventListener listener, Event event) {
 +
((EventListener.Status) listener).notifyStatus(
 +
(StatusEvent) event
 +
);
 +
}
 +
});
 +
 
 +
// win
 +
_invokers.put(EventListener.Win.class, new Invoker() {
 +
protected boolean consumesEvent(Event event) {
 +
return event instanceof WinEvent;
 +
}
 +
 
 +
protected void invoke(EventListener listener, Event event) {
 +
((EventListener.Win) listener).notifyWin((WinEvent) event);
 +
}
 +
});
 +
}
 +
 
 +
 
 +
private ArrayList<EventListener> _listeners =
 +
new ArrayList<EventListener>();
 +
private PaintEvent _lastPaintEvent = null;
 +
 
 +
public ListenerDelegate() {
 +
register(this); // register itself for the PaintEvent
 
}
 
}
  
Line 509: Line 940:
 
* Hand out event notifications to the EventListeners.  
 
* Hand out event notifications to the EventListeners.  
 
*/
 
*/
public void processEvents(Vector<Event> events) {
+
public void processEvents(List<Event> events) {
 
// Notify listeners in the order they were registered
 
// Notify listeners in the order they were registered
for(EventListener listener : _listeners) {
+
for (EventListener listener : _listeners) {
 
Class[] interfaces = listener.getClass().getInterfaces();
 
Class[] interfaces = listener.getClass().getInterfaces();
  
// Iterate the interfaces on each listener that descend from EventListener
+
// Iterate the interfaces on each listener
for(Class iface : interfaces) {
+
for (Class iface : interfaces) {
if(!EventListener.class.isAssignableFrom(iface)) continue;
+
// Skip if interface does not descend from EventListener
 +
if (!EventListener.class.isAssignableFrom(iface)) {
 +
continue;
 +
}
 +
 
 +
// Get the invoker for this interface
 +
Invoker invoker = _invokers.get(iface);
  
// Get the invoker and the corresponding event class for this interface
+
// Find the events this invoker consumes
ListenerInvoker invoker = _invokers.get(iface);
+
for (Event event : events) {
Class<? extends Event> eventClass = invoker.eventClass();
+
// Skip if listener isn't interested in this kind of event
 +
if (!invoker.consumesEvent(event)) {
 +
continue;
 +
}
  
// Iterate the events and hand the ones of the proper type to the invoker
+
// Notify the listener
for(Event event : events) {
+
invoker.invoke(listener, event);
if(!eventClass.isAssignableFrom(event.getClass())) continue;
 
invoker.invokeListener(listener, event);
 
 
}
 
}
 
}
 
}
Line 531: Line 969:
 
}
 
}
  
 
 
/**
 
/**
* An object that knows about a Robocode Event class and how to invoke its corresponding
+
* Called by a special internal EventListener to handle PaintEvents.
* EventListener.
+
*/
* @author Robert J. Walker
+
@Override
 +
public void notifyPaint(PaintEvent event) {
 +
_lastPaintEvent = event;
 +
}
 +
 
 +
/**
 +
* Returns the most recently received PaintEvent, or null if no PaintEvent
 +
* has been received.
 +
*/
 +
public PaintEvent getLastPaintEvent() {
 +
return _lastPaintEvent;
 +
}
 +
 
 +
 
 +
/**
 +
* An object that knows about a Robocode Event class and how to invoke its
 +
* corresponding EventListener.
 
*/
 
*/
private static abstract class ListenerInvoker<K extends EventListener, V extends Event> {
+
private static abstract class Invoker {
/**
+
protected abstract boolean consumesEvent(Event event);
* Returns the Robocode Event class handled by this ListenerInvoker.
 
*/
 
protected abstract Class<V> eventClass();
 
  
 
/**
 
/**
 
* Invokes the given EventListener, passing in a Robocode Event object.
 
* Invokes the given EventListener, passing in a Robocode Event object.
 
*/
 
*/
protected abstract void invokeListener(K listener, V event);
+
protected abstract void invoke(EventListener listener, Event event);
 
}
 
}
 
}
 
}
</nowiki></pre>
+
</nowiki></syntaxhighlight>
  
 
== Math2.java ==
 
== Math2.java ==
<pre><nowiki>
+
<syntaxhighlight><nowiki>
 
/*
 
/*
 
  * PluggableRobot, by Robert J. Walker
 
  * PluggableRobot, by Robert J. Walker
  * Home page: http://robowiki.net/cgi-bin/robowiki?PluggableRobot
+
  * Home page: http://robowiki.net/w/index.php?title=PluggableRobot
  * This software is made available under the RoboWiki Limited Public Code License (RWLPCL). The full
+
  * This software is made available under the RoboWiki Limited Public Code
* text of the license may be found at http://robowiki.net/cgi-bin/robowiki?RWLPCL.
+
* License (RWLPCL). The full text of the license may be found at:
 +
* http://robowiki.net/w/index.php?title=RWLPCL
 
  */
 
  */
 
package rjw.pluggablerobot;
 
package rjw.pluggablerobot;
Line 567: Line 1,018:
  
 
/**
 
/**
  * Math utility class.
+
  * Math utility class. Note that trig functions are reversed in order to provide
 +
* correct results for the Robocode coordinate system.
 +
*
 
  * @author Robert J. Walker
 
  * @author Robert J. Walker
 
  */
 
  */
Line 586: Line 1,039:
  
 
     /**
 
     /**
    * Returns a random double value between 0.0 (inclusive) and 1.0 (exclusive).
+
     * If value is less than min, returns min. If value is greater than max,
    */
+
    * returns max. Otherwise, returns value.
    public static double randomDouble() {
 
    return random.nextDouble();
 
    }
 
 
 
    /**
 
     * If value is less than min, returns min. If value is greater than max, returns max. Otherwise,
 
    * returns value.
 
 
     */
 
     */
 
     public static double limit(double min, double value, double max) {
 
     public static double limit(double min, double value, double max) {
Line 601: Line 1,047:
  
 
     /**
 
     /**
     * Adds the X and Y components of the given Point2D.Double objects and returns a new
+
     * Adds the X and Y components of the given Point2D.Double objects and
    * Point2D.Double object with the result.
+
    * returns a new Point2D.Double object with the result.
 
     */
 
     */
     public static Point2D.Double add(Point2D.Double point1, Point2D.Double point2) {
+
     public static Point2D.Double add(Point2D.Double point1,
 +
    Point2D.Double point2) {
 
return new Point2D.Double(point1.x + point2.x, point1.y + point2.y);
 
return new Point2D.Double(point1.x + point2.x, point1.y + point2.y);
 
}
 
}
  
 
     /**
 
     /**
     * Subtracts the X and Y components of the second given Point2D.Double object from those of the
+
     * Subtracts the X and Y components of the second given Point2D.Double
    * first and returns a new Point2D.Double object with the result.
+
    * object from those of the first and returns a new Point2D.Double object
 +
    * with the result.
 
     */
 
     */
 
public static Point2D.Double subtract(Point2D.Double point1, Point2D.Double point2) {
 
public static Point2D.Double subtract(Point2D.Double point1, Point2D.Double point2) {
Line 617: Line 1,065:
  
 
/**
 
/**
* Returns the absolute bearing in radians from the given origin point to the given target
+
* Returns the absolute bearing in radians from the given origin point to
* point.
+
* the given target point.
 
*/
 
*/
public static double getAbsoluteTargetBearing(Point2D.Double origin, Point2D.Double target) {
+
public static double getAbsoluteTargetBearing(Point2D.Double origin,
return Utils.normalAbsoluteAngle(Math.atan2(target.x - origin.x, target.y - origin.y));
+
Point2D.Double target) {
 +
return Utils.normalAbsoluteAngle(Math.atan2(target.x - origin.x,
 +
target.y - origin.y));
 
}
 
}
  
 
/**
 
/**
* Returns a Point2D.Double object indicating the relative position of an object at the given
+
* Returns a Point2D.Double object indicating the relative position of an
* angle and distance from the origin.
+
* object at the given angle (in radians) and distance from the origin.
 
*/
 
*/
public static Point2D.Double getRelativePosition(double angle, double distance) {
+
public static Point2D.Double getRelativePosition(double angle,
 +
double distance) {
 
double dx = distance * Math.sin(angle);
 
double dx = distance * Math.sin(angle);
 
double dy = distance * Math.cos(angle);
 
double dy = distance * Math.cos(angle);
Line 635: Line 1,086:
  
 
/**
 
/**
* Returns a Point2D.Double object indicating the position of an object at the given angle and
+
* Returns a Point2D.Double object indicating the position of an object at
* distance from the given origin point.
+
* the given angle (in radians) and distance from the given origin point.
 
*/
 
*/
public static Point2D.Double getAbsolutePosition(Point2D.Double origin, double angle, double distance) {
+
public static Point2D.Double getAbsolutePosition(Point2D.Double origin,
 +
double angle, double distance) {
 
double x = origin.x + distance * Math.sin(angle);
 
double x = origin.x + distance * Math.sin(angle);
 
double y = origin.y + distance * Math.cos(angle);
 
double y = origin.y + distance * Math.cos(angle);
Line 648: Line 1,100:
 
     */
 
     */
 
     public static double degToRad(double degrees) {
 
     public static double degToRad(double degrees) {
     return degrees * Math.PI / 180;
+
     return Math.toRadians(degrees);
 
     }
 
     }
  
Line 655: Line 1,107:
 
     */
 
     */
 
     public static double radToDeg(double radians) {
 
     public static double radToDeg(double radians) {
     return radians * 180 / Math.PI;
+
     return Math.toDegrees(radians);
 
     }
 
     }
 
}
 
}
</nowiki></pre>
+
</nowiki></syntaxhighlight>
  
 
== PluggableRobot.java ==
 
== PluggableRobot.java ==
<pre><nowiki>
+
<syntaxhighlight><nowiki>
 
/*
 
/*
 
  * PluggableRobot, by Robert J. Walker
 
  * PluggableRobot, by Robert J. Walker
  * Home page: http://robowiki.net/cgi-bin/robowiki?PluggableRobot
+
  * Home page: http://robowiki.net/w/index.php?title=PluggableRobot
  * This software is made available under the RoboWiki Limited Public Code License (RWLPCL). The full
+
  * This software is made available under the RoboWiki Limited Public Code
* text of the license may be found at http://robowiki.net/cgi-bin/robowiki?RWLPCL.
+
* License (RWLPCL). The full text of the license may be found at:
 +
* http://robowiki.net/w/index.php?title=RWLPCL
 
  */
 
  */
 
package rjw.pluggablerobot;
 
package rjw.pluggablerobot;
  
 
import java.awt.Graphics2D;
 
import java.awt.Graphics2D;
 +
import java.awt.event.KeyEvent;
 +
import java.awt.event.MouseEvent;
 +
import java.awt.event.MouseWheelEvent;
 
import java.awt.geom.Point2D;
 
import java.awt.geom.Point2D;
 
import java.util.ArrayList;
 
import java.util.ArrayList;
  
 +
import rjw.pluggablerobot.Hud.Painter;
 
import robocode.*;
 
import robocode.*;
  
 
/**
 
/**
  * A pluggable listener and strategy architecture for a robot.
+
  * An abstract robot class that provides a pluggable architecture, sophisticated
  * http://robowiki.net/cgi-bin/robowiki?PluggableRobot
+
* event management and advanced debug graphics handling.
  * @author Robert J. Walker
+
  *  
 +
  * @author Robert Walker
 
  */
 
  */
 
public abstract class PluggableRobot extends AdvancedRobot {
 
public abstract class PluggableRobot extends AdvancedRobot {
 
private static boolean _battleInitialized = false;
 
private static boolean _battleInitialized = false;
private static Hud _hud;
+
private static Point2D.Double _center;
  
 
private ListenerDelegate _listenerDelegate;
 
private ListenerDelegate _listenerDelegate;
private ArrayList<Component> _components;
+
private ArrayList<Component> _components = new ArrayList<Component>();
private ArrayList<Hud.Painter> _painters;
+
private Hud _hud;
private Point2D.Double _center;
 
  
/**
+
public PluggableRobot() {
* Sets up the ListenerDelegate and the Component and Painter lists.
 
*/
 
protected PluggableRobot() {
 
 
_listenerDelegate = new ListenerDelegate();
 
_listenerDelegate = new ListenerDelegate();
_components = new ArrayList<Component>();
 
_painters = new ArrayList<Hud.Painter>();
 
 
}
 
}
  
 
/**
 
/**
* Set up the robot, then continuously collect events and invoke components.
+
* PluggableRobot's main execution loop. Rather that implementing run() in
 +
* your own robot, you will register listeners, components and painters in
 +
* the initRound() method, and those objects will handle your robot's combat
 +
* logic. This allows you to more easily separate concerns into separate
 +
* objects, and replace parts to change robot behavior.
 
*/
 
*/
 
@Override
 
@Override
 
public final void run() {
 
public final void run() {
 
// Initialize battle (at start of first round only)
 
// Initialize battle (at start of first round only)
if(!_battleInitialized) {
+
if (!_battleInitialized) {
_hud = new Hud(this);
+
_center = new Point2D.Double(getWidth() / 2, getHeight() / 2);
initializeBattle();
+
initBattle();
 
_battleInitialized = true;
 
_battleInitialized = true;
 
}
 
}
  
// Register custom event test() hook for event manager
+
// Mechanism for capturing all events and handing them to the
 +
// ListenerDelegate.
 
addCustomEvent(new Condition("eventManager") {
 
addCustomEvent(new Condition("eventManager") {
 
public boolean test() {
 
public boolean test() {
Line 719: Line 1,176:
 
});
 
});
  
// Round is starting
+
// Initialize the Hud
initializeRound();
+
_hud = new Hud(this);
 +
registerListener(_hud);
 +
 
 +
// Allow robot to initialize its parts
 +
initRound();
  
 
// Main loop
 
// Main loop
while(true) {
+
while (true) {
for(Component component : _components) {
+
// Let each component act
 +
for (Component component : _components) {
 
component.go();
 
component.go();
 +
}
 +
 +
// Handle painting
 +
PaintEvent pe = _listenerDelegate.getLastPaintEvent();
 +
 +
if (pe != null && pe.getTime() == getTime()) {
 +
_hud.paint(getTime());
 
}
 
}
  
Line 733: Line 1,202:
  
 
/**
 
/**
* This method will be called at the beginning of a battle. Robots can override this method to
+
* Returns a Point2D object located at the exact center of the battlefield.
* initialize their properties. This is a good place to initialize static properties or set your
 
* tank color.
 
 
*/
 
*/
protected void initializeBattle() {
+
public Point2D.Double getCenter() {
// Default implementation does nothing
+
return _center;
 
}
 
}
  
 
/**
 
/**
* This method will be called at the beginning of each round. Robots can override this method to
+
* Called by PluggableRobot at the start of a battle. Your implementation of
* initialize their properties. This is a good place to set up non-static properties and
+
* this method should perform whatever operations you wish to handle at the
* register listeners, painters and components.
+
* start of a battle, such as setting tank colors and initializing memory
 +
* objects that will persist between rounds.
 
*/
 
*/
protected void initializeRound() {
+
protected abstract void initBattle();
// Default implementation does nothing
 
}
 
  
 
/**
 
/**
* Called before events get processed each tick. The default implementation does nothing.
+
* Called by PluggableRobot at the start of each round. Your implementation
 +
* of this method should create Hud layers, register your robot's
 +
* EventListeners, Components and Painters, and perform any other operations
 +
* you wish to handle at the start of a round.
 
*/
 
*/
public void onBeforeEventsProcessed() {
+
protected abstract void initRound();
// Do nothing
 
}
 
 
 
/**
 
* Returns a Point2D.Double object representing the center of the battlefield.
 
*/
 
public Point2D.Double getCenter() {
 
if(_center == null) {
 
_center = new Point2D.Double(getBattleFieldWidth() / 2, getBattleFieldHeight() / 2);
 
}
 
 
 
return _center;
 
}
 
 
 
  
 
/**
 
/**
* Registers the given EventListener, which will cause it to receive notifications of the events
+
* Registers an EventListener. Registration lasts until the end of the round
* indicated by the listener interfaces it implements.
+
* and enables the listener to receive event notifications.
 
*/
 
*/
protected void registerListener(EventListener listener) {
+
protected final void registerListener(EventListener listener) {
 
_listenerDelegate.register(listener);
 
_listenerDelegate.register(listener);
 
}
 
}
  
 
/**
 
/**
* Reigsters the given Component, which will give it the opportunity to act each turn.
+
* Registers a Component. Registration lasts until the end of the round and
 +
* enables the Component to be notified when it is time to act.
 
*/
 
*/
 
protected void registerComponent(Component component) {
 
protected void registerComponent(Component component) {
Line 785: Line 1,241:
  
 
/**
 
/**
* Reigsters the given Painter, which will give it the opportunity to draw on the HUD each turn.
+
* Constructs a new Hud layer with the given name and bound to the indicated
 +
* key. The enabled argument determines whether or not the layer should
 +
* be on or off by default.
 
*/
 
*/
protected void registerPainter(Hud.Painter painter) {
+
protected void createLayer(int key, String name, boolean enabled) {
_painters.add(painter);
+
_hud.createLayer(key, name, enabled);
 
}
 
}
  
 
/**
 
/**
* Hand out notifications to the Painters.
+
* Registers a Painter and binds it to the layer corresponding to the given
 +
* key. Registration lasts until the end of the round and enables the
 +
* Painter to draw on a Hud layer when it's time to paint.
 
*/
 
*/
@Override
+
protected void registerPainter(int key, Painter painter) {
public final void onPaint(Graphics2D g) {
+
_hud.registerPainter(key, painter);
_hud.setContext(g); // Inject the graphics context into the Hud
 
 
 
for(Hud.Painter painter : _painters) {
 
painter.paint(_hud, getTime());
 
}
 
 
 
_hud.setContext(null); // Clear the injected graphics context
 
 
}
 
}
  
 
/**
 
/**
* Process all the events in the queue.
+
* Called by a custom event registered by PluggableRobot. This method hands
 +
* the event list to the ListenerDelegate, which will in turn notify the
 +
* EventListeners in the desired order.
 
*/
 
*/
 
private void handleEvents() {
 
private void handleEvents() {
onBeforeEventsProcessed();
 
 
_listenerDelegate.processEvents(getAllEvents());
 
_listenerDelegate.processEvents(getAllEvents());
 
clearAllEvents();
 
clearAllEvents();
 
}
 
}
  
// Since we have our own event manager, we want to prevent overrides of the Robocode event
+
/*
// methods, so we'll make them final.
+
* Since we've got our own event handling mechanism, we don't want to use
 +
* the existing one, so make these methods final.
 +
*/
 +
@Override
 +
public final void onBattleEnded(BattleEndedEvent event) {
 +
}
 +
 
 +
@Override
 +
public final void onBulletHit(BulletHitEvent event) {
 +
}
 +
 
 +
@Override
 +
public final void onBulletHitBullet(BulletHitBulletEvent event) {
 +
}
 +
 
 +
@Override
 +
public final void onBulletMissed(BulletMissedEvent event) {
 +
}
  
 
@Override
 
@Override
Line 826: Line 1,297:
  
 
@Override
 
@Override
public final void onSkippedTurn(SkippedTurnEvent event) {
+
public final void onHitByBullet(HitByBulletEvent event) {
 +
}
 +
 
 +
@Override
 +
public final void onHitRobot(HitRobotEvent event) {
 +
}
 +
 
 +
@Override
 +
public final void onHitWall(HitWallEvent event) {
 +
}
 +
 
 +
@Override
 +
public final void onKeyPressed(KeyEvent e) {
 +
}
 +
 
 +
@Override
 +
public final void onKeyReleased(KeyEvent e) {
 +
}
 +
 
 +
@Override
 +
public final void onKeyTyped(KeyEvent e) {
 +
}
 +
 
 +
@Override
 +
public final void onMouseClicked(MouseEvent e) {
 +
}
 +
 
 +
@Override
 +
public final void onMouseDragged(MouseEvent e) {
 +
}
 +
 
 +
@Override
 +
public final void onMouseEntered(MouseEvent e) {
 
}
 
}
  
 
@Override
 
@Override
public final void onBulletHit(BulletHitEvent event) {
+
public final void onMouseExited(MouseEvent e) {
 
}
 
}
  
 
@Override
 
@Override
public final void onBulletHitBullet(BulletHitBulletEvent event) {
+
public final void onMouseMoved(MouseEvent e) {
 
}
 
}
  
 
@Override
 
@Override
public final void onBulletMissed(BulletMissedEvent event) {
+
public final void onMousePressed(MouseEvent e) {
 
}
 
}
  
 
@Override
 
@Override
public final void onHitByBullet(HitByBulletEvent event) {
+
public final void onMouseReleased(MouseEvent e) {
 
}
 
}
  
 
@Override
 
@Override
public final void onHitRobot(HitRobotEvent event) {
+
public final void onMouseWheelMoved(MouseWheelEvent e) {
 
}
 
}
  
 
@Override
 
@Override
public final void onHitWall(HitWallEvent event) {
+
public final void onPaint(Graphics2D g) {
 
}
 
}
  
Line 859: Line 1,362:
 
@Override
 
@Override
 
public final void onScannedRobot(ScannedRobotEvent event) {
 
public final void onScannedRobot(ScannedRobotEvent event) {
 +
}
 +
 +
@Override
 +
public final void onSkippedTurn(SkippedTurnEvent event) {
 +
}
 +
 +
@Override
 +
public final void onStatus(StatusEvent e) {
 
}
 
}
  
Line 865: Line 1,376:
 
}
 
}
 
}
 
}
</nowiki></pre>
+
</nowiki></syntaxhighlight>
 +
[[Category:Source Code|PluggableRobot/Source]]

Latest revision as of 09:30, 1 July 2010

Below is the source for PluggableRobot. Pillage to your heart's content. PluggableRobot is released under the RoboWiki Limited Public Code License.

Canvas.java

<nowiki>
/*
 * PluggableRobot, by Robert J. Walker
 * Home page: http://robowiki.net/w/index.php?title=PluggableRobot
 * This software is made available under the RoboWiki Limited Public Code
 * License (RWLPCL). The full text of the license may be found at:
 * http://robowiki.net/w/index.php?title=RWLPCL
 */
package rjw.pluggablerobot;

import java.awt.*;
import java.awt.geom.Point2D;

import robocode.AdvancedRobot;

/**
 * A convenience wrapper around Graphics2D which provides the following
 * features:
 * 
 * - Accepts doubles for many arguments which are ints in Graphics2D
 * - getCenter(), getHeight() and getWidth()
 * - drawCircle(), fillCircle()
 * 
 * @author Robert J. Walker
 */
public class Canvas {
	private Graphics2D _g;
	private double _width;
	private double _height;
	private Point2D.Double _center;

	Canvas(AdvancedRobot bot) {
		_g = bot.getGraphics();
		_width = bot.getBattleFieldWidth();
		_height = bot.getBattleFieldHeight();
		_center = new Point2D.Double(_width / 2, _height / 2);
	}

	/**
	 * @see java awt.Graphics2D.clearRect(int, int, int, int)
	 */
	public void clearRect(double x, double y, double width, double height) {
		_g.clearRect(i(x), i(y), i(width), i(height));
	}

	/**
	 * @see java awt.Graphics2D.clip(java.awt.Shape)
	 */
	public void clip(Shape shape) {
		_g.clip(shape);
	}

	/**
	 * @see java awt.Graphics2D.clipRect(int, int, int, int)
	 */
	public void clipRect(double x, double y, double width, double height) {
		_g.clipRect(i(x), i(y), i(width), i(height));
	}

	/**
	 * @see java awt.Graphics2D.copyArea(int, int, int, int, int, int)
	 */
	public void copyArea(double x, double y, double width, double height,
			double dx, double dy) {
		_g.copyArea(i(x), i(y), i(width), i(height), i(dx), i(dy));
	}

	/**
	 * @see java awt.Graphics2D.draw(java.awt.Shape)
	 */
	public void draw(Shape shape) {
		_g.draw(shape);
	}

	/**
	 * @see java awt.Graphics2D.drawArc(int, int, int, int, int, int)
	 */
	public void drawArc(double x, double y, double width, double height,
			double startAngle, double arcAngle) {
		_g.drawArc(i(x), i(y), i(width), i(height), i(startAngle), i(arcAngle));
	}

	/**
	 * Convenience method for drawing a circle, given the center coordinates and
	 * radius.
	 */
	public void drawCircle(double x, double y, double r) {
		int d = i(r * 2);
		_g.drawOval(i(x - r), i(y - r), d, d);
	}

	/**
	 * @see java awt.Graphics2D.drawLine(int, int, int, int)
	 */
	public void drawLine(double x1, double y1, double x2, double y2) {
		_g.drawLine(i(x1), i(y1), i(x2), i(y2));
	}

	/**
	 * @see java awt.Graphics2D.drawOval(int, int, int, int)
	 */
	public void drawOval(double x, double y, double width, double height) {
		_g.drawOval(i(x), i(y), i(width), i(height));
	}

	/**
	 * @see java awt.Graphics2D.drawRect(int, int, int, int)
	 */
	public void drawRect(double x, double y, double width, double height) { 
		_g.drawRect(i(x), i(y), i(width), i(height));
	}

	/**
	 * @see java awt.Graphics2D.drawRoundRect(int, int, int, int, int, int)
	 */
	public void drawRoundRect(double x, double y, double width, double height,
			double arcWidth, double arcHeight) { 
		_g.drawRoundRect(i(x), i(y), i(width), i(height), i(arcWidth),
				i(arcHeight));
	}

	/**
	 * @see java awt.Graphics2D.drawString(String, float, float)
	 */
	public void drawString(String str, double x, double y) {
		_g.drawString(str, (float) x, (float) y);
	}

	/**
	 * @see java awt.Graphics2D.fill(java.awt.Shape)
	 */
	public void fill(Shape shape) {
		_g.fill(shape);
	}

	/**
	 * @see java awt.Graphics2D.fillArc(int, int, int, int, int, int)
	 */
	public void fillArc(double x, double y, double width, double height,
			double startAngle, double arcAngle) {
		_g.fillArc(i(x), i(y), i(width), i(height), i(startAngle), i(arcAngle));
	}

	/**
	 * Convenience method for filling a circle, given the center coordinates and
	 * radius.
	 */
	public void fillCircle(double x, double y, double r) {
		int d = i(r * 2);
		_g.fillOval(i(x - r), i(y - r), d, d);
	}

	/**
	 * @see java awt.Graphics2D.fillOval(int, int, int, int)
	 */
	public void fillOval(double x, double y, double width, double height) {
		_g.fillOval(i(x), i(y), i(width), i(height));
	}

	/**
	 * @see java awt.Graphics2D.fillRect(int, int, int, int)
	 */
	public void fillRect(double x, double y, double width, double height) { 
		_g.fillRect(i(x), i(y), i(width), i(height));
	}

	/**
	 * @see java awt.Graphics2D.fillRoundRect(int, int, int, int, int, int)
	 */
	public void fillRoundRect(double x, double y, double width, double height,
			double arcWidth, double arcHeight) { 
		_g.fillRoundRect(i(x), i(y), i(width), i(height), i(arcWidth),
				i(arcHeight));
	}

	/**
	 * @see java awt.Graphics2D.getBackground()
	 */
	public Color getBackground() {
		return _g.getBackground();
	}

	/**
	 * Returns a Point2D located at the center of the canvas.
	 */
	public Point2D.Double getCenter() {
		return _center;
	}

	/**
	 * @see java awt.Graphics2D.getClip()
	 */
	public Shape getClip() {
		return _g.getClip();
	}

	/**
	 * @see java awt.Graphics2D.getClipBounds()
	 */
	public Rectangle getClipBounds() {
		return _g.getClipBounds();
	}

	/**
	 * @see java awt.Graphics2D.getClipBounds(java.awt.Rectangle)
	 */
	public Rectangle getClipBounds(Rectangle r) {
		return _g.getClipBounds(r);
	}

	/**
	 * @see java awt.Graphics2D.getColor()
	 */
	public Color getColor() {
		return _g.getColor();
	}

	/**
	 * @see java awt.Graphics2D.getDeviceConfiguration()
	 */
	public GraphicsConfiguration getDeviceConfiguration() {
		return _g.getDeviceConfiguration();
	}

	/**
	 * Returns a reference to the actual Graphics2D object wrapped by the
	 * Canvas.
	 */
	public Graphics2D getGraphics() {
		return _g;
	}

	/**
	 * Returns the canvas's height.
	 */
	public double getHeight() {
		return _height;
	}

	/**
	 * @see java awt.Graphics2D.getPaint()
	 */
	public Paint getPaint() {
		return _g.getPaint();
	}

	/**
	 * @see java awt.Graphics2D.getStroke()
	 */
	public Stroke getStroke() {
		return _g.getStroke();
	}

	/**
	 * Returns the canvas's width.
	 */
	public double getWidth() {
		return _width;
	}

	/**
	 * @see java awt.Graphics2D.hit(java.awt.Rectangle, java.awt.Shape, boolean)
	 */
	public boolean hit(Rectangle rect, Shape s, boolean onStroke) {
		return _g.hit(rect, s, onStroke);
	}

	/**
	 * @see java awt.Graphics2D.hitClip(int, int, int, int)
	 */
	public boolean hitClip(double x, double y, double width, double height) {
		return _g.hitClip(i(x), i(y), i(width), i(height));
	}

	/**
	 * @see java awt.Graphics2D.setBackground(java.awt.Color)
	 */
	public void setBackground(Color color) {
		_g.setBackground(color);
	}

	/**
	 * @see java awt.Graphics2D.setClip(int, int, int, int)
	 */
	public void setClip(double x, double y, double width, double height) {
		_g.setClip(i(x), i(y), i(width), i(height));
	}

	/**
	 * @see java awt.Graphics2D.setClip(java.awt.Shape)
	 */
	public void setClip(Shape clip) {
		_g.setClip(clip);
	}

	/**
	 * @see java awt.Graphics2D.setColor(java.awt.Color)
	 */
	public void setColor(Color c) {
		_g.setColor(c);
	}

	/**
	 * @see java awt.Graphics2D.setPaint(java.awt.Paint)
	 */
	public void setPaint(Paint paint) {
		_g.setPaint(paint);
	}

	/**
	 * @see java awt.Graphics2D.setStroke(java.awt.Stroke)
	 */
	public void setStroke(Stroke stroke) {
		_g.setStroke(stroke);
	}

	/**
	 * Rounds a double to the nearest integer and returns it as an int.
	 */
	private static int i(double d) {
		return (int) Math.round(d);
	}
}
</nowiki>

Component.java

<nowiki>
/*
 * PluggableRobot, by Robert J. Walker
 * Home page: http://robowiki.net/w/index.php?title=PluggableRobot
 * This software is made available under the RoboWiki Limited Public Code
 * License (RWLPCL). The full text of the license may be found at:
 * http://robowiki.net/w/index.php?title=RWLPCL
 */
package rjw.pluggablerobot;

/**
 * Components encapsulate the main combat behavior of the robot into pluggable
 * modules. Any code that actually sets an action for the robot (moving,
 * turning, rotating the turret or radar, etc.) should be done in the go()
 * method. Components should NEVER call any blocking methods; PluggableRobot
 * will call execute() automatically when all components have had a chance to
 * act.
 * @author Robert J. Walker
 */
public interface Component {
	/**
	 * Asks this Component to execute any actions that it wants to take this
	 * turn. PluggableRobot will call this method once per turn for each
	 * registered Component. Don't put any blocking calls in here;
	 * PluggableRobot will call execute() for you automatically after calling
	 * go() on each Component.
	 */
	public abstract void go();
}
</nowiki>

EventListener.java

<nowiki>
/*
 * PluggableRobot, by Robert J. Walker
 * Home page: http://robowiki.net/w/index.php?title=PluggableRobot
 * This software is made available under the RoboWiki Limited Public Code
 * License (RWLPCL). The full text of the license may be found at:
 * http://robowiki.net/w/index.php?title=RWLPCL
 */
package rjw.pluggablerobot;

import robocode.*;

/**
 * Event listener interfaces. Objects that wish to be notified of events must
 * extend one or more of these subinterfaces and register themselves with
 * PluggableRobot at the start of the round via the registerListener() method.
 * @author Robert J. Walker
 */
public interface EventListener {
	public interface BattleEnded extends EventListener {
		/**
		 * Called by the ListenerDelegate when the battle ends.
		 */
		public void notifyBattleEnded(BattleEndedEvent event);
	}

	public interface BulletHitBullet extends EventListener {
		/**
		 * Called by the ListenerDelegate when a bullet fired by your robot has
		 * hit another bullet.
		 */
		public void notifyBulletHitBullet(BulletHitBulletEvent event);
	}

	public interface BulletHit extends EventListener {
		/**
		 * Called by the ListenerDelegate when a bullet fired by your robot has
		 * hit another robot.
		 */
		public void notifyBulletHit(BulletHitEvent event);
	}

	public interface BulletMissed extends EventListener {
		/**
		 * Called by the ListenerDelegate when a bullet fired by your robot has
		 * hit a wall.
		 */
		public void notifyBulletMissed(BulletMissedEvent event);
	}

	public interface Death extends EventListener {
		/**
		 * Called by the ListenerDelegate when your robot has been destroyed.
		 */
		public void notifyDeath(DeathEvent event);
	}

	public interface HitByBullet extends EventListener {
		/**
		 * Called by the ListenerDelegate when your robot has been hit by an
		 * enemy bullet.
		 */
		public void notifyHitByBullet(HitByBulletEvent event);
	}

	public interface HitRobot extends EventListener {
		/**
		 * Called by the ListenerDelegate when your robot has collided with
		 * another robot.
		 */
		public void notifyHitRobot(HitRobotEvent event);
	}

	public interface HitWall extends EventListener {
		/**
		 * Called by the ListenerDelegate when your robot has collided with a
		 * wall.
		 */
		public void notifyHitWall(HitWallEvent event);
	}

	public interface RobotDeath extends EventListener {
		/**
		 * Called by the ListenerDelegate when an enemy robot has been
		 * destroyed.
		 */
		public void notifyRobotDeath(RobotDeathEvent event);
	}

	public interface ScannedRobot extends EventListener {
		/**
		 * Called by the ListenerDelegate when your radar has swept over an
		 * enemy robot.
		 */
		public void notifyScannedRobot(ScannedRobotEvent event);
	}

	public interface SkippedTurn extends EventListener {
		/**
		 * Called by the ListenerDelegate when your robot has skipped a turn.
		 */
		public void notifySkippedTurn(SkippedTurnEvent event);
	}

	public interface Status extends EventListener {
		/**
		 * Called by the ListenerDelegate every turn with a robot status update.
		 */
		public void notifyStatus(StatusEvent event);
	}

	public interface Win extends EventListener {
		/**
		 * Called by the ListenerDelegate when all robots besides yours have
		 * been destroyed.
		 */
		public void notifyWin(WinEvent event);
	}


	// Internal event listeners

	/**
	 * An EventListener used only by the Hud to inform it of KeyPressedEvents
	 * so that it handle requests to toggle layers.
	 */
	interface _KeyPressed extends EventListener {
		/**
		 * Notifies the Hud that a key was pressed.
		 */
		public void notifyKeyPressed(KeyPressedEvent event);
	}

	/**
	 * An EventListener used only by the ListenerDelegate to inform it of
	 * PaintEvents. The ListenerDelegate registers with itself as being
	 * interested in this event. This is the connection point for
	 * PluggableRobot's debug graphics harness.
	 */
	interface _Paint extends EventListener {
		/**
		 * Notifies the ListenerDelegate that a PaintEvent has been received.
		 */
		public void notifyPaint(PaintEvent event);
	}
}
</nowiki>

Hud.java

<nowiki>
/*
 * PluggableRobot, by Robert J. Walker
 * Home page: http://robowiki.net/w/index.php?title=PluggableRobot
 * This software is made available under the RoboWiki Limited Public Code
 * License (RWLPCL). The full text of the license may be found at:
 * http://robowiki.net/w/index.php?title=RWLPCL
 */
package rjw.pluggablerobot;

import java.util.ArrayList;

import rjw.pluggablerobot.EventListener._KeyPressed;
import robocode.AdvancedRobot;
import robocode.KeyPressedEvent;

/**
 * The Hud is responsible for drawing debug graphics. The Hud has multiple
 * layers, each of which can be enabled or disabled independently through a key
 * binding. Any object which is interested in contributing to the Hud must
 * register itself with PluggableRobot, declaring which layer it wishes to paint
 * on. Layers are painted in the order in which they were declared, and
 * individual painters are invoked in the order that they were registered for
 * that layer.
 * 
 * Concept based on previous work by Nfwu and David Alves:
 * http://robowiki.net/w/index.php?title=User:Nfwu/Painter
 *
 * @author Robert J. Walker
 */
public class Hud implements _KeyPressed {
	private Canvas _canvas;
	private ArrayList<Layer> _layers = new ArrayList<Layer>();

	public Hud(AdvancedRobot bot) {
		_canvas = new Canvas(bot);
	}

	/**
	 * Constructs a new Layer with the given name and bound to the indicated
	 * key. The enabled argument determines whether or not the layer should
	 * be on or off by default.
	 */
	public void createLayer(int key, String name, boolean enabled) {
		Layer layer = new Layer(key, name, enabled);
		_layers.add(layer);
	}

	/**
	 * Registers a painter with the layer bound to the given key.
	 */
	public void registerPainter(int key, Painter painter) {
		for (Layer layer : _layers) {
			if (layer.getKey() == key) {
				layer.addPainter(painter);
				return;
			}
		}

		throw new IllegalArgumentException("No layer bound to that key!");
	}

	/**
	 * Notifes the Hud that a key was pressed, and toggles the corresponding
	 * layer, if it exists.
	 */
	@Override
	public void notifyKeyPressed(KeyPressedEvent event) {
		Layer layer = getLayer(event.getSourceEvent().getKeyCode());
		 
		if (layer != null) {
			layer.toggle();
		}
	}

	/**
	 * Called by PluggableRobot when it's time to paint the Hud.
	 */
	void paint(long tick) {
		for (Layer layer : _layers) {
			layer.paint(_canvas, tick);
		}
	}

	/**
	 * Returns the layer bound to the given key.
	 */
	private Layer getLayer(int key) {
		for (Layer layer : _layers) {
			if (layer.getKey() == key) {
				return layer;
			}
		}

		return null;
	}


	/**
	 * Objects which implement the Painter interface and are registered
	 * PluggableRobot will get their paint() methods called when it is time for
	 * them to paint. Note that any one object that implements Painter may only
	 * paint on one layer of the Hud.
	 */
	public interface Painter {
		/**
		 * Notifies the Painter that it's time to paint, and provides it with a
		 * Canvas object to paint with.
		 */
		public void paint(Canvas canvas, long tick);
	}

	/**
	 * A single Hud layer, responsible for painting itself by calling the
	 * Painters that which to paint on it. 
	 */
	private static class Layer {
		private int _key;
		private String _name;
		private boolean _enabled;
		private ArrayList<Painter> _painters = new ArrayList<Painter>();

		/**
		 * Constructs a new Layer with the given name and bound to the indicated
		 * key. The enabled argument determines whether or not the layer should
		 * be on or off by default.
		 */
		Layer(int key, String name, boolean enabled) {
			_key = key;
			_name = name;
			_enabled = enabled;
		}

		/**
		 * Returns the key to which this Layer is bound.
		 */
		int getKey() {
			return _key;
		}

		/**
		 * Returns this Layer's name.
		 */
		String getName() {
			return _name;
		}

		/**
		 * Adds a new Painter to this Layer.
		 */
		void addPainter(Painter painter) {
			_painters.add(painter);
		}

		/**
		 * Returns whether or not this Layer is enabled.
		 */
		boolean isEnabled() {
			return _enabled;
		}

		/**
		 * Toggles this Layer between being enabled and disabled.
		 */
		void toggle() {
			_enabled = !_enabled;
		}

		/**
		 * Notifies the Painter that it's time to paint, and provides it with a
		 * Canvas object to paint with.
		 */
		void paint(Canvas canvas, long tick) {
			if (!_enabled) {
				return;
			}

			for (Painter painter : _painters) {
				painter.paint(canvas, tick);
			}
		}
	}
}
</nowiki>

ListenerDelegate.java

<nowiki>
/*
 * PluggableRobot, by Robert J. Walker
 * Home page: http://robowiki.net/w/index.php?title=PluggableRobot
 * This software is made available under the RoboWiki Limited Public Code
 * License (RWLPCL). The full text of the license may be found at:
 * http://robowiki.net/w/index.php?title=RWLPCL
 */
package rjw.pluggablerobot;

import java.util.*;

import robocode.*;

/**
 * Class that manages all the event listeners for a PluggableRobot and delegates
 * events to the appropriate EventListeners. Unlike the default Robocode
 * behavior, events are doled out first by listener (first registered, first
 * notified), then by the order of the listener interfaces declared on the
 * listener implementation. This allows each component to get notified of events
 * in any order it likes, regardless of event priorities or the order used by
 * other components.
 * 
 * PaintEvents are handled differently; they are captured and held until all
 * EventListeners have been notified and Components have acted, so that as much
 * information as possible is available for debug painting.
 * 
 * @author Robert J. Walker
 */
public class ListenerDelegate implements EventListener._Paint {
	private static HashMap<Class, Invoker> _invokers;

	// Build the invoker map, so we can look up invokers by listener class
	static {
		_invokers = new HashMap<Class, Invoker>();

		// interal paint event listener
		_invokers.put(_Paint.class, new Invoker() {
			protected boolean consumesEvent(Event event) {
				return event instanceof PaintEvent;
			}

			protected void invoke(EventListener listener, Event event) {
				((_Paint) listener).notifyPaint((PaintEvent) event);
			}
		});

		// interal key pressed event listener
		_invokers.put(_KeyPressed.class, new Invoker() {
			protected boolean consumesEvent(Event event) {
				return event instanceof KeyPressedEvent;
			}

			protected void invoke(EventListener listener, Event event) {
				((_KeyPressed) listener).notifyKeyPressed(
						(KeyPressedEvent) event
				);
			}
		});

		// battle ended
		_invokers.put(EventListener.BattleEnded.class, new Invoker() {
			protected boolean consumesEvent(Event event) {
				return event instanceof BattleEndedEvent;
			}

			protected void invoke(EventListener listener, Event event) {
				((EventListener.BattleEnded) listener).notifyBattleEnded(
						(BattleEndedEvent) event
				);
			}
		});

		// bullet hit
		_invokers.put(EventListener.BulletHit.class, new Invoker() {
			protected boolean consumesEvent(Event event) {
				return event instanceof BulletHitEvent;
			}

			protected void invoke(EventListener listener, Event event) {
				((EventListener.BulletHit) listener).notifyBulletHit(
						(BulletHitEvent) event
				);
			}
		});

		// bullet hit bullet
		_invokers.put(EventListener.BulletHitBullet.class, new Invoker() {
			protected boolean consumesEvent(Event event) {
				return event instanceof BulletHitBulletEvent;
			}

			protected void invoke(EventListener listener, Event event) {
				((EventListener.BulletHitBullet) listener)
					.notifyBulletHitBullet((BulletHitBulletEvent) event);
			}
		});

		// bullet missed
		_invokers.put(EventListener.BulletMissed.class, new Invoker() {
			protected boolean consumesEvent(Event event) {
				return event instanceof BulletMissedEvent;
			}

			protected void invoke(EventListener listener, Event event) {
				((EventListener.BulletMissed) listener).notifyBulletMissed(
						(BulletMissedEvent) event
				);
			}
		});

		// death
		_invokers.put(EventListener.Death.class, new Invoker() {
			protected boolean consumesEvent(Event event) {
				return event instanceof DeathEvent;
			}

			protected void invoke(EventListener listener, Event event) {
				((EventListener.Death) listener).notifyDeath(
						(DeathEvent) event
				);
			}
		});

		// hit by bullet
		_invokers.put(EventListener.HitByBullet.class, new Invoker() {
			protected boolean consumesEvent(Event event) {
				return event instanceof HitByBulletEvent;
			}

			protected void invoke(EventListener listener, Event event) {
				((EventListener.HitByBullet) listener).notifyHitByBullet(
						(HitByBulletEvent) event
				);
			}
		});

		// hit robot
		_invokers.put(EventListener.HitRobot.class, new Invoker() {
			protected boolean consumesEvent(Event event) {
				return event instanceof HitRobotEvent;
			}

			protected void invoke(EventListener listener, Event event) {
				((EventListener.HitRobot) listener).notifyHitRobot(
						(HitRobotEvent) event
				);
			}
		});

		// hit wall
		_invokers.put(EventListener.HitWall.class, new Invoker() {
			protected boolean consumesEvent(Event event) {
				return event instanceof HitWallEvent;
			}

			protected void invoke(EventListener listener, Event event) {
				((EventListener.HitWall) listener).notifyHitWall(
						(HitWallEvent) event
				);
			}
		});

		// robot death
		_invokers.put(EventListener.RobotDeath.class, new Invoker() {
			protected boolean consumesEvent(Event event) {
				return event instanceof RobotDeathEvent;
			}

			protected void invoke(EventListener listener, Event event) {
				((EventListener.RobotDeath) listener).notifyRobotDeath(
						(RobotDeathEvent) event
				);
			}
		});

		// scanned robot
		_invokers.put(EventListener.ScannedRobot.class, new Invoker() {
			protected boolean consumesEvent(Event event) {
				return event instanceof ScannedRobotEvent;
			}

			protected void invoke(EventListener listener, Event event) {
				((EventListener.ScannedRobot) listener).notifyScannedRobot(
						(ScannedRobotEvent) event
				);
			}
		});

		// skipped turn
		_invokers.put(EventListener.SkippedTurn.class, new Invoker() {
			protected boolean consumesEvent(Event event) {
				return event instanceof SkippedTurnEvent;
			}

			protected void invoke(EventListener listener, Event event) {
				((EventListener.SkippedTurn) listener).notifySkippedTurn(
						(SkippedTurnEvent) event
				);
			}
		});

		// status
		_invokers.put(EventListener.Status.class, new Invoker() {
			protected boolean consumesEvent(Event event) {
				return event instanceof StatusEvent;
			}

			protected void invoke(EventListener listener, Event event) {
				((EventListener.Status) listener).notifyStatus(
						(StatusEvent) event
				);
			}
		});

		// win
		_invokers.put(EventListener.Win.class, new Invoker() {
			protected boolean consumesEvent(Event event) {
				return event instanceof WinEvent;
			}

			protected void invoke(EventListener listener, Event event) {
				((EventListener.Win) listener).notifyWin((WinEvent) event);
			}
		});
	}


	private ArrayList<EventListener> _listeners =
			new ArrayList<EventListener>();
	private PaintEvent _lastPaintEvent = null;

	public ListenerDelegate() {
		register(this);	// register itself for the PaintEvent
	}

	/**
	 * Register a new EventListener.
	 */
	public void register(EventListener listener) {
		_listeners.add(listener);
	}

	/**
	 * Hand out event notifications to the EventListeners. 
	 */
	public void processEvents(List<Event> events) {
		// Notify listeners in the order they were registered
		for (EventListener listener : _listeners) {
			Class[] interfaces = listener.getClass().getInterfaces();

			// Iterate the interfaces on each listener
			for (Class iface : interfaces) {
				// Skip if interface does not descend from EventListener
				if (!EventListener.class.isAssignableFrom(iface)) {
					continue;
				}

				// Get the invoker for this interface
				Invoker invoker = _invokers.get(iface);

				// Find the events this invoker consumes
				for (Event event : events) {
					// Skip if listener isn't interested in this kind of event
					if (!invoker.consumesEvent(event)) {
						continue;
					}

					// Notify the listener
					invoker.invoke(listener, event);
				}
			}
		}
	}

	/**
	 * Called by a special internal EventListener to handle PaintEvents.
	 */
	@Override
	public void notifyPaint(PaintEvent event) {
		_lastPaintEvent = event;
	}

	/**
	 * Returns the most recently received PaintEvent, or null if no PaintEvent
	 * has been received.
	 */
	public PaintEvent getLastPaintEvent() {
		return _lastPaintEvent;
	}


	/**
	 * An object that knows about a Robocode Event class and how to invoke its
	 * corresponding EventListener.
	 */
	private static abstract class Invoker {
		protected abstract boolean consumesEvent(Event event);

		/**
		 * Invokes the given EventListener, passing in a Robocode Event object.
		 */
		protected abstract void invoke(EventListener listener, Event event);
	}
}
</nowiki>

Math2.java

<nowiki>
/*
 * PluggableRobot, by Robert J. Walker
 * Home page: http://robowiki.net/w/index.php?title=PluggableRobot
 * This software is made available under the RoboWiki Limited Public Code
 * License (RWLPCL). The full text of the license may be found at:
 * http://robowiki.net/w/index.php?title=RWLPCL
 */
package rjw.pluggablerobot;

import java.awt.geom.Point2D;
import java.util.Random;

import robocode.util.Utils;

/**
 * Math utility class. Note that trig functions are reversed in order to provide
 * correct results for the Robocode coordinate system.
 * 
 * @author Robert J. Walker
 */
public final class Math2 {
	public static final double PI_OVER_2 = Math.PI / 2;

	private static final Random random = new Random();

	private Math2() {
	}

	/**
	 * Returns a random int between the min and max arguments, inclusive.
	 */
    public static int randomInteger(int min, int max) {
    	return random.nextInt(max - min + 1) + min;
    }

    /**
     * If value is less than min, returns min. If value is greater than max,
     * returns max. Otherwise, returns value.
     */
    public static double limit(double min, double value, double max) {
        return Math.max(min, Math.min(value, max));
    }

    /**
     * Adds the X and Y components of the given Point2D.Double objects and
     * returns a new Point2D.Double object with the result.
     */
    public static Point2D.Double add(Point2D.Double point1,
    		Point2D.Double point2) {
		return new Point2D.Double(point1.x + point2.x, point1.y + point2.y);
	}

    /**
     * Subtracts the X and Y components of the second given Point2D.Double
     * object from those of the first and returns a new Point2D.Double object
     * with the result.
     */
	public static Point2D.Double subtract(Point2D.Double point1, Point2D.Double point2) {
		return new Point2D.Double(point1.x - point2.x, point1.y - point2.y);
	}

	/**
	 * Returns the absolute bearing in radians from the given origin point to
	 * the given target point.
	 */
	public static double getAbsoluteTargetBearing(Point2D.Double origin,
			Point2D.Double target) {
		return Utils.normalAbsoluteAngle(Math.atan2(target.x - origin.x,
				target.y - origin.y));
	}

	/**
	 * Returns a Point2D.Double object indicating the relative position of an
	 * object at the given angle (in radians) and distance from the origin.
	 */
	public static Point2D.Double getRelativePosition(double angle,
			double distance) {
		double dx = distance * Math.sin(angle);
		double dy = distance * Math.cos(angle);
		return new Point2D.Double(dx, dy);
	}

	/**
	 * Returns a Point2D.Double object indicating the position of an object at
	 * the given angle (in radians) and distance from the given origin point.
	 */
	public static Point2D.Double getAbsolutePosition(Point2D.Double origin,
			double angle, double distance) {
		double x = origin.x + distance * Math.sin(angle);
		double y = origin.y + distance * Math.cos(angle);
		return new Point2D.Double(x, y);
	}

    /**
     * Converts degrees to radians.
     */
    public static double degToRad(double degrees) {
    	return Math.toRadians(degrees);
    }

    /**
     * Converts radians to degrees.
     */
    public static double radToDeg(double radians) {
    	return Math.toDegrees(radians);
    }
}
</nowiki>

PluggableRobot.java

<nowiki>
/*
 * PluggableRobot, by Robert J. Walker
 * Home page: http://robowiki.net/w/index.php?title=PluggableRobot
 * This software is made available under the RoboWiki Limited Public Code
 * License (RWLPCL). The full text of the license may be found at:
 * http://robowiki.net/w/index.php?title=RWLPCL
 */
package rjw.pluggablerobot;

import java.awt.Graphics2D;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import java.awt.event.MouseWheelEvent;
import java.awt.geom.Point2D;
import java.util.ArrayList;

import rjw.pluggablerobot.Hud.Painter;
import robocode.*;

/**
 * An abstract robot class that provides a pluggable architecture, sophisticated
 * event management and advanced debug graphics handling.
 * 
 * @author Robert Walker
 */
public abstract class PluggableRobot extends AdvancedRobot {
	private static boolean _battleInitialized = false;
	private static Point2D.Double _center;

	private ListenerDelegate _listenerDelegate;
	private ArrayList<Component> _components = new ArrayList<Component>();
	private Hud _hud;

	public PluggableRobot() {
		_listenerDelegate = new ListenerDelegate();
	}

	/**
	 * PluggableRobot's main execution loop. Rather that implementing run() in
	 * your own robot, you will register listeners, components and painters in
	 * the initRound() method, and those objects will handle your robot's combat
	 * logic. This allows you to more easily separate concerns into separate
	 * objects, and replace parts to change robot behavior.  
	 */
	@Override
	public final void run() {
		// Initialize battle (at start of first round only)
		if (!_battleInitialized) {
			_center = new Point2D.Double(getWidth() / 2, getHeight() / 2);
			initBattle();
			_battleInitialized = true;
		}

		// Mechanism for capturing all events and handing them to the
		// ListenerDelegate. 
		addCustomEvent(new Condition("eventManager") {
			public boolean test() {
				PluggableRobot.this.handleEvents();
				return false;
			}
		});

		// Initialize the Hud
		_hud = new Hud(this);
		registerListener(_hud);

		// Allow robot to initialize its parts
		initRound();

		// Main loop
		while (true) {
			// Let each component act
			for (Component component : _components) {
				component.go();
			}

			// Handle painting
			PaintEvent pe = _listenerDelegate.getLastPaintEvent();
	
			if (pe != null && pe.getTime() == getTime()) {
				_hud.paint(getTime());
			}

			execute();
		}
	}

	/**
	 * Returns a Point2D object located at the exact center of the battlefield.
	 */
	public Point2D.Double getCenter() {
		return _center;
	}

	/**
	 * Called by PluggableRobot at the start of a battle. Your implementation of
	 * this method should perform whatever operations you wish to handle at the
	 * start of a battle, such as setting tank colors and initializing memory
	 * objects that will persist between rounds.
	 */
	protected abstract void initBattle();

	/**
	 * Called by PluggableRobot at the start of each round. Your implementation
	 * of this method should create Hud layers, register your robot's
	 * EventListeners, Components and Painters, and perform any other operations
	 * you wish to handle at the start of a round.
	 */
	protected abstract void initRound();

	/**
	 * Registers an EventListener. Registration lasts until the end of the round
	 * and enables the listener to receive event notifications.
	 */
	protected final void registerListener(EventListener listener) {
		_listenerDelegate.register(listener);
	}

	/**
	 * Registers a Component. Registration lasts until the end of the round and
	 * enables the Component to be notified when it is time to act.
	 */
	protected void registerComponent(Component component) {
		_components.add(component);
	}

	/**
	 * Constructs a new Hud layer with the given name and bound to the indicated
	 * key. The enabled argument determines whether or not the layer should
	 * be on or off by default.
	 */
	protected void createLayer(int key, String name, boolean enabled) {
		_hud.createLayer(key, name, enabled);
	}

	/**
	 * Registers a Painter and binds it to the layer corresponding to the given
	 * key. Registration lasts until the end of the round and enables the
	 * Painter to draw on a Hud layer when it's time to paint.
	 */
	protected void registerPainter(int key, Painter painter) {
		_hud.registerPainter(key, painter);
	}

	/**
	 * Called by a custom event registered by PluggableRobot. This method hands
	 * the event list to the ListenerDelegate, which will in turn notify the
	 * EventListeners in the desired order.
	 */
	private void handleEvents() {
		_listenerDelegate.processEvents(getAllEvents());
		clearAllEvents();
	}

	/*
	 * Since we've got our own event handling mechanism, we don't want to use
	 * the existing one, so make these methods final.
	 */
	@Override
	public final void onBattleEnded(BattleEndedEvent event) {
	}

	@Override
	public final void onBulletHit(BulletHitEvent event) {
	}

	@Override
	public final void onBulletHitBullet(BulletHitBulletEvent event) {
	}

	@Override
	public final void onBulletMissed(BulletMissedEvent event) {
	}

	@Override
	public final void onCustomEvent(CustomEvent event) {
	}

	@Override
	public final void onDeath(DeathEvent event) {
	}

	@Override
	public final void onHitByBullet(HitByBulletEvent event) {
	}

	@Override
	public final void onHitRobot(HitRobotEvent event) {
	}

	@Override
	public final void onHitWall(HitWallEvent event) {
	}

	@Override
	public final void onKeyPressed(KeyEvent e) {
	}

	@Override
	public final void onKeyReleased(KeyEvent e) {
	}

	@Override
	public final void onKeyTyped(KeyEvent e) {
	}

	@Override
	public final void onMouseClicked(MouseEvent e) {
	}

	@Override
	public final void onMouseDragged(MouseEvent e) {
	}

	@Override
	public final void onMouseEntered(MouseEvent e) {
	}

	@Override
	public final void onMouseExited(MouseEvent e) {
	}

	@Override
	public final void onMouseMoved(MouseEvent e) {
	}

	@Override
	public final void onMousePressed(MouseEvent e) {
	}

	@Override
	public final void onMouseReleased(MouseEvent e) {
	}

	@Override
	public final void onMouseWheelMoved(MouseWheelEvent e) {
	}

	@Override
	public final void onPaint(Graphics2D g) {
	}

	@Override
	public final void onRobotDeath(RobotDeathEvent event) {
	}

	@Override
	public final void onScannedRobot(ScannedRobotEvent event) {
	}

	@Override
	public final void onSkippedTurn(SkippedTurnEvent event) {
	}

	@Override
	public final void onStatus(StatusEvent e) {
	}

	@Override
	public final void onWin(WinEvent event) {
	}
}
</nowiki>