Merge branch 'story9'

# Conflicts:
#	src/main/java/seng302/Controllers/RaceController.java
#	src/main/java/seng302/Model/Race.java
#	src/main/java/seng302/Model/ResizableRaceCanvas.java
#	src/main/resources/scenes/racepane.fxml
main
David Wu 9 years ago
commit f8dff6359d

@ -4,12 +4,18 @@ package seng302.Controllers;
import javafx.beans.property.ReadOnlyObjectWrapper; import javafx.beans.property.ReadOnlyObjectWrapper;
import javafx.beans.value.ObservableValue; import javafx.beans.value.ObservableValue;
import javafx.collections.ObservableList; import javafx.collections.ObservableList;
import javafx.event.EventHandler;
import javafx.fxml.FXML; import javafx.fxml.FXML;
import javafx.scene.control.Label; import javafx.scene.control.Label;
import javafx.scene.control.SplitPane; import javafx.scene.control.SplitPane;
import javafx.scene.control.TableColumn; import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView; import javafx.scene.control.TableView;
import javafx.scene.control.TitledPane;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.AnchorPane; import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.HBox;
import javafx.scene.paint.Color;
import javafx.scene.layout.GridPane; import javafx.scene.layout.GridPane;
import javafx.util.Callback; import javafx.util.Callback;
import seng302.Constants; import seng302.Constants;
@ -22,12 +28,12 @@ import java.util.ResourceBundle;
/** /**
* Created by fwy13 on 15/03/2017. * Created by fwy13 on 15/03/2017.
*/ */
public class RaceController extends Controller { public class RaceController extends Controller{
ResizableRaceCanvas raceMap;
@FXML @FXML
AnchorPane canvasBase; AnchorPane canvasBase;
ResizableRaceCanvas raceMap;
@FXML @FXML
GridPane startScreen; GridPane startScreen;
@FXML @FXML
@ -36,6 +42,11 @@ public class RaceController extends Controller {
@FXML @FXML
Label timer; Label timer;
@FXML
Label FPS;
@FXML @FXML
TableView<BoatInRace> boatInfoTable; TableView<BoatInRace> boatInfoTable;
@FXML @FXML
@ -128,12 +139,12 @@ public class RaceController extends Controller {
ConstantVelocityRace race = new ConstantVelocityRace(boats, legs, this, scaleFactor); ConstantVelocityRace race = new ConstantVelocityRace(boats, legs, this, scaleFactor);
(new Thread(race)).start(); new Thread((race)).start();
} }
/** /**
* Generates an example race course (Bermuda 2017) * Function for the Bermuda Race.
*
* @return legs in the Bermuda Race. * @return legs in the Bermuda Race.
*/ */
private ArrayList<Leg> generateBermudaCourseLegs() { private ArrayList<Leg> generateBermudaCourseLegs() {
@ -172,4 +183,7 @@ public class RaceController extends Controller {
timer.setText(time); timer.setText(time);
} }
public void setFrames(String fps) { FPS.setText((fps)); }
} }

@ -21,7 +21,7 @@ public class Boat {
*/ */
public Boat(String name, double velocity, String abbrev) { public Boat(String name, double velocity, String abbrev) {
this.velocity = velocity; this.velocity = velocity;
this.velocityProp = new SimpleStringProperty(String.valueOf(velocity)); this.velocityProp = new SimpleStringProperty(String.valueOf(velocity* 1.94384));
this.abbrev = abbrev; this.abbrev = abbrev;
this.name = new SimpleStringProperty(name); this.name = new SimpleStringProperty(name);
} }

@ -1,10 +1,14 @@
package seng302.Model; package seng302.Model;
import javafx.animation.AnimationTimer;
import javafx.application.Platform; import javafx.application.Platform;
import javafx.beans.property.StringProperty;
import javafx.collections.FXCollections; import javafx.collections.FXCollections;
import javafx.collections.ObservableArray;
import javafx.collections.ObservableList; import javafx.collections.ObservableList;
import seng302.Controllers.RaceController; import seng302.Controllers.RaceController;
import seng302.GPSCoordinate;
import java.util.ArrayList; import java.util.ArrayList;
@ -23,14 +27,13 @@ public abstract class Race implements Runnable {
protected int scaleFactor; protected int scaleFactor;
private int SLEEP_TIME = 100; //time in milliseconds to pause in a paced loop private int SLEEP_TIME = 100; //time in milliseconds to pause in a paced loop
protected int PRERACE_TIME = 100;//Integer.MAX_VALUE; //time in milliseconds to pause during pre-race protected int PRERACE_TIME = 10000;//Integer.MAX_VALUE; //time in milliseconds to pause during pre-race
private boolean timerEnabled = true; private boolean timerEnabled = true;
/** /**
* Initailiser for Race * Initailiser for Race
*
* @param boats Takes in an array of boats that are participating in the race. * @param boats Takes in an array of boats that are participating in the race.
* @param legs Number of marks in order that the boats pass in order to complete the race. * @param legs Number of marks in order that the boats pass in order to complete the race.
*/ */
public Race(BoatInRace[] boats, ArrayList<Leg> legs, RaceController controller, int scaleFactor) { public Race(BoatInRace[] boats, ArrayList<Leg> legs, RaceController controller, int scaleFactor) {
if (boats.length > 0) { if (boats.length > 0) {
@ -50,7 +53,6 @@ public abstract class Race implements Runnable {
/** /**
* Constructor for Race class * Constructor for Race class
*
* @param boats boats participating in the race. * @param boats boats participating in the race.
* @param legs legs that there are in the race. * @param legs legs that there are in the race.
*/ */
@ -68,37 +70,41 @@ public abstract class Race implements Runnable {
this.scaleFactor = scaleFactor; this.scaleFactor = scaleFactor;
} }
/** /**
* Runnable for the thread. * Runnable for the thread.
*/ */
public void run() { public void run() {
setControllerListeners(); setControllerListeners();
preRace(); preRace();
if (timerEnabled) countdownTimer(); if(timerEnabled) countdownTimer();
simulateRace(); simulateRace();
} }
/**
* Disable the timer
*/
public void disableTimer() { public void disableTimer() {
timerEnabled = false; timerEnabled = false;
} }
/** /**
* Initialises the boats, * Set up the state in waiting for the race starts.
* Sets the boats' current to the first leg in the race
*/ */
private void preRace() { private void preRace() {
//show the boats participating. //show the boats participating.
System.out.println("Boats Participating:");
System.out.println("====================");
for (int i = 0; i < startingBoats.size(); i++) { for (int i = 0; i < startingBoats.size(); i++) {
if (startingBoats.get(i) != null) { if (startingBoats.get(i) != null) {
System.out.println(i + 1 + ". " + startingBoats.get(i).toString() + ", Speed: "
+ Math.round(startingBoats.get(i).getVelocity() * 1.94384) + "kn");
startingBoats.get(i).setCurrentLeg(legs.get(0)); startingBoats.get(i).setCurrentLeg(legs.get(0));
} }
} }
} }
/** /**
* Prerace timer showing time until the race will begin, as a negative value * Countdown timer until race starts. Use PRERACE_TIME to set countdown duration.
*/ */
protected void countdownTimer() { protected void countdownTimer() {
long currentTime = System.currentTimeMillis(); long currentTime = System.currentTimeMillis();
@ -112,17 +118,13 @@ public abstract class Race implements Runnable {
while (currentTime <= startTime) { while (currentTime <= startTime) {
timeLeft = startTime - currentTime; timeLeft = startTime - currentTime;
if (timeLeft == 0 && controller != null) { currentTimeInSeconds = timeLeft / 1000;
updateTime("Race is starting..."); minutes = currentTimeInSeconds / 60;
} else { remainingSeconds = currentTimeInSeconds % 60;
currentTimeInSeconds = timeLeft / 1000; hours = minutes / 60;
minutes = currentTimeInSeconds / 60; minutes = minutes % 60;
remainingSeconds = currentTimeInSeconds % 60; if (controller != null) {
hours = minutes / 60; updateTime(String.format("Time until race starts: %02d:%02d:%02d", hours, minutes, remainingSeconds));
minutes = minutes % 60;
if (controller != null) {
updateTime(String.format("Race clock: -%02d:%02d:%02d", hours, minutes, remainingSeconds));
}
} }
try { try {
timeLoopEnded = System.currentTimeMillis(); timeLoopEnded = System.currentTimeMillis();
@ -135,8 +137,8 @@ public abstract class Race implements Runnable {
} }
/** /**
* Takes elapsed time in minutes and scales it, converts to hh:mm:ss format * Takes total time elapsed and format to hour:minute:second
* @return String formatted race time, scaled * @return Formatted time as string
*/ */
protected String calcTimer() { protected String calcTimer() {
long minutes; long minutes;
@ -145,23 +147,23 @@ public abstract class Race implements Runnable {
long hours; long hours;
currentTimeInSeconds = totalTimeElapsed / 1000; currentTimeInSeconds = totalTimeElapsed / 1000;
long scaledTimeInSeconds = currentTimeInSeconds * scaleFactor; minutes = currentTimeInSeconds / 60;
minutes = scaledTimeInSeconds / 60; remainingSeconds = currentTimeInSeconds % 60;
remainingSeconds = scaledTimeInSeconds % 60;
hours = minutes / 60; hours = minutes / 60;
minutes = minutes % 60; minutes = minutes % 60;
return String.format("Race clock: %02d:%02d:%02d", hours, minutes, remainingSeconds); return String.format("Race clock: %02d:%02d:%02d", hours, minutes, remainingSeconds);
} }
/** /**
* Updates the GUI race clock * Updates the calculated time to the timer label
* @param time * @param time The calculated time from calcTimer() method
*/ */
protected void updateTime(String time) { protected void updateTime(String time){
Platform.runLater(() -> {controller.setTimer(time);});
}
Platform.runLater(() -> { private void updateFPS(int fps) {
controller.setTimer(time); Platform.runLater(() -> {controller.setFrames("FPS: " + fps);});
});
} }
/** /**
@ -170,42 +172,66 @@ public abstract class Race implements Runnable {
*/ */
private void simulateRace() { private void simulateRace() {
long timeRaceStarted = System.currentTimeMillis(); System.setProperty("javafx.animation.fullspeed", "true");
long timeLoopStarted;
long timeLoopEnded;
while (boatsFinished < startingBoats.size()) { new AnimationTimer() {
timeLoopStarted = System.currentTimeMillis();
totalTimeElapsed = System.currentTimeMillis() - timeRaceStarted;
long timeRaceStarted = System.currentTimeMillis();
int fps = 0;
long timeCurrent = System.currentTimeMillis();
for (BoatInRace boat : startingBoats) { @Override
if (boat != null && !boat.isFinished()) { public void handle(long arg0) {
updatePosition(boat, SLEEP_TIME);
checkPosition(boat, totalTimeElapsed);
}
}
if (controller != null) controller.updateMap(startingBoats); /*long timeLoopStarted;
if (timerEnabled) updateTime(calcTimer()); long timeLoopEnded;
try { int fps = 0;*/
timeLoopEnded = System.currentTimeMillis();
Thread.sleep(SLEEP_TIME - (timeLoopEnded - timeLoopStarted)); if (boatsFinished < startingBoats.size()) {
} catch (InterruptedException e) { //timeLoopStarted = System.currentTimeMillis();
return; totalTimeElapsed = System.currentTimeMillis() - timeRaceStarted;
}
} for (BoatInRace boat : startingBoats) {
if (boat != null && !boat.isFinished()) {
updatePosition(boat, SLEEP_TIME);
checkPosition(boat, totalTimeElapsed);
}
}
if (controller != null) controller.updateMap(startingBoats);
if (timerEnabled)
updateTime(calcTimer());
}
fps++;
if ((System.currentTimeMillis()-timeCurrent) > 1000){
updateFPS(fps);
fps = 0;
timeCurrent = System.currentTimeMillis();
}
;
/*fps++;
try {
timeLoopEnded = System.currentTimeMillis();
Thread.sleep(SLEEP_TIME - (timeLoopEnded - timeLoopStarted));
} catch (InterruptedException e) {
return;
}*/
};
//System.out.println("Avg fps:" + fps/(totalTimeElapsed/1000));
}.start();
} }
/** /**
* Checks the position of the boat, this updates the boats current position. * Checks the position of the boat, this updates the boats current position.
* * @param boat Boat that the postion is to be updated for.
* @param boat Boat that the postion is to be updated for.
* @param timeElapsed Time that has elapse since the start of the the race. * @param timeElapsed Time that has elapse since the start of the the race.
* @see BoatInRace * @see BoatInRace
*/ */
protected void checkPosition(BoatInRace boat, long timeElapsed) { protected void checkPosition(BoatInRace boat, long timeElapsed) {
if (boat.getDistanceTravelledInLeg() > boat.getCurrentLeg().getDistance()) { if (boat.getDistanceTravelledInLeg() > boat.getCurrentLeg().getDistance()){
// updateController();
//boat has passed onto new leg //boat has passed onto new leg
if (boat.getCurrentLeg().getName().equals("Finish")) { if (boat.getCurrentLeg().getName().equals("Finish")) {
//boat has finished //boat has finished
@ -213,16 +239,13 @@ public abstract class Race implements Runnable {
boat.setFinished(true); boat.setFinished(true);
boat.setTimeFinished(timeElapsed); boat.setTimeFinished(timeElapsed);
} else { } else {
//Calculate how much the boat overshot the marker by
boat.setDistanceTravelledInLeg(boat.getDistanceTravelledInLeg() - boat.getCurrentLeg().getDistance()); boat.setDistanceTravelledInLeg(boat.getDistanceTravelledInLeg() - boat.getCurrentLeg().getDistance());
//Move boat on to next leg
Leg nextLeg = legs.get(boat.getCurrentLeg().getLegNumber() + 1); Leg nextLeg = legs.get(boat.getCurrentLeg().getLegNumber() + 1);
boat.setCurrentLeg(nextLeg); boat.setCurrentLeg(nextLeg);
//Add overshoot distance into the distance travelled for the next leg
boat.setDistanceTravelledInLeg(boat.getDistanceTravelledInLeg()); boat.setDistanceTravelledInLeg(boat.getDistanceTravelledInLeg());
} }
//Update the boat display table in the GUI to reflect the leg change FXCollections.sort(startingBoats, (a,b) -> b.getCurrentLeg().getLegNumber() - a.getCurrentLeg().getLegNumber());
FXCollections.sort(startingBoats, (a, b) -> b.getCurrentLeg().getLegNumber() - a.getCurrentLeg().getLegNumber());
} }
} }
@ -230,12 +253,11 @@ public abstract class Race implements Runnable {
* Update call for the controller. * Update call for the controller.
*/ */
protected void setControllerListeners() { protected void setControllerListeners() {
if (controller != null) controller.setInfoTable(this); if(controller != null) controller.setInfoTable(this);
} }
/** /**
* Returns the boats that have started the race. * Returns the boats that have started the race.
*
* @return ObservableList of BoatInRace class that participated in the race. * @return ObservableList of BoatInRace class that participated in the race.
* @see ObservableList * @see ObservableList
* @see BoatInRace * @see BoatInRace
@ -244,12 +266,12 @@ public abstract class Race implements Runnable {
return startingBoats; return startingBoats;
} }
/** /**
* Updates the boat's gps coordinates depending on time elapsed * This function is a function that generates the Race and populates the events list.
* @param boat * Is automatically called by the initialiser function, so that simulateRace() does not return an empty race.
* @param millisecondsElapsed * @see Race#simulateRace()
*/ */
protected abstract void updatePosition(BoatInRace boat, int millisecondsElapsed); protected abstract void updatePosition(BoatInRace boat, int millisecondsElapsed);
} }

@ -11,6 +11,11 @@ import seng302.GPSCoordinate;
import seng302.GraphCoordinate; import seng302.GraphCoordinate;
import seng302.RaceMap; import seng302.RaceMap;
import java.awt.*;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
import java.util.Random;
/** /**
* This creates a JavaFX Canvas that is fills it's parent. * This creates a JavaFX Canvas that is fills it's parent.
* Cannot be downsized. * Cannot be downsized.
@ -56,9 +61,8 @@ public class ResizableRaceCanvas extends Canvas {
/** /**
* Displays the mark of a race as a circle. * Displays the mark of a race as a circle.
*
* @param graphCoordinate Latitude and Logintude in GraphCoordinate that it is to be displayed as. * @param graphCoordinate Latitude and Logintude in GraphCoordinate that it is to be displayed as.
* @param paint Colour the mark is to be coloured. * @param paint Colour the mark is to be coloured.
* @see GraphCoordinate * @see GraphCoordinate
* @see Color * @see Color
* @see Paint * @see Paint
@ -70,10 +74,9 @@ public class ResizableRaceCanvas extends Canvas {
/** /**
* Displays a line on the map with rectangles on the starting and ending point of the line. * Displays a line on the map with rectangles on the starting and ending point of the line.
*
* @param graphCoordinateA Starting Point of the line in GraphCoordinate. * @param graphCoordinateA Starting Point of the line in GraphCoordinate.
* @param graphCoordinateB End Point of the line in GraphCoordinate. * @param graphCoordinateB End Point of the line in GraphCoordinate.
* @param paint Colour the line is to coloured. * @param paint Colour the line is to coloured.
* @see GraphCoordinate * @see GraphCoordinate
* @see Color * @see Color
* @see Paint * @see Paint
@ -88,9 +91,8 @@ public class ResizableRaceCanvas extends Canvas {
/** /**
* Display a point on the Canvas * Display a point on the Canvas
*
* @param graphCoordinate Coordinate that the point is to be displayed at. * @param graphCoordinate Coordinate that the point is to be displayed at.
* @param paint Colour that the boat is to be coloured. * @param paint Colour that the boat is to be coloured.
* @see GraphCoordinate * @see GraphCoordinate
* @see Paint * @see Paint
* @see Color * @see Color
@ -102,26 +104,25 @@ public class ResizableRaceCanvas extends Canvas {
/** /**
* Displays an arrow on the Canvas * Displays an arrow on the Canvas
*
* @param coordinate Coordinate that the arrow is to be displayed at. * @param coordinate Coordinate that the arrow is to be displayed at.
* @param angle Angle that the arrow is to be facing in degrees 0 degrees = North (Up). * @param angle Angle that the arrow is to be facing in degrees 0 degrees = North (Up).
* @see GraphCoordinate * @see GraphCoordinate
*/ */
public void displayArrow(GraphCoordinate coordinate, int angle) { public void displayArrow(GraphCoordinate coordinate, int angle) {
gc.save(); gc.save();
rotate(angle, coordinate.getX(), coordinate.getY()); rotate(angle, coordinate.getX(),coordinate.getY());
gc.fillPolygon(new double[]{coordinate.getX() - 12, coordinate.getX() - 6, coordinate.getX(), coordinate.getX() - 4, coordinate.getX() - 4, coordinate.getX() - 8, coordinate.getX() - 8}, gc.setFill(Color.BLACK);
new double[]{coordinate.getY() - 5, coordinate.getY() - 20, coordinate.getY() - 5, coordinate.getY() - 5, coordinate.getY() + 20, coordinate.getY() + 20, coordinate.getY() - 5}, gc.fillPolygon(new double[]{coordinate.getX()-12, coordinate.getX()-6, coordinate.getX(), coordinate.getX()-4, coordinate.getX()-4, coordinate.getX()-8, coordinate.getX()-8},
new double[]{coordinate.getY()-5, coordinate.getY()-20, coordinate.getY()-5, coordinate.getY()-5, coordinate.getY()+20, coordinate.getY()+20, coordinate.getY()-5},
7); 7);
gc.restore(); gc.restore();
} }
/** /**
* Rotates things on the canvas Note: this must be called in between gc.save() and gc.restore() else they will rotate everything * Rotates things on the canvas Note: this must be called in between gc.save() and gc.restore() else they will rotate everything
*
* @param angle Bearing angle to rotate at in degrees * @param angle Bearing angle to rotate at in degrees
* @param px Pivot point x of rotation. * @param px Pivot point x of rotation.
* @param py Pivot point y of rotation. * @param py Pivot point y of rotation.
*/ */
private void rotate(double angle, double px, double py) { private void rotate(double angle, double px, double py) {
Rotate r = new Rotate(angle, px, py); Rotate r = new Rotate(angle, px, py);
@ -130,14 +131,22 @@ public class ResizableRaceCanvas extends Canvas {
/** /**
* Display given name and speed of boat at a graph coordinate * Display given name and speed of boat at a graph coordinate
* * @param name name of the boat
* @param name name of the boat * @param speed speed of the boat
* @param speed speed of the boat
* @param coordinate coordinate the text appears * @param coordinate coordinate the text appears
*/ */
public void displayText(String name, double speed, GraphCoordinate coordinate) { public void displayText(String name, double speed, GraphCoordinate coordinate){
String text = name + ", " + speed + " knots"; String text = String.format("%s, %2$.2f knots", name, speed);
gc.fillText(text, coordinate.getX() + 20, coordinate.getY()); //System.out.println(text.length()*7);
long xCoord = coordinate.getX()+20;
long yCoord = coordinate.getY();
if (xCoord+(text.length()*7) >= getWidth()){
xCoord -= text.length()*7;
}
if (yCoord-(text.length()*2) <= 0){
yCoord += 30;
}
gc.fillText(text, xCoord, yCoord);
} }
/** /**
@ -193,8 +202,7 @@ public class ResizableRaceCanvas extends Canvas {
/** /**
* Draws a boat at a certain GPSCoordinate * Draws a boat at a certain GPSCoordinate
* * @param colour Colour to colour boat.
* @param colour Colour to colour boat.
* @param gpsCoordinates GPScoordinate that the boat is to be drawn at. * @param gpsCoordinates GPScoordinate that the boat is to be drawn at.
* @see GPSCoordinate * @see GPSCoordinate
* @see Color * @see Color

Loading…
Cancel
Save