How to write a pawn

A program which controls a pawn implements various interfaces which notify the program when certain events happen. The program can then ask the pawn questions about its current state or the equipment it has (scanners, weapons, etc.), as well as control the pawn and its attachments.

The most important interface to implement is GameListener. It hands the program one or more Pawn objects, then sends events when the the game starts and ends. It also calls the program regularly to give it a chance to control the pawn during the game.

public class MyController implements GameListener
{
	public boolean use(Pawn pawn)
	{
		// Scenario has handed you a pawn to control.
		// Note that you may control multiple pawns.
	}
	public void gameStarted()
	{
		// Game is starting.
	}
	public void gameTick(double tick)
	{
		// 'tick' represents how much time has passed since the
		// last call to this function.  From here you can check the
		// state of your pawn, change speed & direction, fire, etc.
	}
	public void gameEnded()
	{
		// Game over.
	}
}

You may also want to implement DamageListener so you're notified when your pawn is damaged. This is actually a more general interface which works with a unit. The Unit interface is implemented by pawns, scanners, weapons, etc. To be informed of damage events, call the unit's addDamageListener function.

public class MyController implements GameListener, DamageListener
{
	public boolean use(Pawn pawn)
	{
		pawn.addDamageListener(this);
	}
	...
	public void unitDamaged(Unit unit, double amount)
	{
		// 'unit' has been damaged by 'amount'
	}
	public void unitDestroyed(Unit unit)
	{
		// 'unit' has been destroyed
	}

}

Controlling your pawn

The Pawn interface allows you to control your pawn and get information about it and the equipment it has. You can change the speed and direction of your pawn with changeSpeed, turnLeft and turnRight. You can find out about its current speed with getCurrentSpeed. getAcceleration and getMaxSpeed describe how quickly the pawn can move.

getScanners gives you a list of all the scanners the pawn has. Scanners are how the pawn detects what is in the outside world. getWeapons returns a list of all the weapons the pawn can use.

Your pawn also inherits from Unit. This allows you to add or remove damage listeners as well as query how much damage your unit has sustained so far.

Using scanners

Scanners give you information about the objects and pawns around you. How you use them and what they tell you varies by type of scanner. All scanners are derived from the Scanner class.

A ScannerPerfect gives you complete information about all the pawns and obstacles within its range. You explicitly tell it to scan, then you ask it for details about what it found. It returns an array of ScannedUnit objects. ScannedUnit tells you where the unit is relative to you. It can also tell you the Identity of the unit. Every unit can have multiple names associated with it. This is how you can tell friend from foe or differentiate between units in various groups.

	scanner.scan();
	ScannedList pawns = scanner.getPawns();
	for (int i=0; i<pawns.getCount(); i++)
	{
		ScannedUnit unit = pawns.getUnit(i);
		double distance = unit.getDistance();
		String name = unit.getIdentity().getFirstName();
	}

In contrast, ScannerRadar notifies you when it has spotted something and then it only tells you where the object is, not what it is. You register a ScannerListener with it so it can notify you when it has found something.

public class MyController implements GameListener, ScannerListener
{
	public boolean use(Pawn pawn)
	{
		mPawn = pawn;
		for (Enumeration e=pawn.getScanners(); e!=null && e.hasMoreElements();)
		{
			Object scanner = e.nextElement();
			if (scanner instanceof ScannerRadar)
				// so unitScanned will be called when something is seen
				((ScannerRadar)scanner).addScannerListener(this);
		}
		return true;
	}

	// ScannerListener
	// called automatically when the scanner spots something
	public void unitScanned(double distance, double angle)
	{
		// turn in direction of scanned object
		if (angle > 0)
			mPawn.turnLeft(angle);
		else if (angle < 0)
			mPawn.turnRight(-angle);
	}

	protected Pawn mPawn = null;
}

Using weapons

There are different types of weapons derived from Weapon. Call fire to fire the weapon. getRemainingRounds will tell you how many more times you can fire the weapon. getAmmoSpeed tells you how fast the ammo will travel once fired.

Generally weapons have a maximum firing speed. You can find out how long it takes to reload by calling getReloadSpeed. How long until you can next fire is obtained through getReloadTime. canFire tells you whether or not the weapon is ready to fire now.

WeaponTurret sits on top of your pawn and needs to be aimed in the proper direction before firing. Keep in mind that your pawn may be turning at the same time you're trying to aim your turret.

	public void unitScanned(double distance, double angle)
	{
		// rotate turret in direction of scanned object
		double turretdelta = angle - mWeaponTurret.getCurrentAngle();
		mWeaponTurret.turnLeft(turretdelta);
		// if we're almost aiming at pawn, fire
		if (Math.abs(turretdelta) < 10)
			mWeaponTurret.fire();
	}

WeaponMineLayer drops a mine each time you fire it. Be careful not to lay mines while you're backing up!

Tools

Pawns may also have tools which allow them to perform other tasks. Tool is the base class for all tools, but contains no functionality.

Generally, all information a pawn gets and uses is relative to its own location and orientation - driving, scanners, and weapons all work this way. If you need to be able to orient your pawn relative to other pawns or to the world in general, you can use a ToolCompass or ToolGPS. A compass orients you relative to an absolute direction. It's useful if pawns know where each other are relative to themselves, but not the direction others are faced. In contrast, a GPS (Global Positioning System) tool tells you exactly where you are in 3 dimensions. This makes it simple to have pawns communicate locations of targets between themselves.

Energy

A pawn only has so much energy before it runs out of gas. You can call Pawn.getEnergy to get the Energy object. You can ask it directly how much energy is left or register an EnergyListener which will be notified when your energy runs low or gives out completely.

public class MyController implements GameListener, EnergyListener
{
	public boolean use(Pawn pawn)
	{
		mPawn = pawn;
		// when our energy is down to 10% or completely
		//	runs out, let us know
		pawn.getEnergy().addEnergyListener(this, 10);
		return true;
	}
	public void gameTick(double tick)
	{
		// we can explicitly ask how much energy pawn has left
		double energy = mPawn.getEnergy().getEnergy();
	}

	// EnergyListener
	public void energyLow(Unit unit, double remaining)
	{
		// we're running low, maybe we should head back to base
	}
	public void energyDrained(Unit unit)
	{
		// called when we're completely out of energy
	}

	Pawn mPawn = null;
}