[Home]RobocodeSG

Robo Home | Changes | Preferences | AllPages

RobocodeSG (Swing Graphics) is a simple extension of Robocode that allows you to draw on the screen using standard Swing graphics.

RobocodeSG functionality is built into newer versions of Robocode, so you don't need to downloading anything separate.

RobocodeSG works with Robocode version 1.0.7.

RobocodeSG adds an onPaint method to the AdvancedRobot class. This onPaint method gets called once per frame.

Here is the source for the SGSample robot:

package stefw;
import robocode.*;
import java.awt.*;
import java.awt.geom.*;

public class SGSample extends AdvancedRobot
{
	public void run() {
		while(true) {
			ahead(100);
			turnGunRight(360);
			back(100);
			turnGunRight(360);
		}
	}

	public void onScannedRobot(ScannedRobotEvent e) {
		fire(1);
	}

	public void onHitByBullet(HitByBulletEvent e) {
		turnLeft(90 - e.getBearing());
	}
	public void onPaint(java.awt.Graphics2D g) {
		g.setColor(Color.red);
		g.drawOval((int)(getX()-50),(int)(600-getY()-50),
			100,100);
        }
}

Don't forget to add the extra import statements for the swing classes, otherwise it will not work.

Installation

Download http://uk.geocities.com/westenstefan/robocodesg.zip and unzip it in the robocode directory. You can start RobocodeSG by clicking on the robocodesg.bat file or typing robocodesg.bat.

If you are not using Windows, type the following on the command prompt to start RobocodeSG (in the robocode directory):

java -Xmx256M -cp robocodesg.jar;robocode.jar robocode.Robocode

The robocodesg.jar file contains some class files that override class files in the robocode.jar file because they come first in the class path. You can still run normal Robocode by using robocode.bat.

A nice feature is that robots that use RobocodeSG will still work in normal Robocode because onPaint will just be ignored.


Comments

This sounds too cool to be real, finaly I would be able to do visual debugging... --lRem

Two questions: Is it usable with Kawigi's version of 1.0.7 (see OpenSourceRobocode/Contributions) and what priority does the onPaint event have. I was always afraid to try using RobocodeGL, but this seems very easy usable and to use. --GrubbmGait

I have just tested it with Kawigi's version of 1.0.7, just type the following (or change the batch file):

java -Xmx256M -cp robocodesg.jar;newrobocode.jar robocode.Robocode

-- StefW

I don't think it uses Robocode events, but just calls onPaint when the battlefield is drawn, which is during execute() if you didn't skip the turn. Edit: why were you afraid to use RobocodeGL? -- Jonathan

You're right, it just calls onPaint when the battlefield is drawn. -- StefW

My main system is not the most stable one (4.5 year old WinME installation without backups (shame on me)) and it seemed that it takes quite some effort to get RobocodeGL up and running. Therefor I did not even bother trying it. --GrubbmGait

RobocodeGL is not hard to get up and running, if you know what you need to do. IIRC:

  1. Get and install gl4java
  2. Extract robocode.jar
  3. Add RobocodeGL files, replacing old files where needed
  4. Put them back in the jar or change the compiler classpath of the ingame editor (necessary if you use it)
  5. Works for me without modifying the VM classpath
-- Jonathan

Personally I think it is nice to have a choice between Swing and GL, I think many experienced Java programmers will be more familiar with Swing than with GL (like me), that's the reason I wrote RobocodeSG. -- StefW

Actually you can't use GL without hacking RobocodeClassLoader? (probably), so you are limited to the included RenderElements?. :-( And yes, choice is a good thing. -- Jonathan

