转自: http://www.ibm.com/developerworks/java/library/j-antigrav/
{
/*
* ok, we should really be using accessors and mutators here,
* (i.e getName() and setName()) but life's too short.
*/
String name;
public double bearing, heading, speed, x, y, distance, changehead;
public long ctime; //game time that the scan was produced
public bool live; //is the enemy alive?
public PointF guessPosition(long when)
{
double diff = when - ctime;
double newY = y + Math.Cos(heading) * speed * diff;
double newX = x + Math.Sin(heading) * speed * diff;
return new PointF((float)newX, (float)newY);
}
}
public class Anti_Gravity : AdvancedRobot
{
Dictionary<string, Enemy> enemyList = new Dictionary<string, Enemy>();
Enemy target;
private const double PI = Math.PI;
private int direction = 1; // direction we are heading. 1 = forward, -1 = back.
private double firePower; // the pow of the shot we will battle.
private double midPointStrength = 0; // The strength of the gravity point in the middle of field.
private int midPointCount = 0; // Number of turns since that strenght was changed.
public override void Run()
{
target.Distance = 100000;
this.IsAdjustGunForRobotTurn = true;
this.IsAdjustRadarForGunTurn = true;
TurnRadarRightRadians(2 * Math.PI);
while (true)
{
antiGravMove(); // Move
doFirePower(); // Set fire power to the pot
doScanner(); // Scan the robot.
doGun();
Fire(firePower);
Execute();
}
}
public void antiGravMove()
{
double xforce = 0;
double yforce = 0;
double force;
double ang;
GravPoint p;
Enemy en;
Enumeration e = targets.elements();
//cycle through all the enemies. If they are alive, they are repulsive. Calculate the force on us
while (e.hasMoreElements())
{
en = (Enemy)e.nextElement();
if (en.live)
{
p = new GravPoint(en.x, en.y, -1000);
force = p.power / Math.pow(getRange(getX(), getY(), p.x, p.y), 2);
//Find the bearing from the point to us
ang = normaliseBearing(Math.PI / 2 - Math.atan2(getY() - p.y, getX() - p.x));
//Add the components of this force to the total force in their respective directions
xforce += Math.sin(ang) * force;
yforce += Math.cos(ang) * force;
}
}
/**The next section adds a middle point with a random (positive or negative) strength.
The strength changes every 5 turns, and goes between -1000 and 1000. This gives a better
overall movement.**/
midpointcount++;
if (midpointcount > 5)
{
midpointcount = 0;
midpointstrength = (Math.random() * 2000) - 1000;
}
p = new GravPoint(getBattleFieldWidth() / 2, getBattleFieldHeight() / 2, midpointstrength);
force = p.power / Math.pow(getRange(getX(), getY(), p.x, p.y), 1.5);
ang = normaliseBearing(Math.PI / 2 - Math.atan2(getY() - p.y, getX() - p.x));
xforce += Math.sin(ang) * force;
yforce += Math.cos(ang) * force;
/**The following four lines add wall avoidance. They will only affect us if the bot is close
to the walls due to the force from the walls decreasing at a power 3.**/
xforce += 5000 / Math.pow(getRange(getX(), getY(), getBattleFieldWidth(), getY()), 3);
xforce -= 5000 / Math.pow(getRange(getX(), getY(), 0, getY()), 3);
yforce += 5000 / Math.pow(getRange(getX(), getY(), getX(), getBattleFieldHeight()), 3);
yforce -= 5000 / Math.pow(getRange(getX(), getY(), getX(), 0), 3);
//Move in the direction of our resolved force.
goTo(getX() - xforce, getY() - yforce);
}
public void doFirePower()
{
firePower = 400 / target.Distance;
if (firePower > 3)
{
firePower = 3;
}
}
public void doScanner()
{
SetTurnRadarLeftRadians(2 * Math.PI);
}
/**Move the gun to the predicted next bearing of the enemy**/
public void doGun()
{
//long time = getTime() + (int)Math.round((getRange(getX(), getY(), target.x, target.y) / (20 - (3 * firePower))));
//Point2D.Double p = target.guessPosition(time);
offsets the gun by the angle to the next shot based on linear targeting provided by the enemy class
//double gunOffset = getGunHeadingRadians() - (Math.PI / 2 - Math.atan2(p.y - getY(), p.x - getX()));
//setTurnGunLeftRadians(normaliseBearing(gunOffset));
}
/**Turns the shortest angle possible to come to a heading, then returns the direction the
the bot needs to move in.**/
public int turnTo(double angle)
{
double ang;
int dir;
ang = normaliseBearing(getHeading() - angle);
if (ang > 90)
{
ang -= 180;
dir = -1;
}
else if (ang < -90)
{
ang += 180;
dir = -1;
}
else
{
dir = 1;
}
setTurnLeft(ang);
return dir;
}
/**Move towards an x and y coordinate**/
public void goTo(double x, double y)
{
double dist = 20;
double angle = Utils.ToDegrees(absbearing(X, Y, x, y));
//double angle = Math.toDegrees(absbearing(getX(), getY(), x, y));
double r = turnTo(angle);
SetAhead(dist * r);
}
//if a bearing is not within the -pi to pi range, alters it to provide the shortest angle
public double normaliseBearing(double ang)
{
if (ang > PI)
ang -= 2 * PI;
if (ang < -PI)
ang += 2 * PI;
return ang;
}
//if a heading is not within the 0 to 2pi range, alters it to provide the shortest angle
double normaliseHeading(double ang)
{
if (ang > 2 * PI)
ang -= 2 * PI;
if (ang < 0)
ang += 2 * PI;
return ang;
}
//returns the distance between two x,y coordinates
public double getRange(double x1, double y1, double x2, double y2)
{
double xo = x2 - x1;
double yo = y2 - y1;
double h = Math.Sqrt(xo * xo + yo * yo);
return h;
}
//gets the absolute bearing between to x,y coordinates
public double absbearing(double x1, double y1, double x2, double y2)
{
double xo = x2 - x1;
double yo = y2 - y1;
double h = getRange(x1, y1, x2, y2);
if (xo > 0 && yo > 0)
{
return Math.Asin(xo / h);
}
if (xo > 0 && yo < 0)
{
return Math.PI - Math.Asin(xo / h);
}
if (xo < 0 && yo < 0)
{
return Math.PI + Math.Asin(-xo / h);
}
if (xo < 0 && yo > 0)
{
return 2.0 * Math.PI - Math.Asin(-xo / h);
}
return 0;
}
public void onScannedRobot(ScannedRobotEvent e)
{
Enemy en;
if (targets.containsKey(e.getName()))
{
en = (Enemy)targets.get(e.getName());
}
else
{
en = new Enemy();
targets.put(e.getName(), en);
}
//the next line gets the absolute bearing to the point where the bot is
double absbearing_rad = (getHeadingRadians() + e.getBearingRadians()) % (2 * PI);
//this section sets all the information about our target
en.name = e.getName();
double h = normaliseBearing(e.getHeadingRadians() - en.heading);
h = h / (getTime() - en.ctime);
en.changehead = h;
en.x = getX() + Math.sin(absbearing_rad) * e.getDistance(); //works out the x coordinate of where the target is
en.y = getY() + Math.cos(absbearing_rad) * e.getDistance(); //works out the y coordinate of where the target is
en.bearing = e.getBearingRadians();
en.heading = e.getHeadingRadians();
en.ctime = getTime(); //game time at which this scan was produced
en.speed = e.getVelocity();
en.distance = e.getDistance();
en.live = true;
if ((en.distance < target.distance) || (target.live == false))
{
target = en;
}
}
}
}