From 4a0d04d7ab8a5b434a0d7c26b8361971cca3965a Mon Sep 17 00:00:00 2001 From: Jessica Syder Date: Mon, 4 Sep 2017 23:10:25 +1200 Subject: [PATCH 01/37] Created new abstract Controller class with load methods. - loadScene method to load into current stage - loadPopupScene method to load into a new window - icon added to popup windows - load methods return Controller of the new scee - KeyBindingsController extends new Controller class and works correctly #story[1261] --- .../Controllers/KeyBindingsController.java | 28 ++++++++- .../Controllers/MainController.java | 3 +- .../Controllers/TitleController.java | 36 +++-------- .../visualiser/Controllers2/Controller.java | 62 +++++++++++++++++++ 4 files changed, 97 insertions(+), 32 deletions(-) create mode 100644 racevisionGame/src/main/java/visualiser/Controllers2/Controller.java diff --git a/racevisionGame/src/main/java/visualiser/Controllers/KeyBindingsController.java b/racevisionGame/src/main/java/visualiser/Controllers/KeyBindingsController.java index 84d82e91..1ac0e371 100644 --- a/racevisionGame/src/main/java/visualiser/Controllers/KeyBindingsController.java +++ b/racevisionGame/src/main/java/visualiser/Controllers/KeyBindingsController.java @@ -1,6 +1,7 @@ package visualiser.Controllers; import javafx.application.Platform; +import javafx.event.EventHandler; import javafx.fxml.FXML; import javafx.fxml.FXMLLoader; import javafx.scene.Parent; @@ -13,6 +14,7 @@ import javafx.scene.layout.AnchorPane; import javafx.stage.Modality; import javafx.stage.Stage; import javafx.stage.WindowEvent; +import visualiser.Controllers2.Controller; import visualiser.gameController.Keys.ControlKey; import visualiser.gameController.Keys.KeyFactory; @@ -25,7 +27,7 @@ import static visualiser.app.App.keyFactory; /** * Controller for the scene used to display and update current key bindings. */ -public class KeyBindingsController { +public class KeyBindingsController extends Controller{ private @FXML Button btnSave; private @FXML Button btnCancel; private @FXML Button btnReset; @@ -43,6 +45,7 @@ public class KeyBindingsController { initializeTable(); populateTable(); setKeyListener(); + setClosedListener(); } /** @@ -115,6 +118,29 @@ public class KeyBindingsController { return newKeyFactory; } + /** + * Creates a listener for when a user tries to close the current window. + */ + public void setClosedListener(){ + anchor.sceneProperty().addListener((obsS, oldS, newS) -> { + if (newS != null) { + newS.windowProperty().addListener((obsW, oldW, newW) -> { + if (newW != null) { + Stage stage = (Stage)newW; + // WE is processed by onExit method + stage.setOnCloseRequest(new EventHandler() { + public void handle(WindowEvent we) { + if (we.getEventType() == WindowEvent.WINDOW_CLOSE_REQUEST) { + onExit(we); + } + } + }); + } + }); + } + }); + } + /** * Creates a listener for the base anchorpane for key presses. * It updates the current key bindings of the {@link KeyFactory} if diff --git a/racevisionGame/src/main/java/visualiser/Controllers/MainController.java b/racevisionGame/src/main/java/visualiser/Controllers/MainController.java index 57d18830..0452f4a5 100644 --- a/racevisionGame/src/main/java/visualiser/Controllers/MainController.java +++ b/racevisionGame/src/main/java/visualiser/Controllers/MainController.java @@ -3,7 +3,6 @@ package visualiser.Controllers; import javafx.collections.ObservableList; import javafx.fxml.FXML; import javafx.scene.layout.AnchorPane; -import visualiser.app.App; import visualiser.gameController.ControllerClient; import visualiser.model.VisualiserBoat; import visualiser.model.VisualiserRaceEvent; @@ -99,7 +98,7 @@ public class MainController extends Controller { raceController.setParent(this); connectionController.setParent(this); finishController.setParent(this); - titleController.setParent(this); +// titleController.setParent(this); hostController.setParent(this); lobbyController.setParent(this); diff --git a/racevisionGame/src/main/java/visualiser/Controllers/TitleController.java b/racevisionGame/src/main/java/visualiser/Controllers/TitleController.java index aa2edf13..b028e92a 100644 --- a/racevisionGame/src/main/java/visualiser/Controllers/TitleController.java +++ b/racevisionGame/src/main/java/visualiser/Controllers/TitleController.java @@ -1,16 +1,11 @@ package visualiser.Controllers; -import javafx.event.EventHandler; import javafx.fxml.FXML; -import javafx.fxml.FXMLLoader; -import javafx.scene.Parent; -import javafx.scene.Scene; import javafx.scene.control.Button; import javafx.scene.control.RadioButton; import javafx.scene.layout.AnchorPane; import javafx.stage.Modality; -import javafx.stage.Stage; -import javafx.stage.WindowEvent; +import visualiser.Controllers2.Controller; import visualiser.app.App; import java.io.IOException; @@ -42,7 +37,7 @@ public class TitleController extends Controller { */ public void hostAGame() throws IOException { titleWrapper.setVisible(false); - parent.hostGame(); +// parent.hostGame(); App.getStage().setResizable(true); } @@ -59,7 +54,7 @@ public class TitleController extends Controller { */ public void joinAGame() { titleWrapper.setVisible(false); - parent.enterLobby(); +// parent.enterLobby(); App.getStage().setResizable(true); } @@ -81,7 +76,7 @@ public class TitleController extends Controller { dayModeRD.setSelected(false); } - @Override +// @Override public void initialize(URL location, ResourceBundle resources) { } @@ -90,26 +85,9 @@ public class TitleController extends Controller { */ public void controlBtnPressed(){ try { - FXMLLoader loader = new FXMLLoader(); - loader.setLocation(getClass().getResource("/visualiser/scenes/keyBindings.fxml")); - Parent layout = loader.load(); - Scene scene = new Scene(layout); - Stage popupStage = new Stage(); - popupStage.setResizable(false); - popupStage.setTitle("Game Controls"); - popupStage.initModality(Modality.WINDOW_MODAL); - popupStage.centerOnScreen(); - popupStage.setScene(scene); - popupStage.show(); - KeyBindingsController controller = loader.getController(); - popupStage.setOnCloseRequest(new EventHandler() { - public void handle(WindowEvent we) { - if (we.getEventType() == WindowEvent.WINDOW_CLOSE_REQUEST) { - controller.onExit(we); - } - } - }); - } catch (Exception e){ + loadPopupScene("/visualiser/scenes/keyBindings.fxml", + "Game Controls", Modality.WINDOW_MODAL); + } catch (IOException e) { e.printStackTrace(); } } diff --git a/racevisionGame/src/main/java/visualiser/Controllers2/Controller.java b/racevisionGame/src/main/java/visualiser/Controllers2/Controller.java new file mode 100644 index 00000000..0117d9dc --- /dev/null +++ b/racevisionGame/src/main/java/visualiser/Controllers2/Controller.java @@ -0,0 +1,62 @@ +package visualiser.Controllers2; + +import javafx.fxml.FXMLLoader; +import javafx.scene.Parent; +import javafx.scene.Scene; +import javafx.scene.image.Image; +import javafx.stage.Modality; +import javafx.stage.Stage; +import visualiser.app.App; + +import java.io.IOException; + +/** + * Abstract controller class to give each subclass the functionality to load + * a new scene into the existing stage, or create a new popup window. + */ +public abstract class Controller { + + /** + * Used to load a new scene in the currently open stage. + * @param fxmlUrl the URL of the FXML file to be loaded + * @return the controller of the new scene + * @throws IOException if there is an issue with the fxmlUrl + */ + protected Controller loadScene(String fxmlUrl) throws IOException { + FXMLLoader loader = new FXMLLoader(); + loader.setLocation(getClass().getResource(fxmlUrl)); + Parent root = loader.load(); + Stage stage = App.getStage(); + Scene scene = new Scene(root); + stage.setScene(scene); + stage.show(); + + return loader.getController(); + } + + /** + * Used to load a scene in a new separate popup stage. + * @param fxmlUrl the URL of the FXML file to be loaded + * @param title title for the new window + * @param modality modality settings for popup window + * @return the controller of the new scene + * @throws IOException if there is an issue with the fxmlUrl + */ + protected Controller loadPopupScene(String fxmlUrl, String title, Modality + modality) throws IOException { + FXMLLoader loader = new FXMLLoader(); + loader.setLocation(getClass().getResource(fxmlUrl)); + Parent root = loader.load(); + Stage stage = new Stage(); + stage.initModality(modality); + stage.setTitle(title); + stage.centerOnScreen(); + stage.getIcons().add(new Image(getClass().getClassLoader().getResourceAsStream("images/SailIcon.png"))); + Scene scene = new Scene(root); + stage.setScene(scene); + stage.show(); + + return loader.getController(); + } + +} From f4cb1a3ac4fdb4397750793400cfa807b462c74f Mon Sep 17 00:00:00 2001 From: Joseph Date: Tue, 5 Sep 2017 12:40:34 +1200 Subject: [PATCH 02/37] Made ObserverCommands and made racestate an observable. ObserverCommands observes the race passes in the params. #story[1196] --- .../src/main/java/mock/model/MockRace.java | 6 ++++++ .../src/main/java/mock/model/RaceLogic.java | 4 ++++ .../mock/model/commandFactory/Command.java | 2 ++ .../model/commandFactory/ObserverCommand.java | 20 +++++++++++++++++++ .../model/commandFactory/SailsCommand.java | 14 ++++++++----- .../model/commandFactory/TackGybeCommand.java | 13 +++++++----- .../mock/model/commandFactory/VMGCommand.java | 14 ++++++++----- .../model/commandFactory/WindCommand.java | 14 ++++++++----- .../src/main/java/shared/model/RaceState.java | 3 ++- 9 files changed, 69 insertions(+), 21 deletions(-) create mode 100644 racevisionGame/src/main/java/mock/model/commandFactory/ObserverCommand.java diff --git a/racevisionGame/src/main/java/mock/model/MockRace.java b/racevisionGame/src/main/java/mock/model/MockRace.java index f606c29d..e69db01e 100644 --- a/racevisionGame/src/main/java/mock/model/MockRace.java +++ b/racevisionGame/src/main/java/mock/model/MockRace.java @@ -743,4 +743,10 @@ public class MockRace extends RaceState { } + /** + * Made public, so race logic can control it + */ + public void setChanged() { + super.setChanged(); + } } diff --git a/racevisionGame/src/main/java/mock/model/RaceLogic.java b/racevisionGame/src/main/java/mock/model/RaceLogic.java index d1ef39e0..977bd8d6 100644 --- a/racevisionGame/src/main/java/mock/model/RaceLogic.java +++ b/racevisionGame/src/main/java/mock/model/RaceLogic.java @@ -185,6 +185,10 @@ public class RaceLogic implements RunnableWithFramePeriod, Observer { previousFrameTime = currentTime; } + // Notify Observers + race.setChanged(); + race.notifyObservers(); + waitForFramePeriod(previousFrameTime, currentTime, 50); previousFrameTime = currentTime; } diff --git a/racevisionGame/src/main/java/mock/model/commandFactory/Command.java b/racevisionGame/src/main/java/mock/model/commandFactory/Command.java index e0486114..421d5b32 100644 --- a/racevisionGame/src/main/java/mock/model/commandFactory/Command.java +++ b/racevisionGame/src/main/java/mock/model/commandFactory/Command.java @@ -3,6 +3,8 @@ package mock.model.commandFactory; import mock.model.MockBoat; import mock.model.MockRace; +import java.util.Observer; + /** * Allows RaceLogic to control MockRace state according to the Command pattern */ diff --git a/racevisionGame/src/main/java/mock/model/commandFactory/ObserverCommand.java b/racevisionGame/src/main/java/mock/model/commandFactory/ObserverCommand.java new file mode 100644 index 00000000..a9ca9209 --- /dev/null +++ b/racevisionGame/src/main/java/mock/model/commandFactory/ObserverCommand.java @@ -0,0 +1,20 @@ +package mock.model.commandFactory; + +import mock.model.MockBoat; +import mock.model.MockRace; + +import java.util.Observer; + +/** + * Command that can observe the race + */ +public abstract class ObserverCommand implements Command, Observer { + MockRace race; + MockBoat boat; + + public ObserverCommand(MockRace race, MockBoat boat) { + this.race = race; + this.boat = boat; + race.addObserver(this); + } +} diff --git a/racevisionGame/src/main/java/mock/model/commandFactory/SailsCommand.java b/racevisionGame/src/main/java/mock/model/commandFactory/SailsCommand.java index 7d620a42..bfb752ea 100644 --- a/racevisionGame/src/main/java/mock/model/commandFactory/SailsCommand.java +++ b/racevisionGame/src/main/java/mock/model/commandFactory/SailsCommand.java @@ -3,14 +3,13 @@ package mock.model.commandFactory; import mock.model.MockBoat; import mock.model.MockRace; -public class SailsCommand implements Command { - private MockRace race; - private MockBoat boat; +import java.util.Observable; + +public class SailsCommand extends ObserverCommand { private boolean sailsOut; public SailsCommand(MockRace race, MockBoat boat, Boolean sailsOut) { - this.race = race; - this.boat = boat; + super(race, boat); this.sailsOut = sailsOut; } @@ -18,4 +17,9 @@ public class SailsCommand implements Command { public void execute() { this.boat.setSailsOut(this.sailsOut); } + + @Override + public void update(Observable o, Object arg) { + + } } diff --git a/racevisionGame/src/main/java/mock/model/commandFactory/TackGybeCommand.java b/racevisionGame/src/main/java/mock/model/commandFactory/TackGybeCommand.java index d0b0584b..28ace831 100644 --- a/racevisionGame/src/main/java/mock/model/commandFactory/TackGybeCommand.java +++ b/racevisionGame/src/main/java/mock/model/commandFactory/TackGybeCommand.java @@ -4,12 +4,12 @@ import mock.model.MockBoat; import mock.model.MockRace; import shared.model.Bearing; +import java.util.Observable; + /** * Command class for tacking and gybing */ -public class TackGybeCommand implements Command { - private MockRace race; - private MockBoat boat; +public class TackGybeCommand extends ObserverCommand { /** * Constructor for class @@ -17,8 +17,7 @@ public class TackGybeCommand implements Command { * @param boat mock boat to update */ public TackGybeCommand(MockRace race, MockBoat boat) { - this.race = race; - this.boat = boat; + super(race, boat); } @Override @@ -49,5 +48,9 @@ public class TackGybeCommand implements Command { return phi > 180 ? 360 - phi : phi; } + @Override + public void update(Observable o, Object arg) { + + } } diff --git a/racevisionGame/src/main/java/mock/model/commandFactory/VMGCommand.java b/racevisionGame/src/main/java/mock/model/commandFactory/VMGCommand.java index 39469cf8..45f666ec 100644 --- a/racevisionGame/src/main/java/mock/model/commandFactory/VMGCommand.java +++ b/racevisionGame/src/main/java/mock/model/commandFactory/VMGCommand.java @@ -3,12 +3,12 @@ package mock.model.commandFactory; import mock.model.MockBoat; import mock.model.MockRace; +import java.util.Observable; + /** * Command class for autoVMG */ -public class VMGCommand implements Command { - private MockRace race; - private MockBoat boat; +public class VMGCommand extends ObserverCommand { /** * Constructor for class @@ -16,8 +16,7 @@ public class VMGCommand implements Command { * @param boat mock boat to update */ public VMGCommand(MockRace race, MockBoat boat) { - this.race = race; - this.boat = boat; + super(race, boat); } @Override @@ -28,4 +27,9 @@ public class VMGCommand implements Command { boat.setAutoVMG(true); } } + + @Override + public void update(Observable o, Object arg) { + + } } diff --git a/racevisionGame/src/main/java/mock/model/commandFactory/WindCommand.java b/racevisionGame/src/main/java/mock/model/commandFactory/WindCommand.java index 530bf5bc..138ccff0 100644 --- a/racevisionGame/src/main/java/mock/model/commandFactory/WindCommand.java +++ b/racevisionGame/src/main/java/mock/model/commandFactory/WindCommand.java @@ -4,17 +4,16 @@ import mock.model.MockBoat; import mock.model.MockRace; import shared.model.Bearing; +import java.util.Observable; + /** * Created by connortaylorbrown on 4/08/17. */ -public class WindCommand implements Command { - private MockRace race; - private MockBoat boat; +public class WindCommand extends ObserverCommand { private int direction; public WindCommand(MockRace race, MockBoat boat, boolean upwind) { - this.race = race; - this.boat = boat; + super(race, boat); this.direction = upwind? -1 : 1; } @@ -34,4 +33,9 @@ public class WindCommand implements Command { boat.setBearing(Bearing.fromDegrees(heading + offset)); } + + @Override + public void update(Observable o, Object arg) { + + } } diff --git a/racevisionGame/src/main/java/shared/model/RaceState.java b/racevisionGame/src/main/java/shared/model/RaceState.java index 48361da2..e755ba80 100644 --- a/racevisionGame/src/main/java/shared/model/RaceState.java +++ b/racevisionGame/src/main/java/shared/model/RaceState.java @@ -13,6 +13,7 @@ import shared.dataInput.RegattaDataSource; import java.time.ZonedDateTime; import java.util.ArrayList; import java.util.List; +import java.util.Observable; /** @@ -20,7 +21,7 @@ import java.util.List; * This is a base class inherited by {@link mock.model.MockRace} and {@link visualiser.model.VisualiserRaceState}. * Has a course, state, wind, boundaries, etc.... Boats are added by inheriting classes (see {@link Boat}, {@link mock.model.MockBoat}, {@link visualiser.model.VisualiserBoat}. */ -public abstract class RaceState { +public abstract class RaceState extends Observable{ From 00cedf4d4d30a3763480f120a48b4580b250771a Mon Sep 17 00:00:00 2001 From: Joseph Gardner Date: Wed, 6 Sep 2017 15:19:30 +1200 Subject: [PATCH 03/37] TackGybeCommand now smooths the rotation of the boat. #story[1196] --- .../src/main/java/mock/model/RaceLogic.java | 10 +++--- .../model/commandFactory/TackGybeCommand.java | 35 ++++++++++++++----- .../src/main/java/shared/model/Constants.java | 4 ++- 3 files changed, 35 insertions(+), 14 deletions(-) diff --git a/racevisionGame/src/main/java/mock/model/RaceLogic.java b/racevisionGame/src/main/java/mock/model/RaceLogic.java index 977bd8d6..308c4b46 100644 --- a/racevisionGame/src/main/java/mock/model/RaceLogic.java +++ b/racevisionGame/src/main/java/mock/model/RaceLogic.java @@ -145,9 +145,13 @@ public class RaceLogic implements RunnableWithFramePeriod, Observer { //Get the current time. long currentTime = System.currentTimeMillis(); - //Execute commands from clients. + // Execute commands from clients. commands.execute(); + // Notify Observers + race.setChanged(); + race.notifyObservers(); + //Update race time. race.updateRaceTime(currentTime); @@ -185,10 +189,6 @@ public class RaceLogic implements RunnableWithFramePeriod, Observer { previousFrameTime = currentTime; } - // Notify Observers - race.setChanged(); - race.notifyObservers(); - waitForFramePeriod(previousFrameTime, currentTime, 50); previousFrameTime = currentTime; } diff --git a/racevisionGame/src/main/java/mock/model/commandFactory/TackGybeCommand.java b/racevisionGame/src/main/java/mock/model/commandFactory/TackGybeCommand.java index 28ace831..0fa17279 100644 --- a/racevisionGame/src/main/java/mock/model/commandFactory/TackGybeCommand.java +++ b/racevisionGame/src/main/java/mock/model/commandFactory/TackGybeCommand.java @@ -10,6 +10,10 @@ import java.util.Observable; * Command class for tacking and gybing */ public class TackGybeCommand extends ObserverCommand { + private double goalRotation; + private double totalRotation = 0; + private int direction; // -1 for anticlockwise, 1 for clockwise + private double goalAngle; /** * Constructor for class @@ -22,18 +26,26 @@ public class TackGybeCommand extends ObserverCommand { @Override public void execute() { - - boat.setAutoVMG(false); - double boatAngle = boat.getBearing().degrees(); - double windAngle =race.getWindDirection().degrees(); + double windAngle = race.getWindDirection().degrees(); double differenceAngle = calcDistance(boatAngle, windAngle); double angleA = windAngle + differenceAngle; double angleB = windAngle - differenceAngle; - if(angleA % 360 == boatAngle){ - boat.setBearing(Bearing.fromDegrees(angleB)); + if (angleA % 360 == boatAngle) { + goalAngle = angleB % 360; } else { - boat.setBearing(Bearing.fromDegrees(angleA)); + goalAngle = angleA % 360; + } + + goalRotation = goalAngle - boatAngle; + if (goalRotation < 0) { + goalRotation += 360; + } + if (goalRotation > 180) { + goalRotation = 360 - goalRotation; + direction = -1; + } else { + direction = 1; } } @@ -50,7 +62,14 @@ public class TackGybeCommand extends ObserverCommand { @Override public void update(Observable o, Object arg) { - + double offset = 3.0; + if (totalRotation < goalRotation) { + boat.setBearing(Bearing.fromDegrees(boat.getBearing().degrees() + offset * direction)); + totalRotation += offset; + } else { + System.out.println(goalAngle + " " + boat.getBearing().degrees()); + race.deleteObserver(this); + } } } diff --git a/racevisionGame/src/main/java/shared/model/Constants.java b/racevisionGame/src/main/java/shared/model/Constants.java index bb7ec598..a415ece2 100644 --- a/racevisionGame/src/main/java/shared/model/Constants.java +++ b/racevisionGame/src/main/java/shared/model/Constants.java @@ -38,7 +38,9 @@ public class Constants { /** * The race pre-start time, in milliseconds. 3 minutes. */ - public static final long RacePreStartTime = 3 * 60 * 1000; + // + // TODO: CHANGE BACK TO 3 MINUTES BEFORE MERGING TO MASTER + public static final long RacePreStartTime = 30000; //3 * 60 * 1000; /** From 844b48a81a3718526b9b32fbca586726a5b85217 Mon Sep 17 00:00:00 2001 From: cbt24 Date: Thu, 7 Sep 2017 13:23:56 +1200 Subject: [PATCH 04/37] Resolved issue #42 - "putting sails out changes boat bearing to face target gate" #story[1196] --- racevisionGame/src/main/java/mock/model/MockRace.java | 5 ----- .../main/java/mock/model/commandFactory/SailsCommand.java | 4 +++- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/racevisionGame/src/main/java/mock/model/MockRace.java b/racevisionGame/src/main/java/mock/model/MockRace.java index e69db01e..e574ae5a 100644 --- a/racevisionGame/src/main/java/mock/model/MockRace.java +++ b/racevisionGame/src/main/java/mock/model/MockRace.java @@ -356,11 +356,6 @@ public class MockRace extends RaceState { checkPosition(boat, totalElapsedMilliseconds); - if (boat.getCurrentSpeed() == 0) { - newOptimalVMG(boat); - boat.setBearing(boat.calculateBearingToNextMarker()); - } - setBoatSpeed(boat); //Calculates the distance travelled, in meters, in the current timeslice. diff --git a/racevisionGame/src/main/java/mock/model/commandFactory/SailsCommand.java b/racevisionGame/src/main/java/mock/model/commandFactory/SailsCommand.java index bfb752ea..60ebb584 100644 --- a/racevisionGame/src/main/java/mock/model/commandFactory/SailsCommand.java +++ b/racevisionGame/src/main/java/mock/model/commandFactory/SailsCommand.java @@ -7,8 +7,9 @@ import java.util.Observable; public class SailsCommand extends ObserverCommand { private boolean sailsOut; + private double goalVelocity; - public SailsCommand(MockRace race, MockBoat boat, Boolean sailsOut) { + public SailsCommand(MockRace race, MockBoat boat, boolean sailsOut) { super(race, boat); this.sailsOut = sailsOut; } @@ -16,6 +17,7 @@ public class SailsCommand extends ObserverCommand { @Override public void execute() { this.boat.setSailsOut(this.sailsOut); + } @Override From eba70ab2d4d00e60510bc3e38b7e5f2b4fdc2bef Mon Sep 17 00:00:00 2001 From: cbt24 Date: Thu, 7 Sep 2017 14:27:20 +1200 Subject: [PATCH 05/37] Sails command now listens to race to check if goal velocity is met #story[1196] --- .../src/main/java/mock/model/MockRace.java | 26 +------------------ .../model/commandFactory/SailsCommand.java | 22 ++++++++++++++-- 2 files changed, 21 insertions(+), 27 deletions(-) diff --git a/racevisionGame/src/main/java/mock/model/MockRace.java b/racevisionGame/src/main/java/mock/model/MockRace.java index a338cd5d..60ed2498 100644 --- a/racevisionGame/src/main/java/mock/model/MockRace.java +++ b/racevisionGame/src/main/java/mock/model/MockRace.java @@ -362,11 +362,7 @@ public class MockRace extends RaceState { setBoatSpeed(boat); //Calculates the distance travelled, in meters, in the current timeslice. - double distanceTravelledMeters = boat.calculateMetersTravelled(updatePeriodMilliseconds); - - //Scale it. - distanceTravelledMeters = distanceTravelledMeters * this.scaleFactor; - + double distanceTravelledMeters = boat.calculateMetersTravelled(updatePeriodMilliseconds) * this.scaleFactor; //Move the boat forwards that many meters, and advances its time counters by enough milliseconds. boat.moveForwards(distanceTravelledMeters); @@ -388,32 +384,12 @@ public class MockRace extends RaceState { private void newOptimalVMG(MockBoat boat) { long tackPeriod = 1000; if (boat.getTimeSinceTackChange() > tackPeriod) { - //System.out.println("optim called"); - //Calculate the new VMG. -// VMG newVMG = boat.getPolars().calculateVMG( -// this.getWindDirection(), -// this.getWindSpeed(), -// boat.calculateBearingToNextMarker(), -// Bearing.fromDegrees(0d), -// Bearing.fromDegrees(359.99999d)); - VMG newVMG = NewPolars.setBestVMG(this.getWindDirection(), this.getWindSpeed(), boat.getBearing()); - //System.out.println(newVMG); - //If the new vmg improves velocity, use it. - /*if (improvesVelocity(boat, newVMG)) { - }*/ boat.setVMG(newVMG); } } private void setBoatSpeed(MockBoat boat) { -// VMG vmg = boat.getPolars().calculateVMG( -// this.getWindDirection(), -// this.getWindSpeed(), -// boat.getBearing(), -// Bearing.fromDegrees(boat.getBearing().degrees() - 1), -// Bearing.fromDegrees(boat.getBearing().degrees() + 1)); - //VMG vmg = boat.getPolars().setBestVMG(this.getWindDirection(), this.getWindSpeed(), boat.getBearing()); VMG vmg = new VMG(NewPolars.calculateSpeed( this.getWindDirection(), this.getWindSpeed(), diff --git a/racevisionGame/src/main/java/mock/model/commandFactory/SailsCommand.java b/racevisionGame/src/main/java/mock/model/commandFactory/SailsCommand.java index 60ebb584..efddc8df 100644 --- a/racevisionGame/src/main/java/mock/model/commandFactory/SailsCommand.java +++ b/racevisionGame/src/main/java/mock/model/commandFactory/SailsCommand.java @@ -2,12 +2,15 @@ package mock.model.commandFactory; import mock.model.MockBoat; import mock.model.MockRace; +import mock.model.NewPolars; +import mock.model.VMG; import java.util.Observable; public class SailsCommand extends ObserverCommand { private boolean sailsOut; private double goalVelocity; + private double acceleration = 1; public SailsCommand(MockRace race, MockBoat boat, boolean sailsOut) { super(race, boat); @@ -17,11 +20,26 @@ public class SailsCommand extends ObserverCommand { @Override public void execute() { this.boat.setSailsOut(this.sailsOut); - + if(sailsOut) { + // Accelerate to VMG speed + double polarSpeed = NewPolars.calculateSpeed(race.getWindDirection(), race.getWindSpeed(), boat.getBearing()); + VMG vmg = new VMG(polarSpeed, boat.getBearing()); + goalVelocity = vmg.getSpeed(); + } else { + // Decelerate to 0 + goalVelocity = 0; + } } @Override public void update(Observable o, Object arg) { - + if(sailsOut && boat.getCurrentSpeed() < goalVelocity) { + // Apply acceleration + } else if (!sailsOut && boat.getCurrentSpeed() > goalVelocity) { + // Apply deceleration + } else { + System.out.println(goalVelocity + " " + boat.getCurrentSpeed()); + race.deleteObserver(this); + } } } From 9cba3934ea51f76c627e01c69b8b84a8b39a32bf Mon Sep 17 00:00:00 2001 From: cbt24 Date: Thu, 7 Sep 2017 14:50:53 +1200 Subject: [PATCH 06/37] Sails command now applies acceleration to boat - Race only has control over speed while Sails command is not in action - This is governed by a default velocity property on the boat - Sails command returns control when sails are out and boat is up to speed - Speed never falls below 0 - Speed never goes above VMG velocity to prevent exploitation #story[1196] --- .../src/main/java/mock/model/MockBoat.java | 13 ++++++++++++- .../src/main/java/mock/model/MockRace.java | 6 ++---- .../mock/model/commandFactory/SailsCommand.java | 13 ++++++++++--- 3 files changed, 24 insertions(+), 8 deletions(-) diff --git a/racevisionGame/src/main/java/mock/model/MockBoat.java b/racevisionGame/src/main/java/mock/model/MockBoat.java index b6cd7a24..a5dc98fe 100644 --- a/racevisionGame/src/main/java/mock/model/MockBoat.java +++ b/racevisionGame/src/main/java/mock/model/MockBoat.java @@ -34,7 +34,10 @@ public class MockBoat extends Boat { */ private boolean autoVMG = false; - + /** + * Indicates whether boat velocity is determined by wind + */ + private boolean velocityDefault = true; /** * Constructs a boat object with a given sourceID, name, country/team abbreviation, and polars table. @@ -300,4 +303,12 @@ public class MockBoat extends Boat { public void setAutoVMG(boolean autoVMG) { this.autoVMG = autoVMG; } + + public boolean isVelocityDefault() { + return velocityDefault; + } + + public void setVelocityDefault(boolean velocityDefault) { + this.velocityDefault = velocityDefault; + } } diff --git a/racevisionGame/src/main/java/mock/model/MockRace.java b/racevisionGame/src/main/java/mock/model/MockRace.java index 60ed2498..2b689276 100644 --- a/racevisionGame/src/main/java/mock/model/MockRace.java +++ b/racevisionGame/src/main/java/mock/model/MockRace.java @@ -355,11 +355,11 @@ public class MockRace extends RaceState { //Checks if the current boat has finished the race or not. boolean finish = this.isLastLeg(boat.getCurrentLeg()); - if (!finish && totalElapsedMilliseconds >= updatePeriodMilliseconds && boat.isSailsOut()) { + if (!finish && totalElapsedMilliseconds >= updatePeriodMilliseconds) { checkPosition(boat, totalElapsedMilliseconds); - setBoatSpeed(boat); + if(boat.isVelocityDefault()) setBoatSpeed(boat); //Calculates the distance travelled, in meters, in the current timeslice. double distanceTravelledMeters = boat.calculateMetersTravelled(updatePeriodMilliseconds) * this.scaleFactor; @@ -373,8 +373,6 @@ public class MockRace extends RaceState { boat.setAutoVMG(false); } - } else { - boat.setCurrentSpeed(0); } this.updateEstimatedTime(boat); diff --git a/racevisionGame/src/main/java/mock/model/commandFactory/SailsCommand.java b/racevisionGame/src/main/java/mock/model/commandFactory/SailsCommand.java index efddc8df..e4a0bf4b 100644 --- a/racevisionGame/src/main/java/mock/model/commandFactory/SailsCommand.java +++ b/racevisionGame/src/main/java/mock/model/commandFactory/SailsCommand.java @@ -10,7 +10,6 @@ import java.util.Observable; public class SailsCommand extends ObserverCommand { private boolean sailsOut; private double goalVelocity; - private double acceleration = 1; public SailsCommand(MockRace race, MockBoat boat, boolean sailsOut) { super(race, boat); @@ -20,6 +19,8 @@ public class SailsCommand extends ObserverCommand { @Override public void execute() { this.boat.setSailsOut(this.sailsOut); + boat.setVelocityDefault(false); + if(sailsOut) { // Accelerate to VMG speed double polarSpeed = NewPolars.calculateSpeed(race.getWindDirection(), race.getWindSpeed(), boat.getBearing()); @@ -33,12 +34,18 @@ public class SailsCommand extends ObserverCommand { @Override public void update(Observable o, Object arg) { + double acceleration = 0.5; + if(sailsOut && boat.getCurrentSpeed() < goalVelocity) { - // Apply acceleration + boat.setCurrentSpeed(Math.min(goalVelocity, boat.getCurrentSpeed() + acceleration)); } else if (!sailsOut && boat.getCurrentSpeed() > goalVelocity) { - // Apply deceleration + // Apply deceleration to strictly 0 speed + boat.setCurrentSpeed(Math.max(0, boat.getCurrentSpeed() - acceleration)); } else { System.out.println(goalVelocity + " " + boat.getCurrentSpeed()); + + // Release boat from SailsCommand control + if(sailsOut) boat.setVelocityDefault(true); race.deleteObserver(this); } } From a6db06a82c448ce1b9b8f4a66567ef261d7b2075 Mon Sep 17 00:00:00 2001 From: cbt24 Date: Thu, 7 Sep 2017 16:57:07 +1200 Subject: [PATCH 07/37] Boats now reverse smoothly when colliding - Collision objects specify which boat is colliding - RaceLogic sets up an observable CollisionCommand when collision bubbles up - Boats now selectively identify observers of collision #story[1196] --- .../src/main/java/mock/model/RaceLogic.java | 11 +++--- .../java/mock/model/collider/Collider.java | 11 ++---- .../mock/model/collider/ColliderRegistry.java | 5 ++- .../java/mock/model/collider/Collision.java | 13 ++++++- .../commandFactory/CollisionCommand.java | 39 +++++++++++++++++++ .../src/main/java/shared/model/Boat.java | 10 ++--- .../src/main/java/shared/model/Mark.java | 5 ++- 7 files changed, 69 insertions(+), 25 deletions(-) create mode 100644 racevisionGame/src/main/java/mock/model/commandFactory/CollisionCommand.java diff --git a/racevisionGame/src/main/java/mock/model/RaceLogic.java b/racevisionGame/src/main/java/mock/model/RaceLogic.java index 308c4b46..3b74d5c8 100644 --- a/racevisionGame/src/main/java/mock/model/RaceLogic.java +++ b/racevisionGame/src/main/java/mock/model/RaceLogic.java @@ -2,6 +2,7 @@ package mock.model; import javafx.animation.AnimationTimer; import mock.model.collider.Collision; +import mock.model.commandFactory.CollisionCommand; import mock.model.commandFactory.Command; import mock.model.commandFactory.CompositeCommand; import mock.model.commandFactory.CommandFactory; @@ -222,11 +223,9 @@ public class RaceLogic implements RunnableWithFramePeriod, Observer { @Override public void update(Observable o, Object arg) { - Collision e = (Collision)arg; - -// if(e.getBearing().degrees() == 0) System.out.println("Ahead"); -// else if(e.getBearing().degrees() < 90) System.out.println("Starboard"); -// else if(e.getBearing().degrees() > 270) System.out.println("Port"); -// else System.out.println("Behind"); + if(arg instanceof Collision) { + Collision collision = (Collision)arg; + commands.addCommand(new CollisionCommand(race, (MockBoat)collision.getBoat())); + } } } diff --git a/racevisionGame/src/main/java/mock/model/collider/Collider.java b/racevisionGame/src/main/java/mock/model/collider/Collider.java index 029fee57..28c01f9f 100644 --- a/racevisionGame/src/main/java/mock/model/collider/Collider.java +++ b/racevisionGame/src/main/java/mock/model/collider/Collider.java @@ -25,13 +25,9 @@ public abstract class Collider extends Observable implements Locatable { Bearing relative = Bearing.fromDegrees(absolute.degrees() - boat.getBearing().degrees()); if(actualDistance <= distance) { - Collision collision = new Collision(relative, distance); + Collision collision = new Collision(boat, relative, distance); // Notify object of collision - onCollisionEnter(boat, collision); - // Notify observers of collision - notifyObservers(collision); - this.setChanged(); - + onCollisionEnter(collision); return true; } else return false; } @@ -45,8 +41,7 @@ public abstract class Collider extends Observable implements Locatable { /** * Handle a collision event - * @param collider Boat that is colliding * @param e details of collision */ - public abstract void onCollisionEnter(Boat collider, Collision e); + public abstract void onCollisionEnter(Collision e); } diff --git a/racevisionGame/src/main/java/mock/model/collider/ColliderRegistry.java b/racevisionGame/src/main/java/mock/model/collider/ColliderRegistry.java index 69eac91a..6f82daeb 100644 --- a/racevisionGame/src/main/java/mock/model/collider/ColliderRegistry.java +++ b/racevisionGame/src/main/java/mock/model/collider/ColliderRegistry.java @@ -1,5 +1,6 @@ package mock.model.collider; +import mock.model.MockBoat; import shared.model.Boat; import shared.model.GPSCoordinate; @@ -39,7 +40,7 @@ public class ColliderRegistry extends Collider implements Observer { } @Override - public void onCollisionEnter(Boat collider, Collision e) {} + public void onCollisionEnter(Collision e) {} @Override public GPSCoordinate getPosition() { @@ -60,7 +61,7 @@ public class ColliderRegistry extends Collider implements Observer { public void update(Observable o, Object arg) { Collision collision = (Collision)arg; - notifyObservers(collision); this.setChanged(); + notifyObservers(collision); } } diff --git a/racevisionGame/src/main/java/mock/model/collider/Collision.java b/racevisionGame/src/main/java/mock/model/collider/Collision.java index 5a987bde..225cf342 100644 --- a/racevisionGame/src/main/java/mock/model/collider/Collision.java +++ b/racevisionGame/src/main/java/mock/model/collider/Collision.java @@ -1,6 +1,7 @@ package mock.model.collider; import shared.model.Bearing; +import shared.model.Boat; /** * Data structure for holding collision details for ray casting and event handling. @@ -14,13 +15,19 @@ public class Collision { * Distance from boat centre to target centre */ private double distance; + /** + * Boat involved in the collision + */ + private Boat boat; /** * Constructor for Collision structure + * @param boat involved in collision * @param bearing from boat heading to target * @param distance from boat centre to target centre */ - public Collision(Bearing bearing, double distance) { + public Collision(Boat boat, Bearing bearing, double distance) { + this.boat = boat; this.bearing = bearing; this.distance = distance; } @@ -32,4 +39,8 @@ public class Collision { public double getDistance() { return distance; } + + public Boat getBoat() { + return boat; + } } diff --git a/racevisionGame/src/main/java/mock/model/commandFactory/CollisionCommand.java b/racevisionGame/src/main/java/mock/model/commandFactory/CollisionCommand.java new file mode 100644 index 00000000..3314c402 --- /dev/null +++ b/racevisionGame/src/main/java/mock/model/commandFactory/CollisionCommand.java @@ -0,0 +1,39 @@ +package mock.model.commandFactory; + +import mock.model.MockBoat; +import mock.model.MockRace; +import shared.model.Azimuth; +import shared.model.GPSCoordinate; + +import java.util.Observable; + +/** + * Created by cbt24 on 7/09/17. + */ +public class CollisionCommand extends ObserverCommand { + private GPSCoordinate startingPosition; + private Azimuth azimuth; + private double distance; + + public CollisionCommand(MockRace race, MockBoat boat) { + super(race, boat); + } + + @Override + public void execute() { + this.azimuth = Azimuth.fromDegrees(boat.getBearing().degrees() - 180d); + this.startingPosition = boat.getPosition(); + this.distance = 30; + boat.setVelocityDefault(false); + } + + @Override + public void update(Observable o, Object arg) { + if(GPSCoordinate.calculateDistanceMeters(boat.getPosition(), startingPosition) < distance) { + boat.setPosition(GPSCoordinate.calculateNewPosition(boat.getPosition(), 2, azimuth)); + } else { + race.deleteObserver(this); + boat.setVelocityDefault(true); + } + } +} diff --git a/racevisionGame/src/main/java/shared/model/Boat.java b/racevisionGame/src/main/java/shared/model/Boat.java index 31ce7ad4..bd3eea5e 100644 --- a/racevisionGame/src/main/java/shared/model/Boat.java +++ b/racevisionGame/src/main/java/shared/model/Boat.java @@ -403,10 +403,6 @@ public class Boat extends Collider { public boolean isSailsOut() { return sailsOut; } - public void bounce(double repulsionRadius) { - Azimuth reverseAzimuth = Azimuth.fromDegrees(getBearing().degrees() - 180d); - setPosition(GPSCoordinate.calculateNewPosition(getPosition(), 2 * repulsionRadius, reverseAzimuth)); - } @Override public boolean rayCast(Boat boat) { @@ -416,9 +412,11 @@ public class Boat extends Collider { } @Override - public void onCollisionEnter(Boat collider, Collision e) { + public void onCollisionEnter(Collision e) { if(e.getBearing().degrees() > 270 || e.getBearing().degrees() < 90) { - collider.bounce(100); + // Notify observers of collision + this.setChanged(); + notifyObservers(e); } } } diff --git a/racevisionGame/src/main/java/shared/model/Mark.java b/racevisionGame/src/main/java/shared/model/Mark.java index d236d076..23778cff 100644 --- a/racevisionGame/src/main/java/shared/model/Mark.java +++ b/racevisionGame/src/main/java/shared/model/Mark.java @@ -101,7 +101,8 @@ public class Mark extends Collider{ } @Override - public void onCollisionEnter(Boat collider, Collision e) { - collider.bounce(repulsionRadius); + public void onCollisionEnter(Collision e) { + this.setChanged(); + notifyObservers(e); } } From 8c7345a30def05616b90c4f5ba6823eff15c8a49 Mon Sep 17 00:00:00 2001 From: cbt24 Date: Thu, 7 Sep 2017 17:01:47 +1200 Subject: [PATCH 08/37] Documented command classes #story[1196] --- .../java/mock/model/commandFactory/CollisionCommand.java | 7 ++++++- .../main/java/mock/model/commandFactory/WindCommand.java | 8 +++++++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/racevisionGame/src/main/java/mock/model/commandFactory/CollisionCommand.java b/racevisionGame/src/main/java/mock/model/commandFactory/CollisionCommand.java index 3314c402..b2fed2ac 100644 --- a/racevisionGame/src/main/java/mock/model/commandFactory/CollisionCommand.java +++ b/racevisionGame/src/main/java/mock/model/commandFactory/CollisionCommand.java @@ -8,13 +8,18 @@ import shared.model.GPSCoordinate; import java.util.Observable; /** - * Created by cbt24 on 7/09/17. + * Command class for collisions */ public class CollisionCommand extends ObserverCommand { private GPSCoordinate startingPosition; private Azimuth azimuth; private double distance; + /** + * Constructor for class + * @param race race context + * @param boat boat controlled by command + */ public CollisionCommand(MockRace race, MockBoat boat) { super(race, boat); } diff --git a/racevisionGame/src/main/java/mock/model/commandFactory/WindCommand.java b/racevisionGame/src/main/java/mock/model/commandFactory/WindCommand.java index 138ccff0..a429b8c4 100644 --- a/racevisionGame/src/main/java/mock/model/commandFactory/WindCommand.java +++ b/racevisionGame/src/main/java/mock/model/commandFactory/WindCommand.java @@ -7,11 +7,17 @@ import shared.model.Bearing; import java.util.Observable; /** - * Created by connortaylorbrown on 4/08/17. + * Command class for upwind and downwind controls */ public class WindCommand extends ObserverCommand { private int direction; + /** + * Constructor for class + * @param race race context + * @param boat boat controlled by command + * @param upwind if true, downwind if false + */ public WindCommand(MockRace race, MockBoat boat, boolean upwind) { super(race, boat); this.direction = upwind? -1 : 1; From 9f3cc53a631ba3ca442f4e13092a532367ac77e5 Mon Sep 17 00:00:00 2001 From: Jessica Syder Date: Thu, 7 Sep 2017 21:40:10 +1200 Subject: [PATCH 09/37] Finished Arrow, Title and StartController scene splitting - scenes do not load in at the same time - scenes do not rely upon previous abstract controller class - scenes are not a part of previous main controller class - unecessary functions and code removed #story[1261] --- .../src/main/java/shared/model/RaceClock.java | 3 +- .../Controllers/FinishController.java | 19 +- .../Controllers/HostController.java | 80 +++-- .../Controllers/KeyBindingsController.java | 4 +- .../Controllers/LobbyController.java | 21 +- .../Controllers/MainController.java | 50 ++-- .../Controllers/RaceController.java | 44 +-- .../Controllers/StartController.java | 275 ------------------ .../ArrowController.java | 83 ++---- .../{Controller.java => Controller2.java} | 28 +- .../Controllers2/StartController.java | 140 +++++++++ .../TitleController.java | 48 +-- .../src/main/java/visualiser/app/App.java | 47 +-- .../resources/visualiser/scenes/arrow.fxml | 2 +- .../scenes/{hostlobby.fxml => hostLobby.fxml} | 0 .../resources/visualiser/scenes/main.fxml | 2 +- .../resources/visualiser/scenes/start.fxml | 2 +- .../visualiser/scenes/titleScreen.fxml | 4 +- 18 files changed, 314 insertions(+), 538 deletions(-) delete mode 100644 racevisionGame/src/main/java/visualiser/Controllers/StartController.java rename racevisionGame/src/main/java/visualiser/{Controllers => Controllers2}/ArrowController.java (66%) rename racevisionGame/src/main/java/visualiser/Controllers2/{Controller.java => Controller2.java} (66%) create mode 100644 racevisionGame/src/main/java/visualiser/Controllers2/StartController.java rename racevisionGame/src/main/java/visualiser/{Controllers => Controllers2}/TitleController.java (61%) rename racevisionGame/src/main/resources/visualiser/scenes/{hostlobby.fxml => hostLobby.fxml} (100%) diff --git a/racevisionGame/src/main/java/shared/model/RaceClock.java b/racevisionGame/src/main/java/shared/model/RaceClock.java index 4c6532a9..b3a631c6 100644 --- a/racevisionGame/src/main/java/shared/model/RaceClock.java +++ b/racevisionGame/src/main/java/shared/model/RaceClock.java @@ -3,6 +3,7 @@ package shared.model; import javafx.beans.property.SimpleStringProperty; import javafx.beans.property.StringProperty; import org.jetbrains.annotations.Nullable; +import visualiser.Controllers2.StartController; import visualiser.model.ResizableRaceCanvas; import java.time.Duration; @@ -16,7 +17,7 @@ import java.util.Date; * displays times relevant to a race. This is displayed on the * {@link ResizableRaceCanvas} via the * {@link visualiser.Controllers.RaceController} and the - * {@link visualiser.Controllers.StartController}. + * {@link StartController}. */ public class RaceClock { diff --git a/racevisionGame/src/main/java/visualiser/Controllers/FinishController.java b/racevisionGame/src/main/java/visualiser/Controllers/FinishController.java index 6de6dcdf..9df07ffe 100644 --- a/racevisionGame/src/main/java/visualiser/Controllers/FinishController.java +++ b/racevisionGame/src/main/java/visualiser/Controllers/FinishController.java @@ -7,16 +7,14 @@ import javafx.scene.control.Label; import javafx.scene.control.TableColumn; import javafx.scene.control.TableView; import javafx.scene.layout.AnchorPane; +import visualiser.Controllers2.Controller2; import visualiser.model.VisualiserBoat; -import java.net.URL; -import java.util.ResourceBundle; - /** * Finish Screen for when the race finishes. */ -public class FinishController extends Controller { +public class FinishController extends Controller2 { @FXML AnchorPane finishWrapper; @@ -40,19 +38,6 @@ public class FinishController extends Controller { private ObservableList boats; - /** - * Ctor. - */ - public FinishController() { - } - - - @Override - public void initialize(URL location, ResourceBundle resources){ - } - - - /** * Sets up the finish table * @param boats Boats to display diff --git a/racevisionGame/src/main/java/visualiser/Controllers/HostController.java b/racevisionGame/src/main/java/visualiser/Controllers/HostController.java index e7583252..0877f807 100644 --- a/racevisionGame/src/main/java/visualiser/Controllers/HostController.java +++ b/racevisionGame/src/main/java/visualiser/Controllers/HostController.java @@ -2,9 +2,14 @@ package visualiser.Controllers; import com.interactivemesh.jfx.importer.stl.StlMeshImporter; import javafx.animation.AnimationTimer; +import javafx.application.Platform; import javafx.collections.FXCollections; import javafx.collections.ObservableList; +import javafx.event.EventHandler; import javafx.fxml.FXML; +import javafx.fxml.FXMLLoader; +import javafx.scene.Parent; +import javafx.scene.Scene; import javafx.scene.control.Alert; import javafx.scene.control.ButtonType; import javafx.scene.control.SplitPane; @@ -12,8 +17,13 @@ import javafx.scene.image.ImageView; import javafx.scene.layout.AnchorPane; import javafx.scene.layout.GridPane; import javafx.scene.shape.MeshView; +import javafx.stage.Stage; +import javafx.stage.WindowEvent; import mock.app.Event; import mock.exceptions.EventConstructionException; +import visualiser.Controllers2.Controller2; +import visualiser.Controllers2.StartController; +import visualiser.app.App; import visualiser.layout.Subject3D; import visualiser.layout.View3D; @@ -21,46 +31,24 @@ import java.io.IOException; import java.net.Socket; import java.net.URL; import java.util.Optional; -import java.util.ResourceBundle; import java.util.logging.Level; import java.util.logging.Logger; /** * Controller for Hosting a game. */ -public class HostController extends Controller { - - -// @FXML -// TextField gameNameField; -// -// @FXML -// TextField hostNameField; - - @FXML - private ImageView imageView; - - @FXML - AnchorPane hostWrapper; - - @FXML - AnchorPane imagePane; - - @FXML - SplitPane splitPane; - - @FXML - AnchorPane specPane; - - @FXML - GridPane playerContainer; - +public class HostController extends Controller2 { + private @FXML ImageView imageView; + private @FXML AnchorPane hostWrapper; + private @FXML AnchorPane imagePane; + private @FXML SplitPane splitPane; + private @FXML AnchorPane specPane; + private @FXML GridPane playerContainer; private Event game; - private View3D view3D; - @Override - public void initialize(URL location, ResourceBundle resources) { + public void initialize() { + hostGame(); ObservableList subjects = FXCollections.observableArrayList(); view3D = new View3D(); @@ -114,15 +102,12 @@ public class HostController extends Controller { public void connectSocket(String address, int port) { try{ Socket socket = new Socket(address, port); - hostWrapper.setVisible(false); - parent.enterLobby(socket, true); + StartController sc = (StartController)loadScene + ("start.fxml"); + sc.enterLobby(socket, true); } catch (IOException e) { /* Never reached */ } } - public AnchorPane startWrapper(){ - return hostWrapper; - } - /** * Hosts a game. */ @@ -131,21 +116,34 @@ public class HostController extends Controller { splitPane.lookupAll(".split-pane-divider").stream().forEach(div -> div.setMouseTransparent(true)); imageView.fitWidthProperty().bind(imagePane.widthProperty()); imageView.fitHeightProperty().bind(imagePane.heightProperty()); - hostWrapper.setVisible(true); +// hostWrapper.setVisible(true); tick } /** * Menu button pressed. Prompt alert then return to menu */ - public void menuBtnPressed(){ + public void menuBtnPressed() throws IOException { Alert alert = new Alert(Alert.AlertType.CONFIRMATION); alert.setTitle("Quitting race"); alert.setContentText("Do you wish to quit the race?"); alert.setHeaderText("You are about to quit the race"); Optional result = alert.showAndWait(); if(result.get() == ButtonType.OK){ - hostWrapper.setVisible(false); - parent.enterTitle(); +// hostWrapper.setVisible(false); + Stage stage = App.getStage(); + FXMLLoader loader = new FXMLLoader(getClass().getResource("/visualiser/scenes/main.fxml")); + Parent root = loader.load(); + stage.setResizable(false); + Scene scene = new Scene(root); + stage.setScene(scene); + stage.show(); + stage.setOnCloseRequest(new EventHandler() { + @Override public void handle(WindowEvent event) { + Platform.exit(); + System.exit(0); + } + }); +// parent.enterTitle(); tick } } diff --git a/racevisionGame/src/main/java/visualiser/Controllers/KeyBindingsController.java b/racevisionGame/src/main/java/visualiser/Controllers/KeyBindingsController.java index 1ac0e371..86347bbd 100644 --- a/racevisionGame/src/main/java/visualiser/Controllers/KeyBindingsController.java +++ b/racevisionGame/src/main/java/visualiser/Controllers/KeyBindingsController.java @@ -14,7 +14,7 @@ import javafx.scene.layout.AnchorPane; import javafx.stage.Modality; import javafx.stage.Stage; import javafx.stage.WindowEvent; -import visualiser.Controllers2.Controller; +import visualiser.Controllers2.Controller2; import visualiser.gameController.Keys.ControlKey; import visualiser.gameController.Keys.KeyFactory; @@ -27,7 +27,7 @@ import static visualiser.app.App.keyFactory; /** * Controller for the scene used to display and update current key bindings. */ -public class KeyBindingsController extends Controller{ +public class KeyBindingsController extends Controller2 { private @FXML Button btnSave; private @FXML Button btnCancel; private @FXML Button btnReset; diff --git a/racevisionGame/src/main/java/visualiser/Controllers/LobbyController.java b/racevisionGame/src/main/java/visualiser/Controllers/LobbyController.java index d541c531..2b69cff5 100644 --- a/racevisionGame/src/main/java/visualiser/Controllers/LobbyController.java +++ b/racevisionGame/src/main/java/visualiser/Controllers/LobbyController.java @@ -8,17 +8,17 @@ import javafx.scene.control.TableColumn; import javafx.scene.control.TableView; import javafx.scene.control.TextField; import javafx.scene.layout.AnchorPane; +import visualiser.Controllers2.Controller2; +import visualiser.Controllers2.StartController; import visualiser.model.RaceConnection; import java.io.IOException; import java.net.Socket; -import java.net.URL; -import java.util.ResourceBundle; /** * Controller for the Lobby for entering games */ -public class LobbyController extends Controller { +public class LobbyController extends Controller2 { @FXML private AnchorPane lobbyWrapper; @@ -40,8 +40,8 @@ public class LobbyController extends Controller { private ObservableList connections; - @Override - public void initialize(URL location, ResourceBundle resources) { +// @Override + public void initialize() { connections = FXCollections.observableArrayList(); //connections.add(new RaceConnection("localhost", 4942, "Local Game")); @@ -86,15 +86,18 @@ public class LobbyController extends Controller { RaceConnection connection = lobbyTable.getSelectionModel().getSelectedItem(); Socket socket = new Socket(connection.getHostname(), connection.getPort()); lobbyWrapper.setVisible(false); - parent.enterLobby(socket, false); +// parent.enterLobby(socket, false); + StartController sc = (StartController)loadScene( + "/visualiser/scenes/start.fxml"); + sc.enterLobby(socket, false); } catch (IOException e) { /* Never reached */ e.printStackTrace(); } } - public void menuBtnPressed(){ - lobbyWrapper.setVisible(false); - parent.enterTitle(); + public void menuBtnPressed() throws IOException { +// parent.enterTitle(); + loadScene("titleScreen.fxml"); } /** diff --git a/racevisionGame/src/main/java/visualiser/Controllers/MainController.java b/racevisionGame/src/main/java/visualiser/Controllers/MainController.java index 0452f4a5..a408904e 100644 --- a/racevisionGame/src/main/java/visualiser/Controllers/MainController.java +++ b/racevisionGame/src/main/java/visualiser/Controllers/MainController.java @@ -3,6 +3,8 @@ package visualiser.Controllers; import javafx.collections.ObservableList; import javafx.fxml.FXML; import javafx.scene.layout.AnchorPane; +import visualiser.Controllers2.StartController; +import visualiser.Controllers2.TitleController; import visualiser.gameController.ControllerClient; import visualiser.model.VisualiserBoat; import visualiser.model.VisualiserRaceEvent; @@ -63,12 +65,12 @@ public class MainController extends Controller { finishController.enterFinish(boats); } - /** - * Transitions into the title screen - */ - public void enterTitle() { - titleController.enterTitle(); - } +// /** +// * Transitions into the title screen +// */ +// public void enterTitle() { +// titleController.enterTitle(); +// } /** * Transitions into lobby screen @@ -94,38 +96,38 @@ public class MainController extends Controller { @Override public void initialize(URL location, ResourceBundle resources) { - startController.setParent(this); - raceController.setParent(this); - connectionController.setParent(this); - finishController.setParent(this); +// startController.setParent(this); +// raceController.setParent(this); +// connectionController.setParent(this); +// finishController.setParent(this); // titleController.setParent(this); - hostController.setParent(this); - lobbyController.setParent(this); +// hostController.setParent(this); +// lobbyController.setParent(this); - AnchorPane.setTopAnchor(startController.startWrapper(), 0.0); - AnchorPane.setBottomAnchor(startController.startWrapper(), 0.0); - AnchorPane.setLeftAnchor(startController.startWrapper(), 0.0); - AnchorPane.setRightAnchor(startController.startWrapper(), 0.0); +// AnchorPane.setTopAnchor(startController.startWrapper(), 0.0); +// AnchorPane.setBottomAnchor(startController.startWrapper(), 0.0); +// AnchorPane.setLeftAnchor(startController.startWrapper(), 0.0); +// AnchorPane.setRightAnchor(startController.startWrapper(), 0.0); AnchorPane.setTopAnchor(lobbyController.startWrapper(), 0.0); AnchorPane.setBottomAnchor(lobbyController.startWrapper(), 0.0); AnchorPane.setLeftAnchor(lobbyController.startWrapper(), 0.0); AnchorPane.setRightAnchor(lobbyController.startWrapper(), 0.0); - AnchorPane.setTopAnchor(hostController.startWrapper(), 0.0); - AnchorPane.setBottomAnchor(hostController.startWrapper(), 0.0); - AnchorPane.setLeftAnchor(hostController.startWrapper(), 0.0); - AnchorPane.setRightAnchor(hostController.startWrapper(), 0.0); +// AnchorPane.setTopAnchor(hostController.startWrapper(), 0.0); +// AnchorPane.setBottomAnchor(hostController.startWrapper(), 0.0); +// AnchorPane.setLeftAnchor(hostController.startWrapper(), 0.0); +// AnchorPane.setRightAnchor(hostController.startWrapper(), 0.0); AnchorPane.setTopAnchor(finishController.finishWrapper, 0.0); AnchorPane.setBottomAnchor(finishController.finishWrapper, 0.0); AnchorPane.setLeftAnchor(finishController.finishWrapper, 0.0); AnchorPane.setRightAnchor(finishController.finishWrapper, 0.0); - AnchorPane.setTopAnchor(titleController.titleWrapper, 0.0); - AnchorPane.setBottomAnchor(titleController.titleWrapper, 0.0); - AnchorPane.setLeftAnchor(titleController.titleWrapper, 0.0); - AnchorPane.setRightAnchor(titleController.titleWrapper, 0.0); +// AnchorPane.setTopAnchor(titleController.titleWrapper, 0.0); +// AnchorPane.setBottomAnchor(titleController.titleWrapper, 0.0); +// AnchorPane.setLeftAnchor(titleController.titleWrapper, 0.0); +// AnchorPane.setRightAnchor(titleController.titleWrapper, 0.0); } } diff --git a/racevisionGame/src/main/java/visualiser/Controllers/RaceController.java b/racevisionGame/src/main/java/visualiser/Controllers/RaceController.java index 6694e8c0..7483c643 100644 --- a/racevisionGame/src/main/java/visualiser/Controllers/RaceController.java +++ b/racevisionGame/src/main/java/visualiser/Controllers/RaceController.java @@ -19,16 +19,15 @@ import javafx.scene.layout.StackPane; import javafx.util.Callback; import network.Messages.Enums.RaceStatusEnum; import shared.model.Leg; -import visualiser.app.App; +import visualiser.Controllers2.ArrowController; +import visualiser.Controllers2.Controller2; import visualiser.gameController.ControllerClient; import visualiser.gameController.Keys.ControlKey; import visualiser.model.*; import java.io.IOException; -import java.net.URL; import java.util.List; import java.util.Optional; -import java.util.ResourceBundle; import java.util.logging.Level; import java.util.logging.Logger; @@ -38,7 +37,7 @@ import static visualiser.app.App.keyFactory; /** * Controller used to display a running race. */ -public class RaceController extends Controller { +public class RaceController extends Controller2 { /** @@ -103,16 +102,7 @@ public class RaceController extends Controller { @FXML private LineChart sparklineChart; @FXML private AnchorPane annotationPane; - - - /** - * Ctor. - */ - public RaceController() { - } - - @Override - public void initialize(URL location, ResourceBundle resources) { + public void initialize() { // KeyFactory keyFactory = KeyFactory.getFactory(); infoTableShow = true; @@ -142,9 +132,12 @@ public class RaceController extends Controller { alert.setContentText("Do you wish to quit the race? You are the host"); Optional result = alert.showAndWait(); if (result.get() == ButtonType.OK) { - parent.endEvent(); +// parent.endEvent(); + HostController hc = (HostController)loadScene( + "/visualiser/scenes/hostgame.fxml"); + hc.endEvent(); race.setVisible(false); - App.app.showMainStage(App.getStage()); +// App.app.showMainStage(App.getStage()); } } else { Alert alert = new Alert(Alert.AlertType.CONFIRMATION); @@ -153,7 +146,7 @@ public class RaceController extends Controller { Optional result = alert.showAndWait(); if (result.get() == ButtonType.OK) { race.setVisible(false); - App.app.showMainStage(App.getStage()); +// App.app.showMainStage(App.getStage()); } } } catch (IOException e) { @@ -434,7 +427,16 @@ public class RaceController extends Controller { */ public void finishRace(ObservableList boats) { race.setVisible(false); - parent.enterFinish(boats); + +// parent.enterFinish(boats); + try { + FinishController fc = (FinishController)loadScene + ("/visualiser/scenes/finish.fxml"); + fc.enterFinish(boats); + } catch (IOException e) { + e.printStackTrace(); + } + } @@ -482,9 +484,9 @@ public class RaceController extends Controller { race.setVisible(false); //parent.enterTitle(); try { - App.app.showMainStage(App.getStage()); - } catch (IOException e) { - e.printStackTrace(); +// App.app.showMainStage(App.getStage()); +// } catch (IOException e) { +// e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } diff --git a/racevisionGame/src/main/java/visualiser/Controllers/StartController.java b/racevisionGame/src/main/java/visualiser/Controllers/StartController.java deleted file mode 100644 index 890eb816..00000000 --- a/racevisionGame/src/main/java/visualiser/Controllers/StartController.java +++ /dev/null @@ -1,275 +0,0 @@ -package visualiser.Controllers; - -import javafx.animation.AnimationTimer; -import javafx.application.Platform; -import javafx.collections.ObservableList; -import javafx.fxml.FXML; -import javafx.scene.control.Label; -import javafx.scene.control.TableColumn; -import javafx.scene.control.TableView; -import javafx.scene.layout.AnchorPane; -import javafx.scene.layout.GridPane; -import mock.model.commandFactory.CompositeCommand; -import network.Messages.Enums.RaceStatusEnum; -import network.Messages.Enums.RequestToJoinEnum; -import network.Messages.LatestMessages; -import shared.dataInput.*; -import shared.enums.XMLFileType; -import shared.exceptions.InvalidBoatDataException; -import shared.exceptions.InvalidRaceDataException; -import shared.exceptions.InvalidRegattaDataException; -import shared.exceptions.XMLReaderException; -import visualiser.gameController.ControllerClient; -import visualiser.model.VisualiserRaceState; -import visualiser.network.ServerConnection; -import visualiser.model.VisualiserBoat; -import visualiser.model.VisualiserRaceEvent; - -import java.io.IOException; -import java.net.Socket; -import java.net.URL; -import java.util.*; -import java.util.logging.Level; -import java.util.logging.Logger; - - -/** - * Controller to for waiting for the race to start. - */ -public class StartController extends Controller { - - @FXML private GridPane start; - @FXML private AnchorPane startWrapper; - - /** - * The name of the race/regatta. - */ - @FXML private Label raceTitleLabel; - - /** - * The time the race starts at. - */ - @FXML private Label raceStartLabel; - - /** - * The current time at the race location. - */ - @FXML private Label timeZoneTime; - - /** - * Time until the race starts. - */ - @FXML private Label timer; - - @FXML private TableView boatNameTable; - @FXML private TableColumn boatNameColumn; - @FXML private TableColumn boatCodeColumn; - - /** - * The status of the race. - */ - @FXML private Label raceStatusLabel; - - - /** - * The race + connection to server. - */ - private VisualiserRaceEvent visualiserRaceEvent; - - - /** - * Writes BoatActions to outgoing message queue. - */ - private ControllerClient controllerClient; - - private boolean isHost; - - - - - - - /** - * Ctor. - */ - public StartController() { - } - - @Override - public void initialize(URL location, ResourceBundle resources) { - } - - - /** - * Starts the race. - */ - private void startRace() { - - //Initialise the boat table. - initialiseBoatTable(this.visualiserRaceEvent.getVisualiserRaceState()); - - //Initialise the race name. - initialiseRaceName(this.visualiserRaceEvent.getVisualiserRaceState()); - - //Initialises the race clock. - initialiseRaceClock(this.visualiserRaceEvent.getVisualiserRaceState()); - - //Starts the race countdown timer. - countdownTimer(); - } - - - - - public AnchorPane startWrapper(){ - return startWrapper; - } - - - /** - * Initialises the boat table that is to be shown on the pane. - * @param visualiserRace The race to get data from. - */ - private void initialiseBoatTable(VisualiserRaceState visualiserRace) { - - //Get the boats. - ObservableList boats = visualiserRace.getBoats(); - - //Populate table. - boatNameTable.setItems(boats); - boatNameColumn.setCellValueFactory(cellData -> cellData.getValue().nameProperty()); - boatCodeColumn.setCellValueFactory(cellData -> cellData.getValue().countryProperty()); - } - - /** - * Initialises the race name which is shown on the pane. - * @param visualiserRace The race to get data from. - */ - private void initialiseRaceName(VisualiserRaceState visualiserRace) { - - raceTitleLabel.setText(visualiserRace.getRegattaName()); - - } - - /** - * Initialises the race clock/timer labels for the start time, current time, and remaining time. - * @param visualiserRace The race to get data from. - */ - private void initialiseRaceClock(VisualiserRaceState visualiserRace) { - - //Start time. - initialiseRaceClockStartTime(visualiserRace); - - //Current time. - initialiseRaceClockCurrentTime(visualiserRace); - - //Remaining time. - initialiseRaceClockDuration(visualiserRace); - - } - - - /** - * Initialises the race current time label. - * @param visualiserRace The race to get data from. - */ - private void initialiseRaceClockStartTime(VisualiserRaceState visualiserRace) { - - raceStartLabel.setText(visualiserRace.getRaceClock().getStartingTimeString()); - - visualiserRace.getRaceClock().startingTimeProperty().addListener((observable, oldValue, newValue) -> { - Platform.runLater(() -> { - raceStartLabel.setText(newValue); - }); - }); - - } - - - /** - * Initialises the race current time label. - * @param visualiserRace The race to get data from. - */ - private void initialiseRaceClockCurrentTime(VisualiserRaceState visualiserRace) { - - visualiserRace.getRaceClock().currentTimeProperty().addListener((observable, oldValue, newValue) -> { - Platform.runLater(() -> { - timeZoneTime.setText(newValue); - }); - }); - - } - - /** - * Initialises the race duration label. - * @param visualiserRace The race to get data from. - */ - private void initialiseRaceClockDuration(VisualiserRaceState visualiserRace) { - - visualiserRace.getRaceClock().durationProperty().addListener((observable, oldValue, newValue) -> { - Platform.runLater(() -> { - timer.setText(newValue); - }); - }); - - } - - /** - * Countdown timer until race starts. - */ - private void countdownTimer() { - new AnimationTimer() { - @Override - public void handle(long arg0) { - - //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) { - //Stop this timer. - stop(); - - //Hide this, and display the race controller. - startWrapper.setVisible(false); - //start.setVisible(false);//TODO is this needed? - - parent.beginRace(visualiserRaceEvent, controllerClient, isHost); - - } - } - }.start(); - } - - - - /** - * Show starting information for a race given a socket. - * @param socket network source of information - * @param isHost is user a host - */ - public void enterLobby(Socket socket, Boolean isHost) { - try { - - this.isHost = isHost; - - this.visualiserRaceEvent = new VisualiserRaceEvent(socket, RequestToJoinEnum.PARTICIPANT); - - this.controllerClient = visualiserRaceEvent.getControllerClient(); - - - startWrapper.setVisible(true); - - startRace(); - - } catch (IOException e) { - //TODO should probably let this propagate, so that we only enter this scene if everything works - Logger.getGlobal().log(Level.WARNING, "Could not connect to server.", e); - } - } - -} diff --git a/racevisionGame/src/main/java/visualiser/Controllers/ArrowController.java b/racevisionGame/src/main/java/visualiser/Controllers2/ArrowController.java similarity index 66% rename from racevisionGame/src/main/java/visualiser/Controllers/ArrowController.java rename to racevisionGame/src/main/java/visualiser/Controllers2/ArrowController.java index eb5d001d..069f04a5 100644 --- a/racevisionGame/src/main/java/visualiser/Controllers/ArrowController.java +++ b/racevisionGame/src/main/java/visualiser/Controllers2/ArrowController.java @@ -1,65 +1,31 @@ -package visualiser.Controllers; - +package visualiser.Controllers2; import javafx.application.Platform; import javafx.beans.property.Property; import javafx.fxml.FXML; import javafx.scene.control.Label; import javafx.scene.image.ImageView; -import javafx.scene.layout.Pane; import javafx.scene.layout.StackPane; -import javafx.scene.shape.Circle; import shared.model.Bearing; import shared.model.Wind; /** - * Controller for the arrow.fxml view. + * Controller for the wind direction arrow on the race screen. */ public class ArrowController { - - - @FXML - private Pane compass; - - @FXML - private StackPane arrowStackPane; - - @FXML - private ImageView arrowImage; - - @FXML - private Circle circle; - - @FXML - private Label northLabel; - - @FXML - private Label windLabel; - - @FXML - private Label speedLabel; - - - /** - * This is the property our arrow control binds to. - */ - private Property wind; - - - /** - * Constructor. - */ - public ArrowController() { - } - + private @FXML StackPane arrowStackPane; + private @FXML ImageView arrowImage; + private @FXML Label speedLabel; + private final static Integer MIN_KNOTS = 2; // knots for min_height + private final static Integer MAX_KNOTS = 30; // knots for max_height + private final static Integer MIN_HEIGHT = 25; // min arrow height + private final static Integer MAX_HEIGHT = 75; // max arrow height /** * Sets which wind property the arrow control should bind to. * @param wind The wind property to bind to. */ public void setWindProperty(Property wind) { - this.wind = wind; - wind.addListener((observable, oldValue, newValue) -> { if (newValue != null) { Platform.runLater(() -> updateWind(newValue)); @@ -67,7 +33,6 @@ public class ArrowController { }); } - /** * Updates the control to use the new wind value. * This updates the arrow direction (due to bearing), arrow length (due to speed), and label (due to speed). @@ -78,7 +43,6 @@ public class ArrowController { updateWindSpeed(wind.getWindSpeed()); } - /** * Updates the control to account for the new wind speed. * This changes the length (height) of the wind arrow, and updates the speed label. @@ -94,29 +58,22 @@ public class ArrowController { * @param speedKnots Wind speed, in knots. */ private void updateWindArrowLength(double speedKnots) { - - //At 2 knots, the arrow reaches its minimum height, and at 30 knots it reaches its maximum height. - double minKnots = 2; - double maxKnots = 30; - double deltaKnots = maxKnots - minKnots; - - double minHeight = 25; - double maxHeight = 75; - double deltaHeight = maxHeight - minHeight; + double deltaKnots = MAX_KNOTS - MIN_KNOTS; + double deltaHeight = MAX_HEIGHT - MIN_HEIGHT; //Clamp speed. - if (speedKnots > maxKnots) { - speedKnots = maxKnots; - } else if (speedKnots < minKnots) { - speedKnots = minKnots; + if (speedKnots > MAX_KNOTS) { + speedKnots = MAX_KNOTS; + } else if (speedKnots < MIN_KNOTS) { + speedKnots = MIN_KNOTS; } //How far between the knots bounds is the current speed? - double currentDeltaKnots = speedKnots - minKnots; + double currentDeltaKnots = speedKnots - MIN_KNOTS; double currentKnotsScalar = currentDeltaKnots / deltaKnots; //Thus, how far between the pixel height bounds should the arrow height be? - double newHeight = minHeight + (currentKnotsScalar * deltaHeight); + double newHeight = MIN_HEIGHT + (currentKnotsScalar * deltaHeight); arrowImage.setFitHeight(newHeight); } @@ -129,7 +86,6 @@ public class ArrowController { speedLabel.setText(String.format("%.1fkn", speedKnots)); } - /** * Updates the control to account for a new wind bearing. * This rotates the arrow according to the bearing. @@ -140,7 +96,4 @@ public class ArrowController { arrowStackPane.setRotate(bearing.degrees()); } - - - -} +} \ No newline at end of file diff --git a/racevisionGame/src/main/java/visualiser/Controllers2/Controller.java b/racevisionGame/src/main/java/visualiser/Controllers2/Controller2.java similarity index 66% rename from racevisionGame/src/main/java/visualiser/Controllers2/Controller.java rename to racevisionGame/src/main/java/visualiser/Controllers2/Controller2.java index 0117d9dc..c941b0f7 100644 --- a/racevisionGame/src/main/java/visualiser/Controllers2/Controller.java +++ b/racevisionGame/src/main/java/visualiser/Controllers2/Controller2.java @@ -7,14 +7,13 @@ import javafx.scene.image.Image; import javafx.stage.Modality; import javafx.stage.Stage; import visualiser.app.App; - import java.io.IOException; /** * Abstract controller class to give each subclass the functionality to load * a new scene into the existing stage, or create a new popup window. */ -public abstract class Controller { +public class Controller2 { /** * Used to load a new scene in the currently open stage. @@ -22,15 +21,27 @@ public abstract class Controller { * @return the controller of the new scene * @throws IOException if there is an issue with the fxmlUrl */ - protected Controller loadScene(String fxmlUrl) throws IOException { + protected Controller2 loadScene(String fxmlUrl) throws IOException { + // load the correct fxml file FXMLLoader loader = new FXMLLoader(); - loader.setLocation(getClass().getResource(fxmlUrl)); + loader.setLocation(getClass().getResource + ("/visualiser/scenes/"+fxmlUrl)); Parent root = loader.load(); + + // reuse previous stage and it's window size Stage stage = App.getStage(); + Double stageHeight = stage.getHeight(); + Double stageWidth = stage.getWidth(); + + // set new scene into existing window Scene scene = new Scene(root); stage.setScene(scene); + stage.setResizable(true); stage.show(); + stage.setHeight(stageHeight); + stage.setWidth(stageWidth); + // return controller for the loaded fxml scene return loader.getController(); } @@ -42,11 +53,15 @@ public abstract class Controller { * @return the controller of the new scene * @throws IOException if there is an issue with the fxmlUrl */ - protected Controller loadPopupScene(String fxmlUrl, String title, Modality + protected Controller2 loadPopupScene(String fxmlUrl, String title, Modality modality) throws IOException { + // load the correct fxml scene FXMLLoader loader = new FXMLLoader(); - loader.setLocation(getClass().getResource(fxmlUrl)); + loader.setLocation(getClass().getResource( + "/visualiser/scenes/" + fxmlUrl)); Parent root = loader.load(); + + // create a new 'pop-up' window Stage stage = new Stage(); stage.initModality(modality); stage.setTitle(title); @@ -56,6 +71,7 @@ public abstract class Controller { stage.setScene(scene); stage.show(); + // return controller for the loaded fxml scene return loader.getController(); } diff --git a/racevisionGame/src/main/java/visualiser/Controllers2/StartController.java b/racevisionGame/src/main/java/visualiser/Controllers2/StartController.java new file mode 100644 index 00000000..4ff74987 --- /dev/null +++ b/racevisionGame/src/main/java/visualiser/Controllers2/StartController.java @@ -0,0 +1,140 @@ +package visualiser.Controllers2; + +import javafx.animation.AnimationTimer; +import javafx.application.Platform; +import javafx.collections.ObservableList; +import javafx.fxml.FXML; +import javafx.scene.control.Label; +import javafx.scene.control.TableColumn; +import javafx.scene.control.TableView; +import network.Messages.Enums.RaceStatusEnum; +import network.Messages.Enums.RequestToJoinEnum; +import visualiser.Controllers.RaceController; +import visualiser.gameController.ControllerClient; +import visualiser.model.VisualiserBoat; +import visualiser.model.VisualiserRaceEvent; +import visualiser.model.VisualiserRaceState; + +import java.io.IOException; +import java.net.Socket; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * Controller to for waiting for the race to start. + */ +public class StartController extends Controller2 { + private @FXML Label raceTitleLabel; + private @FXML Label raceStartLabel; + private @FXML Label timeZoneTime; + private @FXML Label timer; + private @FXML TableView boatNameTable; + private @FXML TableColumn boatNameColumn; + private @FXML TableColumn boatCodeColumn; + private @FXML Label raceStatusLabel; + + private VisualiserRaceEvent visualiserRaceEvent; + private VisualiserRaceState raceState; + private ControllerClient controllerClient; + private boolean isHost; + + /** + * Show starting information for a race given a socket. + * Intended to be called on loading the scene. + * @param socket network source of information + * @param isHost is user a host + */ + public void enterLobby(Socket socket, Boolean isHost) { + try { + this.isHost = isHost; + this.visualiserRaceEvent = new VisualiserRaceEvent(socket, RequestToJoinEnum.PARTICIPANT); + this.controllerClient = visualiserRaceEvent.getControllerClient(); + this.raceState = visualiserRaceEvent.getVisualiserRaceState(); + showRaceDetails(); + } catch (IOException e) { + //TODO should probably let this propagate, so that we only enter this scene if everything works + Logger.getGlobal() + .log(Level.WARNING, "Could not connect to server.", e); + } + } + + /** + * Displays details and starts the timer for the race being started + */ + private void showRaceDetails() { + raceTitleLabel.setText(this.raceState.getRegattaName()); + initialiseBoatTable(); + initialiseRaceClock(); + countdownTimer(); + } + + /** + * Initialises the boat table that is to be shown on the pane. + */ + private void initialiseBoatTable() { + //Get the boats. + ObservableList boats = + this.raceState.getBoats(); + + //Populate table. + boatNameTable.setItems(boats); + boatNameColumn.setCellValueFactory(cellData -> cellData.getValue().nameProperty()); + boatCodeColumn.setCellValueFactory(cellData -> cellData.getValue().countryProperty()); + } + + /** + * Initialises the race clock/timer labels for the start time, current time, and remaining time. + */ + private void initialiseRaceClock() { + raceStartLabel.setText( + this.raceState.getRaceClock().getStartingTimeString()); + + // init clock start time + this.raceState.getRaceClock().startingTimeProperty().addListener((observable, oldValue, newValue) -> { + Platform.runLater(() -> { + raceStartLabel.setText(newValue); + }); + }); + + // init clock current time + this.raceState.getRaceClock().currentTimeProperty().addListener((observable, oldValue, newValue) -> { + Platform.runLater(() -> { + timeZoneTime.setText(newValue); + }); + }); + + // init clock remaining time + this.raceState.getRaceClock().durationProperty().addListener((observable, oldValue, newValue) -> { + Platform.runLater(() -> { + timer.setText(newValue); + }); + }); + } + + /** + * Countdown timer until race starts. + */ + private void countdownTimer() { + new AnimationTimer() { + @Override + public void handle(long arg0) { + // display current race status + RaceStatusEnum raceStatus = raceState.getRaceStatusEnum(); + raceStatusLabel.setText("Race Status: " + raceStatus.name()); + + // if race is in PREPARATORY or STARTED status + if (raceStatus == RaceStatusEnum.PREPARATORY || raceStatus == RaceStatusEnum.STARTED) { + stop(); // stop this timer + // load up the race scene + try { + RaceController rc = (RaceController)loadScene("race.fxml"); + rc.startRace(visualiserRaceEvent, controllerClient, isHost); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + }.start(); + } + +} \ No newline at end of file diff --git a/racevisionGame/src/main/java/visualiser/Controllers/TitleController.java b/racevisionGame/src/main/java/visualiser/Controllers2/TitleController.java similarity index 61% rename from racevisionGame/src/main/java/visualiser/Controllers/TitleController.java rename to racevisionGame/src/main/java/visualiser/Controllers2/TitleController.java index b028e92a..62ef4324 100644 --- a/racevisionGame/src/main/java/visualiser/Controllers/TitleController.java +++ b/racevisionGame/src/main/java/visualiser/Controllers2/TitleController.java @@ -1,16 +1,10 @@ -package visualiser.Controllers; +package visualiser.Controllers2; import javafx.fxml.FXML; -import javafx.scene.control.Button; import javafx.scene.control.RadioButton; -import javafx.scene.layout.AnchorPane; import javafx.stage.Modality; -import visualiser.Controllers2.Controller; -import visualiser.app.App; import java.io.IOException; -import java.net.URL; -import java.util.ResourceBundle; /** * Controller for the opening title window. @@ -18,16 +12,9 @@ import java.util.ResourceBundle; * burger-boat and comic sans styling to allure and entice users into playing * the game. */ -public class TitleController extends Controller { - //FXML stuff - @FXML - Button btnJoin; - @FXML - AnchorPane titleWrapper; - @FXML - RadioButton dayModeRD; - @FXML - RadioButton nightModeRD; +public class TitleController extends Controller2 { + private @FXML RadioButton dayModeRD; + private @FXML RadioButton nightModeRD; /** * Method called when the 'host a game' button is pressed. @@ -36,26 +23,15 @@ public class TitleController extends Controller { * @throws IOException if main has problems */ public void hostAGame() throws IOException { - titleWrapper.setVisible(false); -// parent.hostGame(); - App.getStage().setResizable(true); - } - - /** - * Switch the scene to the title page. - */ - public void enterTitle(){ - titleWrapper.setVisible(true); + loadScene("hostLobby.fxml"); } /** * To be implemented at a later date- will open the next scene displaying * games a player can join. Place holder method for now! */ - public void joinAGame() { - titleWrapper.setVisible(false); -// parent.enterLobby(); - App.getStage().setResizable(true); + public void joinAGame() throws IOException { + loadScene("lobby.fxml"); } /** @@ -76,20 +52,16 @@ public class TitleController extends Controller { dayModeRD.setSelected(false); } -// @Override - public void initialize(URL location, ResourceBundle resources) { - } - /** * Called when control button is pressed. New pop up window displaying controls */ - public void controlBtnPressed(){ + public void showControls(){ try { - loadPopupScene("/visualiser/scenes/keyBindings.fxml", + loadPopupScene("keyBindings.fxml", "Game Controls", Modality.WINDOW_MODAL); } catch (IOException e) { e.printStackTrace(); } } -} +} \ No newline at end of file diff --git a/racevisionGame/src/main/java/visualiser/app/App.java b/racevisionGame/src/main/java/visualiser/app/App.java index e095e04e..08aba761 100644 --- a/racevisionGame/src/main/java/visualiser/app/App.java +++ b/racevisionGame/src/main/java/visualiser/app/App.java @@ -26,7 +26,6 @@ import javafx.stage.Stage; import javafx.stage.StageStyle; import javafx.stage.WindowEvent; import javafx.util.Duration; -import visualiser.Controllers.MainController; import visualiser.gameController.Keys.KeyFactory; public class App extends Application { @@ -42,7 +41,6 @@ public class App extends Application { /** * Entry point for running the programme - * * @param args for starting the programme */ public static void main(String[] args) { @@ -79,10 +77,10 @@ public class App extends Application { /** * Method that sets up and displays the splash screen - * @param initStage the inital stage + * @param stage the inital stage * @throws Exception if something wrong with title screen. */ - public void start(Stage initStage) throws Exception { + public void start(Stage stage) throws Exception { final Task> boatTask = new Task>() { @Override protected ObservableList call() throws InterruptedException { @@ -111,11 +109,11 @@ public class App extends Application { }; showSplash( - initStage, + stage, boatTask, () -> { try { - showMainStage(new Stage()); + loadTitleScreen(); } catch (Exception e) { e.printStackTrace(); } @@ -126,45 +124,26 @@ public class App extends Application { } /** - * Get main stage - * @return main stage + * Get the main stage to be shared for all regular game play scenes. + * @return shared stage */ public static Stage getStage() { return App.stage; } - /** - * Set main stage - * @param stage stage to set main stage - */ - public static void setStage(Stage stage) { - App.stage = stage; - } - - /** - * Show the main stage after the splash screen - * @param stage main stage for application - * @throws Exception Throws an exception on error - */ - public void showMainStage(Stage stage) throws Exception { - App.stage = stage; - App.app = this; - FXMLLoader loader = new FXMLLoader(getClass().getResource("/visualiser/scenes/main.fxml")); + public void loadTitleScreen() throws Exception { + stage = new Stage(); + FXMLLoader loader = new FXMLLoader(getClass().getResource + ("/visualiser/scenes/titleScreen.fxml")); Parent root = loader.load(); stage.setResizable(false); - MainController mc = (MainController) loader.getController(); - mc.enterTitle(); Scene scene = new Scene(root); - - stage.setScene(scene); - stage.setTitle("RaceVision - Team 7"); + stage.setTitle("The Boat Game - Burgers & Boats"); stage.getIcons().add(new Image(getClass().getClassLoader().getResourceAsStream("images/SailIcon.png"))); - mc.startCss(); - setStage(stage); + stage.setScene(scene); stage.show(); stage.setOnCloseRequest(new EventHandler() { - @Override - public void handle(WindowEvent event) { + @Override public void handle(WindowEvent event) { Platform.exit(); System.exit(0); } diff --git a/racevisionGame/src/main/resources/visualiser/scenes/arrow.fxml b/racevisionGame/src/main/resources/visualiser/scenes/arrow.fxml index 196c4c10..1721d988 100644 --- a/racevisionGame/src/main/resources/visualiser/scenes/arrow.fxml +++ b/racevisionGame/src/main/resources/visualiser/scenes/arrow.fxml @@ -8,7 +8,7 @@ - + diff --git a/racevisionGame/src/main/resources/visualiser/scenes/hostlobby.fxml b/racevisionGame/src/main/resources/visualiser/scenes/hostLobby.fxml similarity index 100% rename from racevisionGame/src/main/resources/visualiser/scenes/hostlobby.fxml rename to racevisionGame/src/main/resources/visualiser/scenes/hostLobby.fxml diff --git a/racevisionGame/src/main/resources/visualiser/scenes/main.fxml b/racevisionGame/src/main/resources/visualiser/scenes/main.fxml index 7aff44c0..44db3abb 100644 --- a/racevisionGame/src/main/resources/visualiser/scenes/main.fxml +++ b/racevisionGame/src/main/resources/visualiser/scenes/main.fxml @@ -7,7 +7,7 @@ - + diff --git a/racevisionGame/src/main/resources/visualiser/scenes/start.fxml b/racevisionGame/src/main/resources/visualiser/scenes/start.fxml index 239a6f5d..06cb7b90 100644 --- a/racevisionGame/src/main/resources/visualiser/scenes/start.fxml +++ b/racevisionGame/src/main/resources/visualiser/scenes/start.fxml @@ -3,7 +3,7 @@ - + diff --git a/racevisionGame/src/main/resources/visualiser/scenes/titleScreen.fxml b/racevisionGame/src/main/resources/visualiser/scenes/titleScreen.fxml index 007ef599..9e067b8e 100644 --- a/racevisionGame/src/main/resources/visualiser/scenes/titleScreen.fxml +++ b/racevisionGame/src/main/resources/visualiser/scenes/titleScreen.fxml @@ -5,7 +5,7 @@ - + @@ -37,7 +37,7 @@ - + + + + + + + diff --git a/racevisionGame/src/main/resources/visualiser/scenes/titleScreen.fxml b/racevisionGame/src/main/resources/visualiser/scenes/titleScreen.fxml deleted file mode 100644 index 9e067b8e..00000000 --- a/racevisionGame/src/main/resources/visualiser/scenes/titleScreen.fxml +++ /dev/null @@ -1,85 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - From 0dff85006a2247d3fb7d6af31df161787267ce26 Mon Sep 17 00:00:00 2001 From: Jessica Syder Date: Fri, 8 Sep 2017 22:07:16 +1200 Subject: [PATCH 15/37] Changes to code to use new controller structure. - renamed javadoc referencing old controllers - keybindings no longer need to be static - finished lobby and lobbyhost controllers #story[1261] --- .../Controllers/ConnectionController.java | 2 +- .../{Controller2.java => Controller.java} | 6 ++-- .../Controllers/KeyBindingsController.java | 32 +++++++------------ .../Controllers/LobbyController.java | 2 +- .../Controllers/LobbyHostingController.java | 2 +- .../Controllers/NotificationController.java | 2 +- .../Controllers/RaceFinishController.java | 2 +- .../Controllers/RaceStartController.java | 2 +- .../Controllers/RaceViewController.java | 2 +- .../Controllers/TitleController.java | 2 +- .../src/main/java/visualiser/app/App.java | 11 ++----- .../gameController/InputChecker.java | 8 ++--- .../java/visualiser/model/Annotations.java | 2 +- .../visualiser/model/ResizableRaceCanvas.java | 2 +- .../main/java/visualiser/model/Sparkline.java | 2 +- 15 files changed, 31 insertions(+), 48 deletions(-) rename racevisionGame/src/main/java/visualiser/Controllers/{Controller2.java => Controller.java} (93%) diff --git a/racevisionGame/src/main/java/visualiser/Controllers/ConnectionController.java b/racevisionGame/src/main/java/visualiser/Controllers/ConnectionController.java index dc4535e0..c95ce731 100644 --- a/racevisionGame/src/main/java/visualiser/Controllers/ConnectionController.java +++ b/racevisionGame/src/main/java/visualiser/Controllers/ConnectionController.java @@ -15,7 +15,7 @@ import java.util.ResourceBundle; /** * Controls the connection that the VIsualiser can connect to. */ -public class ConnectionController extends Controller2 { +public class ConnectionController extends Controller { @FXML AnchorPane connectionWrapper; @FXML TableView connectionTable; @FXML TableColumn hostnameColumn; diff --git a/racevisionGame/src/main/java/visualiser/Controllers/Controller2.java b/racevisionGame/src/main/java/visualiser/Controllers/Controller.java similarity index 93% rename from racevisionGame/src/main/java/visualiser/Controllers/Controller2.java rename to racevisionGame/src/main/java/visualiser/Controllers/Controller.java index 74d8390a..23094fd7 100644 --- a/racevisionGame/src/main/java/visualiser/Controllers/Controller2.java +++ b/racevisionGame/src/main/java/visualiser/Controllers/Controller.java @@ -15,7 +15,7 @@ import java.io.IOException; * Abstract controller class to give each subclass the functionality to load * a new scene into the existing stage, or create a new popup window. */ -public abstract class Controller2 { +public abstract class Controller { Stage stage = App.getStage(); protected void loadTitleScreen() throws IOException { @@ -33,7 +33,7 @@ public abstract class Controller2 { * @return the controller of the new scene * @throws IOException if there is an issue with the fxmlUrl */ - protected Controller2 loadScene(String fxmlUrl) throws IOException { + protected Controller loadScene(String fxmlUrl) throws IOException { // load the correct fxml file FXMLLoader loader = new FXMLLoader(); loader.setLocation(getClass().getResource @@ -66,7 +66,7 @@ public abstract class Controller2 { * @return the controller of the new scene * @throws IOException if there is an issue with the fxmlUrl */ - protected Controller2 loadPopupScene(String fxmlUrl, String title, Modality + protected Controller loadPopupScene(String fxmlUrl, String title, Modality modality) throws IOException { // load the correct fxml scene FXMLLoader loader = new FXMLLoader(); diff --git a/racevisionGame/src/main/java/visualiser/Controllers/KeyBindingsController.java b/racevisionGame/src/main/java/visualiser/Controllers/KeyBindingsController.java index 7da5a818..63e7ffda 100644 --- a/racevisionGame/src/main/java/visualiser/Controllers/KeyBindingsController.java +++ b/racevisionGame/src/main/java/visualiser/Controllers/KeyBindingsController.java @@ -3,9 +3,6 @@ package visualiser.Controllers; import javafx.application.Platform; import javafx.event.EventHandler; import javafx.fxml.FXML; -import javafx.fxml.FXMLLoader; -import javafx.scene.Parent; -import javafx.scene.Scene; import javafx.scene.control.Button; import javafx.scene.control.ListView; import javafx.scene.input.KeyCode; @@ -21,12 +18,10 @@ import java.io.IOException; import java.util.HashMap; import java.util.Map; -import static visualiser.app.App.keyFactory; - /** * Controller for the scene used to display and update current key bindings. */ -public class KeyBindingsController extends Controller2 { +public class KeyBindingsController extends Controller { private @FXML Button btnSave; private @FXML Button btnCancel; private @FXML Button btnReset; @@ -34,12 +29,15 @@ public class KeyBindingsController extends Controller2 { private @FXML ListView lstKey; private @FXML ListView lstDescription; private @FXML AnchorPane anchor; + private KeyFactory existingKeyFactory; private KeyFactory newKeyFactory; private Boolean changed = false; // keyBindings have been modified private Button currentButton = null; // last button clicked public void initialize(){ // create new key factory to modify, keeping the existing one safe + existingKeyFactory = new KeyFactory(); + existingKeyFactory.load(); newKeyFactory = copyExistingFactory(); initializeTable(); populateTable(); @@ -106,7 +104,7 @@ public class KeyBindingsController extends Controller2 { */ public KeyFactory copyExistingFactory(){ newKeyFactory = new KeyFactory(); - Map oldKeyState = keyFactory.getKeyState(); + Map oldKeyState = existingKeyFactory.getKeyState(); Map newKeyState = new HashMap<>(); // copy over commands and their keys @@ -204,10 +202,10 @@ public class KeyBindingsController extends Controller2 { */ public void save(){ if (isFactoryValid()) { - keyFactory = newKeyFactory; + existingKeyFactory = newKeyFactory; newKeyFactory = new KeyFactory(); changed = false; - keyFactory.save(); // save persistently + existingKeyFactory.save(); // save persistently loadNotification("Key bindings were successfully saved.", false); } else { loadNotification("One or more key bindings are missing. " + @@ -251,22 +249,14 @@ public class KeyBindingsController extends Controller2 { * @param warning true if the message to be displayed is due to user error */ public void loadNotification(String message, Boolean warning){ - Parent root = null; - FXMLLoader loader = new FXMLLoader(getClass().getResource - ("/visualiser/scenes/notification.fxml")); try { - root = loader.load(); + NotificationController nc = (NotificationController) + loadPopupScene("notification.fxml", + "", Modality.APPLICATION_MODAL); + nc.setMessage(message, warning); } catch (IOException e) { e.printStackTrace(); } - NotificationController controller = loader.getController(); - Stage stage = new Stage(); - stage.setScene(new Scene(root)); - stage.centerOnScreen(); - stage.initModality(Modality.APPLICATION_MODAL); - stage.show(); - // displays given message in the window - controller.setMessage(message, warning); } } diff --git a/racevisionGame/src/main/java/visualiser/Controllers/LobbyController.java b/racevisionGame/src/main/java/visualiser/Controllers/LobbyController.java index 2230bbdb..6a4fc447 100644 --- a/racevisionGame/src/main/java/visualiser/Controllers/LobbyController.java +++ b/racevisionGame/src/main/java/visualiser/Controllers/LobbyController.java @@ -15,7 +15,7 @@ import java.net.Socket; /** * Controller for the Lobby for entering games */ -public class LobbyController extends Controller2 { +public class LobbyController extends Controller { private @FXML TableView lobbyTable; private @FXML TableColumn gameNameColumn; private @FXML TableColumn hostNameColumn; diff --git a/racevisionGame/src/main/java/visualiser/Controllers/LobbyHostingController.java b/racevisionGame/src/main/java/visualiser/Controllers/LobbyHostingController.java index dd2fcb89..9462ad4d 100644 --- a/racevisionGame/src/main/java/visualiser/Controllers/LobbyHostingController.java +++ b/racevisionGame/src/main/java/visualiser/Controllers/LobbyHostingController.java @@ -28,7 +28,7 @@ import java.util.logging.Logger; /** * Controller for Hosting a game. */ -public class LobbyHostingController extends Controller2 { +public class LobbyHostingController extends Controller { private @FXML ImageView imageView; private @FXML AnchorPane imagePane; private @FXML SplitPane splitPane; diff --git a/racevisionGame/src/main/java/visualiser/Controllers/NotificationController.java b/racevisionGame/src/main/java/visualiser/Controllers/NotificationController.java index d122ec80..ce3c25ee 100644 --- a/racevisionGame/src/main/java/visualiser/Controllers/NotificationController.java +++ b/racevisionGame/src/main/java/visualiser/Controllers/NotificationController.java @@ -9,7 +9,7 @@ import javafx.stage.Stage; /** * Controller for a popup notification regarding user activity. */ -public class NotificationController { +public class NotificationController extends Controller{ private @FXML Label lblDescription; private @FXML Text txtMessage; diff --git a/racevisionGame/src/main/java/visualiser/Controllers/RaceFinishController.java b/racevisionGame/src/main/java/visualiser/Controllers/RaceFinishController.java index 659af532..29d2b290 100644 --- a/racevisionGame/src/main/java/visualiser/Controllers/RaceFinishController.java +++ b/racevisionGame/src/main/java/visualiser/Controllers/RaceFinishController.java @@ -10,7 +10,7 @@ import visualiser.model.VisualiserBoat; /** * Finish Screen for when the race finishes. */ -public class RaceFinishController extends Controller2 { +public class RaceFinishController extends Controller { private @FXML TableView boatInfoTable; private @FXML TableColumn boatRankColumn; private @FXML TableColumn boatNameColumn; diff --git a/racevisionGame/src/main/java/visualiser/Controllers/RaceStartController.java b/racevisionGame/src/main/java/visualiser/Controllers/RaceStartController.java index fbf23a58..34057d41 100644 --- a/racevisionGame/src/main/java/visualiser/Controllers/RaceStartController.java +++ b/racevisionGame/src/main/java/visualiser/Controllers/RaceStartController.java @@ -22,7 +22,7 @@ import java.util.logging.Logger; /** * Controller to for waiting for the race to start. */ -public class RaceStartController extends Controller2 { +public class RaceStartController extends Controller { private @FXML Label raceTitleLabel; private @FXML Label raceStartLabel; private @FXML Label timeZoneTime; diff --git a/racevisionGame/src/main/java/visualiser/Controllers/RaceViewController.java b/racevisionGame/src/main/java/visualiser/Controllers/RaceViewController.java index b6836665..45ce8146 100644 --- a/racevisionGame/src/main/java/visualiser/Controllers/RaceViewController.java +++ b/racevisionGame/src/main/java/visualiser/Controllers/RaceViewController.java @@ -32,7 +32,7 @@ import java.util.logging.Logger; /** * Controller used to display a running race. */ -public class RaceViewController extends Controller2 { +public class RaceViewController extends Controller { private VisualiserRaceEvent visualiserRace; private VisualiserRaceState raceState; private ControllerClient controllerClient; diff --git a/racevisionGame/src/main/java/visualiser/Controllers/TitleController.java b/racevisionGame/src/main/java/visualiser/Controllers/TitleController.java index 42925021..68fefe98 100644 --- a/racevisionGame/src/main/java/visualiser/Controllers/TitleController.java +++ b/racevisionGame/src/main/java/visualiser/Controllers/TitleController.java @@ -12,7 +12,7 @@ import java.io.IOException; * burger-boat and comic sans styling to allure and entice users into playing * the game. */ -public class TitleController extends Controller2 { +public class TitleController extends Controller { private @FXML RadioButton dayModeRD; private @FXML RadioButton nightModeRD; diff --git a/racevisionGame/src/main/java/visualiser/app/App.java b/racevisionGame/src/main/java/visualiser/app/App.java index 9cd9794b..c8c8d1f3 100644 --- a/racevisionGame/src/main/java/visualiser/app/App.java +++ b/racevisionGame/src/main/java/visualiser/app/App.java @@ -27,19 +27,16 @@ import javafx.stage.StageStyle; import javafx.stage.WindowEvent; import javafx.util.Duration; import mock.app.Event; -import visualiser.gameController.Keys.KeyFactory; public class App extends Application { - private static Stage stage; + public static Event game; private Pane splashLayout; private ProgressBar loadProgress; private Label progressText; private static final int SPLASH_WIDTH = 676; private static final int SPLASH_HEIGHT = 227; - public static KeyFactory keyFactory; - public static App app = new App(); - public static Event game; + /** * Entry point for running the programme @@ -51,10 +48,6 @@ public class App extends Application { @Override public void init() { - // load the user's personalised key bindings - keyFactory = new KeyFactory(); - keyFactory.load(); - ImageView splash = new ImageView(new Image( getClass().getClassLoader().getResourceAsStream("images/splashScreen.png") )); diff --git a/racevisionGame/src/main/java/visualiser/gameController/InputChecker.java b/racevisionGame/src/main/java/visualiser/gameController/InputChecker.java index b4b3de9b..88cdcb74 100644 --- a/racevisionGame/src/main/java/visualiser/gameController/InputChecker.java +++ b/racevisionGame/src/main/java/visualiser/gameController/InputChecker.java @@ -3,15 +3,14 @@ package visualiser.gameController; import javafx.animation.AnimationTimer; import javafx.scene.Scene; import visualiser.gameController.Keys.ControlKey; - +import visualiser.gameController.Keys.KeyFactory; import java.util.HashMap; -import static visualiser.app.App.keyFactory; - /** * Class for checking what keys are currently being used */ public class InputChecker { + private KeyFactory keyFactory; private HashMap currentlyActiveKeys = new HashMap<>(); /** @@ -19,7 +18,8 @@ public class InputChecker { * @param scene Scene the controller is to run in parallel with. */ public void runWithScene(Scene scene){ -// KeyFactory keyFactory = KeyFactory.getFactory(); + KeyFactory keyFactory = new KeyFactory(); + keyFactory.load(); scene.setOnKeyPressed(event -> { String codeString = event.getCode().toString(); diff --git a/racevisionGame/src/main/java/visualiser/model/Annotations.java b/racevisionGame/src/main/java/visualiser/model/Annotations.java index 54976c35..f5f2c46d 100644 --- a/racevisionGame/src/main/java/visualiser/model/Annotations.java +++ b/racevisionGame/src/main/java/visualiser/model/Annotations.java @@ -15,7 +15,7 @@ import java.util.Map; * Class that processes user selected annotation visibility options to * display the requested information on the * {@link ResizableRaceCanvas}. These are displayed - * via the {@link visualiser.Controllers.RaceController}.
+ * via the {@link visualiser.Controllers.RaceViewController}.
* Annotation options for a {@link VisualiserBoat} include: its name, * abbreviation, speed, the time since it passed the last * {@link shared.model.Mark}, estimated time to the next marker, diff --git a/racevisionGame/src/main/java/visualiser/model/ResizableRaceCanvas.java b/racevisionGame/src/main/java/visualiser/model/ResizableRaceCanvas.java index 03e86e27..0618cd6a 100644 --- a/racevisionGame/src/main/java/visualiser/model/ResizableRaceCanvas.java +++ b/racevisionGame/src/main/java/visualiser/model/ResizableRaceCanvas.java @@ -18,7 +18,7 @@ import java.util.List; /** * This JavaFX Canvas is used to update and display details for a * {@link RaceMap} via the - * {@link visualiser.Controllers.RaceController}.
+ * {@link visualiser.Controllers.RaceViewController}.
* It fills it's parent and cannot be downsized.
* Details displayed include: * {@link VisualiserBoat}s (and their diff --git a/racevisionGame/src/main/java/visualiser/model/Sparkline.java b/racevisionGame/src/main/java/visualiser/model/Sparkline.java index 3f7e07b8..e50931be 100644 --- a/racevisionGame/src/main/java/visualiser/model/Sparkline.java +++ b/racevisionGame/src/main/java/visualiser/model/Sparkline.java @@ -21,7 +21,7 @@ import java.util.Map; * placing position as they complete each {@link shared.model.Leg} by * passing a course {@link shared.model.Mark}.
* This sparkline is displayed using the - * {@link visualiser.Controllers.RaceController}. + * {@link visualiser.Controllers.RaceViewController}. */ public class Sparkline { From 1ed7ccf146d649a2b333406f4ee3b198fe822987 Mon Sep 17 00:00:00 2001 From: Jessica Syder Date: Sat, 9 Sep 2017 10:44:19 +1200 Subject: [PATCH 16/37] Minor changes preparing to merge in 3D #story[1261] --- .../Controllers/ConnectionController.java | 3 +- .../Controllers/KeyBindingsController.java | 37 +++++++++---------- .../Controllers/LobbyHostingController.java | 2 - .../Controllers/RaceViewController.java | 2 - 4 files changed, 19 insertions(+), 25 deletions(-) diff --git a/racevisionGame/src/main/java/visualiser/Controllers/ConnectionController.java b/racevisionGame/src/main/java/visualiser/Controllers/ConnectionController.java index c95ce731..7c9269e3 100644 --- a/racevisionGame/src/main/java/visualiser/Controllers/ConnectionController.java +++ b/racevisionGame/src/main/java/visualiser/Controllers/ConnectionController.java @@ -6,6 +6,7 @@ import javafx.fxml.FXML; import javafx.scene.control.*; import javafx.scene.layout.AnchorPane; import visualiser.model.RaceConnection; + import java.io.IOException; import java.net.Socket; import java.net.URL; @@ -13,7 +14,7 @@ import java.util.ResourceBundle; //TODO it appears this view/controller was replaced by Lobby.fxml. Remove? /** - * Controls the connection that the VIsualiser can connect to. + * Controls the connection that the Visualiser can connect to. */ public class ConnectionController extends Controller { @FXML AnchorPane connectionWrapper; diff --git a/racevisionGame/src/main/java/visualiser/Controllers/KeyBindingsController.java b/racevisionGame/src/main/java/visualiser/Controllers/KeyBindingsController.java index 63e7ffda..b8359aad 100644 --- a/racevisionGame/src/main/java/visualiser/Controllers/KeyBindingsController.java +++ b/racevisionGame/src/main/java/visualiser/Controllers/KeyBindingsController.java @@ -1,7 +1,6 @@ package visualiser.Controllers; import javafx.application.Platform; -import javafx.event.EventHandler; import javafx.fxml.FXML; import javafx.scene.control.Button; import javafx.scene.control.ListView; @@ -49,7 +48,7 @@ public class KeyBindingsController extends Controller { * Sets up table before populating it. * Set up includes headings, CSS styling and modifying default properties. */ - public void initializeTable(){ + private void initializeTable(){ // set the headings for each column lstKey.getItems().add("Key"); lstControl.getItems().add("Command"); @@ -67,15 +66,15 @@ public class KeyBindingsController extends Controller { // stop the columns from being selectable, so only the buttons are lstKey.getSelectionModel().selectedItemProperty() - .addListener((observable, oldvalue, newValue) -> + .addListener((observable, oldValue, newValue) -> Platform.runLater(() -> lstKey.getSelectionModel().select(0))); lstDescription.getSelectionModel().selectedItemProperty() - .addListener((observable, oldvalue, newValue) -> + .addListener((observable, oldValue, newValue) -> Platform.runLater(() -> lstDescription.getSelectionModel().select(0))); lstControl.getSelectionModel().selectedItemProperty() - .addListener((observable, oldvalue, newValue) -> + .addListener((observable, oldValue, newValue) -> Platform.runLater(() -> lstControl.getSelectionModel().select(0))); } @@ -83,7 +82,7 @@ public class KeyBindingsController extends Controller { /** * Populates the table with commands and their key binding details. */ - public void populateTable(){ + private void populateTable(){ // add each command to the table for (Map.Entry entry : newKeyFactory.getKeyState().entrySet()) { // create button for command @@ -100,9 +99,9 @@ public class KeyBindingsController extends Controller { /** * Makes a copy of the {@link KeyFactory} that does not modify the original. - * @return new keyfactory to be modified + * @return new keyFactory to be modified */ - public KeyFactory copyExistingFactory(){ + private KeyFactory copyExistingFactory(){ newKeyFactory = new KeyFactory(); Map oldKeyState = existingKeyFactory.getKeyState(); Map newKeyState = new HashMap<>(); @@ -118,18 +117,16 @@ public class KeyBindingsController extends Controller { /** * Creates a listener for when a user tries to close the current window. */ - public void setClosedListener(){ + private void setClosedListener(){ anchor.sceneProperty().addListener((obsS, oldS, newS) -> { if (newS != null) { newS.windowProperty().addListener((obsW, oldW, newW) -> { if (newW != null) { Stage stage = (Stage)newW; // WE is processed by onExit method - stage.setOnCloseRequest(new EventHandler() { - public void handle(WindowEvent we) { - if (we.getEventType() == WindowEvent.WINDOW_CLOSE_REQUEST) { - onExit(we); - } + stage.setOnCloseRequest(we -> { + if (we.getEventType() == WindowEvent.WINDOW_CLOSE_REQUEST) { + onExit(we); } }); } @@ -139,11 +136,11 @@ public class KeyBindingsController extends Controller { } /** - * Creates a listener for the base anchorpane for key presses. + * Creates a listener for the base anchorPane for key presses. * It updates the current key bindings of the {@link KeyFactory} if * required. */ - public void setKeyListener(){ + private void setKeyListener(){ anchor.addEventFilter(KeyEvent.KEY_PRESSED, event -> { // if esc, cancel current button click if (event.getCode() == KeyCode.ESCAPE){ @@ -218,10 +215,10 @@ public class KeyBindingsController extends Controller { * commands are missing a key binding. * @return True if valid, false if invalid */ - public Boolean isFactoryValid(){ + private Boolean isFactoryValid(){ for (Map.Entry entry : newKeyFactory.getKeyState().entrySet ()) { - if (entry.getKey().toString()==entry.getValue().toString()){ + if (entry.getKey().toString().equals(entry.getValue().toString())){ return false; } } @@ -234,7 +231,7 @@ public class KeyBindingsController extends Controller { * @param we {@link WindowEvent} close request to be consumed if settings * have not been successfully saved. */ - public void onExit(WindowEvent we){ + private void onExit(WindowEvent we){ // if modified KeyFactory hasn't been saved if (changed){ loadNotification("Please cancel or save your changes before exiting" + @@ -248,7 +245,7 @@ public class KeyBindingsController extends Controller { * @param message the message to be displayed to the user * @param warning true if the message to be displayed is due to user error */ - public void loadNotification(String message, Boolean warning){ + private void loadNotification(String message, Boolean warning){ try { NotificationController nc = (NotificationController) loadPopupScene("notification.fxml", diff --git a/racevisionGame/src/main/java/visualiser/Controllers/LobbyHostingController.java b/racevisionGame/src/main/java/visualiser/Controllers/LobbyHostingController.java index 9462ad4d..fdbfea6a 100644 --- a/racevisionGame/src/main/java/visualiser/Controllers/LobbyHostingController.java +++ b/racevisionGame/src/main/java/visualiser/Controllers/LobbyHostingController.java @@ -112,8 +112,6 @@ public class LobbyHostingController extends Controller { alert.setHeaderText("You are about to quit the race"); Optional result = alert.showAndWait(); if(result.get() == ButtonType.OK){ -// getStage().close(); -// App.app.loadTitleScreen(); loadTitleScreen(); } } diff --git a/racevisionGame/src/main/java/visualiser/Controllers/RaceViewController.java b/racevisionGame/src/main/java/visualiser/Controllers/RaceViewController.java index 45ce8146..1b787e2f 100644 --- a/racevisionGame/src/main/java/visualiser/Controllers/RaceViewController.java +++ b/racevisionGame/src/main/java/visualiser/Controllers/RaceViewController.java @@ -120,8 +120,6 @@ public class RaceViewController extends Controller { loadTitleScreen(); } } - } catch (IOException e) { - e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } From 346aa148ef495a7fb06cf4c420568f2b9a0b970c Mon Sep 17 00:00:00 2001 From: fjc40 Date: Mon, 11 Sep 2017 11:35:11 +1200 Subject: [PATCH 17/37] Added some debug statements, and WIP MarkRoundingSequence class. Temporarily disabled source id allocator time checks. Added mark rounding stuff to race canvas to help debug. #story[1185] --- .../src/main/java/mock/model/MockRace.java | 64 ++++++++--- .../java/mock/model/SourceIdAllocator.java | 4 +- .../main/java/shared/model/CompoundMark.java | 2 +- .../src/main/java/shared/model/Constants.java | 2 +- .../shared/model/MarkRoundingSequence.java | 78 ++++++++++++++ .../visualiser/model/ResizableRaceCanvas.java | 101 +++++++++++++++--- 6 files changed, 217 insertions(+), 34 deletions(-) create mode 100644 racevisionGame/src/main/java/shared/model/MarkRoundingSequence.java diff --git a/racevisionGame/src/main/java/mock/model/MockRace.java b/racevisionGame/src/main/java/mock/model/MockRace.java index a9f11770..c598eb05 100644 --- a/racevisionGame/src/main/java/mock/model/MockRace.java +++ b/racevisionGame/src/main/java/mock/model/MockRace.java @@ -8,6 +8,7 @@ import network.Messages.BoatLocation; import network.Messages.BoatStatus; import network.Messages.Enums.BoatStatusEnum; import network.Messages.Enums.RaceStatusEnum; +import network.Utils.AC35UnitConverter; import shared.dataInput.BoatDataSource; import shared.dataInput.RaceDataSource; import shared.dataInput.RegattaDataSource; @@ -524,12 +525,22 @@ public class MockRace extends RaceState { boolean gateCheck = boat.getCurrentLeg().getEndCompoundMark().getMark2() == null || boat.isBetweenGate(boat.getCurrentLeg().getEndCompoundMark()); Mark roundingMark = boat.getCurrentLeg().getEndCompoundMark().getMarkForRounding(legBearing); + System.out.println("boat rounding state: " + boat.getRoundingStatus());//TEMP REMOVE + switch (boat.getRoundingStatus()) { case 0://hasn't started rounding + System.out.println("portside? " + boat.isPortSide(roundingMark));//TEMP REMOVE + System.out.println("passes line? " + GPSCoordinate.passesLine(roundingMark.getPosition(), roundingChecks.get(0), boat.getPosition(), legBearing));//TEMP REMOVE + System.out.println("gatecheck? " + gateCheck);//TEMP REMOVE + System.out.println("between gates? " + boat.isBetweenGate(roundingMark, Mark.tempMark(roundingChecks.get(0))));//TEMP REMOVE if (boat.isPortSide(roundingMark) && - GPSCoordinate.passesLine(roundingMark.getPosition(), - roundingChecks.get(0), boat.getPosition(), legBearing) && - gateCheck && boat.isBetweenGate(roundingMark, Mark.tempMark(roundingChecks.get(0)))) { + GPSCoordinate.passesLine( + roundingMark.getPosition(), + roundingChecks.get(0), + boat.getPosition(), + legBearing) && + gateCheck && + boat.isBetweenGate(roundingMark, Mark.tempMark(roundingChecks.get(0)))) { boat.increaseRoundingStatus(); if (boat.getCurrentLeg().getLegNumber() + 2 >= getLegs().size()){ //boat has finished race @@ -539,8 +550,10 @@ public class MockRace extends RaceState { break; case 1://has been parallel to the mark; if (boat.isPortSide(roundingMark) && - GPSCoordinate.passesLine(roundingMark.getPosition(), - roundingChecks.get(1), boat.getPosition(), + GPSCoordinate.passesLine( + roundingMark.getPosition(), + roundingChecks.get(1), + boat.getPosition(), Bearing.fromDegrees(legBearing.degrees() - 90)) &&//negative 90 from bearing because of port rounding boat.isBetweenGate(roundingMark, Mark.tempMark(roundingChecks.get(1)))) { boat.increaseRoundingStatus(); @@ -568,6 +581,8 @@ public class MockRace extends RaceState { boolean gateCheck = boat.getCurrentLeg().getEndCompoundMark().getMark2() == null || boat.isBetweenGate(boat.getCurrentLeg().getEndCompoundMark()); Mark roundingMark = boat.getCurrentLeg().getEndCompoundMark().getMarkForRounding(legBearing); + System.out.println("boat rounding state: " + boat.getRoundingStatus());//TEMP REMOVE + switch (boat.getRoundingStatus()) { case 0://hasn't started rounding if (boat.isStarboardSide(roundingMark) && @@ -606,19 +621,27 @@ public class MockRace extends RaceState { */ protected void checkPosition(MockBoat boat, long timeElapsed) { //The distance, in nautical miles, within which the boat needs to get in order to consider that it has reached the marker. - double epsilonNauticalMiles = boat.getCurrentLeg().getEndCompoundMark().getRoundingDistance(); //250 meters. + double epsilonMeters = boat.getCurrentLeg().getEndCompoundMark().getRoundingDistance(); //250 meters. + //System.out.println("epsilon dist meters: " + epsilonMeters);//TEMP REMOVE + + //System.out.println("boat dist to next point NM: " + boat.calculateDistanceToNextMarker());//TEMP REMOVE + + double epsilonNM = epsilonMeters / Constants.NMToMetersConversion; - if (boat.calculateDistanceToNextMarker() < epsilonNauticalMiles) { + //System.out.println("epsilon NM: " + epsilonNM);//TEMP REMOVE + + if (boat.calculateDistanceToNextMarker() < epsilonNM) { //Boat is within an acceptable distance from the mark. - GPSCoordinate startDirectionLinePoint = boat.getCurrentLeg().getStartCompoundMark().getMark1Position(); - GPSCoordinate endDirectionLinePoint = boat.getCurrentLeg().getEndCompoundMark().getMark1Position(); + GPSCoordinate startDirectionLinePoint = boat.getCurrentLeg().getStartCompoundMark().getAverageGPSCoordinate(); + GPSCoordinate endDirectionLinePoint = boat.getCurrentLeg().getEndCompoundMark().getAverageGPSCoordinate(); Bearing bearingOfDirectionLine = GPSCoordinate.calculateBearing(startDirectionLinePoint, endDirectionLinePoint); //use the direction line to create three invisible points that act as crossover lines a boat must cross //to round a mark double bearingToAdd; + //System.out.println("leg: " + boat.getCurrentLeg().getName() + " has bearing DL of: " + bearingOfDirectionLine.degrees());//TEMP REMOVE if (boat.getCurrentLeg().getEndCompoundMark().getRoundingType() == RoundingType.Port || boat.getCurrentLeg().getEndCompoundMark().getRoundingType() == RoundingType.SP){ bearingToAdd = 90; @@ -626,25 +649,32 @@ public class MockRace extends RaceState { bearingToAdd = -90; } - GPSCoordinate roundCheck1 = GPSCoordinate.calculateNewPosition(endDirectionLinePoint, - epsilonNauticalMiles, Azimuth.fromDegrees(bearingOfDirectionLine.degrees() + bearingToAdd)); + //System.out.println("so new bearing is " + (bearingToAdd + bearingOfDirectionLine.degrees()));//TEMP REMOVE + + GPSCoordinate roundCheck1 = GPSCoordinate.calculateNewPosition( + endDirectionLinePoint, + epsilonMeters, + Azimuth.fromDegrees(bearingOfDirectionLine.degrees() + bearingToAdd) ); + //System.out.println("this has a rounding coordinate of (" + roundCheck1.getLongitude() + ", " + roundCheck1.getLatitude() + ")");//TEMP REMOVE GPSCoordinate roundCheck2; try{ Leg nextLeg = getLegs().get(getLegs().indexOf(boat.getCurrentLeg()) + 1); - GPSCoordinate startNextDirectionLinePoint = nextLeg.getStartCompoundMark().getMark1Position(); - GPSCoordinate endNextDirectionLinePoint = nextLeg.getEndCompoundMark().getMark1Position(); + GPSCoordinate startNextDirectionLinePoint = nextLeg.getStartCompoundMark().getAverageGPSCoordinate(); + GPSCoordinate endNextDirectionLinePoint = nextLeg.getEndCompoundMark().getAverageGPSCoordinate(); Bearing bearingOfNextDirectionLine = GPSCoordinate.calculateBearing(startNextDirectionLinePoint, endNextDirectionLinePoint); - roundCheck2 = GPSCoordinate.calculateNewPosition(endDirectionLinePoint, - epsilonNauticalMiles, Azimuth.fromDegrees(bearingOfNextDirectionLine.degrees() + bearingToAdd)); + roundCheck2 = GPSCoordinate.calculateNewPosition( + endDirectionLinePoint, + epsilonMeters, + Azimuth.fromDegrees(bearingOfNextDirectionLine.degrees() + bearingToAdd) ); }catch(NullPointerException e){ //this is caused by the last leg not being having a leg after it roundCheck2 = roundCheck1; } - List roundingChecks = new ArrayList(Arrays.asList(roundCheck1, roundCheck2)); + List roundingChecks = new ArrayList<>(Arrays.asList(roundCheck1, roundCheck2)); switch (boat.getCurrentLeg().getEndCompoundMark().getRoundingType()) { case SP://Not yet implemented so these gates will be rounded port side @@ -657,6 +687,8 @@ public class MockRace extends RaceState { break; } + System.out.println("resultant boat rounding state: " + boat.getRoundingStatus());//TEMP REMOVE + //Check if the boat has finished or stopped racing. if (this.isLastLeg(boat.getCurrentLeg())) { diff --git a/racevisionGame/src/main/java/mock/model/SourceIdAllocator.java b/racevisionGame/src/main/java/mock/model/SourceIdAllocator.java index 17a7e85f..ed36093c 100644 --- a/racevisionGame/src/main/java/mock/model/SourceIdAllocator.java +++ b/racevisionGame/src/main/java/mock/model/SourceIdAllocator.java @@ -36,10 +36,10 @@ public class SourceIdAllocator { */ public synchronized int allocateSourceID() throws SourceIDAllocationException { - if (!((mockRace.getRaceStatusEnum() == RaceStatusEnum.PRESTART) + /*if (!((mockRace.getRaceStatusEnum() == RaceStatusEnum.PRESTART) || (mockRace.getRaceStatusEnum() == RaceStatusEnum.WARNING))) { throw new SourceIDAllocationException("Could not allocate a source ID. Can only allocate during pre-start period. It is currently: " + mockRace.getRaceStatusEnum()); - } + }*///TEMP DISABLED FOR TESTING - RE-ENABLE THIS List allocatedIDs = mockRace.getRaceDataSource().getParticipants(); List allIDs = new ArrayList<>(mockRace.getBoatDataSource().getBoats().keySet()); diff --git a/racevisionGame/src/main/java/shared/model/CompoundMark.java b/racevisionGame/src/main/java/shared/model/CompoundMark.java index 4fa2599c..57d9a32b 100644 --- a/racevisionGame/src/main/java/shared/model/CompoundMark.java +++ b/racevisionGame/src/main/java/shared/model/CompoundMark.java @@ -187,7 +187,7 @@ public class CompoundMark extends XMLCompoundMark{ } //finds the mark furthest west and east - if(this.getMark1Position().getLongitude() > this.getMark2Position().getLongitude()){ + if(this.getMark1Position().getLongitude() < this.getMark2Position().getLongitude()){ westMostMark = this.mark1; eastMostMark = this.mark2; }else{ diff --git a/racevisionGame/src/main/java/shared/model/Constants.java b/racevisionGame/src/main/java/shared/model/Constants.java index bb7ec598..247b4c9b 100644 --- a/racevisionGame/src/main/java/shared/model/Constants.java +++ b/racevisionGame/src/main/java/shared/model/Constants.java @@ -33,7 +33,7 @@ public class Constants { * Frame periods are multiplied by this to get the amount of time a single frame represents. * E.g., frame period = 20ms, scale = 5, frame represents 20 * 5 = 100ms, and so boats are simulated for 100ms, even though only 20ms actually occurred. */ - public static final int RaceTimeScale = 2;//10; + public static final int RaceTimeScale = 10;//10; /** * The race pre-start time, in milliseconds. 3 minutes. diff --git a/racevisionGame/src/main/java/shared/model/MarkRoundingSequence.java b/racevisionGame/src/main/java/shared/model/MarkRoundingSequence.java new file mode 100644 index 00000000..48fc3999 --- /dev/null +++ b/racevisionGame/src/main/java/shared/model/MarkRoundingSequence.java @@ -0,0 +1,78 @@ +package shared.model; + +import org.jetbrains.annotations.Nullable; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +/** + * This class contains a sequence of points that describe the mark rounding order for a course. + */ +public class MarkRoundingSequence { + + + /** + * Legs in the race. + */ + private List legs; + + /** + * For each leg, a sequence of rounding points. + */ + private Map> roundingPoints; + + + + public MarkRoundingSequence(List legs) { + this.legs = legs; + generateRoundingPoints(); + } + + + /** + * Generates the rounding points for all legs in the race. + */ + private void generateRoundingPoints() { + this.roundingPoints = new HashMap<>(this.legs.size()); + + for (int i = 0; i < this.legs.size(); i++) { + Leg currentLeg = this.legs.get(i); + Optional nextLeg = Optional.ofNullable(this.legs.get(i + 1)); + + generateRoundingPoint(currentLeg, nextLeg); + } + + } + + + /** + * Generates the rounding points for a specific leg. + * @param currentLeg The leg to generate rounding points for. + * @param nextLeg The following leg, used to help generate rounding points. + */ + private void generateRoundingPoint(Leg currentLeg, Optional nextLeg) { + + + + + + + + //Rounding points: + + //each mark/gate has a specific mark to round. Call this ROUNDINGMARK + // with a mark, it is the mark + // with a gate, it depends if it is a starboard or port gate. + // it is the mark that allows the boat to enter between both marks of the gate, whilst obeying the starboard/port requirement. + + //let the bearing between start of leg and end of leg be called LEGBEARING + + //the first rounding point is ROUNDINGDISTANCE units away from the ROUNDINGMARK, on an angle perpendicular to LEGBEARING. + // the angle means that the rounding mark is at the center of a gate, for gates. + + //the second rounding point is the same as the first, except LEGBEARING is the bearing between end of current leg, and start of next leg. + } + +} diff --git a/racevisionGame/src/main/java/visualiser/model/ResizableRaceCanvas.java b/racevisionGame/src/main/java/visualiser/model/ResizableRaceCanvas.java index 03e86e27..3f475e63 100644 --- a/racevisionGame/src/main/java/visualiser/model/ResizableRaceCanvas.java +++ b/racevisionGame/src/main/java/visualiser/model/ResizableRaceCanvas.java @@ -325,18 +325,6 @@ public class ResizableRaceCanvas extends ResizableCanvas { } - - -/* - //If the race hasn't started, we set the time since last mark to the current time, to ensure we don't start counting until the race actually starts. - if ((boat.getStatus() != BoatStatusEnum.RACING) && (boat.getStatus() == BoatStatusEnum.FINISHED)) { - boat.setTimeAtLastMark(visualiserRace.getVisualiserRaceState().getRaceClock().getCurrentTime()); - } -*/ - - - - } /** @@ -504,6 +492,87 @@ public class ResizableRaceCanvas extends ResizableCanvas { } + private void drawRoundingLines() { + + + + + //ugly hack + //rounding lines + + //Boat is within an acceptable distance from the mark. + VisualiserBoat boat = null; + for (VisualiserBoat visualiserBoat : new ArrayList<>(raceState.getBoats())) { + if (visualiserBoat.isClientBoat()) { + boat = visualiserBoat; + } + } + if (boat == null) { + return; + } + + GPSCoordinate startDirectionLinePoint = boat.getCurrentLeg().getStartCompoundMark().getAverageGPSCoordinate(); + GPSCoordinate endDirectionLinePoint = boat.getCurrentLeg().getEndCompoundMark().getAverageGPSCoordinate(); + Bearing bearingOfDirectionLine = GPSCoordinate.calculateBearing(startDirectionLinePoint, endDirectionLinePoint); + + //use the direction line to create three invisible points that act as crossover lines a boat must cross + //to round a mark + + double bearingToAdd; + if (boat.getCurrentLeg().getEndCompoundMark().getRoundingType() == RoundingType.Port || + boat.getCurrentLeg().getEndCompoundMark().getRoundingType() == RoundingType.SP) { + bearingToAdd = 90; + }else{ + bearingToAdd = -90; + } + + double epsilonMeters = boat.getCurrentLeg().getEndCompoundMark().getRoundingDistance(); + + GPSCoordinate endMarkPos = boat.getCurrentLeg().getEndCompoundMark().getMarkForRounding(bearingOfDirectionLine).getPosition(); + + GPSCoordinate roundCheck1 = GPSCoordinate.calculateNewPosition( + endMarkPos, + epsilonMeters, + Azimuth.fromDegrees(bearingOfDirectionLine.degrees() + bearingToAdd) ); + + GPSCoordinate roundCheck2; + try{ + Leg nextLeg = raceState.getLegs().get(raceState.getLegs().indexOf(boat.getCurrentLeg()) + 1); + + GPSCoordinate startNextDirectionLinePoint = nextLeg.getStartCompoundMark().getAverageGPSCoordinate(); + GPSCoordinate endNextDirectionLinePoint = nextLeg.getEndCompoundMark().getAverageGPSCoordinate(); + Bearing bearingOfNextDirectionLine = GPSCoordinate.calculateBearing(startNextDirectionLinePoint, endNextDirectionLinePoint); + + roundCheck2 = GPSCoordinate.calculateNewPosition( + endDirectionLinePoint, + epsilonMeters, + Azimuth.fromDegrees(bearingOfNextDirectionLine.degrees() + bearingToAdd) ); + } catch(NullPointerException e) { + //this is caused by the last leg not being having a leg after it + roundCheck2 = roundCheck1; + } + + //To screen coords. + GraphCoordinate legEnd = map.convertGPS(endDirectionLinePoint); + GraphCoordinate round1 = map.convertGPS(roundCheck1); + GraphCoordinate round2 = map.convertGPS(roundCheck2); + + + + gc.strokeLine( + legEnd.getX(), + legEnd.getY(), + round1.getX(), + round1.getY() ); + + gc.strokeLine( + legEnd.getX(), + legEnd.getY(), + round2.getX(), + round2.getY() ); + + } + /** * Draws all of the {@link Mark}s on the canvas. @@ -513,6 +582,7 @@ public class ResizableRaceCanvas extends ResizableCanvas { for (Mark mark : new ArrayList<>(raceState.getMarks())) { drawMark(mark); } + } @@ -621,6 +691,9 @@ public class ResizableRaceCanvas extends ResizableCanvas { //Marks. drawMarks(); + //TEMP + drawRoundingLines(); + } /** @@ -655,7 +728,7 @@ public class ResizableRaceCanvas extends ResizableCanvas { //finds the direction of the current leg as a bearing startDirectionLinePoint = legStartPoint; - GPSCoordinate tempEndDirectionLinePoint = legs.get(index).getEndCompoundMark().getAverageGPSCoordinate(); + GPSCoordinate tempEndDirectionLinePoint = legs.get(index).getEndCompoundMark().getMark1Position(); bearingOfDirectionLine = GPSCoordinate.calculateBearing(startDirectionLinePoint, tempEndDirectionLinePoint); @@ -826,4 +899,4 @@ public class ResizableRaceCanvas extends ResizableCanvas { -} \ No newline at end of file +} From 669a303e9b8034c4422481a7a1bda7b3d836c72d Mon Sep 17 00:00:00 2001 From: Jessica Syder Date: Mon, 11 Sep 2017 20:19:10 +1200 Subject: [PATCH 18/37] Merge branch 'master' of https://eng-git.canterbury.ac.nz/seng302-2017/team-7 into controllerSplit # Conflicts: # racevisionGame/src/main/java/visualiser/Controllers/HostGameController.java # racevisionGame/src/main/java/visualiser/Controllers/RaceViewController.java # racevisionGame/src/main/java/visualiser/Controllers/StartController.java # racevisionGame/src/main/java/visualiser/Controllers/hostgame.fxml # racevisionGame/src/main/java/visualiser/Controllers/lobbyHosting.fxml # racevisionGame/src/main/java/visualiser/Controllers/main.fxml # racevisionGame/src/main/java/visualiser/Controllers/raceView.fxml --- .../src/main/java/mock/app/Event.java | 1 - .../main/java/mock/xml/RaceXMLCreator.java | 26 +--- .../visualiser/Controllers/Controller.java | 23 ++- .../Controllers/HostGameController.java | 90 ++++-------- .../Controllers/KeyBindingsController.java | 2 +- .../Controllers/LobbyController.java | 1 - .../Controllers/RaceViewController.java | 134 ++++++++++++------ .../Controllers/TitleController.java | 5 +- .../src/main/java/visualiser/app/App.java | 22 +-- .../resources/visualiser/scenes/hostGame.fxml | 2 +- .../resources/visualiser/scenes/raceView.fxml | 6 +- 11 files changed, 174 insertions(+), 138 deletions(-) diff --git a/racevisionGame/src/main/java/mock/app/Event.java b/racevisionGame/src/main/java/mock/app/Event.java index 84481ce0..f8177612 100644 --- a/racevisionGame/src/main/java/mock/app/Event.java +++ b/racevisionGame/src/main/java/mock/app/Event.java @@ -18,7 +18,6 @@ import shared.exceptions.InvalidRegattaDataException; import shared.exceptions.XMLReaderException; import shared.model.Bearing; import shared.model.Constants; -import shared.xml.XMLUtilities; import java.io.IOException; import java.nio.charset.StandardCharsets; diff --git a/racevisionGame/src/main/java/mock/xml/RaceXMLCreator.java b/racevisionGame/src/main/java/mock/xml/RaceXMLCreator.java index b168862f..6c098ebe 100644 --- a/racevisionGame/src/main/java/mock/xml/RaceXMLCreator.java +++ b/racevisionGame/src/main/java/mock/xml/RaceXMLCreator.java @@ -1,34 +1,22 @@ package mock.xml; -import org.w3c.dom.Document; import org.xml.sax.SAXException; import shared.dataInput.RaceXMLReader; import shared.enums.XMLFileType; import shared.exceptions.InvalidRaceDataException; import shared.exceptions.XMLReaderException; -import shared.model.*; -import shared.xml.Race.*; +import shared.model.CompoundMark; +import shared.model.Constants; +import shared.model.GPSCoordinate; +import shared.xml.Race.XMLCompoundMark; +import shared.xml.Race.XMLLimit; +import shared.xml.Race.XMLMark; +import shared.xml.Race.XMLRace; import shared.xml.XMLUtilities; -import javax.xml.XMLConstants; -import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBException; -import javax.xml.bind.Marshaller; -import javax.xml.bind.Unmarshaller; -import javax.xml.bind.util.JAXBSource; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; -import javax.xml.transform.Source; -import javax.xml.transform.dom.DOMSource; -import javax.xml.validation.Schema; -import javax.xml.validation.SchemaFactory; -import javax.xml.validation.Validator; -import java.io.File; import java.io.IOException; -import java.io.StringWriter; -import java.math.BigInteger; -import java.net.URL; import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; diff --git a/racevisionGame/src/main/java/visualiser/Controllers/Controller.java b/racevisionGame/src/main/java/visualiser/Controllers/Controller.java index 23094fd7..6d14b32d 100644 --- a/racevisionGame/src/main/java/visualiser/Controllers/Controller.java +++ b/racevisionGame/src/main/java/visualiser/Controllers/Controller.java @@ -7,22 +7,25 @@ import javafx.scene.image.Image; import javafx.stage.Modality; import javafx.stage.Stage; import visualiser.app.App; - import java.io.IOException; - /** * Abstract controller class to give each subclass the functionality to load * a new scene into the existing stage, or create a new popup window. */ public abstract class Controller { - Stage stage = App.getStage(); + private Stage stage = App.getStage(); + /** + * Loads the title screen again when app is already running. + * @throws IOException if a problem with the title.fxml + */ protected void loadTitleScreen() throws IOException { FXMLLoader loader = new FXMLLoader(getClass().getResource("/visualiser/scenes/title.fxml")); Parent root = loader.load(); stage.setResizable(false); Scene scene = new Scene(root); + addCssStyle(scene); stage.setScene(scene); stage.show(); } @@ -47,6 +50,7 @@ public abstract class Controller { // set new scene into existing window Scene scene = new Scene(root, stageWidth, stageHeight); + addCssStyle(scene); stage.setScene(scene); stage.setResizable(true); stage.show(); @@ -81,6 +85,7 @@ public abstract class Controller { stage.centerOnScreen(); stage.getIcons().add(new Image(getClass().getClassLoader().getResourceAsStream("images/SailIcon.png"))); Scene scene = new Scene(root); + addCssStyle(scene); stage.setScene(scene); stage.show(); @@ -88,4 +93,16 @@ public abstract class Controller { return loader.getController(); } + /** + * Adds the relevant CSS styling to the scene being loaded. + * @param scene new scene to be loaded and displayed + */ + private void addCssStyle(Scene scene){ + if (App.dayMode) { + scene.getStylesheets().add("/css/dayMode.css"); + } else { + scene.getStylesheets().add("/css/nightMode.css"); + } + } + } diff --git a/racevisionGame/src/main/java/visualiser/Controllers/HostGameController.java b/racevisionGame/src/main/java/visualiser/Controllers/HostGameController.java index b5c9e4b8..dcd2a42d 100644 --- a/racevisionGame/src/main/java/visualiser/Controllers/HostGameController.java +++ b/racevisionGame/src/main/java/visualiser/Controllers/HostGameController.java @@ -2,15 +2,13 @@ package visualiser.Controllers; import javafx.application.Platform; import javafx.fxml.FXML; -import javafx.scene.control.*; +import javafx.scene.control.Alert; +import javafx.scene.control.ButtonType; import javafx.scene.image.Image; import javafx.scene.image.ImageView; -import javafx.scene.layout.AnchorPane; -import javafx.stage.Stage; import mock.app.Event; import mock.exceptions.EventConstructionException; import visualiser.app.App; - import java.io.IOException; import java.net.Socket; import java.util.ArrayList; @@ -22,38 +20,31 @@ import java.util.logging.Logger; /** * Controller for Hosting a game. */ -public class HostController extends Controller { - private @FXML ImageView imageView; - private @FXML AnchorPane imagePane; - private @FXML SplitPane splitPane; - private @FXML AnchorPane specPane; - @FXML ImageView mapImage; +public class HostGameController extends Controller { + private @FXML ImageView mapImage; private ArrayList listOfMaps; private int currentMapIndex = 0; - @FXML TextField gameNameField; - - @FXML TextField hostNameField; - @FXML Button previousButton; - - @FXML Button nextButton; public void initialize() { + loadMaps(); + } + + /** + * Loads in the list of playable maps to be selected from. + */ + private void loadMaps(){ + // image preview of maps Image ac35Map = new Image(getClass().getClassLoader().getResourceAsStream("images/AC35_Racecourse_MAP.png")); Image oMap = new Image(getClass().getClassLoader().getResourceAsStream("images/oMapLayout.png")); Image iMap = new Image(getClass().getClassLoader().getResourceAsStream("images/iMapLayout.png")); Image mMap = new Image(getClass().getClassLoader().getResourceAsStream("images/mMapLayout.png")); listOfMaps = new ArrayList(Arrays.asList(ac35Map, oMap, iMap, mMap)); -// mapImage.setImage(listOfMaps.get(currentMapIndex)); + mapImage.setImage(listOfMaps.get(currentMapIndex)); Platform.runLater(() -> { - mapImage.setImage(listOfMaps.get(currentMapIndex)); + mapImage.fitWidthProperty() + .bind(mapImage.getScene().getWindow().widthProperty().multiply(0.6)); }); - hostGame(); - - - // mapImage..addListener( -// (observable, oldValue, newValue) -> Platform -// .runLater(() -> )); } /** @@ -76,29 +67,12 @@ public class HostController extends Controller { * @param address address of the server * @param port port that the server is run off */ - public void connectSocket(String address, int port) throws IOException { + private void connectSocket(String address, int port) throws IOException { Socket socket = new Socket(address, port); RaceStartController rsc = (RaceStartController)loadScene("raceStart.fxml"); rsc.enterLobby(socket, true); } - /** - * Hosts a game. - */ - public void hostGame(){ -// splitPane.setResizableWithParent(specPane, false); -// splitPane.lookupAll(".split-pane-divider").stream().forEach(div -> div.setMouseTransparent(true)); -// imageView.fitWidthProperty().bind(imagePane.widthProperty()); -// imageView.fitHeightProperty().bind(imagePane.heightProperty()); - - Platform.runLater(() -> { - mapImage.fitWidthProperty() - .bind(((Stage)mapImage.getScene().getWindow()).widthProperty().multiply(0.6)); - - }); -// mapImage.fitWidthProperty().bind(((Stage) mapImage.getScene().getWindow()).widthProperty().multiply(0.6)); - } - /** * Menu button pressed. Prompt alert then return to menu */ @@ -110,32 +84,30 @@ public class HostController extends Controller { Optional result = alert.showAndWait(); if(result.get() == ButtonType.OK){ loadTitleScreen(); - }} + } + } /** - * Start button pressed. Currently only prints out start + * Method called when the 'next' arrow button is pressed. It is used to + * change the currently displayed map preview to the next in the list. */ - public void startBtnPressed() { - //System.out.println("Should start the race. This button is only visible for the host"); - hostGamePressed(); - } - - public void nextImage(){ - increaseIndex(); + // increase index + currentMapIndex = (currentMapIndex + 1) % listOfMaps.size(); + // update map preview mapImage.setImage(listOfMaps.get(currentMapIndex)); } + /** + * Method called when the 'previous' arrow button is pressed. It is used to + * change the currently displayed map preview to the previous in the list. + */ public void previousImage(){ - decreaseIndex(); + // decrease index + currentMapIndex = ((((currentMapIndex - 1) % listOfMaps.size()) + + listOfMaps.size()) % listOfMaps.size()); + // update map preview mapImage.setImage(listOfMaps.get(currentMapIndex)); } - private void increaseIndex(){ - currentMapIndex = (currentMapIndex + 1)%listOfMaps.size(); - } - - private void decreaseIndex(){ - currentMapIndex = ((((currentMapIndex - 1)%listOfMaps.size())+listOfMaps.size())%listOfMaps.size()); - } } diff --git a/racevisionGame/src/main/java/visualiser/Controllers/KeyBindingsController.java b/racevisionGame/src/main/java/visualiser/Controllers/KeyBindingsController.java index b8359aad..617af614 100644 --- a/racevisionGame/src/main/java/visualiser/Controllers/KeyBindingsController.java +++ b/racevisionGame/src/main/java/visualiser/Controllers/KeyBindingsController.java @@ -218,7 +218,7 @@ public class KeyBindingsController extends Controller { private Boolean isFactoryValid(){ for (Map.Entry entry : newKeyFactory.getKeyState().entrySet ()) { - if (entry.getKey().toString().equals(entry.getValue().toString())){ + if (entry.getKey().equals(entry.getValue().toString())){ return false; } } diff --git a/racevisionGame/src/main/java/visualiser/Controllers/LobbyController.java b/racevisionGame/src/main/java/visualiser/Controllers/LobbyController.java index 6a4fc447..3f416536 100644 --- a/racevisionGame/src/main/java/visualiser/Controllers/LobbyController.java +++ b/racevisionGame/src/main/java/visualiser/Controllers/LobbyController.java @@ -8,7 +8,6 @@ import javafx.scene.control.TableColumn; import javafx.scene.control.TableView; import javafx.scene.control.TextField; import visualiser.model.RaceConnection; - import java.io.IOException; import java.net.Socket; diff --git a/racevisionGame/src/main/java/visualiser/Controllers/RaceViewController.java b/racevisionGame/src/main/java/visualiser/Controllers/RaceViewController.java index 1b787e2f..48b02f41 100644 --- a/racevisionGame/src/main/java/visualiser/Controllers/RaceViewController.java +++ b/racevisionGame/src/main/java/visualiser/Controllers/RaceViewController.java @@ -1,5 +1,6 @@ package visualiser.Controllers; +import com.interactivemesh.jfx.importer.stl.StlMeshImporter; import javafx.animation.AnimationTimer; import javafx.application.Platform; import javafx.collections.FXCollections; @@ -11,20 +12,29 @@ 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.layout.GridPane; 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.model.*; - +import visualiser.layout.Subject3D; +import visualiser.layout.View3D; +import visualiser.model.Sparkline; +import visualiser.model.VisualiserBoat; +import visualiser.model.VisualiserRaceEvent; +import visualiser.model.VisualiserRaceState; +import visualiser.utils.GPSConverter; import java.io.IOException; -import java.util.List; +import java.net.URL; import java.util.Optional; import java.util.logging.Level; import java.util.logging.Logger; @@ -36,15 +46,16 @@ public class RaceViewController extends Controller { private VisualiserRaceEvent visualiserRace; private VisualiserRaceState raceState; private ControllerClient controllerClient; - private ResizableRaceCanvas raceCanvas; private KeyFactory keyFactory = new KeyFactory(); private boolean infoTableShow = true; // shown or hidden private boolean isHost; + private View3D view3D; + private ObservableList viewSubjects; // note: it says it's not used but it is! do not remove :) private @FXML ArrowController arrowController; private @FXML GridPane canvasBase; - private @FXML SplitPane race; + private @FXML SplitPane racePane; private @FXML StackPane arrowPane; private @FXML Label timer; private @FXML Label FPS; @@ -56,7 +67,6 @@ public class RaceViewController extends Controller { private @FXML TableColumn boatMarkColumn; private @FXML TableColumn boatSpeedColumn; private @FXML LineChart sparklineChart; - private @FXML AnchorPane annotationPane; /** * Displays a specified race. @@ -79,8 +89,8 @@ public class RaceViewController extends Controller { /** * Sets up the listener and actions that occur when a key is pressed. */ - public void initKeypressHandler() { - race.addEventFilter(KeyEvent.KEY_PRESSED, event -> { + private void initKeypressHandler() { + racePane.addEventFilter(KeyEvent.KEY_PRESSED, event -> { String codeString = event.getCode().toString(); // tab key @@ -124,7 +134,7 @@ public class RaceViewController extends Controller { e.printStackTrace(); } } - }); + }); } /** @@ -134,23 +144,82 @@ public class RaceViewController extends Controller { // initialise displays initialiseFps(); initialiseInfoTable(); - initialiseRaceCanvas(); initialiseView3D(); initialiseRaceClock(); raceTimer(); // start the timer - new Annotations(this.annotationPane, this.raceCanvas); new Sparkline(this.raceState, this.sparklineChart); timeZone.setText(this.raceState.getRaceClock().getTimeZone()); arrowController.setWindProperty(this.raceState.windProperty()); } private void initialiseView3D() { - List boats = raceState.getBoats(); - for(VisualiserBoat boat: boats) { - boat.positionProperty().addListener((o, prev, curr) -> { - System.out.println(boat.getCountry() + " is at " + curr.toString()); - }); + viewSubjects = FXCollections.observableArrayList(); + + // Import boat mesh + URL asset = RaceViewController.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 = raceState.getRaceDataSource(); + final GPSConverter gpsConverter = new GPSConverter(raceData, 450, 450); + + view3D.setItems(viewSubjects); + // Position and add each mark to view + for (Mark mark : raceState.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 : raceState.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; + } + } + }); } /** @@ -178,7 +247,7 @@ public class RaceViewController extends Controller { /** * Initialises the information table view to listen to a given race. */ - public void initialiseInfoTable() { + private void initialiseInfoTable() { // list of boats to display data for ObservableList boats = FXCollections .observableArrayList(this.visualiserRace.getVisualiserRaceState().getBoats()); @@ -243,23 +312,6 @@ public class RaceViewController extends Controller { }); } - /** - * Initialises the {@link ResizableRaceCanvas}, provides the race to - * read data from. - */ - private void initialiseRaceCanvas() { - //Create canvas. - raceCanvas = new ResizableRaceCanvas(raceState); - raceCanvas.setMouseTransparent(true); - raceCanvas.widthProperty().bind(canvasBase.widthProperty()); - raceCanvas.heightProperty().bind(canvasBase.heightProperty()); - - // draw and display - raceCanvas.draw(); - raceCanvas.setVisible(true); - canvasBase.getChildren().add(0, raceCanvas); - } - /** * Initialises the race clock to listen to the specified race. */ @@ -275,7 +327,7 @@ public class RaceViewController extends Controller { /** * Transition from the race view to the finish view. */ - public void finishRace() throws IOException { + private void finishRace() throws IOException { RaceFinishController fc = (RaceFinishController)loadScene("raceFinish.fxml"); fc.loadFinish(raceState.getBoats()); @@ -298,7 +350,7 @@ public class RaceViewController extends Controller { } } else { // refresh visual race display - raceCanvas.drawRace(); +// raceCanvas.drawRace(); boatInfoTable.sort(); } @@ -320,16 +372,18 @@ public class RaceViewController 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); arrowPane.setTranslateX(0 + (arrowPane.getScene().getWidth()/4)*tablePercent); arrowPane.setTranslateY(0 - arrowPane.getScene().getHeight()/4); } else { - race.setDividerPositions(1); + racePane.setDividerPositions(1); arrowPane.setScaleX(1); arrowPane.setScaleY(1); arrowPane.setTranslateX(0); diff --git a/racevisionGame/src/main/java/visualiser/Controllers/TitleController.java b/racevisionGame/src/main/java/visualiser/Controllers/TitleController.java index 68fefe98..20d5bb9a 100644 --- a/racevisionGame/src/main/java/visualiser/Controllers/TitleController.java +++ b/racevisionGame/src/main/java/visualiser/Controllers/TitleController.java @@ -3,6 +3,7 @@ package visualiser.Controllers; import javafx.fxml.FXML; import javafx.scene.control.RadioButton; import javafx.stage.Modality; +import visualiser.app.App; import java.io.IOException; @@ -23,7 +24,7 @@ public class TitleController extends Controller { * @throws IOException if main has problems */ public void hostAGame() throws IOException { - loadScene("lobbyHosting.fxml"); + loadScene("hostGame.fxml"); } /** @@ -41,6 +42,7 @@ public class TitleController extends Controller { dayModeRD.getScene().getStylesheets().clear(); dayModeRD.getScene().getStylesheets().add("/css/dayMode.css"); nightModeRD.setSelected(false); + App.dayMode = true; } /** @@ -50,6 +52,7 @@ public class TitleController extends Controller { nightModeRD.getScene().getStylesheets().clear(); nightModeRD.getScene().getStylesheets().add("/css/nightMode.css"); dayModeRD.setSelected(false); + App.dayMode = false; } /** diff --git a/racevisionGame/src/main/java/visualiser/app/App.java b/racevisionGame/src/main/java/visualiser/app/App.java index c8c8d1f3..ccb25d07 100644 --- a/racevisionGame/src/main/java/visualiser/app/App.java +++ b/racevisionGame/src/main/java/visualiser/app/App.java @@ -7,7 +7,6 @@ import javafx.collections.FXCollections; import javafx.collections.ObservableList; import javafx.concurrent.Task; import javafx.concurrent.Worker; -import javafx.event.EventHandler; import javafx.fxml.FXMLLoader; import javafx.geometry.Pos; import javafx.geometry.Rectangle2D; @@ -24,20 +23,19 @@ import javafx.scene.paint.Color; import javafx.stage.Screen; import javafx.stage.Stage; import javafx.stage.StageStyle; -import javafx.stage.WindowEvent; import javafx.util.Duration; import mock.app.Event; public class App extends Application { private static Stage stage; public static Event game; + public static Boolean dayMode = true; private Pane splashLayout; private ProgressBar loadProgress; private Label progressText; private static final int SPLASH_WIDTH = 676; private static final int SPLASH_HEIGHT = 227; - /** * Entry point for running the programme * @param args for starting the programme @@ -73,7 +71,7 @@ public class App extends Application { /** * Method that sets up and displays the splash screen - * @param stage the inital stage + * @param stage the initial stage * @throws Exception if something wrong with title screen. */ public void start(Stage stage) throws Exception { @@ -81,7 +79,7 @@ public class App extends Application { @Override protected ObservableList call() throws InterruptedException { ObservableList addedFilling = - FXCollections.observableArrayList(); + FXCollections.observableArrayList(); ObservableList burgerFilling = FXCollections.observableArrayList( "Buns", "Patties", "Lettuce", "Onions", "Tomato", @@ -124,7 +122,11 @@ public class App extends Application { return App.stage; } - public void loadTitleScreen() throws Exception { + /** + * Loads the title screen for the first time on app start. + * @throws Exception if there is a problem with a resource loaded + */ + private void loadTitleScreen() throws Exception { stage = new Stage(); FXMLLoader loader = new FXMLLoader(getClass().getResource ("/visualiser/scenes/title.fxml")); @@ -135,11 +137,9 @@ public class App extends Application { stage.getIcons().add(new Image(getClass().getClassLoader().getResourceAsStream("images/SailIcon.png"))); stage.setScene(scene); stage.show(); - stage.setOnCloseRequest(new EventHandler() { - @Override public void handle(WindowEvent event) { - Platform.exit(); - System.exit(0); - } + stage.setOnCloseRequest(event -> { + Platform.exit(); + System.exit(0); }); } diff --git a/racevisionGame/src/main/resources/visualiser/scenes/hostGame.fxml b/racevisionGame/src/main/resources/visualiser/scenes/hostGame.fxml index ab964820..cf82c285 100644 --- a/racevisionGame/src/main/resources/visualiser/scenes/hostGame.fxml +++ b/racevisionGame/src/main/resources/visualiser/scenes/hostGame.fxml @@ -10,7 +10,7 @@ - + diff --git a/racevisionGame/src/main/resources/visualiser/scenes/raceView.fxml b/racevisionGame/src/main/resources/visualiser/scenes/raceView.fxml index b6496743..8733a73e 100644 --- a/racevisionGame/src/main/resources/visualiser/scenes/raceView.fxml +++ b/racevisionGame/src/main/resources/visualiser/scenes/raceView.fxml @@ -22,7 +22,11 @@ - + From 9bc36ba544113c0731414108d5bdc92ee2c5343c Mon Sep 17 00:00:00 2001 From: Jessica Syder Date: Mon, 11 Sep 2017 23:09:48 +1200 Subject: [PATCH 19/37] Merge branch 'master' of https://eng-git.canterbury.ac.nz/seng302-2017/team-7 into controllerSplit # Conflicts: # racevisionGame/src/main/java/visualiser/Controllers/HostController.java # racevisionGame/src/main/java/visualiser/Controllers/MainController.java # racevisionGame/src/main/java/visualiser/Controllers/RaceViewController.java # racevisionGame/src/main/java/visualiser/Controllers/StartController.java # racevisionGame/src/main/java/visualiser/Controllers/TitleController.java # racevisionGame/src/main/resources/visualiser/scenes/raceView.fxml # racevisionGame/src/main/resources/visualiser/scenes/titleScreen.fxml --- .../Controllers/LobbyController.java | 2 +- .../Controllers/RaceViewController.java | 94 +++++++------------ .../Controllers/TitleController.java | 23 +---- .../src/main/java/visualiser/app/App.java | 3 +- .../java/visualiser/enums/TutorialState.java | 6 -- .../resources/visualiser/scenes/title.fxml | 4 +- settings/keyBindings.xml | 2 +- 7 files changed, 44 insertions(+), 90 deletions(-) diff --git a/racevisionGame/src/main/java/visualiser/Controllers/LobbyController.java b/racevisionGame/src/main/java/visualiser/Controllers/LobbyController.java index 3f416536..8df0e4ed 100644 --- a/racevisionGame/src/main/java/visualiser/Controllers/LobbyController.java +++ b/racevisionGame/src/main/java/visualiser/Controllers/LobbyController.java @@ -57,7 +57,7 @@ public class LobbyController extends Controller { } else { joinGameBtn.setDisable(true); } - } catch (Exception e){} + } catch (Exception ignored){} } /** diff --git a/racevisionGame/src/main/java/visualiser/Controllers/RaceViewController.java b/racevisionGame/src/main/java/visualiser/Controllers/RaceViewController.java index b0403cac..5ff07193 100644 --- a/racevisionGame/src/main/java/visualiser/Controllers/RaceViewController.java +++ b/racevisionGame/src/main/java/visualiser/Controllers/RaceViewController.java @@ -12,7 +12,6 @@ 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.layout.GridPane; import javafx.scene.layout.StackPane; import javafx.scene.shape.MeshView; @@ -27,6 +26,7 @@ import visualiser.app.App; import visualiser.enums.TutorialState; 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.Sparkline; @@ -34,9 +34,12 @@ import visualiser.model.VisualiserBoat; import visualiser.model.VisualiserRaceEvent; import visualiser.model.VisualiserRaceState; import visualiser.utils.GPSConverter; + import java.io.IOException; import java.net.URL; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Map; import java.util.Optional; import java.util.logging.Level; import java.util.logging.Logger; @@ -73,7 +76,6 @@ public class RaceViewController extends Controller { private @FXML TableColumn boatMarkColumn; private @FXML TableColumn boatSpeedColumn; private @FXML LineChart sparklineChart; - private @FXML Label tutorialText; @@ -91,10 +93,35 @@ public class RaceViewController extends Controller { this.isHost = isHost; keyFactory.load(); + tutorialCheck(); initKeypressHandler(); initialiseRaceVisuals(); } + /** + * Checks if the current game is a tutorial race and sets up initial + * tutorial displays if it is. + */ + private void tutorialCheck(){ + if (App.gameType == 4) { + isTutorial = true; + tutorialText.setVisible(true); + tutorialStates = new ArrayList<>(Arrays.asList(TutorialState.values())); + + currentState = tutorialStates.get(0); + tutorialStates.remove(0); + searchMapForKey("Upwind"); + + tutorialText.setText( + "Welcome to the tutorial! Exit at anytime with ESC. \nWe will first learn how to turn upwind. Press " + + keyToPress + " to turn upwind."); + + } else { + isTutorial = false; + tutorialText.setVisible(false); + } + } + /** * Sets up the listener and actions that occur when a key is pressed. */ @@ -167,7 +194,6 @@ public class RaceViewController extends Controller { initialiseFps(); initialiseInfoTable(); initialiseView3D(); - initialiseArrow(); initialiseRaceClock(); raceTimer(); // start the timer new Sparkline(this.raceState, this.sparklineChart); @@ -374,45 +400,6 @@ public class RaceViewController extends Controller { }); } - - - /** - * Displays a specified race. - * @param visualiserRace Object modelling the race. - * @param controllerClient Socket Client that manipulates the controller. - * @param isHost is user a host - */ - public void startRace(VisualiserRaceEvent visualiserRace, ControllerClient controllerClient, Boolean isHost) { - - this.visualiserRace = visualiserRace; - this.controllerClient = controllerClient; - this.isHost = isHost; - - - //Check if the game is a tutorial - if (parent.getGameType()==4){ - isTutorial = true; - tutorialText.setVisible(true); - tutorialStates = new ArrayList<>(Arrays.asList(TutorialState.values())); - - currentState = tutorialStates.get(0); - tutorialStates.remove(0); - - searchMapForKey("Upwind"); - - tutorialText.setText("Welcome to the tutorial! Exit at anytime with ESC. \nWe will first learn how to turn upwind. Press " + keyToPress + " to turn upwind."); - - } else { - isTutorial = false; - tutorialText.setVisible(false); - } - - initialiseRace(); - - //Display this controller. - racePane.setVisible(true); - } - /** * Transition from the race view to the finish view. */ @@ -422,16 +409,6 @@ public class RaceViewController extends Controller { fc.loadFinish(raceState.getBoats()); } - - /** - * Initialises the arrow controller with data from the race to observe. - * @param race The race to observe. - */ - private void initialiseArrow(VisualiserRaceEvent race) { - arrowController.setWindProperty(race.getVisualiserRaceState().windProperty()); - } - - /** * Timer which monitors the race. */ @@ -581,19 +558,16 @@ public class RaceViewController extends Controller { alert.setContentText("Now you know the controls you are ready to race!"); Optional result = alert.showAndWait(); if (result.get() == ButtonType.OK) { - parent.endEvent(); - racePane.setVisible(false); - App.app.showMainStage(App.getStage()); + App.game.endEvent(); + loadTitleScreen(); } break; default: //State not found. Exit tutorial to title menu - parent.endEvent(); - racePane.setVisible(false); - App.app.showMainStage(App.getStage()); + App.game.endEvent(); + loadTitleScreen(); break; } - } } \ No newline at end of file diff --git a/racevisionGame/src/main/java/visualiser/Controllers/TitleController.java b/racevisionGame/src/main/java/visualiser/Controllers/TitleController.java index 721833f4..aaf17739 100644 --- a/racevisionGame/src/main/java/visualiser/Controllers/TitleController.java +++ b/racevisionGame/src/main/java/visualiser/Controllers/TitleController.java @@ -1,28 +1,15 @@ package visualiser.Controllers; import javafx.fxml.FXML; -import javafx.fxml.FXMLLoader; -import javafx.scene.Parent; -import javafx.scene.Scene; -import javafx.scene.control.Button; import javafx.scene.control.Label; import javafx.scene.control.RadioButton; import javafx.scene.image.Image; import javafx.scene.image.ImageView; -import javafx.scene.layout.AnchorPane; import javafx.scene.layout.Pane; import javafx.stage.Modality; -import javafx.stage.Stage; -import mock.app.Event; -import mock.exceptions.EventConstructionException; -import javafx.stage.WindowEvent; import visualiser.app.App; import java.io.IOException; -import java.net.URL; -import java.util.ResourceBundle; -import java.util.logging.Level; -import java.util.logging.Logger; /** * Controller for the opening title window. @@ -93,12 +80,10 @@ public class TitleController extends Controller { } } - - public void tutorialStartPressed() throws IOException { - titleWrapper.setVisible(false); - parent.setGameType(4); - parent.beginGame(); - + public void tutorialStartPressed() { + App.gameType = 4; + HostGameController hgc = new HostGameController(); + hgc.hostGamePressed(); } } \ No newline at end of file diff --git a/racevisionGame/src/main/java/visualiser/app/App.java b/racevisionGame/src/main/java/visualiser/app/App.java index 316387c9..2e3287ae 100644 --- a/racevisionGame/src/main/java/visualiser/app/App.java +++ b/racevisionGame/src/main/java/visualiser/app/App.java @@ -3,7 +3,6 @@ package visualiser.app; import javafx.animation.FadeTransition; import javafx.application.Application; import javafx.application.Platform; -import javafx.beans.property.ReadOnlyObjectProperty; import javafx.collections.FXCollections; import javafx.collections.ObservableList; import javafx.concurrent.Task; @@ -14,7 +13,6 @@ import javafx.geometry.Rectangle2D; import javafx.scene.Parent; import javafx.scene.Scene; import javafx.scene.control.Label; -import javafx.scene.control.ListView; import javafx.scene.control.ProgressBar; import javafx.scene.effect.DropShadow; import javafx.scene.image.Image; @@ -32,6 +30,7 @@ public class App extends Application { private static Stage stage; public static Event game; public static Boolean dayMode = true; + public static Integer gameType = 0; private Pane splashLayout; private ProgressBar loadProgress; private Label progressText; diff --git a/racevisionGame/src/main/java/visualiser/enums/TutorialState.java b/racevisionGame/src/main/java/visualiser/enums/TutorialState.java index ab811a43..9764f130 100644 --- a/racevisionGame/src/main/java/visualiser/enums/TutorialState.java +++ b/racevisionGame/src/main/java/visualiser/enums/TutorialState.java @@ -1,12 +1,6 @@ package visualiser.enums; -import javafx.scene.input.KeyCode; -import network.Messages.BoatAction; import network.Messages.Enums.BoatActionEnum; -import visualiser.gameController.Keys.ControlKey; -import static visualiser.app.App.keyFactory; - -import java.util.ArrayList; /** * State of which stage the tutorial is currently in diff --git a/racevisionGame/src/main/resources/visualiser/scenes/title.fxml b/racevisionGame/src/main/resources/visualiser/scenes/title.fxml index da0b495b..eae21544 100644 --- a/racevisionGame/src/main/resources/visualiser/scenes/title.fxml +++ b/racevisionGame/src/main/resources/visualiser/scenes/title.fxml @@ -40,7 +40,9 @@ -