Anti-Gravity Tutorial
Anti-Gravity Movement is a medium-level movement that is used mainly in melee. Like most melee movements, it is focused on keeping your robot as far as possible from other ones. It involves the using the law of gravity, but reversed; you assign objects (in this case robots and walls) a 'gravity' push, then let the gravity pushes your robot.
Contents
Tracking the enemies
Before we can assign forces to robots, we need to know where the robots are. We are using a simple but effective system to track the movements of other robots. In the top of your robot's code, add:
static Point2D.Double[] enemyPoints = new Point2D.Double[NUMBER_OF_ENEMIES]; int count;
For NUMBER_OF_ENEMIES, just put the largest number of robots that you think you'll be fighting. Making the number higher than normal won't hurt, but making it too low will cause an array out of bounds exception. Also, you will need to add import java.awt.geom.*;
at the top for the Point2D.Double
to work.
Then add the following code in your OnScannedRobot method:
double absBearing = e.getBearingRadians() + getHeadingRadians(); enemyPoints[count]=new Point2D.Double(getX()+e.getDistance()*Math.sin(absBearing),getY()+e.getDistance()*Math.cos(absBearing)); if(++count>=getOthers()){ count=0; }
Now, lets assume you understand Absolute Bearing and move on to the formula for finding the enemy's position. To find a point in Robocode, you need to know two things: the point's distance and bearing from you. After you know that, the formula for the coordinate pair is (!not code!):
new X=Your x-coordinate + distance*sin(bearing) new Y=Your y-coordinate + distance*cos(bearing)
In the code, we simply use this formula to find the other robots coordinates. The part after that simply keeps track of which robot we are on, and goes back to the beginning after it reaches the amount of robots left alive.
Please not that this is not exactly the optimal system for tracking the enemies' positions. It can only be used with spinning radar, and will occasionally mess up.
Well then, how do I calculate the enemy robot's force?
The formula for gravity is 1/distance^2. We'll be using that, with distance being the enemy robots distance. To find the distance from our point to theirs, we could go through the trouble of using the distance formula, or just simply use:
double distance=enemyPoints[i].distance(getX(),getY());
We'll be taking the easy way. The other thing we have to figure out is the enemy robot's absolute bearing to us. The way we can find this in Robocode is:
Utils.normalAbsoluteAngle(Math.atan2(Enemy X-Our X,Enemy Y-Our Y));
After we have both of these pieces of information, we can actually start figuring out where we want to move. We're going to sum force vectors to find the direction we're being pushed in:
double xForce=0, yForce= 0; for(int i=0;i<getOthers() && enemyPoints[i] != null;i++){ double absBearing=Utils.normalAbsoluteAngle(Math.atan2(enemyPoints[i].x-getX(),enemyPoints[i].y-getY())); double distance=enemyPoints[i].distance(getX(),getY()); xForce -= Math.sin(absBearing) / (distance * distance); yForce -= Math.cos(absBearing) / (distance * distance); } double angle = Math.atan2(xForce, yForce);
Well, this will find the force for each one. You've seen the absolute bearing, distance, and force calculations; the only real new thing in here is the part that decides whether to add or subtract the robot's force.
So how do we make our robot move?
Next what we have to do is find the direction of least resistance. Since you can easily figure out how to do that with the above loop, I'll let you figure out the best angle. The main problem here is finding the fastest way to turn to the right angle. We don't ever want to make more than a 90 degree turn! Here's how you do it, once you've found the best angle:
if (xForce == 0 && yForce == 0) { // If no force, do nothing } else if(Math.abs(angle-getHeadingRadians())<Math.PI/2){ setTurnRightRadians(Utils.normalRelativeAngle(angle-getHeadingRadians())); setAhead(Double.POSITIVE_INFINITY); } else { setTurnRightRadians(Utils.normalRelativeAngle(angle+Math.PI-getHeadingRadians())); setAhead(-Double.POSITIVE_INFINITY); } }
This is basically the same as figuring out which way a robot pushes us, just applied to the angle we wish to turn to instead of the angle of the other robot. Note, the angle value doesn't mean anything if there was no overall force on the robot, so checking the force values first is helpful.
Well, here you go!
That's it for the tutorial! There's something I would like you to know: this tutorial does not create a competitive movement. We haven't even put in wall avoidance, which is very important. Also, it tends to do some melee no-nos such as staying in one spot too long. Some ways you can improve this:
- Add wall avoidance.
- Weight robots' danger based on energy.
- Try to keep the robot from sitting in one spot.