Nice work, and just in time :) My RobocodeGL stopped working a few weeks ago :( --Krabb

Although I havn't tried this with RobocodeSG, but I imagine if you enable the hardware accelerated rendering (if you are running Java 1.5 only) then it should speed up RobocodeSG no end. To do this, add -Dsun.java2d.opengl=True to the command line when running robocode. Let me know if anyone has any results with this. I know it speeds up my own version of Java2d debug rendering! --wolfman

I had issues getting RobocodeGL running .. well, one issue .. the gl4java file was no longer available. I'll have to give this a whirl. Just been drawing a lot of circles and triangles and looking at text debug output. -- Martin Alan Pedersen

I remember doing a lot of digging to get RobocodeGL working, but I did get it working and found all the gl4java stuff I needed... if you can tell me what specifically you need, Martin, I could probably dig it up. I uploaded the one file that jumped out immediately in my Downloads dir...

http://www.dijitari.com/void/robocode/gl4java2.8.0.8-jar.zip

Swing might be easier to work with anyway if you're used to Java GUI coding. In any case, I've found the graphical output to be extremely valuable in development... -- Voidious

If you run Ugluk v0.7.6 under SG you'll see him tracking outbound and inbound waves very consistently, with some minor glitches when an opponent hits a wall or gets disabled (which is an odd one). You'll also see him tracking anticipated trajectories of head on, linear, and circular targeting (as he would predict it). The odd thing is that the incomming bullet often is not following an incomming trajectory exactly even when I know the targeting mechanism is limited to one of those three. I've yet to find out what is going on in those cases, but I haven't really explored it much yet. -- Martin / Ugluk

The first thing that comes to mind is that your calculations could be off a tick. There's some good info on the EnemyWaves page outlining when the enemy decides where to fire with relation to when they are detected as having fired. It could also be slight variations on the implementation of LinearTargeting, of course, like averaging the last two scans instead of just using the data from one. -- Voidious

One of the things I am happy with is the tick synchronization. If you watch it in action, you'll see an expanding ring and somewhere on that ring is the real bullet (painted by the Robocode client). That is true for both inbound and outbound waves. No issues there. The trajectory problem is a matter of angles. I draw a line from the firing position (center of the wave) to the expected bullet position, but the bullet is a few pixels away (on the wave arc). They are being calculated with the same targeting (mine) while testing against my own guns, and they are still off. It probably comes down to a bad synchronization of firing positions and target positions. I'm calculating the bearing between the two positions, and one or both of the positions are stale or too current. -- Martin

Hmm... but isn't it possible that they are synchronized as to when the bullets are fired, but not synchronized with regards to when it is decided where the bullet should go? Actually, you should be able to print out the positions involved in the calculation from both bots, and then see if they match up. -- Voidious

This is way cool. I'll try write an SG-version of CassiusClay. I guess that'll be some work since CC uses GL today and it works a bit differently. Anyway, is there a way to tell if the Robocode application is minimized or not? I don't want to spend time drawing when noone is watching if I can avoid it. =) -- PEZ

The RobocodeSG client allows you to draw by calling a public void onPaint( Graphics2D console ) method on your robot, which isn't called when the client is minimized, hence no performance hit. Really though I only run SG when I explicitly want to do debugging, and I run it at under 10 frames per second (usually 2-3). Otherwise the lines it draws detracts from watching the battles, and at high frame rates the painted lines get choppy. I have a screenshot at home, but I think I'll make one today at work and link it as an example. -- Martin

I retire waves once they have passed their intended target, so you can see two bullets with no waves. Ugluk has three bullets headed for the DeadOnGun?, which has 2 in flight in return. I only see two trajectories on the outer one which leads me to believe Ugluk's heading hadn't changed at the time the shot was taken, making linear and circular the same. -- Martin

I've fixed the issue with inbound bullet projection. My enemy's information about my position was too current. I tweaked it so he could calculate based on the previous 'scan'. -- Martin

I finally started using RobocodeSG tonight, only to see that my waves (and virtualbullets) are perfectly aligned with the real bullets. The only issue I had to solve was that the check if my vbullets hit the target was one tick too late. That makes that the 'killhit' was not seen as hit, because the target was not present anymore. The change only affects the vgun statistics and therefor gunchoice, not enough to make a new version. RobocodeSG really is an ease to use, I wish I had done it earlier so I had not spent somuch time comparing bulletpositions with virtual bulletpositions manually. -- GrubbmGait


Is there a code sniplet available with waves? --SSO

This is my implementation (x*600 Battlefield):

class HisWave
{
	static int nbullet=0;	//Number of bullets
	public int n;			//Bullet Number
	public Vector2D p;		//Position
	public double t;		//time
	public double pow;		//Power
	public double v; 		//Velocity
	public double d;		//Distance
	public Vector2D mv;		//mate Velocity
	public Vector2D mp;		//mate position
	
	public boolean hit=false;
	public boolean moved=false;
	
	public HisWave(AdvancedRobot r, EnemyStats e, double pow)
	{
		n=nbullet;
		nbullet++;
		p=e.p;
		t=r.getTime()-1;
		this.pow=pow;
		d=e.d;
		v=20-3*pow;
		mp = new Vector2D(new Point2D.Double(r.getX(),r.getY()));
		mv =  new Vector2D(r.getHeadingRadians(),r.getVelocity());
	}
	
	public void onPaint(java.awt.Graphics2D g,AdvancedRobot r)
	{
		g.setColor(Color.red);
		int radius=(int)(v*(r.getTime()-t));
		g.drawOval((int)(p.getX()-radius),(int)(600-p.getY()-radius),2*radius,2*radius);
	}
}

--Krabb

Here's my latest representation of waves and firing angles in SG, included in the three targeting drones I made available. It is a lot easier on the eyes than my first attempts (which look remarkably similar to GrubbmGrb's!) I expect someone will find them useful if only for verifying they are tracking inbound waves correctly. -- Martin

