package gvps.gui; import java.awt.*; import javax.swing.*; import java.util.*; /** *

The VehicleAnimator class provides an automatically updating canvas on * which to display moving vehicles.

*

In order to animate the vehicles "nicely" (without flickering) it uses * a concept called "double buffering" to render the display off-screen (thus * in memory) before transferring it over to the screen. This results in * potentially larger memory usage... however, this should be negligable.

*/ public class VehicleAnimator extends Component implements Runnable { /* for additional functionality (e.g. collisions, etc), extend the Vector * class with a "VehicleManager", which checks for additional vehicle * placement parameters and use it in place of 'vehicles' */ private Vector vehicles; private int state; private Image carImage; private int animationSpeed = 83; // animation speed: ~12fps private Graphics offScreenGraphics; private Image offScreenImage; /** Creates an animated canvas that displays movements of various vehicles * based on their position and speed */ public VehicleAnimator(){ carImage = Toolkit.getDefaultToolkit().getImage("car_icon.png"); vehicles = new Vector(); } public void addVehicle(String vehicleId, Vector path, int speed){ MappedVehicle vehicle = new MappedVehicle(vehicleId, path, speed); vehicles.add(vehicle); Thread vehicleThread = new Thread(vehicle); vehicleThread.start(); } /** * Forces the current location of a vehicle with the specified vehicleID * @param vehicleId the unique identifier of the desired vehicle * @param location the new location of the vehicle */ public void forceVehicleLocation(String vehicleId, Point location){ try { getMappedVehicle(vehicleId).setLocation(location); } catch (VehicleNotFoundException e) { System.out.println(e); } } /** * Changes the predictive speed of a vehicle with the specified vehicleID. * Warning: No mutexes are used to validate the size of vehicles Vector, * resulting in possibly incorrect vehicle counts. * @param vehicleID the id of the vehicle * @param speed the new speed of the chosen vehicle */ public void setVehicleSpeed(String vehicleId, int speed) { try { getMappedVehicle(vehicleId).setSpeed(speed); } catch (VehicleNotFoundException e) { System.out.println(e); } } /** * Pauses a selected vehicles movements. */ public void pauseVehicle(String vehicleId){ /** * Gets a MappedVehicle object based on it's vehicleId. * @param id the unique identifier of a vehicle * @throws VehicleNotFoundException if a vehicle does not exist with this id */ public MappedVehicle getMappedVehicle(String id) throws VehicleNotFoundException { boolean vehicleFound = false; int totalVehicles = vehicles.size(); int count = 0; // loop through each vehicle looking for one with the right ID while ( !vehicleFound || count < totalVehicles ){ if ( vehicles.get(count).getId().equals(id) ){ vehicleFound = true; } else { count++; } } if ( !vehicleFound ){ throw new VehicleNotFoundException("A vehicle does not exist "+ "with the id \"" + id + "\"" ); } else { return vehicles.get(count); } } public void run(){ while (true){ repaint(); try { Thread.sleep(animationSpeed); } catch (InterruptedException e){ System.out.println("This thread has been broken... "+ "I have NO idea what that means"); } } } /** * Redraws the positions of the vehicles on screen. */ public void update(Graphics g){ // clears the offscreen graphics image, places a "car" image at every point // on the map where a car is supposed to be // then draws that to the component int totalVehicles = vehicles.size(); if (offScreenGraphics == null) { //System.out.println("Creating buffer"); offScreenImage = createImage(getWidth(), getHeight()); offScreenGraphics = offScreenImage.getGraphics(); } // clear the screen offScreenGraphics.clearRect(0,0, this.getWidth(),this.getHeight()); // if we have vehicles, loop through them, get their position, and draw them if ( totalVehicles > 0 ){ for ( int i = 0; i < totalVehicles; i++ ){ MappedVehicle currentVehicle = vehicles.get(i); // check if the current vehicle hasn't actually reached its // destination, if it hasn't, draw it if ( !currentVehicle.isFinished() ){ //System.out.println("Drawing to buffer"); offScreenGraphics.drawImage( carImage, (int)currentVehicle.getLocation().getX(), (int)currentVehicle.getLocation().getY(), this); } // else, remove it from the list of vehicles else { vehicles.remove(i); // compensate for removed vehicle i--; totalVehicles = vehicles.size(); } } if ( offScreenGraphics != null ) { //System.out.println("Drawing to screen"); g.drawImage(offScreenImage, 0, 0, this); } } } public void paint(Graphics g){ } }