Implemented Animation Timer, FPS counter and modified display boat names and speed

-Race now uses Animation Timer to simulate the race in Race class
-FPS counter displayed in bottom left corner. TODO: Toggle fps view
-Boat names and speed will now reposition so it is not blocked by the border of the canvas

#story [18, 20]
main
David Wu 9 years ago
parent 26f7b94e13
commit af45be1147

@ -25,12 +25,12 @@ public class Constants {
public static final GPSCoordinate finishLineMarker2 = new GPSCoordinate(32.317257, -64.836260);
public static final BoatInRace[] OFFICIAL_AC35_COMPETITORS = new BoatInRace[]
{new BoatInRace("Oracle Team USA", 200.0, Color.BLUEVIOLET, "USA"),
new BoatInRace("Land Rover BAR", 180.0, Color.BLACK, "BAR"),
new BoatInRace("SoftBank Team Japan", 190.0, Color.RED, "JAP"),
new BoatInRace("Groupama Team France", 210.0, Color.ORANGE, "FRN"),
new BoatInRace("Artemis Racing", 220.0, Color.DARKOLIVEGREEN, "ART"),
new BoatInRace("Emirates Team New Zealand", 310, Color.LIMEGREEN, "ENZ")};
{new BoatInRace("Oracle Team USA", 700.0, Color.BLUEVIOLET, "USA"),
new BoatInRace("Land Rover BAR", 680.0, Color.BLACK, "BAR"),
new BoatInRace("SoftBank Team Japan", 690.0, Color.RED, "JAP"),
new BoatInRace("Groupama Team France", 710.0, Color.ORANGE, "FRN"),
new BoatInRace("Artemis Racing", 720.0, Color.DARKOLIVEGREEN, "ART"),
new BoatInRace("Emirates Team New Zealand", 810, Color.LIMEGREEN, "ENZ")};
//public static final Leg bermudaCourseStartToMark1 = new Leg(0, , new )
}

