package marathon.leela; import java.awt.geom.*; import java.awt.*; import java.util.*; import robocode.*; import robocode.util.Utils; /** * This class is responsible for managing Durandal's movement * @author Matthew Chun-Lum * */ public class MovementManager implements EnemyManagerListener { private HashMap<String, ForcePoint> forcePoints; private ForcePoint windPoint; private HashMap<String, EnemyRobot> enemies; // reference to Durandal's enemy map private Leela reference; public static double width; public static double height; public ForceVector moveVector; /** * Constructor * @param enemies */ public MovementManager() { moveVector = null; } /** * Sets up the initial force points and the other variables */ public void setInitialState(Leela reference, double width, double height) { this.width = width; this.height = height; forcePoints = new HashMap<String, ForcePoint>(); // forcePoints.put("NORTH WALL", new Wall(new Point2D.Double(width / 2, height), Constants.DEFAULT_WALL_MAGNITUDE, Wall.NORTH)); // forcePoints.put("SOUTH WALL",new Wall(new Point2D.Double(width / 2, 0), Constants.DEFAULT_WALL_MAGNITUDE, Wall.SOUTH)); // forcePoints.put("EAST WALL",new Wall(new Point2D.Double(0, height / 2), Constants.DEFAULT_WALL_MAGNITUDE, Wall.EAST)); // forcePoints.put("WEST WALL",new Wall(new Point2D.Double(width, height / 2), Constants.DEFAULT_WALL_MAGNITUDE, Wall.WEST)); forcePoints.put("CENTER",new ForcePoint(new Point2D.Double(width / 2, height / 2), Constants.DEFAULT_CENTER_MAGNITUDE, 3)); forcePoints.put("SWIVEL", new SwivelPoint(reference, Constants.DEFAULT_SWIVEL_MAGNITUDE)); this.reference = reference; } /** * Called by EnemyManager when a robot is updated */ public void enemyUpdated(EnemyRobot enemy) { if(forcePoints.containsKey(enemy.getName())) { forcePoints.get(enemy.getName()).setLocation((Point2D.Double) enemy.getLocation().clone()); } else { forcePoints.put(enemy.getName(), enemy.getForcePoint()); } } /** * Returns the vector sum of all of the force points on the battlefield * @param target * @return a ForceVector representing the vector given the target */ public ForceVector getVectorSum(Point2D.Double target) { double xSum = 0; double ySum = 0; for(ForcePoint point : forcePoints.values()) { ForceVector vect = point.getVectorAt(target); xSum += vect.x; ySum += vect.y; } return new ForceVector(xSum, ySum, Math.sqrt(xSum * xSum + ySum * ySum)); } /** * Instructs the movement manager to determine the next move */ public void makeMove() { Point2D.Double location = reference.getLocation(); ForceVector vector1 = getVectorSum(location); Point2D.Double projectedLocation = new Point2D.Double(location.x + vector1.x, location.y + vector1.y); ForceVector vector2 = getVectorSum(projectedLocation).getCoterminal(Constants.MOVEMENT_FACTOR * vector1.magnitude); moveVector = ForceVector.sumVectors(vector1, vector2); double angle = moveVector.getAngle(); setBackAsFront(angle, Constants.MOVEMENT_FACTOR * moveVector.magnitude); } /** * Draws the force points */ public void draw(Graphics2D g) { if(moveVector != null) moveVector.draw(g, reference.getLocation()); if(!forcePoints.isEmpty()) for(ForcePoint point : forcePoints.values()) if(reference.getLocation() != null) point.draw(g, reference.getLocation()); } // -------- PRIVATE HELPERS --------- // /** * Moves the robot a specified angle and distance in the most efficient manner */ private void setBackAsFront(double goAngle, double distance) { double angle = Utils.normalRelativeAngle(goAngle - reference.getHeadingRadians()); if (Math.abs(angle) > (Math.PI/2)) { if (angle < 0) { reference.setTurnRightRadians(Math.PI + angle); } else { reference.setTurnLeftRadians(Math.PI - angle); } reference.setBack(distance); } else { if (angle < 0) { reference.setTurnLeftRadians(-1*angle); } else { reference.setTurnRightRadians(angle); } reference.setAhead(distance); } } }