Merge remote-tracking branch 'remotes/origin/master' into story77
# Conflicts: # racevisionGame/src/main/java/visualiser/Controllers/HostController.java # racevisionGame/src/main/java/visualiser/layout/Subject3D.java # racevisionGame/src/main/java/visualiser/layout/View3D.java # racevisionGame/src/main/resources/visualiser/scenes/hostlobby.fxml
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
package visualiser.Controllers;
|
||||
|
||||
|
||||
import com.interactivemesh.jfx.importer.stl.StlMeshImporter;
|
||||
import javafx.animation.AnimationTimer;
|
||||
import javafx.application.Platform;
|
||||
import javafx.collections.FXCollections;
|
||||
@@ -12,17 +12,25 @@ import javafx.scene.chart.LineChart;
|
||||
import javafx.scene.control.*;
|
||||
import javafx.scene.input.KeyCode;
|
||||
import javafx.scene.input.KeyEvent;
|
||||
import javafx.scene.layout.AnchorPane;
|
||||
import javafx.scene.input.ScrollEvent;
|
||||
import javafx.scene.layout.GridPane;
|
||||
import javafx.scene.layout.Pane;
|
||||
import javafx.scene.layout.StackPane;
|
||||
import javafx.scene.shape.MeshView;
|
||||
import javafx.scene.shape.Sphere;
|
||||
import javafx.scene.transform.Translate;
|
||||
import javafx.util.Callback;
|
||||
import network.Messages.Enums.RaceStatusEnum;
|
||||
import shared.dataInput.RaceDataSource;
|
||||
import shared.model.Leg;
|
||||
import shared.model.Mark;
|
||||
import visualiser.app.App;
|
||||
import visualiser.gameController.ControllerClient;
|
||||
import visualiser.gameController.Keys.ControlKey;
|
||||
import visualiser.gameController.Keys.KeyFactory;
|
||||
import visualiser.layout.Subject3D;
|
||||
import visualiser.layout.View3D;
|
||||
import visualiser.model.*;
|
||||
import visualiser.utils.GPSConverter;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
@@ -38,53 +46,34 @@ import static visualiser.app.App.keyFactory;
|
||||
* Controller used to display a running race.
|
||||
*/
|
||||
public class RaceController extends Controller {
|
||||
|
||||
|
||||
/**
|
||||
* The race object which describes the currently occurring race.
|
||||
*/
|
||||
private VisualiserRaceEvent visualiserRace;
|
||||
|
||||
|
||||
/**
|
||||
* Service for sending keystrokes to server
|
||||
*/
|
||||
private ControllerClient controllerClient;
|
||||
|
||||
|
||||
private boolean isHost;
|
||||
|
||||
/**
|
||||
* The canvas that draws the race.
|
||||
*/
|
||||
private ResizableRaceCanvas raceCanvas;
|
||||
|
||||
/**
|
||||
* The sparkline graph.
|
||||
*/
|
||||
private Sparkline sparkline;
|
||||
|
||||
/**
|
||||
* state of the info table
|
||||
*/
|
||||
private boolean infoTableShow;
|
||||
|
||||
private View3D view3D;
|
||||
private ObservableList<Subject3D> viewSubjects;
|
||||
|
||||
/**
|
||||
* The arrow controller.
|
||||
*/
|
||||
@FXML private ArrowController arrowController;
|
||||
|
||||
|
||||
|
||||
@FXML private GridPane canvasBase;
|
||||
|
||||
|
||||
@FXML private SplitPane race;
|
||||
|
||||
/**
|
||||
* This is the root node of the arrow control.
|
||||
*/
|
||||
@FXML private Pane arrow;
|
||||
@FXML private SplitPane racePane;
|
||||
|
||||
/**
|
||||
* This is the pane we place the actual arrow control inside of.
|
||||
@@ -100,9 +89,6 @@ public class RaceController extends Controller {
|
||||
@FXML private TableColumn<VisualiserBoat, Leg> boatMarkColumn;
|
||||
@FXML private TableColumn<VisualiserBoat, Number> boatSpeedColumn;
|
||||
@FXML private LineChart<Number, Number> sparklineChart;
|
||||
@FXML private AnchorPane annotationPane;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Ctor.
|
||||
@@ -112,11 +98,10 @@ public class RaceController extends Controller {
|
||||
|
||||
@Override
|
||||
public void initialize(URL location, ResourceBundle resources) {
|
||||
// KeyFactory keyFactory = KeyFactory.getFactory();
|
||||
infoTableShow = true;
|
||||
|
||||
// Initialise keyboard handler
|
||||
race.addEventFilter(KeyEvent.KEY_PRESSED, event -> {
|
||||
racePane.addEventFilter(KeyEvent.KEY_PRESSED, event -> {
|
||||
String codeString = event.getCode().toString();
|
||||
|
||||
if (codeString.equals("TAB")){toggleTable();}
|
||||
@@ -142,7 +127,7 @@ public class RaceController extends Controller {
|
||||
Optional<ButtonType> result = alert.showAndWait();
|
||||
if (result.get() == ButtonType.OK) {
|
||||
parent.endEvent();
|
||||
race.setVisible(false);
|
||||
racePane.setVisible(false);
|
||||
App.app.showMainStage(App.getStage());
|
||||
}
|
||||
} else {
|
||||
@@ -151,7 +136,7 @@ public class RaceController extends Controller {
|
||||
alert.setContentText("Do you wish to quit the race?");
|
||||
Optional<ButtonType> result = alert.showAndWait();
|
||||
if (result.get() == ButtonType.OK) {
|
||||
race.setVisible(false);
|
||||
racePane.setVisible(false);
|
||||
App.app.showMainStage(App.getStage());
|
||||
}
|
||||
}
|
||||
@@ -175,14 +160,10 @@ public class RaceController extends Controller {
|
||||
//Information table.
|
||||
initialiseInfoTable(this.visualiserRace);
|
||||
|
||||
//Sparkline.
|
||||
initialiseSparkline(this.visualiserRace);
|
||||
|
||||
//Arrow.
|
||||
initialiseArrow(this.visualiserRace);
|
||||
|
||||
//Race canvas.
|
||||
initialiseRaceCanvas(this.visualiserRace);
|
||||
initialiseView3D(this.visualiserRace);
|
||||
|
||||
//Race timezone label.
|
||||
initialiseRaceTimezoneLabel(this.visualiserRace);
|
||||
@@ -190,11 +171,79 @@ public class RaceController extends Controller {
|
||||
//Race clock.
|
||||
initialiseRaceClock(this.visualiserRace);
|
||||
|
||||
|
||||
//Start the race animation timer.
|
||||
raceTimer();
|
||||
}
|
||||
|
||||
private void initialiseView3D(VisualiserRaceEvent race) {
|
||||
viewSubjects = FXCollections.observableArrayList();
|
||||
|
||||
// Import boat mesh
|
||||
URL asset = HostController.class.getClassLoader().getResource("assets/V1.2 Complete Boat.stl");
|
||||
StlMeshImporter importer = new StlMeshImporter();
|
||||
importer.read(asset);
|
||||
|
||||
// Configure camera angles and control
|
||||
view3D = new View3D();
|
||||
view3D.setDistance(1050);
|
||||
view3D.setYaw(0);
|
||||
view3D.setPitch(60);
|
||||
view3D.enableTracking();
|
||||
canvasBase.add(view3D, 0, 0);
|
||||
|
||||
// Set up projection from GPS to view
|
||||
RaceDataSource raceData = visualiserRace.getVisualiserRaceState().getRaceDataSource();
|
||||
final GPSConverter gpsConverter = new GPSConverter(raceData, 450, 450);
|
||||
|
||||
view3D.setItems(viewSubjects);
|
||||
// Position and add each mark to view
|
||||
for(Mark mark: race.getVisualiserRaceState().getMarks()) {
|
||||
Subject3D subject = new Subject3D(new Sphere(2));
|
||||
subject.setX(gpsConverter.convertGPS(mark.getPosition()).getX());
|
||||
subject.setZ(gpsConverter.convertGPS(mark.getPosition()).getY());
|
||||
|
||||
viewSubjects.add(subject);
|
||||
}
|
||||
// Position and add each boat to view
|
||||
for(VisualiserBoat boat: race.getVisualiserRaceState().getBoats()) {
|
||||
MeshView mesh = new MeshView(importer.getImport());
|
||||
Subject3D subject = new Subject3D(mesh);
|
||||
viewSubjects.add(subject);
|
||||
|
||||
// Track this boat's movement with the new subject
|
||||
AnimationTimer trackBoat = new AnimationTimer() {
|
||||
@Override
|
||||
public void handle(long now) {
|
||||
subject.setHeading(boat.getBearing().degrees());
|
||||
subject.setX(gpsConverter.convertGPS(boat.getPosition()).getX());
|
||||
subject.setZ(gpsConverter.convertGPS(boat.getPosition()).getY());
|
||||
}
|
||||
};
|
||||
trackBoat.start();
|
||||
}
|
||||
// Fix initial bird's-eye position
|
||||
view3D.updatePivot(new Translate(250, 0, 210));
|
||||
|
||||
// Bind zooming to scrolling
|
||||
view3D.setOnScroll(e -> {
|
||||
view3D.updateDistance(e.getDeltaY());
|
||||
});
|
||||
|
||||
// Bind zooming to keypress (Z/X default)
|
||||
racePane.addEventFilter(KeyEvent.KEY_PRESSED, e -> {
|
||||
ControlKey key = keyFactory.getKey(e.getCode().toString());
|
||||
if(key != null) {
|
||||
switch (key.toString()) {
|
||||
case "Zoom In":
|
||||
view3D.updateDistance(-10);
|
||||
break;
|
||||
case "Zoom Out":
|
||||
view3D.updateDistance(10);
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
@@ -337,42 +386,8 @@ public class RaceController extends Controller {
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Initialises the {@link Sparkline}, and listens to a specified {@link VisualiserRaceEvent}.
|
||||
* @param race The race to listen to.
|
||||
*/
|
||||
private void initialiseSparkline(VisualiserRaceEvent race) {
|
||||
//The race.getBoats() we are passing in is sorted by position in race inside the race class.
|
||||
this.sparkline = new Sparkline(this.visualiserRace.getVisualiserRaceState(), this.sparklineChart);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Initialises the {@link ResizableRaceCanvas}, provides the race to read data from.
|
||||
* @param race Race to read data from.
|
||||
*/
|
||||
private void initialiseRaceCanvas(VisualiserRaceEvent race) {
|
||||
|
||||
//Create canvas.
|
||||
raceCanvas = new ResizableRaceCanvas(race.getVisualiserRaceState());
|
||||
|
||||
//Set properties.
|
||||
raceCanvas.setMouseTransparent(true);
|
||||
raceCanvas.widthProperty().bind(canvasBase.widthProperty());
|
||||
raceCanvas.heightProperty().bind(canvasBase.heightProperty());
|
||||
|
||||
//Draw it and show it.
|
||||
raceCanvas.draw();
|
||||
raceCanvas.setVisible(true);
|
||||
|
||||
//Add to scene.
|
||||
canvasBase.getChildren().add(0, raceCanvas);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Intialises the race time zone label with the race's time zone.
|
||||
* Initialises the race time zone label with the race's time zone.
|
||||
* @param race The race to get time zone from.
|
||||
*/
|
||||
private void initialiseRaceTimezoneLabel(VisualiserRaceEvent race) {
|
||||
@@ -410,11 +425,7 @@ public class RaceController extends Controller {
|
||||
initialiseRace();
|
||||
|
||||
//Display this controller.
|
||||
race.setVisible(true);
|
||||
|
||||
|
||||
// set up annotation displays
|
||||
new Annotations(annotationPane, raceCanvas);
|
||||
racePane.setVisible(true);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -422,7 +433,7 @@ public class RaceController extends Controller {
|
||||
* @param boats boats there are in the race.
|
||||
*/
|
||||
public void finishRace(ObservableList<VisualiserBoat> boats) {
|
||||
race.setVisible(false);
|
||||
racePane.setVisible(false);
|
||||
parent.enterFinish(boats);
|
||||
}
|
||||
|
||||
@@ -457,18 +468,13 @@ public class RaceController extends Controller {
|
||||
finishRace(visualiserRace.getVisualiserRaceState().getBoats());
|
||||
|
||||
} else {
|
||||
//Otherwise, render the canvas.
|
||||
raceCanvas.drawRace();
|
||||
|
||||
|
||||
//Sort the tableview. Doesn't automatically work for all columns.
|
||||
boatInfoTable.sort();
|
||||
|
||||
}
|
||||
|
||||
//Return to main screen if we lose connection.
|
||||
if (!visualiserRace.getServerConnection().isAlive()) {
|
||||
race.setVisible(false);
|
||||
racePane.setVisible(false);
|
||||
//parent.enterTitle();
|
||||
try {
|
||||
App.app.showMainStage(App.getStage());
|
||||
@@ -490,10 +496,10 @@ public class RaceController extends Controller {
|
||||
* toggles if the info table is shown
|
||||
*/
|
||||
private void toggleTable() {
|
||||
double tablePercent = 1 - (boatPlacingColumn.getPrefWidth() + boatTeamColumn.getPrefWidth() + boatMarkColumn.getPrefWidth() + boatSpeedColumn.getPrefWidth())/race.getWidth();
|
||||
double tablePercent = 1 - (boatPlacingColumn.getPrefWidth() + boatTeamColumn.getPrefWidth() + boatMarkColumn.getPrefWidth() + boatSpeedColumn.getPrefWidth())/racePane.getWidth();
|
||||
|
||||
if (infoTableShow){
|
||||
race.setDividerPositions(tablePercent);
|
||||
racePane.setDividerPositions(tablePercent);
|
||||
|
||||
arrowPane.setScaleX(0.5);
|
||||
arrowPane.setScaleY(0.5);
|
||||
@@ -501,7 +507,7 @@ public class RaceController extends Controller {
|
||||
arrowPane.setTranslateY(0 - arrowPane.getScene().getHeight()/4);
|
||||
|
||||
}else{
|
||||
race.setDividerPositions(1);
|
||||
racePane.setDividerPositions(1);
|
||||
|
||||
arrowPane.setScaleX(1);
|
||||
arrowPane.setScaleY(1);
|
||||
|
||||
@@ -225,12 +225,10 @@ public class StartController extends Controller {
|
||||
//Get the current race status.
|
||||
RaceStatusEnum raceStatus = visualiserRaceEvent.getVisualiserRaceState().getRaceStatusEnum();
|
||||
|
||||
//Display it.
|
||||
raceStatusLabel.setText("Race Status: " + raceStatus.name());
|
||||
|
||||
|
||||
//If the race has reached the preparatory phase, or has started...
|
||||
if (raceStatus == RaceStatusEnum.PREPARATORY || raceStatus == RaceStatusEnum.STARTED) {
|
||||
if (raceStatus == RaceStatusEnum.WARNING
|
||||
|| raceStatus == RaceStatusEnum.PREPARATORY
|
||||
|| raceStatus == RaceStatusEnum.STARTED) {
|
||||
//Stop this timer.
|
||||
stop();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user