@ -5,13 +5,17 @@ import javafx.beans.property.ReadOnlyObjectWrapper;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.control.Label;
import javafx.scene.control.TableColumn;
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.HBox;
import javafx.scene.paint.Color;
import javafx.util.Callback;
import org.geotools.referencing.GeodeticCalculator;
@ -38,6 +42,10 @@ public class RaceController extends Controller{
@FXML
Label timer;
@FXML
Label FPS;
@FXML
TableView<BoatInRace> boatInfoTable;
@FXML
@ -54,7 +62,6 @@ public class RaceController extends Controller{
* @param boats boats that are to be displayed in the race
* @see ResizableRaceCanvas
*/
public void updateMap(ObservableList<BoatInRace> boats) {
BoatInRace[] boatInRaces = new BoatInRace[boats.size()];
raceMap.setBoats(boats.toArray(boatInRaces));
@ -96,9 +103,10 @@ public class RaceController extends Controller{
ArrayList<Leg> legs = generateBermudaCourseLegs();
ConstantVelocityRace race = new ConstantVelocityRace(boats, legs, this);
(new Thread(race)).start();
new Thread((race)).start();
}
/**
* Function for the Bermuda Race.
* @return legs in the Bermuda Race.
@ -134,5 +142,7 @@ public class RaceController extends Controller{
timer.setText(time);
}
public void setFrames(String fps) { FPS.setText((fps)); }
}

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

@ -1,6 +1,7 @@
package seng302.Model;
import javafx.animation.AnimationTimer;
import javafx.application.Platform;
import javafx.beans.property.StringProperty;
import javafx.collections.FXCollections;
@ -24,7 +25,7 @@ public abstract class Race implements Runnable {
protected long totalTimeElapsed;
private int SLEEP_TIME = 50; //time in milliseconds to pause in a paced loop
private int SLEEP_TIME = 25; //time in milliseconds to pause in a paced loop
private int PRERACE_TIME = 10000;//Integer.MAX_VALUE; //time in milliseconds to pause during pre-race
private boolean timerEnabled = true;
@ -59,6 +60,9 @@ public abstract class Race implements Runnable {
simulateRace();
}
/**
* Disable the timer
*/
public void disableTimer() {
timerEnabled = false;
}
@ -72,14 +76,16 @@ public abstract class Race implements Runnable {
System.out.println("====================");
for (int i = 0; i < startingBoats.size(); i++) {
if (startingBoats.get(i) != null) {
System.out.println(i + 1 + ". " + startingBoats.get(i).getName() + ", Speed: "
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));
}
}
}
/**
* Countdown timer until race starts. Use PRERACE_TIME to set countdown duration.
*/
private void countdownTimer() {
long currentTime = System.currentTimeMillis();
long startTime = currentTime + PRERACE_TIME;
@ -108,6 +114,10 @@ public abstract class Race implements Runnable {
}
}
/**
* Takes total time elapsed and format to hour:minute:second
* @return Formatted time as string
*/
private String calcTimer() {
long minutes;
long currentTimeInSeconds;
@ -122,28 +132,43 @@ public abstract class Race implements Runnable {
return String.format("Race clock: %02d:%02d:%02d", hours, minutes, remainingSeconds);
}
/**
* Updates the calculated time to the timer label
* @param time The calculated time from calcTimer() method
*/
private void updateTime(String time){
Platform.runLater(() -> {controller.setTimer(time);});
}
private void updateFPS(int fps) {
Platform.runLater(() -> {controller.setFrames("FPS: " + fps);});
}
/**
* Starts the Race Simulation, playing the race start to finish with the timescale.
* This prints the boats participating, the order that the events occur in time order, and the respective information of the events.
*/
private void simulateRace() {
System.setProperty("javafx.animation.fullspeed", "true");
new AnimationTimer() {
long timeRaceStarted = System.currentTimeMillis();
int fps = 0;
long timeCurrent = System.currentTimeMillis();
long timeLoopStarted;
long timeLoopEnded;
@Override
public void handle(long arg0) {
/*long timeLoopStarted;
long timeLoopEnded;
int fps = 0;*/
while (boatsFinished < startingBoats.size()) {
timeLoopStarted = System.currentTimeMillis();
if (boatsFinished < startingBoats.size()) {
//timeLoopStarted = System.currentTimeMillis();
totalTimeElapsed = System.currentTimeMillis() - timeRaceStarted;
for (BoatInRace boat : startingBoats) {
if (boat != null && !boat.isFinished()) {
updatePosition(boat, SLEEP_TIME);
@ -152,14 +177,28 @@ public abstract class Race implements Runnable {
}
if (controller != null) controller.updateMap(startingBoats);
if(timerEnabled) updateTime(calcTimer());
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();
}
/**

@ -11,6 +11,8 @@ import seng302.GPSCoordinate;
import seng302.GraphCoordinate;
import seng302.RaceMap;
import java.awt.*;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
import java.util.Random;
@ -23,6 +25,8 @@ public class ResizableRaceCanvas extends Canvas {
private GraphicsContext gc;
private RaceMap map;
private BoatInRace[] boats;
private Graphics graphics;
private Font font;
/**
* Sets the boats that are to be displayed in this race.
@ -107,6 +111,7 @@ public class ResizableRaceCanvas extends Canvas {
public void displayArrow(GraphCoordinate coordinate, int angle){
gc.save();
rotate(angle, coordinate.getX(),coordinate.getY());
gc.setFill(Color.BLACK);
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);
@ -131,8 +136,17 @@ public class ResizableRaceCanvas extends Canvas {
* @param coordinate coordinate the text appears
*/
public void displayText(String name, double speed, GraphCoordinate coordinate){
String text = name + ", " + speed + " knots";
gc.fillText(text, coordinate.getX()+20, coordinate.getY());
String text = String.format("%s, %2$.2f knots", name, speed);
//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);
}
/**
@ -140,6 +154,8 @@ public class ResizableRaceCanvas extends Canvas {
*/
public void drawRaceMap() {
double width = getWidth();
double height = getHeight();
@ -171,13 +187,12 @@ public class ResizableRaceCanvas extends Canvas {
displayLine(startline1, startline2, Color.GREEN);
if (boats != null) {
for (BoatInRace boat : boats) {
if (boat != null) {
// System.out.print("Drawing Boat At: " + boat.getCurrentPosition());
displayMark(this.map.convertGPS(boat.getCurrentPosition()), boat.getColour());
displayText(boat.getAbbrev(), boat.getVelocity(), this.map.convertGPS(boat.getCurrentPosition()));
displayText(boat.getName().getValue(), boat.getVelocity()* 1.94384, this.map.convertGPS(boat.getCurrentPosition()));
}
}
}

@ -12,9 +12,11 @@
<AnchorPane fx:id="canvasBase">
<children>
<Label fx:id="timer" layoutX="45.0" layoutY="146.0" text="0:0" AnchorPane.bottomAnchor="0.0" AnchorPane.rightAnchor="0.0" />
<Label fx:id="FPS" layoutX="-20.0" layoutY="153.0" text="FPS: 0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="-0.0" />
</children></AnchorPane>
<AnchorPane layoutX="450.0" minHeight="0.0" minWidth="0.0" prefHeight="160.0" prefWidth="100.0" GridPane.columnIndex="1">
<children>
<TableView fx:id="boatInfoTable" prefHeight="400.0" prefWidth="146.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<columns>
<TableColumn fx:id="boatPlacingColumn" prefWidth="50.0" text="Place" />

Loading…
Cancel
Save