mirror of
https://github.com/michaelrausch/Party-Parrots-At-Sea.git
synced 2026-05-09 06:18:44 +00:00
aaf2e6a3f0
#story[923]
430 lines
14 KiB
Java
430 lines
14 KiB
Java
package seng302.controllers;
|
|
|
|
import javafx.animation.KeyFrame;
|
|
import javafx.animation.Timeline;
|
|
import javafx.collections.FXCollections;
|
|
import javafx.collections.ObservableList;
|
|
import javafx.fxml.FXML;
|
|
import javafx.fxml.FXMLLoader;
|
|
import javafx.scene.Scene;
|
|
import javafx.scene.control.Button;
|
|
import javafx.scene.control.CheckBox;
|
|
import javafx.scene.control.ComboBox;
|
|
import javafx.scene.control.Slider;
|
|
import javafx.scene.layout.AnchorPane;
|
|
import javafx.scene.layout.Pane;
|
|
import javafx.scene.layout.VBox;
|
|
import javafx.scene.paint.Color;
|
|
import javafx.scene.paint.Paint;
|
|
import javafx.scene.text.Text;
|
|
import javafx.stage.Stage;
|
|
import javafx.stage.StageStyle;
|
|
import javafx.util.Duration;
|
|
import javafx.util.StringConverter;
|
|
import seng302.controllers.annotations.Annotation;
|
|
import seng302.controllers.annotations.ImportantAnnotationController;
|
|
import seng302.controllers.annotations.ImportantAnnotationDelegate;
|
|
import seng302.controllers.annotations.ImportantAnnotationsState;
|
|
import seng302.models.*;
|
|
import seng302.models.stream.StreamParser;
|
|
|
|
import java.io.IOException;
|
|
import java.util.*;
|
|
|
|
/**
|
|
* Created by ptg19 on 29/03/17.
|
|
*/
|
|
public class RaceViewController extends Thread implements ImportantAnnotationDelegate {
|
|
|
|
@FXML
|
|
private VBox positionVbox;
|
|
@FXML
|
|
private CheckBox toggleFps;
|
|
@FXML
|
|
private Text timerLabel;
|
|
@FXML
|
|
private AnchorPane contentAnchorPane;
|
|
@FXML
|
|
private Text windArrowText, windDirectionText;
|
|
@FXML
|
|
private Slider annotationSlider;
|
|
@FXML
|
|
private Button selectAnnotationBtn;
|
|
@FXML
|
|
private ComboBox boatSelectionComboBox;
|
|
@FXML
|
|
private CanvasController includedCanvasController;
|
|
|
|
private ArrayList<Yacht> startingBoats = new ArrayList<>();
|
|
private boolean displayFps;
|
|
private Timeline timerTimeline;
|
|
private Stage stage;
|
|
|
|
private ImportantAnnotationsState importantAnnotations;
|
|
private Yacht selectedBoat;
|
|
|
|
public void initialize() {
|
|
// Load a default important annotation state
|
|
importantAnnotations = new ImportantAnnotationsState();
|
|
|
|
includedCanvasController.setup(this);
|
|
includedCanvasController.initializeCanvas();
|
|
initializeUpdateTimer();
|
|
initialiseFPSCheckBox();
|
|
initialiseAnnotationSlider();
|
|
initialiseBoatSelectionComboBox();
|
|
includedCanvasController.timer.start();
|
|
|
|
selectAnnotationBtn.setOnAction(event -> {
|
|
loadSelectAnnotationView();
|
|
});
|
|
}
|
|
|
|
/**
|
|
* The important annotations have been changed, update this view
|
|
* @param importantAnnotationsState The current state of the selected annotations
|
|
*/
|
|
public void importantAnnotationsChanged(ImportantAnnotationsState importantAnnotationsState) {
|
|
this.importantAnnotations = importantAnnotationsState;
|
|
setAnnotations((int) annotationSlider.getValue()); // Refresh the displayed annotations
|
|
}
|
|
|
|
/**
|
|
* Loads the "select annotations" view in a new window
|
|
*/
|
|
private void loadSelectAnnotationView() {
|
|
try {
|
|
FXMLLoader fxmlLoader = new FXMLLoader();
|
|
Stage stage = new Stage();
|
|
|
|
// Set controller
|
|
ImportantAnnotationController controller = new ImportantAnnotationController(this,
|
|
stage);
|
|
fxmlLoader.setController(controller);
|
|
|
|
// Load FXML and set CSS
|
|
fxmlLoader
|
|
.setLocation(getClass().getResource("/views/importantAnnotationSelectView.fxml"));
|
|
Scene scene = new Scene(fxmlLoader.load(), 469, 298);
|
|
scene.getStylesheets().add(getClass().getResource("/css/master.css").toString());
|
|
stage.initStyle(StageStyle.UNDECORATED);
|
|
|
|
stage.setScene(scene);
|
|
stage.show();
|
|
|
|
controller.loadState(importantAnnotations);
|
|
|
|
} catch (IOException e) {
|
|
e.printStackTrace();
|
|
}
|
|
}
|
|
|
|
|
|
private void initialiseFPSCheckBox() {
|
|
displayFps = true;
|
|
toggleFps.selectedProperty().addListener(
|
|
(observable, oldValue, newValue) -> displayFps = !displayFps);
|
|
}
|
|
|
|
private void initialiseAnnotationSlider() {
|
|
annotationSlider.setLabelFormatter(new StringConverter<Double>() {
|
|
@Override
|
|
public String toString(Double n) {
|
|
if (n == 0) {
|
|
return "None";
|
|
}
|
|
if (n == 1) {
|
|
return "Important";
|
|
}
|
|
if (n == 2) {
|
|
return "All";
|
|
}
|
|
|
|
return "All";
|
|
}
|
|
|
|
@Override
|
|
public Double fromString(String s) {
|
|
switch (s) {
|
|
case "None":
|
|
return 0d;
|
|
case "Important":
|
|
return 1d;
|
|
case "All":
|
|
return 2d;
|
|
|
|
default:
|
|
return 2d;
|
|
}
|
|
}
|
|
});
|
|
|
|
annotationSlider.valueProperty().addListener((obs, oldval, newVal) ->
|
|
setAnnotations((int) annotationSlider.getValue()));
|
|
|
|
annotationSlider.setValue(2);
|
|
}
|
|
|
|
|
|
/**
|
|
* Initalises a timer which updates elements of the RaceView such as wind direction, boat
|
|
* orderings etc.. which are dependent on the info from the stream parser constantly.
|
|
* Updates of each of these attributes are called ONCE EACH SECOND
|
|
*/
|
|
private void initializeUpdateTimer() {
|
|
timerTimeline = new Timeline();
|
|
timerTimeline.setCycleCount(Timeline.INDEFINITE);
|
|
// Run timer update every second
|
|
timerTimeline.getKeyFrames().add(
|
|
new KeyFrame(Duration.seconds(1),
|
|
event -> {
|
|
updateRaceTime();
|
|
updateWindDirection();
|
|
updateOrder();
|
|
updateBoatSelectionComboBox();
|
|
|
|
})
|
|
);
|
|
|
|
// Start the timer
|
|
timerTimeline.playFromStart();
|
|
}
|
|
|
|
|
|
/**
|
|
* Updates the wind direction arrow and text as from info from the StreamParser
|
|
*/
|
|
private void updateWindDirection() {
|
|
windDirectionText.setText(String.format("%.1f°", StreamParser.getWindDirection()));
|
|
windArrowText.setRotate(StreamParser.getWindDirection());
|
|
}
|
|
|
|
|
|
/**
|
|
* Updates the clock for the race
|
|
*/
|
|
private void updateRaceTime() {
|
|
if (StreamParser.isRaceFinished()) {
|
|
timerLabel.setFill(Color.RED);
|
|
timerLabel.setText("Race Finished!");
|
|
} else {
|
|
timerLabel.setText(getTimeSinceStartOfRace());
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Grabs the boats currently in the race as from the StreamParser and sets them to be selectable
|
|
* in the boat selection combo box
|
|
*/
|
|
private void updateBoatSelectionComboBox() {
|
|
ObservableList<Yacht> observableBoats = FXCollections
|
|
.observableArrayList(StreamParser.getBoatsPos().values());
|
|
boatSelectionComboBox.setItems(observableBoats);
|
|
}
|
|
|
|
|
|
/**
|
|
* Updates the order of the boats as from the StreamParser and sets them in the boat order
|
|
* section
|
|
*/
|
|
private void updateOrder() {
|
|
positionVbox.getChildren().clear();
|
|
positionVbox.getChildren().removeAll();
|
|
positionVbox.getStylesheets().add(getClass().getResource("/css/master.css").toString());
|
|
|
|
for (Yacht boat : StreamParser.getBoatsPos().values()) {
|
|
if (boat.getBoatStatus() == 3) { // 3 is finish status
|
|
Text textToAdd = new Text(boat.getPosition() + ". " +
|
|
boat.getShortName() + " (Finished)");
|
|
textToAdd.setFill(Paint.valueOf("#d3d3d3"));
|
|
positionVbox.getChildren().add(textToAdd);
|
|
|
|
} else {
|
|
Text textToAdd = new Text(boat.getPosition() + ". " +
|
|
boat.getShortName() + " ");
|
|
textToAdd.setFill(Paint.valueOf("#d3d3d3"));
|
|
textToAdd.setStyle("");
|
|
positionVbox.getChildren().add(textToAdd);
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Initialised the combo box with any boats currently in the race and adds the required listener
|
|
* for the combobox to take action upon selection
|
|
*/
|
|
private void initialiseBoatSelectionComboBox() {
|
|
updateBoatSelectionComboBox();
|
|
boatSelectionComboBox.valueProperty().addListener((observable, oldValue, newValue) -> {
|
|
//This listener is fired whenever the combo box changes. This means when the values are updated
|
|
//We dont want to set the selected value if the values are updated but nothing clicked (null)
|
|
if (newValue != null && newValue != selectedBoat) {
|
|
Yacht thisYacht = (Yacht) newValue;
|
|
setSelectedBoat(thisYacht);
|
|
}
|
|
});
|
|
}
|
|
|
|
|
|
/**
|
|
* Display the list of boats in the order they finished the race
|
|
*/
|
|
private void loadRaceResultView() {
|
|
FXMLLoader loader = new FXMLLoader(getClass().getResource("/views/FinishView.fxml"));
|
|
|
|
try {
|
|
contentAnchorPane.getChildren().removeAll();
|
|
contentAnchorPane.getChildren().clear();
|
|
contentAnchorPane.getChildren().addAll((Pane) loader.load());
|
|
|
|
} catch (javafx.fxml.LoadException e) {
|
|
System.err.println(e.getCause());
|
|
} catch (IOException e) {
|
|
System.err.println(e);
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Convert seconds to a string of the format mm:ss
|
|
*
|
|
* @param time the time in seconds
|
|
* @return a formatted string
|
|
*/
|
|
public String convertTimeToMinutesSeconds(int time) {
|
|
if (time < 0) {
|
|
return String.format("-%02d:%02d", (time * -1) / 60, (time * -1) % 60);
|
|
}
|
|
return String.format("%02d:%02d", time / 60, time % 60);
|
|
}
|
|
|
|
private String getTimeSinceStartOfRace() {
|
|
String timerString = "0:00";
|
|
if (StreamParser.getTimeSinceStart() > 0) {
|
|
String timerMinute = Long.toString(StreamParser.getTimeSinceStart() / 60);
|
|
String timerSecond = Long.toString(StreamParser.getTimeSinceStart() % 60);
|
|
if (timerSecond.length() == 1) {
|
|
timerSecond = "0" + timerSecond;
|
|
}
|
|
timerString = "-" + timerMinute + ":" + timerSecond;
|
|
} else {
|
|
String timerMinute = Long.toString(-1 * StreamParser.getTimeSinceStart() / 60);
|
|
String timerSecond = Long.toString(-1 * StreamParser.getTimeSinceStart() % 60);
|
|
if (timerSecond.length() == 1) {
|
|
timerSecond = "0" + timerSecond;
|
|
}
|
|
timerString = timerMinute + ":" + timerSecond;
|
|
}
|
|
return timerString;
|
|
}
|
|
|
|
|
|
public boolean isDisplayFps() {
|
|
return displayFps;
|
|
}
|
|
|
|
/**
|
|
* Display the important annotations for a specific BoatGroup
|
|
* @param bg The boat group to set the annotations for
|
|
*/
|
|
private void setBoatGroupImportantAnnotations(BoatGroup bg) {
|
|
if (importantAnnotations.getAnnotationState(Annotation.NAME)) {
|
|
bg.setTeamNameObjectVisible(true);
|
|
} else {
|
|
bg.setTeamNameObjectVisible(false);
|
|
}
|
|
|
|
if (importantAnnotations.getAnnotationState(Annotation.SPEED)) {
|
|
bg.setVelocityObjectVisible(true);
|
|
} else {
|
|
bg.setVelocityObjectVisible(false);
|
|
}
|
|
|
|
if (importantAnnotations.getAnnotationState(Annotation.TRACK)) {
|
|
bg.setLineGroupVisible(true);
|
|
} else {
|
|
bg.setLineGroupVisible(false);
|
|
}
|
|
|
|
if (importantAnnotations.getAnnotationState(Annotation.WAKE)) {
|
|
bg.setWakeVisible(true);
|
|
} else {
|
|
bg.setWakeVisible(false);
|
|
}
|
|
//TODO fix boat annotations with new boatgroup
|
|
if (importantAnnotations.getAnnotationState(Annotation.ESTTIMETONEXTMARK)) {
|
|
bg.setEstTimeToNextMarkObjectVisible(true);
|
|
} else {
|
|
bg.setEstTimeToNextMarkObjectVisible(false);
|
|
}
|
|
|
|
if (importantAnnotations.getAnnotationState(Annotation.LEGTIME)) {
|
|
bg.setLegTimeObjectVisible(true);
|
|
} else {
|
|
bg.setLegTimeObjectVisible(false);
|
|
}
|
|
}
|
|
|
|
private void setAnnotations(Integer annotationLevel) {
|
|
switch (annotationLevel) {
|
|
// No Annotations
|
|
case 0:
|
|
for (BoatGroup bg : includedCanvasController.getBoatGroups()) {
|
|
bg.setTeamNameObjectVisible(false);
|
|
bg.setVelocityObjectVisible(false);
|
|
bg.setEstTimeToNextMarkObjectVisible(false);
|
|
bg.setLegTimeObjectVisible(false);
|
|
bg.setLineGroupVisible(false);
|
|
bg.setWakeVisible(false);
|
|
}
|
|
break;
|
|
// Important Annotations
|
|
case 1:
|
|
for (BoatGroup bg : includedCanvasController.getBoatGroups()) {
|
|
setBoatGroupImportantAnnotations(bg);
|
|
}
|
|
break;
|
|
// All Annotations
|
|
case 2:
|
|
for (BoatGroup bg : includedCanvasController.getBoatGroups()) {
|
|
bg.setTeamNameObjectVisible(true);
|
|
bg.setVelocityObjectVisible(true);
|
|
bg.setEstTimeToNextMarkObjectVisible(true);
|
|
bg.setLegTimeObjectVisible(true);
|
|
bg.setLineGroupVisible(true);
|
|
bg.setWakeVisible(true);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Sets all the annotations of the selected boat to be visible and all others to be hidden
|
|
*
|
|
* @param yacht The yacht for which we want to view all annotations
|
|
*/
|
|
private void setSelectedBoat(Yacht yacht) {
|
|
for (BoatGroup bg : includedCanvasController.getBoatGroups()) {
|
|
//We need to iterate over all race groups to get the matching boat group belonging to this boat if we
|
|
//are to toggle its annotations, there is no other backwards knowledge of a yacht to its boatgroup.
|
|
if (bg.getBoat().getHullID().equals(yacht.getHullID())) {
|
|
bg.setIsSelected(true);
|
|
selectedBoat = yacht;
|
|
} else {
|
|
bg.setIsSelected(false);
|
|
}
|
|
}
|
|
}
|
|
|
|
void setStage(Stage stage) {
|
|
this.stage = stage;
|
|
}
|
|
|
|
Stage getStage() {
|
|
return stage;
|
|
}
|
|
} |