Any chance of an updated version of RobocodeSG for the newer versions of robocode (such as the newest 1.1.3), or perhaps built in robocode support (i'm looking at you Fnl ;) ) --Chase-san

It's already built in to the new versions of Robocode, RobocodeSG is outdated now. You can draw onto the screen by using adding the method onPaint(Graphics2D g) to your robot. Start the battle, go into your robot's console, and click the button labeled "Paint". For an example of a bot that uses this, take a look at Phoenix or VirtualBullets/VirtualBulletsSampleBot. They both draw to the screen when you click the "Paint" button. --David Alves

err, well, thats good to know (after making complete fool of myself) --Chase-san

Not at all, it brings attention to the fact that this page should have that noted at the top... -- Voidious

--

I've heard a little about a "one off wave bug" in which drawn waves look aligned to the bullets on the screen, but are really one tick off. I think SG graphics are drawn before the other events happen (like the bullet moving). Is this right? Does this mean drawn Waves should appear one bullet speed before the bullet's position? -- Kev

I'm not sure, but I can tell you this much: a bullet's "start time" is the tick in which setFireBullet was called. So the tick after that, it has traveled (1*bulletVelocity). The tick in which you detect an EnergyDrop, that bullet has already traveled (1*bulletVelocity). You should be able to tell us then if the graphics line up correctly =) -- Voidious

Hmmm... further testing shows that the paint event happens after everything else is updated, so waves should align with bullets. I was confused because one version of Dookious has the comment "Fixed 'start time' of EnemyWaves. (They lined up visually in RobocodeGL, but were, in fact, still off by 1 tick)." I thought Waves were created each tick with a radius already at 1 bulletVelocity. The next tick the wave expands and you detect the EnergyDrop, so the radius is actually 2 bulletVelocities. But now I am hearing is should be 1 bulletVelocity. Am I misssing something here? -- Kev

Well, about the graphics... I was using RobocodeGL, not RobocodeSG, so it could be different in each, right? I'm pretty sure that they have traveled 1*bulletVelocity on the tick after you call setFireBullet, and have traveled 1 tick's worth when you detect the EnergyDrop. That's definitely how Dookious thinks it is... But I was confused back and forth about this many times, so hopefully somebody else can confirm this for me. -- Voidious

Thanks for the help guys, the theory now makes some sense to me. I was going by what I saw on the EnemyWave page, which turns out to be incorrect. But when I switch my surfing to what I see as the correct way (creating Waves with a radius of 1 bulletVelocity at the shooter's last location), drawn Waves don't align with bullets and my WaveSurfingChallenge scores go down. This may be a mistake in my implementation or maybe my surfing has just evolved to work well with one off waves. Whatever the case, I'll stick with what works for now. -- Kev

Do you perform your main logic in the onScannedRobot event? If so, that (I think) occurs before the waves are painted, so it would likely throw your drawing off by one tick (i.e. your waves would be drawn one tick further out than they actually are) compared to your logic being in the run(). -- Martin

(Edit Conflict) Well, I think what ABC says on that page is all correct. When you detect EnergyDrop, the wave is from their location last tick with radius of bulletVelocity, but you should segment the data from 2 ticks ago, because that's the last data they were able to use to aim before calling setFireBullet. Anyway, definitely stick with what you find to work, of course! -- Voidious

@Voidious - I was more refering to jim's explanation of Wave location being advanced two bulletVelocities on the EnergyDrop. @Martin - Yes the logic is done through the onScannedRobotEvent. So my Waves probably are one tick ahead. Until the results start improving though, I'm keeping things the way the are. -- Kev

Just a couple final thoughts... First, what Martin said about collision detection is important, and while I do use the setFireBullet tick as the "start time", I also advance the bullet one extra tick's worth when checking when it hits, because it advances one last time before collision detection. What I ended up doing when I doubted the debug graphics was just create a couple of test tanks, which move to specific positions, one fires at the other, and they print the ticks that the bullet was fired and when it hit. I then compared that to when I thought the bullet should hit, and corrected from there. A pain in the butt, for sure, but it left less doubt for me than the debug graphics. Anyway, best of luck. -- Voidious

I've done my own set of tests, and it turns out the onPaint and onHitByBullet? events occur before the onScannedRobot event. Wave's radii in WaveSerpent were dependant on the variable gameTime, which was set to getTime() on the scanned robot event. On the paint event, the variable hadn't been updated so the waves were drawn one tick back, causing them to align graphically when they were really one tick ahead. I can now say with confidence that waves are created with a radius of 1 when you detected the energy drop (so I've been doing it worng all this time :P). -- Kev

You receive onHitByBullet events before onScannedRobot events because onScannedRobot has a lower priority setting (by default). This became a problem for me when trying to match bullet hits to waves when fighting rambots. I'd be told of the hit before I saw the energy drop. I solved it at the same time I was addressing that onPaint appears to be called before any events, so when I was painting stuff it was based on data processed the turn before. I redid my event handling to process all events as soon as any event is received, and it is called by onPaint before going any further. Basically whenever painting is enabled I process my turn in the onPaint method and ignore that turn in the run() loop. -- Martin

You could use the setEventPriority? to change the Priority of the events. This is taken from the API.

The default priorities are, from lowest to highest: 
        ScannedRobotEvent:              10
        HitRobotEvent:                  20
        HitWallEvent:                   30
        HitByBulletEvent:               40
        BulletHitEvent:                 50
        BulletHitBulletEvent:           50
        BulletMissedEvent:              60
        RobotDeathEvent:                70
        CustomEvent:                    80
        SkippedTurnEvent:               100
        WinEvent:                       100
        DeathEvent:                     100
A note of mention, CustomEvent refers to a true return from the test value of the Condition, the actual testing of the Conditions happens I think after onPaint. -- Chase-san

Robo Home | Changes | Preferences | AllPages
Edit text of this page | View other revisions
Last edited July 10, 2008 14:54 EST by 85-114-13-9.obit.ru (diff)
Search: