From 027324cc4fa8e08f9af59aaf5d98c625ba230456 Mon Sep 17 00:00:00 2001 From: Zhi You Tan Date: Tue, 19 Sep 2017 18:40:01 +1200 Subject: [PATCH 01/36] - Fixed JFXDialog initialised in lobby, raceview, serverlist controller by default. Now, dialog only appears when called. - [WIP] Created keybindingdialog fxml. CSS not yet done. - Removed top most anchorpane on raceview so parent is stackpane like other views. #story[1278] --- .../controllers/LobbyController.java | 12 +- .../controllers/RaceViewController.java | 46 +- .../controllers/ServerListController.java | 15 +- .../visualiser/controllers/ViewManager.java | 71 ++- .../css/dialogs/KeyBindingDialog.css | 0 src/main/resources/views/RaceView.fxml | 452 +++++++++--------- .../views/dialogs/KeyBindingDialog.fxml | 50 ++ 7 files changed, 380 insertions(+), 266 deletions(-) create mode 100644 src/main/resources/css/dialogs/KeyBindingDialog.css create mode 100644 src/main/resources/views/dialogs/KeyBindingDialog.fxml diff --git a/src/main/java/seng302/visualiser/controllers/LobbyController.java b/src/main/java/seng302/visualiser/controllers/LobbyController.java index bbb39f75..36089eca 100644 --- a/src/main/java/seng302/visualiser/controllers/LobbyController.java +++ b/src/main/java/seng302/visualiser/controllers/LobbyController.java @@ -90,16 +90,16 @@ public class LobbyController implements Initializable { ViewManager.getInstance().getPlayerList().setAll(ViewManager.getInstance().getPlayerList().sorted()); }); + customizeButton.setOnMouseReleased(event -> { + customizationDialog = createCustomizeDialog(); + Sounds.playButtonClick(); + customizationDialog.show(); + }); + Platform.runLater(() -> { Integer playerId = ViewManager.getInstance().getGameClient().getServerThread().getClientId(); playersColor = Colors.getColor(playerId - 1); - customizationDialog = createCustomizeDialog(); - - customizeButton.setOnMouseReleased(event -> { - Sounds.playButtonClick(); - customizationDialog.show(); - }); }); leaveLobbyButton.setOnMouseEntered(e -> Sounds.playHoverSound()); diff --git a/src/main/java/seng302/visualiser/controllers/RaceViewController.java b/src/main/java/seng302/visualiser/controllers/RaceViewController.java index 2ac06dfb..3d011a0d 100644 --- a/src/main/java/seng302/visualiser/controllers/RaceViewController.java +++ b/src/main/java/seng302/visualiser/controllers/RaceViewController.java @@ -87,7 +87,7 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel @FXML private Label timerLabel; @FXML - private StackPane contentAnchorPane; + private StackPane contentStackPane; private GridPane contentGridPane; @FXML @@ -134,8 +134,6 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel Sounds.stopMusic(); Sounds.playRaceMusic(); - finishScreenDialog = createFinishDialog(); - // Load a default important annotation state //importantAnnotations = new ImportantAnnotationsState(); @@ -180,9 +178,10 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel // chatHistory.textProperty().addListener((obs, oldValue, newValue) -> { // chatHistory.setScrollTop(Double.MAX_VALUE); // }); - rvAnchorPane.setOnMouseClicked((event) -> - rvAnchorPane.requestFocus() - ); + + contentStackPane.setOnMouseClicked(event -> { + contentStackPane.requestFocus(); + }); //Makes the chat history non transparent when clicked on chatInput.focusedProperty().addListener(new ChangeListener() { @@ -200,26 +199,27 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel public void showFinishDialog(ArrayList finishedBoats) { raceState.setRaceStarted(false); - finishDialogController.setFinishedBoats(finishedBoats); - finishScreenDialog.show(); + createFinishDialog(finishedBoats); } - private JFXDialog createFinishDialog() { + /** + * Create finishScreenDialog and set up finishDialogController. + */ + private void createFinishDialog(ArrayList finishedBoats) { FXMLLoader dialog = new FXMLLoader( getClass().getResource("/views/dialogs/RaceFinishDialog.fxml")); - JFXDialog finishScreenDialog = null; - - try { - finishScreenDialog = new JFXDialog(contentAnchorPane, dialog.load(), - JFXDialog.DialogTransition.CENTER); - } catch (IOException e) { - e.printStackTrace(); - } - - finishDialogController = dialog.getController(); - - return finishScreenDialog; + Platform.runLater(() -> { + try { + finishScreenDialog = new JFXDialog(contentStackPane, dialog.load(), + JFXDialog.DialogTransition.CENTER); + finishDialogController = dialog.getController(); + finishDialogController.setFinishedBoats(finishedBoats); + finishScreenDialog.show(); + } catch (IOException e) { + e.printStackTrace(); + } + }); } public void loadRace ( @@ -245,7 +245,7 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel gameView = new GameView3D(); // gameView.setFrameRateFXText(fpsDisplay); Platform.runLater(() -> { - contentAnchorPane.getChildren().add(0, gameView.getAssets()); + contentStackPane.getChildren().add(0, gameView.getAssets()); ((SubScene) gameView.getAssets()).widthProperty() .bind(ViewManager.getInstance().getStage().widthProperty()); ((SubScene) gameView.getAssets()).heightProperty() @@ -805,7 +805,7 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel public String readChatInput() { String chat = chatInput.getText(); chatInput.clear(); - rvAnchorPane.requestFocus(); + contentStackPane.requestFocus(); return chat; } diff --git a/src/main/java/seng302/visualiser/controllers/ServerListController.java b/src/main/java/seng302/visualiser/controllers/ServerListController.java index 3d457bd4..c6dc4325 100644 --- a/src/main/java/seng302/visualiser/controllers/ServerListController.java +++ b/src/main/java/seng302/visualiser/controllers/ServerListController.java @@ -112,16 +112,23 @@ public class ServerListController implements Initializable, ServerListenerDelega serverListVBox.getChildren().add(noServersFound); // Set up dialog for server creation + serverListHostButton.setOnAction(action -> { + showServerCreationDialog(); + }); + } + + /** + * Shows Server Creation Dialog when "Host" button is clicked. + */ + private void showServerCreationDialog() { Platform.runLater(() -> { FXMLLoader dialogContent = new FXMLLoader(getClass().getResource( "/views/dialogs/ServerCreationDialog.fxml")); try { JFXDialog dialog = new JFXDialog(serverListMainStackPane, dialogContent.load(), DialogTransition.CENTER); - serverListHostButton.setOnAction(action -> { - dialog.show(); - Sounds.playButtonClick(); - }); + dialog.show(); + Sounds.playButtonClick(); } catch (IOException e) { logger.warn("Could not create Server Creation Dialog."); } diff --git a/src/main/java/seng302/visualiser/controllers/ViewManager.java b/src/main/java/seng302/visualiser/controllers/ViewManager.java index 165d0c39..0fab0cdb 100644 --- a/src/main/java/seng302/visualiser/controllers/ViewManager.java +++ b/src/main/java/seng302/visualiser/controllers/ViewManager.java @@ -2,11 +2,17 @@ package seng302.visualiser.controllers; import com.jfoenix.controls.JFXButton; import com.jfoenix.controls.JFXDecorator; +import com.jfoenix.controls.JFXDialog; +import com.jfoenix.controls.JFXDialog.DialogTransition; +import com.jfoenix.controls.events.JFXDialogEvent; import com.jfoenix.svg.SVGGlyph; +import com.sun.org.apache.xpath.internal.operations.Bool; import java.io.IOException; import java.util.HashMap; import javafx.application.Platform; import javafx.collections.ObservableList; +import javafx.event.ActionEvent; +import javafx.event.EventHandler; import javafx.fxml.FXMLLoader; import javafx.scene.Cursor; import javafx.scene.Node; @@ -14,7 +20,10 @@ import javafx.scene.Parent; import javafx.scene.Scene; import javafx.scene.SceneAntialiasing; import javafx.scene.image.Image; +import javafx.scene.input.MouseEvent; import javafx.scene.layout.HBox; +import javafx.scene.layout.Pane; +import javafx.scene.layout.StackPane; import javafx.scene.paint.Color; import javafx.stage.Stage; import org.slf4j.Logger; @@ -32,11 +41,6 @@ public class ViewManager { private HashMap properties; //TODO is this the best way to do this?? private ObservableList playerList; private Logger logger = LoggerFactory.getLogger(ViewManager.class); - - public Stage getStage() { - return stage; - } - private Stage stage; private ViewManager() { @@ -119,6 +123,23 @@ public class ViewManager { //Get the button box HBox btns = (HBox) decorator.getChildren().get(0); + //Create settings button -- [WIP] + JFXButton btnSettings = new JFXButton(); + btnSettings.setText(" Key Bindings"); + btnSettings.setStyle("-fx-text-fill:#fff"); + btnSettings.getStyleClass().add("jfx-decorator-button"); + btnSettings.setCursor(Cursor.HAND); + + btnSettings.setOnMouseClicked(event -> Platform.runLater(() -> { + try { + if (!checkDialogOpened(decorator.getChildren())) { + showKeyBindingDialog(); + } + } catch (IOException e) { + logger.warn("Could not create Key Binding Dialog."); + } + })); + //Create new button JFXButton btnMute = new JFXButton(); btnMute.setText(" Toggle Sound"); @@ -134,9 +155,13 @@ public class ViewManager { SVGGlyph volumeOff = new SVGGlyph(0, "VOLUME_ON", "M13.5,9 C13.5,7.2 12.5,5.7 11,5 L11,7.2 L13.5,9.7 L13.5,9 L13.5,9 Z M16,9 C16,9.9 15.8,10.8 15.5,11.6 L17,13.1 C17.7,11.9 18,10.4 18,8.9 C18,4.6 15,1 11,0.1 L11,2.2 C13.9,3.2 16,5.8 16,9 L16,9 Z M1.3,0 L0,1.3 L4.7,6 L0,6 L0,12 L4,12 L9,17 L9,10.3 L13.3,14.6 C12.6,15.1 11.9,15.5 11,15.8 L11,17.9 C12.4,17.6 13.6,17 14.7,16.1 L16.7,18.1 L18,16.8 L9,7.8 L1.3,0 L1.3,0 Z M9,1 L6.9,3.1 L9,5.2 L9,1 L9,1 Z", Color.WHITE); + SVGGlyph keyBindingGlyph = new SVGGlyph(0, "KEY_BINDING", + "M19.43 12.98c.04-.32.07-.64.07-.98s-.03-.66-.07-.98l2.11-1.65c.19-.15.24-.42.12-.64l-2-3.46c-.12-.22-.39-.3-.61-.22l-2.49 1c-.52-.4-1.08-.73-1.69-.98l-.38-2.65C14.46 2.18 14.25 2 14 2h-4c-.25 0-.46.18-.49.42l-.38 2.65c-.61.25-1.17.59-1.69.98l-2.49-1c-.23-.09-.49 0-.61.22l-2 3.46c-.13.22-.07.49.12.64l2.11 1.65c-.04.32-.07.65-.07.98s.03.66.07.98l-2.11 1.65c-.19.15-.24.42-.12.64l2 3.46c.12.22.39.3.61.22l2.49-1c.52.4 1.08.73 1.69.98l.38 2.65c.03.24.24.42.49.42h4c.25 0 .46-.18.49-.42l.38-2.65c.61-.25 1.17-.59 1.69-.98l2.49 1c.23.09.49 0 .61-.22l2-3.46c.12-.22.07-.49-.12-.64l-2.11-1.65zM12 15.5c-1.93 0-3.5-1.57-3.5-3.5s1.57-3.5 3.5-3.5 3.5 1.57 3.5 3.5-1.57 3.5-3.5 3.5z", + Color.WHITE); volumeOn.setSize(16, 16); volumeOff.setSize(16, 16); spacer.setSize(40, 16); + keyBindingGlyph.setSize(16,16); // Determine which graphic should go on the button if (Sounds.isMusicMuted() && Sounds.isSoundEffectsMuted()) { @@ -145,9 +170,12 @@ public class ViewManager { btnMute.setGraphic(volumeOn); } + btnSettings.setGraphic(keyBindingGlyph); + // Add Buttons btns.getChildren().add(0, spacer); btns.getChildren().add(0, btnMute); + btns.getChildren().add(0, btnSettings); btnMute.setOnAction((action) -> { Sounds.toggleAllSounds(); if (btnMute.getGraphic().equals(volumeOff)) { @@ -159,6 +187,31 @@ public class ViewManager { } + private Boolean checkDialogOpened(ObservableList nodes) { + for (Node node : nodes) { + if (node instanceof JFXDialog) { + return true; + } else if (node instanceof StackPane) { + return checkDialogOpened(((StackPane) node).getChildren()); + } + } + return false; + } + + private void showKeyBindingDialog() throws IOException { + FXMLLoader dialogContent = new FXMLLoader(getClass().getResource( + "/views/dialogs/KeyBindingDialog.fxml")); + for (Node node : decorator.getChildren()) { + if (node instanceof StackPane) { + JFXDialog dialog = new JFXDialog((StackPane) node, + dialogContent.load(), + DialogTransition.CENTER); + dialog.show(); + Sounds.playButtonClick(); + } + } + } + /** * Determines if a PC has compatibility with the bonjour protocol for server detection. */ @@ -221,6 +274,7 @@ public class ViewManager { /** * Change the view to the Lobby Screen + * * @param disableReadyButton Boolean value so that clients can't try start a game. * @return A LobbyController object for the Lobby Screen. */ @@ -243,6 +297,7 @@ public class ViewManager { /** * Sets up the view for the race. Creating a new decorator and destroying the old one. + * * @return A RaceViewController for the race view screen. */ @@ -286,7 +341,7 @@ public class ViewManager { } }); - while (loader.getController() == null){ + while (loader.getController() == null) { try { Thread.sleep(50); } catch (InterruptedException e) { @@ -296,4 +351,8 @@ public class ViewManager { return loader.getController(); } + + public Stage getStage() { + return stage; + } } diff --git a/src/main/resources/css/dialogs/KeyBindingDialog.css b/src/main/resources/css/dialogs/KeyBindingDialog.css new file mode 100644 index 00000000..e69de29b diff --git a/src/main/resources/views/RaceView.fxml b/src/main/resources/views/RaceView.fxml index fba9bb27..879b2f22 100644 --- a/src/main/resources/views/RaceView.fxml +++ b/src/main/resources/views/RaceView.fxml @@ -14,234 +14,232 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + - + diff --git a/src/main/resources/views/dialogs/KeyBindingDialog.fxml b/src/main/resources/views/dialogs/KeyBindingDialog.fxml new file mode 100644 index 00000000..34340b05 --- /dev/null +++ b/src/main/resources/views/dialogs/KeyBindingDialog.fxml @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 9ed52a12258dc5b16227c4b4d8f0180556b35902 Mon Sep 17 00:00:00 2001 From: Peter Galloway Date: Tue, 19 Sep 2017 19:43:03 +1200 Subject: [PATCH 02/36] created catamaran mesh #story[1274] --- src/main/resources/meshes/catamaran_hull.stl | Bin 0 -> 58884 bytes src/main/resources/meshes/catamaran_mast.stl | Bin 0 -> 58884 bytes src/main/resources/meshes/catamaran_sail.stl | Bin 0 -> 58884 bytes 3 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 src/main/resources/meshes/catamaran_hull.stl create mode 100644 src/main/resources/meshes/catamaran_mast.stl create mode 100644 src/main/resources/meshes/catamaran_sail.stl diff --git a/src/main/resources/meshes/catamaran_hull.stl b/src/main/resources/meshes/catamaran_hull.stl new file mode 100644 index 0000000000000000000000000000000000000000..f80d0b8efa893bb7ef58a18d081f137f5b99e245 GIT binary patch literal 58884 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 P43k;KoMd;Eon-t4n0 Date: Tue, 19 Sep 2017 19:49:36 +1200 Subject: [PATCH 03/36] Done some CSS on keybindingdialog #story[1278] --- .../css/dialogs/KeyBindingDialog.css | 28 ++++++++++ .../views/dialogs/KeyBindingDialog.fxml | 52 +++++++++++++------ 2 files changed, 65 insertions(+), 15 deletions(-) diff --git a/src/main/resources/css/dialogs/KeyBindingDialog.css b/src/main/resources/css/dialogs/KeyBindingDialog.css index e69de29b..e5cdc773 100644 --- a/src/main/resources/css/dialogs/KeyBindingDialog.css +++ b/src/main/resources/css/dialogs/KeyBindingDialog.css @@ -0,0 +1,28 @@ +#keyBindingDialogHeader { + -fx-font-size: 30px; + -fx-text-fill: -fx-pp-dark-text-color; +} + +JFXButton { + -fx-background-color: -fx-pp-light-text-color; + -fx-text-fill: -fx-pp-theme-color; + -fx-font-size: 17px; + -fx-effect: -fx-pp-dropshadow-dark; +} + +Label { + -fx-font-size: 25px; + -fx-text-fill: -fx-pp-theme-color; + /*-fx-effect: -fx-pp-dropshadow-dark;*/ +} + +JFXButton:hover { + -fx-font-size: 20px; + -fx-background-color: -fx-pp-light-theme-color; +} + +JFXButton:focused { + -fx-font-size: 20px; + -fx-background-color: -fx-pp-theme-color; + -fx-text-fill: -fx-pp-light-text-color; +} \ No newline at end of file diff --git a/src/main/resources/views/dialogs/KeyBindingDialog.fxml b/src/main/resources/views/dialogs/KeyBindingDialog.fxml index 34340b05..fec643fb 100644 --- a/src/main/resources/views/dialogs/KeyBindingDialog.fxml +++ b/src/main/resources/views/dialogs/KeyBindingDialog.fxml @@ -1,5 +1,6 @@ + @@ -25,21 +26,42 @@ - From 8084a613333f46eb403a665500e828aeb62adf21 Mon Sep 17 00:00:00 2001 From: Zhi You Tan Date: Tue, 19 Sep 2017 23:41:06 +1200 Subject: [PATCH 04/36] Fix keybinding dialog creating on top of another keybinding dialog. #story[1278] --- .../visualiser/controllers/ViewManager.java | 28 +++++++++---------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/src/main/java/seng302/visualiser/controllers/ViewManager.java b/src/main/java/seng302/visualiser/controllers/ViewManager.java index 0fab0cdb..1388eba9 100644 --- a/src/main/java/seng302/visualiser/controllers/ViewManager.java +++ b/src/main/java/seng302/visualiser/controllers/ViewManager.java @@ -4,25 +4,13 @@ import com.jfoenix.controls.JFXButton; import com.jfoenix.controls.JFXDecorator; import com.jfoenix.controls.JFXDialog; import com.jfoenix.controls.JFXDialog.DialogTransition; -import com.jfoenix.controls.events.JFXDialogEvent; import com.jfoenix.svg.SVGGlyph; -import com.sun.org.apache.xpath.internal.operations.Bool; -import java.io.IOException; -import java.util.HashMap; import javafx.application.Platform; import javafx.collections.ObservableList; -import javafx.event.ActionEvent; -import javafx.event.EventHandler; import javafx.fxml.FXMLLoader; -import javafx.scene.Cursor; -import javafx.scene.Node; -import javafx.scene.Parent; -import javafx.scene.Scene; -import javafx.scene.SceneAntialiasing; +import javafx.scene.*; import javafx.scene.image.Image; -import javafx.scene.input.MouseEvent; import javafx.scene.layout.HBox; -import javafx.scene.layout.Pane; import javafx.scene.layout.StackPane; import javafx.scene.paint.Color; import javafx.stage.Stage; @@ -33,6 +21,9 @@ import seng302.utilities.BonjourInstallChecker; import seng302.utilities.Sounds; import seng302.visualiser.GameClient; +import java.io.IOException; +import java.util.HashMap; + public class ViewManager { private static ViewManager instance; @@ -187,15 +178,22 @@ public class ViewManager { } + /** + * Recursively find JFXDialog given a starting node. Will traverse children of StackPane. + * + * @param nodes children nodes to be check. + * @return true if node contains JFXDialog. + */ private Boolean checkDialogOpened(ObservableList nodes) { + boolean foundJFXDialog = false; for (Node node : nodes) { if (node instanceof JFXDialog) { return true; } else if (node instanceof StackPane) { - return checkDialogOpened(((StackPane) node).getChildren()); + foundJFXDialog = checkDialogOpened(((StackPane) node).getChildren()); } } - return false; + return foundJFXDialog; } private void showKeyBindingDialog() throws IOException { From a1933c2869403e50a21dc65b4387ca58c6f14dfd Mon Sep 17 00:00:00 2001 From: Zhi You Tan Date: Wed, 20 Sep 2017 02:42:02 +1200 Subject: [PATCH 05/36] - Created keybindingcontroller which can detect keypress and can save the keybind throughout the app - Changed keybindingglyph to keyboard icon - Fix button hover CSS to change text fill #story[1278] --- .../visualiser/controllers/ViewManager.java | 15 ++- .../dialogs/KeyBindingDialogController.java | 115 ++++++++++++++++++ .../css/dialogs/KeyBindingDialog.css | 1 + .../views/dialogs/KeyBindingDialog.fxml | 19 +-- 4 files changed, 137 insertions(+), 13 deletions(-) create mode 100644 src/main/java/seng302/visualiser/controllers/dialogs/KeyBindingDialogController.java diff --git a/src/main/java/seng302/visualiser/controllers/ViewManager.java b/src/main/java/seng302/visualiser/controllers/ViewManager.java index 1388eba9..ef1df0bd 100644 --- a/src/main/java/seng302/visualiser/controllers/ViewManager.java +++ b/src/main/java/seng302/visualiser/controllers/ViewManager.java @@ -5,10 +5,16 @@ import com.jfoenix.controls.JFXDecorator; import com.jfoenix.controls.JFXDialog; import com.jfoenix.controls.JFXDialog.DialogTransition; import com.jfoenix.svg.SVGGlyph; +import java.io.IOException; +import java.util.HashMap; import javafx.application.Platform; import javafx.collections.ObservableList; import javafx.fxml.FXMLLoader; -import javafx.scene.*; +import javafx.scene.Cursor; +import javafx.scene.Node; +import javafx.scene.Parent; +import javafx.scene.Scene; +import javafx.scene.SceneAntialiasing; import javafx.scene.image.Image; import javafx.scene.layout.HBox; import javafx.scene.layout.StackPane; @@ -21,9 +27,6 @@ import seng302.utilities.BonjourInstallChecker; import seng302.utilities.Sounds; import seng302.visualiser.GameClient; -import java.io.IOException; -import java.util.HashMap; - public class ViewManager { private static ViewManager instance; @@ -147,12 +150,12 @@ public class ViewManager { "M13.5,9 C13.5,7.2 12.5,5.7 11,5 L11,7.2 L13.5,9.7 L13.5,9 L13.5,9 Z M16,9 C16,9.9 15.8,10.8 15.5,11.6 L17,13.1 C17.7,11.9 18,10.4 18,8.9 C18,4.6 15,1 11,0.1 L11,2.2 C13.9,3.2 16,5.8 16,9 L16,9 Z M1.3,0 L0,1.3 L4.7,6 L0,6 L0,12 L4,12 L9,17 L9,10.3 L13.3,14.6 C12.6,15.1 11.9,15.5 11,15.8 L11,17.9 C12.4,17.6 13.6,17 14.7,16.1 L16.7,18.1 L18,16.8 L9,7.8 L1.3,0 L1.3,0 Z M9,1 L6.9,3.1 L9,5.2 L9,1 L9,1 Z", Color.WHITE); SVGGlyph keyBindingGlyph = new SVGGlyph(0, "KEY_BINDING", - "M19.43 12.98c.04-.32.07-.64.07-.98s-.03-.66-.07-.98l2.11-1.65c.19-.15.24-.42.12-.64l-2-3.46c-.12-.22-.39-.3-.61-.22l-2.49 1c-.52-.4-1.08-.73-1.69-.98l-.38-2.65C14.46 2.18 14.25 2 14 2h-4c-.25 0-.46.18-.49.42l-.38 2.65c-.61.25-1.17.59-1.69.98l-2.49-1c-.23-.09-.49 0-.61.22l-2 3.46c-.13.22-.07.49.12.64l2.11 1.65c-.04.32-.07.65-.07.98s.03.66.07.98l-2.11 1.65c-.19.15-.24.42-.12.64l2 3.46c.12.22.39.3.61.22l2.49-1c.52.4 1.08.73 1.69.98l.38 2.65c.03.24.24.42.49.42h4c.25 0 .46-.18.49-.42l.38-2.65c.61-.25 1.17-.59 1.69-.98l2.49 1c.23.09.49 0 .61-.22l2-3.46c.12-.22.07-.49-.12-.64l-2.11-1.65zM12 15.5c-1.93 0-3.5-1.57-3.5-3.5s1.57-3.5 3.5-3.5 3.5 1.57 3.5 3.5-1.57 3.5-3.5 3.5z", + "M20 5H4c-1.1 0-1.99.9-1.99 2L2 17c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2zm-9 3h2v2h-2V8zm0 3h2v2h-2v-2zM8 8h2v2H8V8zm0 3h2v2H8v-2zm-1 2H5v-2h2v2zm0-3H5V8h2v2zm9 7H8v-2h8v2zm0-4h-2v-2h2v2zm0-3h-2V8h2v2zm3 3h-2v-2h2v2zm0-3h-2V8h2v2z", Color.WHITE); volumeOn.setSize(16, 16); volumeOff.setSize(16, 16); spacer.setSize(40, 16); - keyBindingGlyph.setSize(16,16); + keyBindingGlyph.setSize(24, 16); // Determine which graphic should go on the button if (Sounds.isMusicMuted() && Sounds.isSoundEffectsMuted()) { diff --git a/src/main/java/seng302/visualiser/controllers/dialogs/KeyBindingDialogController.java b/src/main/java/seng302/visualiser/controllers/dialogs/KeyBindingDialogController.java new file mode 100644 index 00000000..4c1a8b6d --- /dev/null +++ b/src/main/java/seng302/visualiser/controllers/dialogs/KeyBindingDialogController.java @@ -0,0 +1,115 @@ +package seng302.visualiser.controllers.dialogs; + +import com.jfoenix.controls.JFXButton; +import javafx.fxml.FXML; +import javafx.fxml.Initializable; +import javafx.scene.control.Label; +import javafx.scene.input.KeyCode; +import javafx.scene.input.KeyEvent; + +import java.net.URL; +import java.util.*; + +public class KeyBindingDialogController implements Initializable { + + //--------FXML BEGIN--------// + @FXML + private Label keyBindingDialogHeader; + @FXML + private JFXButton zoomInbtn; + @FXML + private JFXButton zoomOutBtn; + @FXML + private JFXButton vmgBtn; + @FXML + private JFXButton sailInOutBtn; + @FXML + private JFXButton tackGybeBtn; + @FXML + private JFXButton upwindBtn; + @FXML + private JFXButton downwindBtn; + //---------FXML END---------// + + private static Map keys; // static button and saved keybinding pair + private List buttons = new ArrayList<>(); + + @Override + public void initialize(URL location, ResourceBundle resources) { + buttons = new ArrayList<>(); + Collections + .addAll(buttons, zoomInbtn, zoomOutBtn, vmgBtn, sailInOutBtn, tackGybeBtn, upwindBtn, + downwindBtn); + + initializeKeys(); + initializeButtons(); + } + + /** + * Initialise default button-keybinding pair if not exist, else rebind the existing keybinding + * to the new button which is created when javafx reinitialise a new controller. + */ + private void initializeKeys() { + if (keys == null) { + initializeDefaultKeys(); + } else { + Map tempKey = new LinkedHashMap<>(); + int buttonIndex = 0; + for (JFXButton jfxButton : keys.keySet()) { + tempKey.put(buttons.get(buttonIndex), keys.get(jfxButton)); + buttonIndex++; + } + keys = tempKey; + } + } + + /** + * Initialise default keybinding to a button. + */ + private void initializeDefaultKeys() { + keys = new LinkedHashMap<>(); + keys.put(zoomInbtn, KeyCode.Z); + keys.put(zoomOutBtn, KeyCode.X); + keys.put(vmgBtn, KeyCode.SPACE); + keys.put(sailInOutBtn, KeyCode.SHIFT); + keys.put(tackGybeBtn, KeyCode.ENTER); + keys.put(upwindBtn, KeyCode.PAGE_UP); + keys.put(downwindBtn, KeyCode.PAGE_DOWN); + } + + /** + * Change button text to match current keybinding. Adds focusedProperty and keyPressed listener + * to each buttons. + */ + private void initializeButtons() { + for (JFXButton jfxButton : buttons) { + if (keys.get(jfxButton) != null) { + jfxButton.setText(keys.get(jfxButton).getName()); + } else { + jfxButton.setText(""); + } + jfxButton.focusedProperty().addListener((observable, oldValue, newValue) -> { + jfxButton.setOnKeyPressed(event -> { + event.consume(); + doSomething(event, jfxButton); + }); + }); + } + } + + /** + * HAOMING PLEASE CHANGE THIS DOCSTRING AND THE FUNCTION NAME!!! + * + * @param event BLAH + * @param button BLAH + */ + private void doSomething(KeyEvent event, JFXButton button) { + if (keys.containsValue(event.getCode())) { + keys.replace(button, null); + button.setText(""); + } else { + keys.replace(button, event.getCode()); + button.setText(event.getCode().getName()); + } + } +} diff --git a/src/main/resources/css/dialogs/KeyBindingDialog.css b/src/main/resources/css/dialogs/KeyBindingDialog.css index e5cdc773..33a239d3 100644 --- a/src/main/resources/css/dialogs/KeyBindingDialog.css +++ b/src/main/resources/css/dialogs/KeyBindingDialog.css @@ -19,6 +19,7 @@ Label { JFXButton:hover { -fx-font-size: 20px; -fx-background-color: -fx-pp-light-theme-color; + -fx-text-fill: -fx-pp-light-text-color; } JFXButton:focused { diff --git a/src/main/resources/views/dialogs/KeyBindingDialog.fxml b/src/main/resources/views/dialogs/KeyBindingDialog.fxml index fec643fb..55a4c44f 100644 --- a/src/main/resources/views/dialogs/KeyBindingDialog.fxml +++ b/src/main/resources/views/dialogs/KeyBindingDialog.fxml @@ -1,13 +1,18 @@ - - - - - - + + + + + + + + - + From d4d7ddf8e267f1b9dc58fb33526b98ff2b5d4f65 Mon Sep 17 00:00:00 2001 From: Zhi You Tan Date: Wed, 20 Sep 2017 11:02:13 +1200 Subject: [PATCH 06/36] Keybinding now works in the actual race. A map of keybind is shared between GameClient and KeyBindDialogController. #story[1278] --- .../java/seng302/model/GameClientAction.java | 35 +++++++++++ .../java/seng302/visualiser/GameClient.java | 58 +++++++++++------ .../visualiser/controllers/ViewManager.java | 4 ++ .../dialogs/KeyBindingDialogController.java | 62 +++++++++++++------ 4 files changed, 121 insertions(+), 38 deletions(-) create mode 100644 src/main/java/seng302/model/GameClientAction.java diff --git a/src/main/java/seng302/model/GameClientAction.java b/src/main/java/seng302/model/GameClientAction.java new file mode 100644 index 00000000..21848e74 --- /dev/null +++ b/src/main/java/seng302/model/GameClientAction.java @@ -0,0 +1,35 @@ +package seng302.model; + +import java.util.HashMap; +import java.util.Map; + +public enum GameClientAction { + ZOOM_IN(1), + ZOOM_OUT(2), + VMG(3), + SAILS_STATE(4), + TACK_GYBE(5), + UPWIND(6), + DOWNWIND(7); + + private final int type; + private static final Map intToTypeMap = new HashMap<>(); + + static { + for (GameClientAction type : GameClientAction.values()) { + intToTypeMap.put(type.getValue(), type); + } + } + + GameClientAction(int type) { + this.type = type; + } + + public static GameClientAction getType(int value) { + return intToTypeMap.get(value); + } + + public int getValue() { + return this.type; + } +} diff --git a/src/main/java/seng302/visualiser/GameClient.java b/src/main/java/seng302/visualiser/GameClient.java index 7040d7ee..9019b53e 100644 --- a/src/main/java/seng302/visualiser/GameClient.java +++ b/src/main/java/seng302/visualiser/GameClient.java @@ -7,6 +7,7 @@ import java.time.ZoneOffset; import java.util.ArrayList; import java.util.Collections; import java.util.Date; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.TimeZone; @@ -28,6 +29,7 @@ import seng302.gameServer.messages.BoatAction; import seng302.gameServer.messages.BoatStatus; import seng302.gameServer.messages.YachtEventType; import seng302.model.ClientYacht; +import seng302.model.GameClientAction; import seng302.model.RaceState; import seng302.model.stream.packets.StreamPacket; import seng302.model.stream.parser.MarkRoundingData; @@ -65,6 +67,7 @@ public class GameClient { private RaceViewController raceViewController; private ArrayList finishedBoats = new ArrayList<>(); + private Map keyBind = new HashMap<>(); private ObservableList clientLobbyList = FXCollections.observableArrayList(); @@ -75,6 +78,21 @@ public class GameClient { */ public GameClient(Pane holder) { this.holderPane = holder; + initialiseKeyBind(); + } + + /** + * Initialise default keybind. + */ + private void initialiseKeyBind() { + keyBind = new HashMap<>(); + keyBind.put(GameClientAction.ZOOM_IN, KeyCode.Z); + keyBind.put(GameClientAction.ZOOM_OUT, KeyCode.X); + keyBind.put(GameClientAction.VMG, KeyCode.SPACE); + keyBind.put(GameClientAction.SAILS_STATE, KeyCode.SHIFT); + keyBind.put(GameClientAction.TACK_GYBE, KeyCode.ENTER); + keyBind.put(GameClientAction.UPWIND, KeyCode.PAGE_UP); + keyBind.put(GameClientAction.DOWNWIND, KeyCode.PAGE_DOWN); } /** @@ -373,16 +391,16 @@ public class GameClient { } return; } - switch (e.getCode()) { - case SPACE: // align with vmg - socketThread.sendBoatAction(BoatAction.VMG); break; - case PAGE_UP: // upwind - socketThread.sendBoatAction(BoatAction.UPWIND); break; - case PAGE_DOWN: // downwind - socketThread.sendBoatAction(BoatAction.DOWNWIND); break; - case ENTER: // tack/gybe - // if chat box is active take whatever is in there and send it to server - socketThread.sendBoatAction(BoatAction.TACK_GYBE); break; + + if (keyBind.get(GameClientAction.VMG) == e.getCode()) { // align with vmg + socketThread.sendBoatAction(BoatAction.VMG); + } else if (keyBind.get(GameClientAction.UPWIND) == e.getCode()) { // upwind + socketThread.sendBoatAction(BoatAction.UPWIND); + } else if (keyBind.get(GameClientAction.DOWNWIND) == e.getCode()) { // downwind + socketThread.sendBoatAction(BoatAction.DOWNWIND); + } else if (keyBind.get(GameClientAction.TACK_GYBE) == e.getCode()) { // tack/gybe + // if chat box is active take whatever is in there and send it to server + socketThread.sendBoatAction(BoatAction.TACK_GYBE); } } @@ -391,15 +409,13 @@ public class GameClient { if (raceView.isChatInputFocused()) { return; } - switch (e.getCode()) { - //TODO 12/07/17 Determine the sail state and send the appropriate packet (eg. if sails are in, send a sail out packet) - case SHIFT: // sails in/sails out - socketThread.sendBoatAction(BoatAction.SAILS_IN); - allBoatsMap.get(socketThread.getClientId()).toggleSail(); - break; - case PAGE_UP: - case PAGE_DOWN: - socketThread.sendBoatAction(BoatAction.MAINTAIN_HEADING); break; + + if (keyBind.get(GameClientAction.SAILS_STATE) == e.getCode()) { // sails in/sails out + socketThread.sendBoatAction(BoatAction.SAILS_IN); + allBoatsMap.get(socketThread.getClientId()).toggleSail(); + } else if (keyBind.get(GameClientAction.UPWIND) == e.getCode() + || keyBind.get(GameClientAction.DOWNWIND) == e.getCode()) { + socketThread.sendBoatAction(BoatAction.MAINTAIN_HEADING); } } @@ -456,4 +472,8 @@ public class GameClient { public Map getAllBoatsMap() { return allBoatsMap; } + + public Map getKeyBind() { + return keyBind; + } } diff --git a/src/main/java/seng302/visualiser/controllers/ViewManager.java b/src/main/java/seng302/visualiser/controllers/ViewManager.java index ef1df0bd..d47da171 100644 --- a/src/main/java/seng302/visualiser/controllers/ViewManager.java +++ b/src/main/java/seng302/visualiser/controllers/ViewManager.java @@ -26,6 +26,7 @@ import seng302.gameServer.ServerAdvertiser; import seng302.utilities.BonjourInstallChecker; import seng302.utilities.Sounds; import seng302.visualiser.GameClient; +import seng302.visualiser.controllers.dialogs.KeyBindingDialogController; public class ViewManager { @@ -207,6 +208,9 @@ public class ViewManager { JFXDialog dialog = new JFXDialog((StackPane) node, dialogContent.load(), DialogTransition.CENTER); + KeyBindingDialogController keyBindingDialogController = dialogContent + .getController(); + keyBindingDialogController.init(gameClient.getKeyBind()); dialog.show(); Sounds.playButtonClick(); } diff --git a/src/main/java/seng302/visualiser/controllers/dialogs/KeyBindingDialogController.java b/src/main/java/seng302/visualiser/controllers/dialogs/KeyBindingDialogController.java index 4c1a8b6d..114b2f74 100644 --- a/src/main/java/seng302/visualiser/controllers/dialogs/KeyBindingDialogController.java +++ b/src/main/java/seng302/visualiser/controllers/dialogs/KeyBindingDialogController.java @@ -9,6 +9,7 @@ import javafx.scene.input.KeyEvent; import java.net.URL; import java.util.*; +import seng302.model.GameClientAction; public class KeyBindingDialogController implements Initializable { @@ -31,11 +32,25 @@ public class KeyBindingDialogController implements Initializable { private JFXButton downwindBtn; //---------FXML END---------// - private static Map keys; // static button and saved keybinding pair + private Map keys; private List buttons = new ArrayList<>(); + private Map keyBind; + private LinkedHashMap buttonAndGameClientActionMap; @Override public void initialize(URL location, ResourceBundle resources) { + } + + /** + * HAOMING HELP!!! CHANGE FUNCTION NAME PLS :)) + * + * Takes in a map from GameClient and initialise button mapping to the keys. + * + * @param keyBind a map with GameClientAction and KeyCode pair to be used in GameClient. + */ + public void init(Map keyBind) { + this.keyBind = keyBind; + buttons = new ArrayList<>(); Collections .addAll(buttons, zoomInbtn, zoomOutBtn, vmgBtn, sailInOutBtn, tackGybeBtn, upwindBtn, @@ -50,17 +65,24 @@ public class KeyBindingDialogController implements Initializable { * to the new button which is created when javafx reinitialise a new controller. */ private void initializeKeys() { - if (keys == null) { - initializeDefaultKeys(); - } else { - Map tempKey = new LinkedHashMap<>(); - int buttonIndex = 0; - for (JFXButton jfxButton : keys.keySet()) { - tempKey.put(buttons.get(buttonIndex), keys.get(jfxButton)); - buttonIndex++; - } - keys = tempKey; - } + initButtonAndGameClientActionMap(); + initializeDefaultKeys(); + } + + /** + * HAOMING CHANGE FUNCTION NAME HERE TOO :) OR BETTER, REMOVE THIS FUNCTION + * + * Link buttons and the GameClientAction to be used in accessing keys. + */ + private void initButtonAndGameClientActionMap() { + buttonAndGameClientActionMap = new LinkedHashMap<>(); + buttonAndGameClientActionMap.put(zoomInbtn, GameClientAction.ZOOM_IN); + buttonAndGameClientActionMap.put(zoomOutBtn, GameClientAction.ZOOM_OUT); + buttonAndGameClientActionMap.put(vmgBtn, GameClientAction.VMG); + buttonAndGameClientActionMap.put(sailInOutBtn, GameClientAction.SAILS_STATE); + buttonAndGameClientActionMap.put(tackGybeBtn, GameClientAction.TACK_GYBE); + buttonAndGameClientActionMap.put(upwindBtn, GameClientAction.UPWIND); + buttonAndGameClientActionMap.put(downwindBtn, GameClientAction.DOWNWIND); } /** @@ -68,13 +90,13 @@ public class KeyBindingDialogController implements Initializable { */ private void initializeDefaultKeys() { keys = new LinkedHashMap<>(); - keys.put(zoomInbtn, KeyCode.Z); - keys.put(zoomOutBtn, KeyCode.X); - keys.put(vmgBtn, KeyCode.SPACE); - keys.put(sailInOutBtn, KeyCode.SHIFT); - keys.put(tackGybeBtn, KeyCode.ENTER); - keys.put(upwindBtn, KeyCode.PAGE_UP); - keys.put(downwindBtn, KeyCode.PAGE_DOWN); + keys.put(zoomInbtn, keyBind.get(GameClientAction.ZOOM_IN)); + keys.put(zoomOutBtn, keyBind.get(GameClientAction.ZOOM_OUT)); + keys.put(vmgBtn, keyBind.get(GameClientAction.VMG)); + keys.put(sailInOutBtn, keyBind.get(GameClientAction.SAILS_STATE)); + keys.put(tackGybeBtn, keyBind.get(GameClientAction.TACK_GYBE)); + keys.put(upwindBtn, keyBind.get(GameClientAction.UPWIND)); + keys.put(downwindBtn, keyBind.get(GameClientAction.DOWNWIND)); } /** @@ -106,9 +128,11 @@ public class KeyBindingDialogController implements Initializable { private void doSomething(KeyEvent event, JFXButton button) { if (keys.containsValue(event.getCode())) { keys.replace(button, null); + keyBind.replace(buttonAndGameClientActionMap.get(button), null); button.setText(""); } else { keys.replace(button, event.getCode()); + keyBind.replace(buttonAndGameClientActionMap.get(button), event.getCode()); button.setText(event.getCode().getName()); } } From c39582de5cd91218a1d335ee760168362ba52a59 Mon Sep 17 00:00:00 2001 From: Kusal Ekanayake Date: Wed, 20 Sep 2017 15:41:20 +1200 Subject: [PATCH 07/36] Updated PartyParrot logo --- src/main/resources/PP.png | Bin 2857 -> 94034 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/src/main/resources/PP.png b/src/main/resources/PP.png index 1cc88a95c7d4870772a8f8f4c244560f5e0c8c62..6db4eb3dcc0a5dea9c865118308c36c45579df15 100644 GIT binary patch literal 94034 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 literal 2857 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 Date: Wed, 20 Sep 2017 15:58:22 +1200 Subject: [PATCH 08/36] Added catamaran mesh to possible boat meshes. Made catamaran the default boat. #implement #story[1274] --- .../controllers/cells/PlayerCell.java | 2 +- .../fxObjects/assets_3D/BoatMeshType.java | 3 +- .../fxObjects/assets_3D/BoatObject.java | 2 +- .../fxObjects/assets_3D/ModelFactory.java | 10 +- src/main/java/seng302/visualiser/test3d.java | 108 ------------------ .../meshes/boatSTLs/catamaran_hull.stl | Bin 0 -> 55184 bytes .../meshes/boatSTLs/catamaran_mast.stl | Bin 0 -> 2284 bytes .../meshes/boatSTLs/catamaran_sail.stl | Bin 0 -> 1484 bytes .../meshes/{ => boatSTLs}/dinghy_hull.stl | Bin .../meshes/{ => boatSTLs}/dinghy_mast.stl | Bin .../meshes/{ => boatSTLs}/dinghy_sail.stl | Bin src/main/resources/meshes/catamaran_hull.stl | Bin 58884 -> 0 bytes src/main/resources/meshes/catamaran_mast.stl | Bin 58884 -> 0 bytes src/main/resources/meshes/catamaran_sail.stl | Bin 58884 -> 0 bytes 14 files changed, 9 insertions(+), 116 deletions(-) delete mode 100644 src/main/java/seng302/visualiser/test3d.java create mode 100644 src/main/resources/meshes/boatSTLs/catamaran_hull.stl create mode 100644 src/main/resources/meshes/boatSTLs/catamaran_mast.stl create mode 100644 src/main/resources/meshes/boatSTLs/catamaran_sail.stl rename src/main/resources/meshes/{ => boatSTLs}/dinghy_hull.stl (100%) rename src/main/resources/meshes/{ => boatSTLs}/dinghy_mast.stl (100%) rename src/main/resources/meshes/{ => boatSTLs}/dinghy_sail.stl (100%) delete mode 100644 src/main/resources/meshes/catamaran_hull.stl delete mode 100644 src/main/resources/meshes/catamaran_mast.stl delete mode 100644 src/main/resources/meshes/catamaran_sail.stl diff --git a/src/main/java/seng302/visualiser/controllers/cells/PlayerCell.java b/src/main/java/seng302/visualiser/controllers/cells/PlayerCell.java index 6fb35708..7af80e04 100644 --- a/src/main/java/seng302/visualiser/controllers/cells/PlayerCell.java +++ b/src/main/java/seng302/visualiser/controllers/cells/PlayerCell.java @@ -37,7 +37,7 @@ public class PlayerCell { // Add Rotating Boat to Player Cell with players color on it. Group group = new Group(); boatPane.getChildren().add(group); - BoatModel bo = ModelFactory.boatIconView(BoatMeshType.DINGHY, this.boatColor); + BoatModel bo = ModelFactory.boatIconView(BoatMeshType.CATAMARAN, this.boatColor); group.getChildren().add(bo.getAssets()); } diff --git a/src/main/java/seng302/visualiser/fxObjects/assets_3D/BoatMeshType.java b/src/main/java/seng302/visualiser/fxObjects/assets_3D/BoatMeshType.java index 9747b892..96bd3459 100644 --- a/src/main/java/seng302/visualiser/fxObjects/assets_3D/BoatMeshType.java +++ b/src/main/java/seng302/visualiser/fxObjects/assets_3D/BoatMeshType.java @@ -7,7 +7,8 @@ package seng302.visualiser.fxObjects.assets_3D; */ public enum BoatMeshType { - DINGHY ("dinghy_hull.stl", "dinghy_mast.stl", -1.36653, "dinghy_sail.stl", -1.36653); + DINGHY ("dinghy_hull.stl", "dinghy_mast.stl", -1.36653, "dinghy_sail.stl", -1.36653), + CATAMARAN ("catamaran_hull.stl", "catamaran_mast.stl", -1.36845, "catamaran_sail.stl", -1.36845); final String hullFile, mastFile, sailFile; final double mastOffset, sailOffset; diff --git a/src/main/java/seng302/visualiser/fxObjects/assets_3D/BoatObject.java b/src/main/java/seng302/visualiser/fxObjects/assets_3D/BoatObject.java index 57975935..e93152d5 100644 --- a/src/main/java/seng302/visualiser/fxObjects/assets_3D/BoatObject.java +++ b/src/main/java/seng302/visualiser/fxObjects/assets_3D/BoatObject.java @@ -36,7 +36,7 @@ public class BoatObject extends Group { * Creates a BoatGroup with the default triangular boat polygon. */ public BoatObject() { - boatAssets = ModelFactory.boatGameView(BoatMeshType.DINGHY, colour); + boatAssets = ModelFactory.boatGameView(BoatMeshType.CATAMARAN, colour); boatAssets.hideSail(); boatAssets.getAssets().getTransforms().addAll( rotation diff --git a/src/main/java/seng302/visualiser/fxObjects/assets_3D/ModelFactory.java b/src/main/java/seng302/visualiser/fxObjects/assets_3D/ModelFactory.java index f0c50abe..702e8619 100644 --- a/src/main/java/seng302/visualiser/fxObjects/assets_3D/ModelFactory.java +++ b/src/main/java/seng302/visualiser/fxObjects/assets_3D/ModelFactory.java @@ -86,19 +86,19 @@ public class ModelFactory { private static Group getUnmodifiedBoatModel(BoatMeshType boatType, Color primaryColour) { Group boatAssets = new Group(); - MeshView hull = importFile(boatType.hullFile); + MeshView hull = importSTL(boatType.hullFile); hull.setMaterial(new PhongMaterial(primaryColour)); - MeshView mast = importFile(boatType.mastFile); + MeshView mast = importSTL(boatType.mastFile); mast.setMaterial(new PhongMaterial(primaryColour)); - MeshView sail = importFile(boatType.sailFile); + MeshView sail = importSTL(boatType.sailFile); sail.setMaterial(new PhongMaterial(Color.WHITE)); boatAssets.getChildren().addAll(hull, mast, sail); return boatAssets; } - private static MeshView importFile(String fileName) { + private static MeshView importSTL(String fileName) { StlMeshImporter importer = new StlMeshImporter(); - importer.read(ModelFactory.class.getResource("/meshes/" + fileName)); + importer.read(ModelFactory.class.getResource("/meshes/boatSTLs/" + fileName)); MeshView importedFile = new MeshView(importer.getImport()); importedFile.setCache(true); importedFile.setCacheHint(CacheHint.SCALE_AND_ROTATE); diff --git a/src/main/java/seng302/visualiser/test3d.java b/src/main/java/seng302/visualiser/test3d.java deleted file mode 100644 index 6440e563..00000000 --- a/src/main/java/seng302/visualiser/test3d.java +++ /dev/null @@ -1,108 +0,0 @@ -package seng302.visualiser; - -import com.interactivemesh.jfx.importer.stl.StlMeshImporter; -import javafx.animation.AnimationTimer; -import javafx.application.Application; -import javafx.geometry.Point3D; -import javafx.scene.Camera; -import javafx.scene.Group; -import javafx.scene.PerspectiveCamera; -import javafx.scene.Scene; -import javafx.scene.SceneAntialiasing; -import javafx.scene.paint.Color; -import javafx.scene.paint.PhongMaterial; -import javafx.scene.shape.MeshView; -import javafx.scene.transform.Rotate; -import javafx.scene.transform.Scale; -import javafx.scene.transform.Translate; -import javafx.stage.Stage; - -/** - * Created by cir27 on 7/09/17. - */ -public class test3d extends Application { - - Group root = new Group(); - Scene scene; - - @Override - public void start(Stage primaryStage) throws Exception { -// camera = new PerspectiveCamera(); -// gameObjects = new Group(); -// root3D = new Group(camera, gameObjects); - scene = new Scene( - root, 1000, 1000, true, SceneAntialiasing.BALANCED - ); - gameView3DTest(); - primaryStage.setScene(scene); - primaryStage.show(); -// scene.setCamera(camera); -// primaryStage.setScene(scene); -// primaryStage.show(); -// -// StlMeshImporter importer = new StlMeshImporter(); -// importer.read(test3d.class.getResource("/meshes/dinghy_hull.stl").toString()); -// MeshView boat = new MeshView(importer.getImport()); -// boat.setMaterial(new PhongMaterial(Color.GREENYELLOW)); -// -// importer = new StlMeshImporter(); -// importer.read(getClass().getResource("/meshes/dinghy_mast.stl").toString()); -// MeshView mast = new MeshView(importer.getImport()); -// mast.setMaterial(new PhongMaterial(Color.GREENYELLOW)); -// -// importer = new StlMeshImporter(); -// importer.read(getClass().getResource("/meshes/dinghy_sail.stl").toString()); -// MeshView sail = new MeshView(importer.getImport()); -// sail.setMaterial(new PhongMaterial(Color.LIGHTGREY)); -// -// gameObjects.getChildren().addAll(boat, mast, sail); -// -// gameObjects.getTransforms().add(new Scale(25, 25,25)); -// gameObjects.getTransforms().add(new Translate(15, 20,0)); -// gameObjects.getTransforms().addAll( -// new Rotate(90, new Point3D(0,0,1)), -// new Rotate(90, new Point3D(0, 1, 0)) -// ); -// -//// PointLight light = new PointLight(); -//// light.setLightOn(true); -//// light.getTransforms().add(new Translate(15, 20, 0)); -//// -//// PointLight light2 = new PointLight(); -//// light2.setLightOn(true); -//// light2.getTransforms().add(new Translate(30, 40, 0)); -// -//// root3D.getChildren().addAll(light); -// -// scene.setOnKeyPressed(event -> { -// switch (event.getCode()) { -// case UP: -// gameObjects.getTransforms().add(new Rotate(5, new Point3D(0,0,1))); -// break; -// case DOWN: -// gameObjects.getTransforms().add(new Rotate(-5, new Point3D(0,0,1))); -// break; -// case LEFT: -// gameObjects.getTransforms().add(new Rotate(-5, new Point3D(0,1,0))); -// break; -// case RIGHT: -// gameObjects.getTransforms().add(new Rotate(5, new Point3D(0,1,0))); -// break; -// } -// }); -// -// AnimationTimer animationTimer = new AnimationTimer() { -// @Override -// public void handle(long now) { -// sail.getTransforms().add(new Rotate(0.5, 0, -1.36653, 0, new Point3D(0, 0, 1))); -// } -// }; -// -//// animationTimer.start(); - } - - private void gameView3DTest() { - GameView3D gameView3D = new GameView3D(); - root.getChildren().add(gameView3D.getAssets()); - } -} diff --git a/src/main/resources/meshes/boatSTLs/catamaran_hull.stl b/src/main/resources/meshes/boatSTLs/catamaran_hull.stl new file mode 100644 index 0000000000000000000000000000000000000000..e93a9787f7e11aa3d47b5cd6055ca0d5bbc4e5fb GIT binary patch literal 55184 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/meshes/boatSTLs/catamaran_mast.stl b/src/main/resources/meshes/boatSTLs/catamaran_mast.stl new file mode 100644 index 0000000000000000000000000000000000000000..79bc742b54e04e8e979c0397b2d67e4a67094299 GIT binary patch literal 2284 zcmb7_Pis?A5XG+&mwtfaCYyvR^$*pMLNGz01vd)axNxO3uGC7Z)P>-K6#N1rl!Cju z3AiarP|VYfOFx0)!m0(uzX;+c&UtfB-g$j13xxwSzd3hi?tPiRb$z*aqq|hS+*`g{ zJ$NkJbR=$SDjwDd8vBrVEC`U8O#2?&=VmlHVp;j8&JSvU!Z>3=>1kIvG-CAq?`I*{-=<(f%KatP~HR_Uf zkB|Me(dUKL%tN!N;c@%^x7iE#HloKTBdnK<&BOe25#=ENXZhYE89q7ofA9ciu!o zBh;u%I`&~6cCSX*xn@zbkCk&n@vwPi1Zputjk=`WGs$Eo zi0B5n^D?0k5PTE7?N0Da=tCp=YWdE~ghq5e+F$Mf4~=NIdfFnP5j~-L7YX%Hx=3u> zP2aoE-v=-eQ??WThO8dRSuYr9TvRA9~p+=U{{`+BHpN!B5HBLpk zw2zcosLL#RVE=xq=Ai!ACzfOcBb*PixPK?|`6j7GxDRCUj+F_Ga33V{Z^@oPy}?uQ zh9ir&1e$N9?4c2E5Lr4At3Lnw1U)nY%_(SqAkI!^r4j8(PwUm`p%FcydKZb^9-L2+ F_y>8sayI|~ literal 0 HcmV?d00001 diff --git a/src/main/resources/meshes/boatSTLs/catamaran_sail.stl b/src/main/resources/meshes/boatSTLs/catamaran_sail.stl new file mode 100644 index 0000000000000000000000000000000000000000..a2723d980b7b68c4ed654f7d5c4f57f253606439 GIT binary patch literal 1484 zcmb7DJuE{}7`>#cL5PK+lMqqOBhg5>t^b5d2ZIQUv=%?52m^6rZ6YEziJuT*DVlB~ zZxAG6Gc*RNc94kGhH$_4`qe2hcuT+Zob#RU?{+Lqg(I_}pmQ`5o^ZB~hbDueNUh;& z^f;?#=0=?EYVohHBF9!Hg@H?dbIDE2Os7kI99OnSeeO&DIsH$uE&2RhwiJkPoB}mv zB84*BKX&63A&Xi5F)GMZU$SUN0*sc4zlNF|+AcnTUimi`AIPX0Dg)S^L2Gu$pS;*wJ&Pr_1~9 z-N~FFVrY-G-yk8_ zEi1mSop*u=$EZdRt2&8WV+Cz6ke#l*bK=^cl8E$a7VjK0+1&cmA^Cb%An{G$W&Eu` z1U)d5?eVj7x>v3cW9%b;x`bfo9Dl!B{XUG;yQ2>CVkKB1Ri$J@#f^3Ch_D)`YkPbF Di()J} literal 0 HcmV?d00001 diff --git a/src/main/resources/meshes/dinghy_hull.stl b/src/main/resources/meshes/boatSTLs/dinghy_hull.stl similarity index 100% rename from src/main/resources/meshes/dinghy_hull.stl rename to src/main/resources/meshes/boatSTLs/dinghy_hull.stl diff --git a/src/main/resources/meshes/dinghy_mast.stl b/src/main/resources/meshes/boatSTLs/dinghy_mast.stl similarity index 100% rename from src/main/resources/meshes/dinghy_mast.stl rename to src/main/resources/meshes/boatSTLs/dinghy_mast.stl diff --git a/src/main/resources/meshes/dinghy_sail.stl b/src/main/resources/meshes/boatSTLs/dinghy_sail.stl similarity index 100% rename from src/main/resources/meshes/dinghy_sail.stl rename to src/main/resources/meshes/boatSTLs/dinghy_sail.stl diff --git a/src/main/resources/meshes/catamaran_hull.stl b/src/main/resources/meshes/catamaran_hull.stl deleted file mode 100644 index f80d0b8efa893bb7ef58a18d081f137f5b99e245..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 58884 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 P43k;KoMd;Eon-t4n0 Date: Wed, 20 Sep 2017 16:36:27 +1200 Subject: [PATCH 09/36] Started working on the boat selection screen. Customised the boat customisation UI to contain it. Need to have another boat to test whether we can switch boats and also if the messages get sent correctly. #story[1274] --- .../java/seng302/gameServer/GameState.java | 3 + .../gameServer/ServerToClientThread.java | 2 +- src/main/java/seng302/model/ServerYacht.java | 3 + .../controllers/LobbyController.java | 2 + .../dialogs/BoatCustomizeController.java | 42 ++++++++++++ .../fxObjects/assets_3D/ModelFactory.java | 29 ++++++++ .../views/dialogs/BoatCustomizeDialog.fxml | 68 +++++++++++-------- 7 files changed, 119 insertions(+), 30 deletions(-) diff --git a/src/main/java/seng302/gameServer/GameState.java b/src/main/java/seng302/gameServer/GameState.java index 0b495a8e..41c619b7 100644 --- a/src/main/java/seng302/gameServer/GameState.java +++ b/src/main/java/seng302/gameServer/GameState.java @@ -702,6 +702,9 @@ public class GameState implements Runnable { int blue = customizeData[2] & 0xFF; Color yachtColor = Color.rgb(red, green, blue); playerYacht.setBoatColor(yachtColor); + } else if (requestType.equals(CustomizeRequestType.SHAPE)) { + String type = new String(customizeData); + playerYacht.setBoatType(type); } } diff --git a/src/main/java/seng302/gameServer/ServerToClientThread.java b/src/main/java/seng302/gameServer/ServerToClientThread.java index 1138f53d..728e6adb 100644 --- a/src/main/java/seng302/gameServer/ServerToClientThread.java +++ b/src/main/java/seng302/gameServer/ServerToClientThread.java @@ -125,7 +125,7 @@ public class ServerToClientThread implements Runnable { lName = all.get(ThreadLocalRandom.current().nextInt(0, all.size())); ServerYacht yacht = new ServerYacht( - "Yacht", sourceId, sourceId.toString(), fName, fName + " " + lName, "NZ" + "DINGHY", sourceId, sourceId.toString(), fName, fName + " " + lName, "NZ" ); player = new Player(socket, yacht); diff --git a/src/main/java/seng302/model/ServerYacht.java b/src/main/java/seng302/model/ServerYacht.java index f2d54538..da5aa37b 100644 --- a/src/main/java/seng302/model/ServerYacht.java +++ b/src/main/java/seng302/model/ServerYacht.java @@ -421,4 +421,7 @@ public class ServerYacht { return boatColor; } + public void setBoatType(String boatType) { + this.boatType = boatType; + } } diff --git a/src/main/java/seng302/visualiser/controllers/LobbyController.java b/src/main/java/seng302/visualiser/controllers/LobbyController.java index bbb39f75..a292fc8a 100644 --- a/src/main/java/seng302/visualiser/controllers/LobbyController.java +++ b/src/main/java/seng302/visualiser/controllers/LobbyController.java @@ -33,6 +33,7 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.ResourceBundle; +import seng302.visualiser.fxObjects.assets_3D.BoatMeshType; public class LobbyController implements Initializable { @@ -129,6 +130,7 @@ public class LobbyController implements Initializable { controller.setPlayerName(this.playerBoats .get(ViewManager.getInstance().getGameClient().getServerThread().getClientId()) .getBoatName()); + controller.setCurrentBoat(BoatMeshType.DINGHY); return customizationDialog; } diff --git a/src/main/java/seng302/visualiser/controllers/dialogs/BoatCustomizeController.java b/src/main/java/seng302/visualiser/controllers/dialogs/BoatCustomizeController.java index 339f08b8..5690dc35 100644 --- a/src/main/java/seng302/visualiser/controllers/dialogs/BoatCustomizeController.java +++ b/src/main/java/seng302/visualiser/controllers/dialogs/BoatCustomizeController.java @@ -9,12 +9,21 @@ import java.util.ResourceBundle; import javafx.event.ActionEvent; import javafx.fxml.FXML; import javafx.fxml.Initializable; +import javafx.geometry.Insets; +import javafx.scene.Group; +import javafx.scene.layout.Background; +import javafx.scene.layout.BackgroundFill; +import javafx.scene.layout.CornerRadii; +import javafx.scene.layout.Pane; import javafx.scene.paint.Color; import seng302.gameServer.messages.CustomizeRequestType; import seng302.utilities.Sounds; import seng302.visualiser.ClientToServerThread; import seng302.visualiser.controllers.LobbyController; import seng302.visualiser.controllers.ViewManager; +import seng302.visualiser.fxObjects.assets_3D.BoatMeshType; +import seng302.visualiser.fxObjects.assets_3D.BoatModel; +import seng302.visualiser.fxObjects.assets_3D.ModelFactory; import seng302.visualiser.validators.FieldLengthValidator; import seng302.visualiser.validators.ValidationTools; @@ -28,13 +37,17 @@ public class BoatCustomizeController implements Initializable{ @FXML private JFXTextField boatName; @FXML + private Pane boatPane; + @FXML void colorChanged(ActionEvent event) { Color color = colorPicker.getValue(); + RefreshBoat(); } //---------FXML END---------// private ClientToServerThread socketThread; private LobbyController lobbyController; + private BoatMeshType currentBoat; @Override public void initialize(URL location, ResourceBundle resources) { @@ -55,6 +68,7 @@ public class BoatCustomizeController implements Initializable{ }); submitBtn.setOnMouseEntered(e -> Sounds.playHoverSound()); + } /** @@ -78,7 +92,10 @@ public class BoatCustomizeController implements Initializable{ colorArray[2] = (byte) blue; socketThread.sendCustomizationRequest(CustomizeRequestType.COLOR, colorArray); + socketThread.sendCustomizationRequest(CustomizeRequestType.SHAPE, currentBoat.toString().getBytes()); lobbyController.closeCustomizationDialog(); + + } } @@ -93,4 +110,29 @@ public class BoatCustomizeController implements Initializable{ public void setParentController(LobbyController lobbyController){ this.lobbyController = lobbyController; } + + public void setCurrentBoat(BoatMeshType boatType) { + Group group = new Group(); + this.currentBoat = boatType; + System.out.println(boatType.toString()); + boatPane.setBackground(new Background(new BackgroundFill(Color.SKYBLUE, CornerRadii.EMPTY, Insets.EMPTY))); + boatPane.getChildren().add(group); + BoatModel bo = ModelFactory.boatCustomiseView(boatType, colorPicker.getValue()); + group.getChildren().add(bo.getAssets()); + } + + public void nextBoat(ActionEvent actionEvent) { + boatPane.getChildren().clear(); + } + + public void prevBoat(ActionEvent actionEvent) { + } + + private void RefreshBoat() { + boatPane.getChildren().clear(); + Group group = new Group(); + boatPane.getChildren().add(group); + BoatModel bo = ModelFactory.boatCustomiseView(currentBoat, colorPicker.getValue()); + group.getChildren().add(bo.getAssets()); + } } diff --git a/src/main/java/seng302/visualiser/fxObjects/assets_3D/ModelFactory.java b/src/main/java/seng302/visualiser/fxObjects/assets_3D/ModelFactory.java index b49c36c1..54d5768a 100644 --- a/src/main/java/seng302/visualiser/fxObjects/assets_3D/ModelFactory.java +++ b/src/main/java/seng302/visualiser/fxObjects/assets_3D/ModelFactory.java @@ -51,6 +51,35 @@ public class ModelFactory { return bo; } + public static BoatModel boatCustomiseView(BoatMeshType boatType, Color primaryColour) { + Group boatAssets = getUnmodifiedBoatModel(boatType, primaryColour); + final Rotate animationRotate = new Rotate(0, new Point3D(0,0,1)); + boatAssets.getTransforms().addAll( + new Scale(8.0, 8.0, 8.0), + new Rotate(-70, new Point3D(1,0,0)), + new Translate(16,50, 0), + animationRotate + ); + + boatAssets.getTransforms().add(animationRotate); + BoatModel bo = new BoatModel(boatAssets, null, boatType); + bo.rotateSail(45); + + bo.setAnimation(new AnimationTimer() { + double boatAngle = 0; + Rotate rotate = animationRotate; + @Override + public void handle(long now) { + boatAngle += 0.5; + rotate.setAngle(boatAngle); + } + }); + boatAssets.getChildren().addAll( + new AmbientLight() + ); + return bo; + } + public static BoatModel boatRotatingView(BoatMeshType boatType, Color primaryColour) { Group boatAssets = getUnmodifiedBoatModel(boatType, primaryColour); boatAssets.getTransforms().addAll( diff --git a/src/main/resources/views/dialogs/BoatCustomizeDialog.fxml b/src/main/resources/views/dialogs/BoatCustomizeDialog.fxml index 8e8653cf..1d355a33 100644 --- a/src/main/resources/views/dialogs/BoatCustomizeDialog.fxml +++ b/src/main/resources/views/dialogs/BoatCustomizeDialog.fxml @@ -1,5 +1,10 @@ + + + + + @@ -10,54 +15,44 @@ - + + - - - - + + + + + - - - + + From c5d56065b690512e57868a58236659ed90813fb2 Mon Sep 17 00:00:00 2001 From: Calum Date: Wed, 20 Sep 2017 16:42:26 +1200 Subject: [PATCH 10/36] Fixed cat ate a meringue sail rotation. #fix #story[1274] --- .../fxObjects/assets_3D/BoatMeshType.java | 4 ++-- .../fxObjects/assets_3D/BoatModel.java | 4 ++-- .../fxObjects/assets_3D/BoatObject.java | 4 +--- .../meshes/boatSTLs/catamaran_hull.stl | Bin 55184 -> 55184 bytes .../meshes/boatSTLs/catamaran_mast.stl | Bin 2284 -> 2284 bytes .../meshes/boatSTLs/catamaran_sail.stl | Bin 1484 -> 1484 bytes .../resources/meshes/boatSTLs/dinghy_hull.stl | Bin 14284 -> 14284 bytes .../resources/meshes/boatSTLs/dinghy_mast.stl | Bin 2284 -> 2284 bytes .../resources/meshes/boatSTLs/dinghy_sail.stl | Bin 1484 -> 1484 bytes 9 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/main/java/seng302/visualiser/fxObjects/assets_3D/BoatMeshType.java b/src/main/java/seng302/visualiser/fxObjects/assets_3D/BoatMeshType.java index 75e21604..dfe3d5e5 100644 --- a/src/main/java/seng302/visualiser/fxObjects/assets_3D/BoatMeshType.java +++ b/src/main/java/seng302/visualiser/fxObjects/assets_3D/BoatMeshType.java @@ -7,8 +7,8 @@ package seng302.visualiser.fxObjects.assets_3D; */ public enum BoatMeshType { - DINGHY ("dinghy_hull.stl", "dinghy_mast.stl", -1.36653, "dinghy_sail.stl", -1.36653), - CATAMARAN ("catamaran_hull.stl", "catamaran_mast.stl", -1.36845, "catamaran_sail.stl", -1.36845); + DINGHY ("dinghy_hull.stl", "dinghy_mast.stl", 1.36653, "dinghy_sail.stl", 1.36653), + CATAMARAN ("catamaran_hull.stl", "catamaran_mast.stl", 0.997, "catamaran_sail.stl", 0.997); final String hullFile, mastFile, sailFile; final double mastOffset, sailOffset; diff --git a/src/main/java/seng302/visualiser/fxObjects/assets_3D/BoatModel.java b/src/main/java/seng302/visualiser/fxObjects/assets_3D/BoatModel.java index b1373c67..78d2c837 100644 --- a/src/main/java/seng302/visualiser/fxObjects/assets_3D/BoatModel.java +++ b/src/main/java/seng302/visualiser/fxObjects/assets_3D/BoatModel.java @@ -37,10 +37,10 @@ public class BoatModel extends Model { MeshView mast = getMeshViewChild(MAST_INDEX); MeshView sail = getMeshViewChild(SAIL_INDEX); mast.getTransforms().setAll( - new Rotate(degrees, -meshType.mastOffset, 0,0, new Point3D(0, 0, 1)) + new Rotate(degrees, 0, -meshType.mastOffset, 0, new Point3D(0, 0, 1)) ); sail.getTransforms().setAll( - new Rotate(degrees, -meshType.sailOffset, 0,0, new Point3D(0, 0, 1)) + new Rotate(degrees, 0, -meshType.sailOffset,0, new Point3D(0, 0, 1)) ); } diff --git a/src/main/java/seng302/visualiser/fxObjects/assets_3D/BoatObject.java b/src/main/java/seng302/visualiser/fxObjects/assets_3D/BoatObject.java index e93152d5..30820660 100644 --- a/src/main/java/seng302/visualiser/fxObjects/assets_3D/BoatObject.java +++ b/src/main/java/seng302/visualiser/fxObjects/assets_3D/BoatObject.java @@ -28,7 +28,7 @@ public class BoatObject extends Group { private Group wake; private Color colour = Color.BLACK; private Boolean isSelected = false; - private Rotate rotation = new Rotate(0,0,1); + private Rotate rotation = new Rotate(0, new Point3D(0,0,1)); private List selectedBoatListenerListeners = new ArrayList<>(); @@ -66,8 +66,6 @@ public class BoatObject extends Group { * @param windDir . */ public void moveTo(double x, double y, double rotation, double velocity, Boolean sailIn, double windDir) { - Double dx = Math.abs(boatAssets.getAssets().getLayoutX() - x); - Double dy = Math.abs(boatAssets.getAssets().getLayoutY() - y); Platform.runLater(() -> { rotateTo(rotation, sailIn, windDir); this.layoutXProperty().setValue(x); diff --git a/src/main/resources/meshes/boatSTLs/catamaran_hull.stl b/src/main/resources/meshes/boatSTLs/catamaran_hull.stl index e93a9787f7e11aa3d47b5cd6055ca0d5bbc4e5fb..a7f70e54257b99704f432a60648be44fc6bba305 100644 GIT binary patch literal 55184 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 literal 55184 zcmb5XWqcIL_r_beySoOrKwyFNq#EKRcpwl05!^x&f)l}=Ac2Gs0wlrRVVUk~d>3~M zE{iVCE{onXGd=Tr`hV}6%L|wfPuJ=0(sQc2&)0K&_7>8$Bkxdb9fM|JR>Rxf$!8D_SHKKIA(8>3VfVc!u^i>#FO<^)gqTGqhG2 z3Ec8~N#aUv>Zm!qrAuWu#%A1)5}os>xE|ZTK}F@`{*~I?fk#c2qtFs#EyCUT^Qu*p zhgF^UT2D#)`RkV`5xJGuFWN@?{wrP-rQe6H%UW$7BMP?^oUyS7JbB5!rIoTlH4VzG zJ?>f^{z(+0qtFs#r_TC_7IW4r^`=zea@cC^+b^z_BD<67r)gh*#an;RD7iwb$z!zQ z)^n6`_Y~o!lN9eNH90CT->%epH~r0e6k1|z;nz5E)c>q&rB3@5yhER|S=!9%Yg$_F zgFVjF3a|uj{mn-Gh!f*K9(BFdW1oTw)-GCNY{jQI(LQ>q^r_-L1&_kgA39}f)O2!T z%lTL!o#XA9`O<$qb}OiC$y%#bc4l(M|7lIeHh+!d8(toDT|xIT;mU8C$Jnthmg~LL z)>UH}w)UTv=BhdC?ax@xA94I~+q14S0`@7W{A$yhuEch?Xo<1o>0bQis@$e2{x!I1 zv`Nds669QTjt^C3`n^WZNxzHN@YW`7NRe|`+rzt+C+}_kEY&Pr%b@hrJhX;9M$Sn` zp(Vx!zKs)3^Ol+2FYi~d4X{RcoL#GBJc$*XsTLSJ@K2oBvoFo;ac_@;%7^ip+H1Wh zq9w+B-^B6FJJQTeukBZ`e(-LwA2W96-#A`-*)sE+8+#N~whWTAjrx_KCC2ubj^?KI zGo&tE*Q*)(C9RU)YFN|R4}7%Ajxl&6GMal236^GiWvQsh$9=W_axS?hjX|`;SiLTB zyvWB@%JbFRluqNgRwn(Y*h+PRqbSYPPWz>g8^)aCi5Uk`eSio@m+uA=ZaYxE6XYLJF=#qwkoro{Jn)`PQ0>jG@o1Gj`UacG!>PbkNveZ+41r< zItnc@HYrz}NEgSH!?!XNoMi_6waQVu6RxFdpAN-YYnrhlh2q5PzGs!+b|)#Q;0%YB z82cU?C!#7RD>vtFQ}AxF7VvzGHIIlB_j9K!d75S@sGwc6#F+YiEcdVXO}YO$LY=y( ztG2G}YHcso&xqvS+USj{wx51KDHx{p7MJ zON`wNGVyo$>ZoRyy1f0tfiw>8YvpK;I=M5DehaNE{eD?FSnJ#LfL6*nU%guH%O}07 ztR^QD}*=rK5bszG0P3Z?{+B=R;T0JjmKv=E1NxX%0n?YQEa0 z6m8&2S0c;#sIG7f8b{O*ns+PgD`6VGbfba_t{G^Fu~u*5L{`Da(&DDO6d>{hTwv8M5!7<=$v z9G_nDu~hM&Z3-%Q?P!TH=SNX|(&K}!e(N@<*v`1hR9)hu4cEOh#=7N*=C#VDxVHbe zUPT4h612qF5o!;EirZ? zI$G4YH$$3VKTAd52W#|hm6h5ceTAd-ym+)oC>bo>ov>a-1^rUA#F*mV2|nTwU+v{%_m}P`L{UHt#cvM_{AF)RMzfYtv%FNAGAdNZZj|8cdD^kt5RjY zy>62BL!YDG)>=TnZFARy-Sf2e`b!Z(VXo<1f`NoQ^ zf4P{7?3$W7uW^A|n7*YE|DN~dAi&a!!4ocR1_1OR| zF&6#Goez7J=6d8rZH_(_&N$aA$eOdgrkVdnci!8y#B~j|AS#Pgt~EHB=wfLPw8U8F z=dnDs{aGd9M}~sl3wky6w|P^&+2RDohSZ7ULAQ@7ZO0`ksMP7vLHnq$$Y_bNKL^JO z_q$AWJvCGL**Ar3t=7uWe0Bb}WGzcy6MMNVb*zbuX(6$K4auY4bc$3^!8Slkj1`|7 z%P-7%r(8&1rr?zruF#`1tyi{lGnQ~6mQNk|O!>5LhEfL5M%$&h~>jxGquCd z2n7}N`p^<%H4^;z;oMbCS6LDG}&MC)IB7$#8{uFUZPFWaSD&9&e1nS?-iqa#?Jh77i$~!S6-E@%~3(05iK!x zc)BzdZWcZ;=P^!mo+pUAI&3Q((V>8+qL=kp+~L*aYc!T;keGnV7g1o8Ar zfSU1eih{EN_P!1?=4-xsX~x#R`2 zyVNlOvlP5rtOYzDV}n{p@q!~at0lIVQBXml@wI)p3o9wEuCZd#l~i3b@wGI&iXiW4p9TNDg8!k!PfaI?sGJ6dM#Cn zNKaEyDSxiBmej4K^(eH&*vo7WKE2xx>2_i*j@})5ec=b%YoYoGX6(j!cdj1Hkgi>= z%~2Uuqn*}RpAFCw&58YE#GG4|OxK$wtLRxgiAdLk?zc^um7?YOn6CTn3%89Hy`C}C zk&0<5Dn%Bq&@%M67A@I&N%@3H2~luCh`= zkLA$#bh4{iV>OK17)vT1FMJlbnzA#NDyX2hgq9c!_&ZMYsOW0i;+dh~mEaZP`524L z6EBJ{Xl`;Zyi!30?V=^d7JZE4)f1YVM)M2>J#X~LF>a&Y{wt3E;pA%aFTGMhWl~Xh znyGDfj+Sg~zPRi_F>%@x6-O$LuI*nEv|kCIw5hi7vEy^AEmWcel|bca(Kzj=eiT|_ zY-o{qzFXy{mK&EUIO}877=Fc1+tlWl9)ENy9nTAt^fGl$Sg4?aeF-fw_WmdBk;S{3 z_R*c=-C`}^`N-=l5YLxJc$ijhU#g&jcF_`JeaA%e1K#JQ@)t5yjP5WV#9cg!AoGmo z<|&({b*XDqRB)dOEm4UuFYemXthkh|&e7{bKe1GHN7_lZ?}gvl;m_~5>{E7>EYDGS zniimq-;kn}B%c8-+1gzE8PDHk)=@mmrfQq@ddG2&HO*MXkX0@UmDrnAM?nSK1})K! zS75Zrq5ZBj^GsLK|HPfCxC$xSGJQrRZ|P=?C|V#*Dc)(3ipq^O%e1Nb?2MLZX87VM zs{5BPohd?38enYW7>pW~rcH9}Q>RS!5xY7TFqQpWm80^s`bwIe4_NnP&=Nf{$saGC z=l3#s?^>$hY=E-_)*EAC72?IsliXA=e4&C0)(=`@?Ag)?9^0~kTJcwwVOOo@rQzDj zwb!%>H16ugM{1LYoz=od1*nX@=r@diI*?Nh2soyqGN$zqEtj%g8%{^z{v2cNONEFj zEd$MR`ELd<9H0C=@Li@|Dc8p>(|V2}IYPyQF%8UZ&it#QQta;}?R`U&SV>2rKTqe# zGnlt*Q^+Je&sK4F2zQPA3kPd4OU?8=!Ezrj-wfd$?mv_Q{=TB3vhZ$S&3(~r>rrTl zvEPb>@tEhUq(85IH0;*m=o%i_Q_D3YpM1c2AGhj-^DiqWN-~=g;(XSl9{p}{ zABCR$bREe%xtvl`BMzy!LyJ8FdkkZ}+YY0Bl9fu-$I~h*zsdczdWRNiqp7aY62+Xe zhKMrFjwvUnUsN&L!YJ%r$U?2YUYfE0ij5K{1Jae;7k8_uTzWju(Ra}j&AZ=1#PE~z zUEBWsuZsN@cZ$|FT&4}{wT#>PZsN`mvEhARSLNFm6&38qXo>dQ{Ri?oH*=e26?tsf z<$Uw5lf$R_*d<8&G$mc{yTzIe=I0Aula9{FR#Cxzj6I*?59d(c;=G@9qs+gC)c|+y z#Ks=lV8?y5dK${>46Y%4Snx?j1^Y4feCj0!L-?$;`L4_Eela{ymyHGK6n!mIm=#$||HTH1q`HbzT9x7VhuP&wb`By~++aG%jV_p6nApTC= zs=QkJ(6DQOD^9^xi?q6YpcZSLOT2Fm6V(sTQ-=Ndhl&dJW9<2il?)!rGji=zcHTW_ zh$e6p;pk$lf%70P{++E18gy4h<>!fhnv;Gd7?&^>zBJ9HN$@0|SgO5>s|>ErlRos& z{+j+xj}0t7Km#iAol2l`DDN`IQD}+Q!A&E1=8FyLhT<($jN;JKLl2O#JP{E*<^Fut zR6j;V1y?n+#Mrbgqs8rNc}!g@q^Y=Lirzg&FN}@OFf58tbH%l)utamu>&=TFp+9=UuPNK5Hd!33tF79mNjweNsOGb;c z$0C%yN~($q`o3t1VuPGxdCG^@rrF9o6~{J4FGg>vz>~3j=(EbE2XAK>JTe^fXo;Sm zpN`@0W4owrJOWkRBg2u3Bbc$jOULkBwVJ3a^Tw;FpqGJ`7z+-J;e$&yG-dE)72`9E zYjNGB{av3iymrN+CYSidDk`|Xq9w*IMT{2n{<*81ADX1%zA;7+IL|Xyx%XIc{`?{3 zvF|h$6`aq}676MNj}pDVc2s9(PFHbk<6fW9lNn!hoVeAlnVRa;!Qd_7m`6*D)j2#? z_)KnNIyZNwictg3&Nyo`wy)+`(LSQG>E(cVDk|u`q9w+*Ei}O;Sgf%KYufv%W zXH;5iW1_`|s+*;(@0ltpxH_XH@=I2a<{SG|GJPqYreZteGe~^ng5Dz=7sH=*$zjS> zHd#dl+aE2_`z4Qpc_HWP(zmub1V#|(k>&p}KzniVurrTlc35@>@XtGkORq*26&OLFM;5gwR4a6>kX+Mxj>$E8a;FEaBu~%6 z0+qS3VOsvzUUDls3N10#H6}!?+ICaotr(YpszrF>Fu%s-ham^e8 zm9bM6XfO4p7a|jZK_vTptppPMeBBnT0#8^8GEukK)hPgQd*Z%RG{Lu zK2a;G-z{3ArvPsU@gpBnl=7=@89W(`EIQPT(CVw}weRIE?XkW|IKR&ZDG_DfsHhAd zG)(K>Z;r;OuFxl9%=}xZkm8e+pI)C-j3Ce>yK;7}7ND1AEc^2i(dX$1OS{M5^C;?Tevt~<+=5U8yA znW#0@Ho94kLQ9Ozj0)mII{hgP?3qVkf5ph+?T-Fh?UCtv-@WiFm^;r;lj>E?AyC17 zjFuQ%oY%DSKIbBqsg8djRF*fXTH*S`? zx_-@5LZDrYERN?4)f(uvKt6+ecRpiN4cEm<#RV#OKD0zL!}DOVYxx;zcgq|CBM9u_ z*z*~aCI*T3M^dFtfq4Wfx$7;|>gY9!mKZBBCqQ(bU0w>^QB+_%V-LrkPfrxbcNgc% zy>z|eQCy&c?T?n|O^ypeV!iWJrSqd)0{bgQ7DFe^*COu*YI&{wD(B^JQK)ZcW&W2} zDk|8I(Gp_?%7*c+f6q`%DeqN`AaE4n=whrwWH9G*e3haLa|l$V0)rh_f|eNb851Om zr|*~kqrTf{?NV)DZ_B$80V>ug)-*-*O?rvEdFM$V3KtNl%n=KT##`KDM*@!61^iCUEBF;U!FR~6Uw5{Vy~lIfIR zpfcOSXN{;&aFG19PVuR!;PmGIob(o|C@ldjOU)Kj)0&9p+6{QQ1&u zk>e;_gQ@R62;mdI1)6)b`C@o`2R-r^PCd2H`VJdoXPbo3&P0844)Ik*1xFP6@bq*^ z8zjtYYO5X;bE0Q~zKC&#TSo8V)XkYsUDPARFpG}YW@)kdt|MAvETe5WU)uhxbk*;z zVRgoxG~=qab9;Y&H9SLFbn}H_y-QPiX?yh^gX=u4=NpG`=}sxr(bHEAQ7Zbl#?`sW z*I~SE`@f`q+fS>gVB278GUjsZSgR}J-Nb@I4FyK27lr3w}cVv|LN_tJ6O8=T4~C{w<;>QI-}o3@9*v# zCU(^?V`{qejN$Da?0wiP8OwY%W<&Dlcamq6w@~tZ917`{odS zBeaj|)nmVk3hs+zTta&?SNnI{b~s;N zXn@jS-Ydh3Q{rooW7fvK0mkxv4ChrR_EXxle`R>H29LthwEHnOlvkM9SQ%>itfGQ_ z40|QLhrGEzU!VO>D!=}PA%esi2WKLRAO{TOYXxo6|NBTq1wAs1MHnl1EJS?j)kitj z>R-bXEbJNBW9Z$FL;Xeh!p)Rpcb=;T1=b})YqH!u28xI^AEdwXJ~r%l;qC{nyNsRO z)?aMwqDo~?y)dlEIIrMLMBn@b`HP!#nn))bRy24r==BdAHAkzXb&%yBO$F@~4eKEM z)9$!_I8a%j^4GRG+UlVtok)}?7Rt>@@_ zESM*H6jic2Ihu2woxGX#K7K6l5y!;w zwjC>06R6C4GDn;L*^XMEuWO>aiofbgQsYLY1S;c?%y!f$ z`l$5w=kN|dt|LfyrU53;gn zU~z%{6}|qjgR`_btGu*&);2%XuCE9h%anuDnLq{mFyey{?uD3v^2Ls?;b}H zjxNSLC->k>{`%M4qC^paN{7Tq$CaQZddd*fRmAO{DUGO6N}zX-HHtM&-+yfFBpN)c zCp9lrPN34X+8nKCp{drsiWqwN)2! z%RSw^KfAO*rDf`DEvI)8YmK5M^4pJg;t&6wE){%Q)(~y~l@P97*CUp+BO@JG$k^1V zuH3g?Luqi6QUVnmk2r#_YC{ca7G*!D63y!OAfl-oHdjsm;bYS@~zQ#83V_x3+)ZhNte zKn2f-mKaNI(M_a$tY#ixp`<`>33ohrjw+iI9;v9{ii0~-7C)cX z^ugn}ymXquL&j(#@8QAPn8<(hJsC@huY<;MK_yTbS98AODD<@%+bDJCrA2kK(~9B( zBRceu`NB{~EiksJM>oFl!#{^JUX~E3;4F%kXx^O^D!vW=sx->;#^70E3}{@{-2RRb zx4)cGqB3@>sC>ITL))O&DEg>0&fRQ4MNaU#Iov=o+rs+N8HiP(*8g?D_kC;&S0`>b>nxRP0MQig0vMwCy)W`7V%P?4CKcDsC zmy7jP-UQ?n7}2yw@^2(6>AW?-f0L^Z*$v+;@nJy#y-g@1h?}drKt;ySUviy7w1-0gra^ zsOAesXge-kRhw9SpZleT?{%dTma9T#*r7Sv7X2u+WV;?oFM&s4Y4kX3B`jBEIR`4} zYoR4uiFWrFT1((jSlZxmSc~}SB~U>h4lUWv@x0S@>p8GSv8K^Gx0QIOmp}z$9JFLB zQ8BssK5OklB!s0gLbjDCtCv8fd5w{plOAE?`D`V8?-#Y51CGMd=q=kyw9`wVf_^EU z&sM_rcY?qg#hONM&{zT$j789rt%O7^Xz9Cn6qd#)!&bsyZ*x>I#z9NA5J+bC{&r2P>bQ?0bPh}HqH?lVg5xN(WIKoL?*v1{f;|Q!GGhr;Fvh_?W-Nh6 zVQGxQjU`aQy$rPUzY>-^$D^=x(3@FWjUqSo{Stc_O9@omYehPaLQD4JE&nD6JPJz( zPno3+IQZ%R;~c2C{fKlNg_g)qTo5Qm&0Zt*&Rx*()Dk^1JRf6~;sS(sS0Cxu;i887 zz&ppC5PGL*SqJ{-}q>cL{k>%&UBMNFXgiqRy_c8rDYj}Ttv5)`)v z`&CqMjzUX})r$1zy%&T^s|!{%cx2f7uvaqHWq5^Ua~oy`Y#X#>Yr%w9B}DhYZUQ3~^z?Doww2gR z@&7|AfeOy^Xo<1vzjqSD%J!FreJX2sdk5o8oagBoi@(269u$?*y3CQEG6jfItOjHJt6pr!MEm3pGtMKRQv#u=|0Y zKKhLGHtq@^u0?yAU1--C73|^I^XX{@eH%XMMH6++qIrg$BCJuYX}YSEA-sFXE6N_} zf{F@`d7LE}8~@f@B#IU0Pv@%{-cG<72WKMcyZ8OXq76P~kFym8D(K^4{K;7Bz5PVJ zz17tbA#YXeOE`*fbkSm>~JV?XNueII2z|J&SN!fyBf)~NjoZMB=T z$ac3K8*(aXt0E0wHTqQd(fa8b{>Gl@sbvQ?){2ckO)Xgeq~bQJ(LHnC%_BJ~r+)=$ zXR8gi9);gW(whSrzpL&Q3M-r2L>Mv%U`D~Z2}`s;_0o(@sj^c&-{idcT!%=GN|#kh z+I9U(Fc$&sKu$HgcaCuh3l2^wRLS{%(W%Od7wd@`V`p9NM-sI*p z*vtH6P83HadrEihOtojCC>@2CXmwuyL;Z7WQ?-0LG%J28Tz((U_V?NYU8)}!#-cltWB$9nb9P-m%3g=l_y^(w8Ao&gcFc(hDg zu005BEa$PF!_9e%dLgW+G_hS2N99NMGVOA;!E#PI3N6{jQu>9S>gkRXIko}z4D2zC zE!lEle+MdYo=TvCZG)C*Cv}8yJGf`A)My}mM+lia@az6A`GU2JdM(gC-0;J0DW|(j z(Jdo5D*t@%t=-UT6fIFU5|7Pp7gw~DRu7FbWJ18qkw3iysHSbTK;KRLTJN^-NkJ*$ zM-)dT@l-eMu3n>bc9sHUI`jfoHugnUj)Agzwa`fTX-T2ivW93~th_8Vq zO!D5!92J}y@T+gi&v3^>$WggW=BQd6zd6TT7RFKgx~R8kU*L=M@Q><-@r>W1qb0_k z&T|(p8-`2CO`JI94Z@tVhHPdmG0a1x{@Y!e<6N7gg876DmRPeS58kkLy3+ehO^$g6 zFvk|IyYxhHw=aJ-Bw5)%wK7Kq*H^T}Sk}Q#B5}tprQ7V%9J5PdW*cKK$==XGh?=LA zQzI%GdSd#nW!gABuK`-J_4c$IiW*DVNH8M|W~0IRk)G8aO5C4$T~T*Z2~=<%L`(Fx zNGA_otx$hyymxJmdCo9f3ubYlw^*0C^KoUnOZjU%aa1t>8Cs%z8RMFZYGbFXi47Za z%w~gEf>%iA7}`Lj7a5^u>}qLP4RF+=CHm%PhA%(Zs*>sc(kdLYTwwMK<4he{)`xdL zSIl&OR5inDP)GIELiF4TXo=pEZR*SaxP3+OFICx)ixaa^V3rEXE;g|X-*@}0a;{fN zjtb7yn5~J{+9(fkeO#1zc%|AL^8jLoP@Gq2k1UIF0uBl_mn`XI@G@}zKufd^PH^J& zGsmc1N47EKSi)RL#?|1$oYp)%Jzl*z!^yDXU?0O?$=I7!p8Vn6hf)^hNyWTDm}L>y zM0#5!(1Yg~d`T+mRGXuMYad#ox7#w^dB)^O^Q;ndKajs0Gw$JfMQB;CzPjRN~6{)DH zCPxKV8MH)u$k!(Au}5C$WlX!(MY~yTFt@Cn^3r7Of&QB@W&E@j_7bSzT8ox!$J$Gv zf+cX(HkLpIeIK-BE8(*FDn-HxhKL1AV+6q1%C~+l&8P(J=^J7LjB)UMwsZV>vWWE@ zcof>jNRPg>C>`u_Q7?fC#-C`(b`C1h(sCc)os+2zp78?I26@uDYFG5%=*ikj{GpdX z1>*#?WWSFE*89K~#5TwC*-D%{xxiXisGwc6M1JB1pS^AM_P{H_D@5M2~;q~ zK}+-=PTMgqf6!G~>I$QHjJ!YQSft$_y+|uz_1i6HIj)yLrRDb!?SXz2T4L;K>EOM# zYfCWf8enVU`E1A9OQ3>wvHfkwUekLCUI|_yddrNB>b}Lr-V;&5SOhIG)_*{*mgndk zmfnt03VP%i>CrCdy3PBK=p|6W*bpt*?nBk@1FrZi34)&qrPixK~&H#S~Aw| z&~HiFGAph$|P`97UoW(c+hqfTCyE~R=+Cjeb_7U ze6|wy7DNT@qNV>`lcn$CmEaX(RBSAP3hp_eCGti0ML7B{9)+bb(xWdx`DAJf%bx^8 ze2%dpTB1B&T{gHacyq+O@?Mm|)5o>XIK#cZu**&CUt=DVE0UvvV*=Mix{p5F-EO=0 zmdZERUUWiaLm&e zp#B@xrIl06A-_j)RB$!GohjPCTCz#)*Ri`aZ&s8cyBMy{#$FP0e24n$bOUMF$ViR~ z_A87HDc8&0Kh(c3IV(?E4L6Wa(5u0Dg}zWYaaetkoU zinH`omb!oUT-W5#XoJUsYZS(~v@go{xGkGDMp}P-lz~cuUM7x5iU&P*xGit)D!rN( zX_!l}k72JQ=F5)^x4A1mwjI4a+TbB$bcgFMz2ns@!>yf%($@8KG)D#f9rU&7DRN?# zn`i1S*8@YN4Oz1>n#5I`F>xxx?QM=Zt~m}w8$1go3YDTBdt`X;^%;A!5OiiX)i5;F-Qby;$v*>zHRz1`ip1LyUdsdz^O% z-R8ZVF6G=FVTd4c{{q)U$^mhAuiL{z9i$!;MsZYdHo#fJO3vaIa@J8IXHl*wxkR#! zwM4n1?(^qtoMPvJ@AtkOizTJ0&x zx#-p`tgRb++~p=ZALYPxS$1)-wpxX|izh_qx>wbSqf)nM8#ymM0kn{z&=Tbxbob=_ ziJaw2#HH^yg~RO0JOWIr58MJnO@=XRlRi5S38*6I;QLT;>ovR8_tx%zT7`aG0w$E}DT4Jmho#X9k z8#xQ@Zp&ILm(>|epE_mA-w29iV{H+gi=T*GDt#q7mqCFmK}%M0mRR2Itm||lXVD&s zym*z#dL=ms$M8kJ_8Doea(xGDi|AZ}y*cW-obCe^%Bv-_R9lZhOY~i8D^HO@J;LK)0t^@*LeMRYD6GP6Q<_ zGruNs7T)cqL6Uq>w~M{fO6L;Swx^k$iOz)z)(={uXge}mOdA|5%_4GE)_zGYr?+$a zC1;6~M9w--qVl0UoVRpx zR*I<|jZNFQA@8+IoVfmBmGYYCT&Uo;ilxa+SRA#xVBbDO(sWg-Jv=amqTHF9+aYb$$S91q>%u8bo(7b@8PXo=qI z+c#SLUht0ejL2Dgm&j`h?eL(mWVj+ zmnU7xN8~K5A3O?6Tj^Xp57D_U5uFPatT(hoUvoSjBbpI8>&=Df>f}XTG+R>uTsq zniGFnXSGKmDKsbA$XVBptdNP1qtA(%qkQ@AMCZCibS_i|zDc9f_pPPT5@QiWgBlyN zRBBA*ES%5FhPRQw>uZK_W*|D37)*4ohD7H=1?Lj9WF=>b=Y2|>1d+2&-1U*W=-i## ziQVN>IytL$^RBX&gSAz<)))~^bgp$o=R(Enji+2jC-|Tx>WMV(=G$Mw6i(!4Ug)4w@M78;wxR&09O!bJ)g$j;Av_#*^5M|8&{Y}Y}$XU3)Mx0qA-_l3z=V2L+ zb5oXPA}==8>0GGbx{H<=yZ2w5SXlb8RG!FL*amndc!iWV>Rp`JPIRtdqI02wZG)C5 zuUd|15mYh7wH=YOu+?y7piDaQL*1XV(z(Rx7YAK^h|Yxyu1jc%F?YI;7$Rq_CUO?G z0j|!CYP!p22WyMyT;l4Ynx-J4bD@H5gO(UOSe)K5C=o2(A#xUaEa+w4ud-4O)z?JY z6OE4ME3;=vNkr#D1=|2EF?Q~aJI_VrtQSPiLXV81ExDS`bE3FSuCej!UK?x6jo41Z zh|V>O*iNVz`~>i|tmG^{u2UgX9FeoIFJD3pvY)$XVI>SIMRIk@{v(vh1mk?NY6m%O~_PPd-Dwv3v*7xpESn3zf=? zSIV9BSpqH5oJj1mU?OK_QthILL^}oYs0MEPENyVJf-Ki?u(n3Oau@0E(p<%f+6D#Z zD73`b@H%ng_glvlUm|Crzf-+O2l-!peXX_4n`*)4^;_v&!b0boMRYDy&<{dOv@;PB z%WDxiD~ZTiU;C0z%hp&~TUet3E=%Qc`U*#HV-Akx-HFcCk?35goc=9Y-l(slXo+Hy z3$Y@C$XQkQ&rtB%akZ@O(b;isW}$P57ewc}LUb-v@Se~T zP{DgbON`}S6eV1UoRvi6Ec8;(O!Jl7>DS)syPtf(!P+7^m)ND#xlln587&bFD!(TW z6q(YWM9#w5z&|Tp?yGZmyhp8;ogAz!qI2<5e%qx#iOz)zu2E>oO3o7AM9%Ujau)U_ z^vKYwp|=g&#fsKM=VCm!k~(9=T?5cdOU*ZHXz zKSFe_=0xX01wCZ6M0*+eCyJd!&gx0zEUcgS&x2%toqc8W`pgR^h(CzV^S5mNk@Cxys=*@u# zk^B(Rxe6vvS5U!vLrXO8evTG@TuoI*5IGBH{nF<;%PBhNC0q@VXE<0}t(;@TaH4aq zAUYQ+IM<>jniJ1cUWP+9au#}bQ8n5*#`d5C?d4zxYwJn2huG15hxCx>T&SRDiI(Uc zmTjZ?p{LAroXA<|ixgY9!V%Zbm_=)sgSB;jgp6_aUMdU2>SkRNfD2%bjU*dRrbgJ_BN6L@GQ;i(_B;{XO$w>mS5RadA(lmSku@x^i7=m zGAnDVFR`{z!Euh3=o#eA7+#FXS%rw4h2G?~HOu7L`dmA?LW;c7!P+Vo7|nALovRVi zxlqBqEVM*Sq{%*fP^SW>il3`;98oW-ucW!wM$Q^DDov(0bM-x$&R;xvv|kC+38HhM zf@2UZk(W^+p8q^yBWL0Kfp?3wV5M{MqD1FvKy)rta9%-6^aQKlFmaH`Sv`oHg}Z7a zTMv=*=;W+w@sV_)em8aiVjff=`#w5@Ub886s9ccqk1bau)6) z0fmF*Xa{SH=v-oQ+d`%`MCU>U_nFWVV?@ppK5HjReTbZe<8H)&KzWkRr5YL7Q~ovG z&f02IBuvB-o$CbAxlqCJh?W?OsympkA#&CtB4=T|eB-~xa+H4Utx7DGWe00((ZM17 z7SXvfiOz)z#?fero>YGi<*r1|%0c8T-2L#on&i0l(;br>_e9w#ox`~&(YdA)oePx{ z5vg*jzMGAfXufJYOspbuRw$9Pa8K7+?k_jc*;m-dh_%&qq-aTWt|dh0LIwL0TB4`O z#YXWhM9wNm&uuY2JNI~=qwl^BStvJlu(pWK#s6z+qjRBxaT{8qRc&Vox0AE5_hGN3 zEaq}Q2cxRbw-7!|r*ol#yHRL~-hgN_Skx$dO*%#7EbM*QEC1^fB!6(Qwtn~z6w_|x zHq9hD7b>6Lb&_-GUKm=U_Zgmsigo>KNbiW8g}o1Z<&lj& zJTiEeGj1%A-|6*(V}&ud!h?A#(Ye|ZoeLEl6X>H-#8N$!ceqzwT1Dh6Y&C3694m}{ zdKb!@#rjK|iOz)zjtR6x`=U38ac-Wc3@36H_CD;D`ByEH8#`EA9seA_KNFqn7ty&; z!Bq_{Q9c0YL1Gq>vt|%E3!{mzC;G|tb-Oqot#mH2hv-~eC{sErIPTDrh4g1?=}hFT zIYiFFbxGu1CO^{oS~EWMke@hMTkr3#u+q6UQ3+Jg13*hwa+X*{UeM7WFK6Q@Ke8$jh=_ir1aK{v9IE;6!bS|DzJ&&my(Ya8;cmOTY z_a6nKxvG=1a0d!kGULoZbS{4X-~#gvqI02w&z;c{dB{7X`8FbFMG`p+y<+s1$CsNc zuXeDuVmlAzu|(&ZMszMzFs?;QR&th*E7-_cxbu&r7WcB~3GcTkG3oOH^B+X#LIwA% z&=S2Vn>Shb{Z{q5S{A)(Ya8;co{8G*1Cuo-fm?P(+VPI zVf2Hu0nQRuIv2Olx%`RFg$hPqXoGFFAyXWfa;l}vOlRB$g8Em7XjCu7AhB4=G8 zau$wM9Kl9!sZY+aVj0o7mJ*!{6^wV#5`FViI!0vIY@((SISY5T&;!6RZ>4jIpG4jM9#vIiX+(Q$sD;J#Rm|b zYaY?LP{F-Ev_$X8)Evuq54VxCFls>066bjGi>aSo<0i*t_V$=Z3TH_^FJ!MPSKQC*FT5f*Y*K_X{it6^*6I~rCxm$1;ez7m}a z6?_JXmaOC~abd2FoP{w*M$jO6m(Has{$qgr%)#0sI+rLybgu72=RyU&KD0!UaE+eg z^8HqlH<7b2=2#dTCg;|1PAh>?4TOV5eUg$jCoXo<*j--3Avk+Yf; zISaj|iBlHHf9co0`|^CpJ<(fXF(G^{(YYEEoeLF=MbHvskCzAVaY-$u^+e7>Z^>tU zqMTp9_O|U39rwi8qh>w%KB9B2Cps4@7>l4K`a-%%xLBOSM$SS{X5gSil+)`1(FYDMEBER4^7nON?FnJcJkfYlQNI$XOV3JbE)*ZfqxKot-Q9bg;H= z{1!@7_9SJUh0X;EdVOe#zAS#(jqfFL)^;LiVa!2!yyPFkM$V#4>2ePTql)NUyfe|c z>Jps`74%-w5ym>c4VbK{?N`_hGO6ty!oX;JA;Z#O}g;wVV_{bS_jdnm|kR{h)hy@pfko*F{9m z!lSS>W#y7{J6KyIK6ewxh|cvN(Ya8;SOhIuzQ_&YpNX86MOjZV=Ez@fp`(6qtWZS% zJeY4KI@j++=RyU?1X{9^v-qqEFI}$@ISX42TNB3$MUZm>c#o;&rT#?cLIuYJTB7$} zFNgEwkj_dwB4=Um!(KUf(tLTWgSFN9LJ*H6I#&?UxlqAa1T8UEBQjV>M9#`hr%OiP6I+qj0J{`X=x#6c@Q}ZSI%v97Rl{&zSh>=A+o!JwPkjb zT9zO>*H)r)p@JS6TB3JYnuLhASL&O;t6vRo?_h6#=G0Tpr|-!zHsL{tsPi+>+=b{| zsGtvzUO(-N(z`fih@7>Y$XV!%#AvhRczqAiIKy4m2Jst2=jur@Co1Tppe0(JxAzxi z2V_X|iJXP2bB5AO-mSO4aaGG|8!mpeJ1bowIu|Oq_lB0}i>j}~#4`84qya?E!WzYz zHm=ThHx3btvrCx{5uFPa^nKBi?P*41B4;%qau!CZd8Wq6JMDZek?_CYY}U79`_=Jo zB9lrmP%yefOY~hT?cDVaSSw8@au#|^xN;hMJJGrLlO;Af7b+Ozq9r=V>mmGu>4|iJ z$XVzcq6dKen7+H)H;m^YI#(s4bD@I$6)n+M*v&&k-d*?1VMNZt-iN(%XQ5tlLkDY% z=v*Qn(YdA&oeLF=Akh-VwKs=|SR!Zn5;+T_3Ebs2v<-{6HbS@%o$EN!xlqA2Kuh#& zJ1~sbzVg5vO5`kzyl`eH2K(al_1V>ad=}BU#t@wg72GvIOVl2fM)Rn`1Jy=E&cdF7 zJqE`kF{Dl5{Nt7xY8j$)p@QSiV97$x;udn&ej;aK#Dc4VafVAd6UKWHovRqpxlq9< z6)n-T)Z5|0PR_!JzR1@gd9FSO8&`vAR|X0%qH`q^oeLF=w$T#3i!(M48#Yas@n~9u-F$a1}ICoj;T*6N0LIvk2 zw8U8Yq5gcBPR_y_#hS)GW~FoSX1)6;$BE8`3ic(mMA;U$_2+?|RjC@0vv4-RSprv4 z+7a$CkUv}XLApnDE>v)b1ufBj`>+oDUJxjDi-wDSDh;u~F zxU+9Eoa*btH=?I$`HDi|lACF0|B?jT+`C%V=kau&t| zt+GbQDSDe1>^?%S?YNI(KE9&FANO3l5uFPa^z_jZ#hjmgL_+=(ZGSGWYKSJVG-dCV zLmjNGv*|u!-Mk8}?&-Ic#0a#k%OXQ5{~`N(WX{frNq?Wi}(dKwYH z?Q||wFit>Al*g;4FJBbA(DjjpoCR?owkD1hOAfjY{7JzFuDyuPg$j-dv_zE3c76HF zF-+MroeAuH*egR0&XN;XdFiYzqI2;GqI2yfIu|M!C!i%-YbW;*2cG_GZb0NLj0e0D zBOP{eJW@W(tRV5n6K{nPoeLElcW8;eUf$Y?Z@ynoawc*X#skjP=Ewm$ISbo{&Ov0k zSfX=95}gYbYy-4JSp-{k;d8yx%_6(Bz<8iV>TEf`PR^o?v~sS8cGgzH6JI_(@SQm~ z(Ya8;H~}p&Ha)7V@FQ|oIFYjqqX@=b#*vYZdtz+#(N4lb=PE*UE>vD8ggc@lv_$bo zRXaH{zqB4@Sv7A8;7W0|)RBjud>wXZ%C;kYMaNMGtC>bCmF+?eQGsC;iSKz^b} zMQDlgAy4isdib3+wqa})Q26pFV>wY=hmdIJ? zEm0m}*-f&Mvy3y`iWc2?@P}&VaYW}r1@}nM5@RDf3=m#K&e}!fEZiN!)u2pJjBF=E z(bEjmaIu=`TqlUmg$jC>Xvr2E9*6v}rIovR+vxlqB_5G^q_ra><;BxUV?(q=Zxy!=7h7s8uxnX>w)MHag^v>r7d(W z*agPe5G~o-{4tTUz7cB+qlugkC^Cz2YO4!87{YTFFwOLRoYE-E>zI#Lre7BAT@-0*4rrkB61eSfVex1{g~c? z%o)x@h|aZw=v=5^e??1_%VJ75vGCzq^9v$pVei9UX`FqU{ShEm6P;^2(Ya7TPaiGO zciU|S34bDIT_kcAj#M1M*fx{_^J|1K5uGcR=v=5^8=xh6{?VZa|2lH8YnAaYheB4=R?h#r7(RUh0gVX=v=5^Y>1Y~_vsZNE}s5wjv#Ut_6+PXcs_bZn6B#bi8{(w zx++xAE?S~@ohJv0Nkq zEL6}gTB5%Dy29SJIvEJK%MM9(>+qW2Wk$ysQ( zRgIByH9cO&2$`6y0V7&e(MzC$=R-@jx{`Hr7TQHG6a8zNMWdoynDi2;;Q7#!?HrcB zDR-N|Ho(XNy+LCMRIqK(lC1>SSzBlqV;qb!Y$Ys2Hp^9^g6Bg^wh~qJo``XO!_;Z= zVx6zG<;-};Z(9jFISUosb3jYB5<&Vo@Y?YxENv^{ua`gt?+Gp0O4Pk)qu1fJAMKSO zU)A|qv7O=_zilNt>*qiP?+Gp0O4$BRFhnf4gMbm4u>>mE$FNr#OQ2oc%fKl7e@_W-^LQC z;Q7!Jy&)7Az%Asg??leR-3YuYEKT2Y&JW~6h|V>f=v=6v*N2wqdo`24_?dRk)w4%M zgBOmofpPZfxvYa&ny0Z;hUi?V;9d{<^TZh?qE5M9e$qN3XQ3C4cWbQOOTz=iF`{#o zp(oX-;GPv)VvNXHynRIS;VMMVLXQkr8RM$<=$<$Kx$foRIHGf*g7GI>q9<|bVPZd# zvnCQb3*$^2!8p1oOY^*;Vhqu_+7q1%74%-wlC77lAad3lB4?o&jy(qZn61PNDiKa} zE>tioLQCYAl=2Y|XDmM)Pvk6&GtmRUm74a#OZtijMCa;DbS_lT(??769>D$xK29fR zq4$b24$hBOIu~z3bS`(IbD@IqCt9NKQa5xGf6py0B@;Qz;E};T4EAHo({O*GE)12{ z5So&xy$^G*+oN=Zb{!Z;H>0GzccN8|6Ecu}HrjU+l3 zDj0vFC8E(1A@ALHf2l5!vv9`2nF#waWA}Fj@lr(R8cK97RItCIC3?ejg^$<~~HHe&raVC1KICs$w%Uf^WUt3}RMszMzaE?MtGzK3| z;Dv~sHHOGp*fX%l;CQ6`?R)$27DVS7M074xaNMCK+S9MvlUvAHC221M<4p9zj9%Zq zbshP9qH~#v&V>rbpJ>U*+RDjj??tk)w(M*t3mMA(+eT`l5kfg-ZFDYF?4>P7*?-#@ zRTf{t`)w0zCR%$5i()50;cxpn5`>Rl!hV!Rv6sf*wsRnz%U;5wSn{jA(%D}2-?nog z0Spy;Y0FXe-?npD?wWXB*0|GN!lK~a+JD>5VJmUdnvoq9duhv2_TRR1Jc~PPXKfjH zUiQ-e_nycDh&yX%Z3(o6*KV&j`#JpWk+9tyOyKu=d+b4 zaZ*vc6P>FN(Yf%;$&(qh z=Bv}WFiSzFRY~$4-L6x@68VCI=S2iCw>dfi3>D0Ch?eNv@Tq0Q3Ziob5}j+Vh^22s zZS1Seo^f;^HaeHTIYK7dk6R56i_e4)d*Z*)UwXLaIiwIz-w5vXazOJ#=0$QT)4Nhme)!oL;or%tcImjqy zzkFT4_KJMDeA&VC@_n+=t@4;y^JF4`p@Nwy&=Reji;uc(xzk5#M076vD!%9U#WJzT ztU1D`n?wXKR4{KCTB3I#owvBf5S?oR(Yem9UM1Jj^D_R* zUM3S+&PwO{Ep54c+rjht&||&ZNg{xiCIT2Ln2iK2QNF&Q$X3IM&UL2aM2pXWlpcF;1NQl zq=QmpB7mWSSqjh+^{Zd&Rnyag(qzh8i`f>Ip6Vvw((5OuPXM)zo#&OybF=y?wWYL* z2wRFdGIYF?sq-5@#_jv^dg@1_r=F>mL2`FA^^`Vj$aI1#{5!F+URiLrcR zvec2~mL8r#bS@l4IJzifvpjQx$37d+YaubJ3bg$FuqQF9P{9mMXo=ou$aHo&L3FN@ z)Ph)}Sku^#DT_yT)#i(+goXNs3iemDMBkFNxa78i=v+04&V@Oz7Md0~>IcU>d6u$5hKcaJOBRUsmCcxDaS5aciCV7Y&L;&kV1Ta)Ej~7~^ zXktSLewXN6$B52_Ij>T8Et4ndxf6`NWc9&LJc0;dy@&vY3g+8EOO!uxC~FgO=zVLmTicqI0byIu~Zl!4ZY`#8{7U&3StwfUP0|7%F(}Xo<0~ zvOeM$(YZbloeMK*G*Nvi|CKF2gK?%_Kf_n_B?8z>B7mWSSv=4ZW9=t)5toV1b&BX* zn3V}30M=n( zZH@}&okL6ZsLS$ig2BtcwU+1z@<|8J>wjeuEZhu-GUHYk$8Ypk=)2U*MXV8|g(ZXv z`aZa7Q|_HB+#aPG)^ofnv_yG|4s>o|r*olQjBzjmuwK<}XPxJT3SJ3XA_5q@x#zgf z`9ZrFO=4_FZ?PWeyyvoB0u?+TTB02<-&`&1bgrMy$rKORcwXrBqwh=m)GIPu5UI&Z z07E5TT34Ca%T^i~TC$edb6TfbVGH6>SlZU&XY~@OV4I^Q%9wRF-yUC`&V|>GF%Ej? zjMctY*QK6b0u{U`w8U8QZnwQR^{c|Tzv=f7nb=NNhS%F1i)3Ox={&EDnCdM~>LpOY zSRE~qFB((by1QZ-AK1=#6qaUe1H0+i{XhlVA1&Ex_Z0OK%lN=+$H)TxYx3Kp5A8Xj z_bXKJp3o9KMa~%5Dnc)TaScX#7#mXd?+ZKk+6iE&pbw9h7<+eNr;B}j;I-pXSlV{y z=k=>X1@8$h5fiCHlA}FFeoK;x)n<(?m*h^Oc+f`Ydhkym#m;t~*PaOr9PNQh{Q^B@ zVz^mLqb2$(e!_x1XY{MW{)$IoY4R-3=4)|5FM$g7W3)t>ZdX;e?pIp+6<#~;AYdHL z*wMK1)}2912~_Z&&=O-Ah5nza&gLbmC=BCgQp%6NpiLx$5F%8FF1n|8$VC#k5M4=a zDrn`Zuuaj%*%XB-ga`xSaK%w9HOnlWLy3+FHAPeqWuQbY+V~GdJvo#7X8kbFz&#)D z$36G_#`m5TeOc+THq>d{qnW*DMTP%Ir+;HU7aE?H=v<6_oZ*!_+~KYX-5l_8c~k^2 zDvXJA(wXgeDkO@HJ}o*IGZ{WzK6RZ#KKn3S69Mdv2w+s0Wzb1|>du_~5S{D1=v?d$ zai``A)+yFwvo=&FfKg$8k50~IR%fhrqsd7-}19$Ve~t>~WUT&!goqbeiL#p$e#-JOYAL;$108kbJH zbgnSfQlfKlW^l%Eb?IGEYCa66`+ZIXFe=PT>7*Nh#HjjD=VFG;?1fQOox9)JFqbP4 zz^Jf-q?2>S^=vrlZbp9=E?3;l&0jNW>uva892!IbdnN)H71p2pKlNVQp4k4|r+l^O zTzu9pd5R5)Mhv`go*-ZGtwqsGx>2B>!v>J;sW0M;e~7!_7`bkcYn zd~GA5a}`AA;tc1^XY|n*ZXdqb6%oMpy}gv8!kz=2#E?GyJ*Y-=|J06;_aR(yd%K zmaP6rw|^lz7yDw2033g1;qM+bgYkZ#wU{tua>Eztj=Hu|SOy}ZC diff --git a/src/main/resources/meshes/boatSTLs/catamaran_mast.stl b/src/main/resources/meshes/boatSTLs/catamaran_mast.stl index 79bc742b54e04e8e979c0397b2d67e4a67094299..536184da9faa85d6a8d967c5977910f7478de576 100644 GIT binary patch literal 2284 zcmb7EJ!_Lu7`;mU0WM}M85LAS2o)r~)Q_%i(J53(iijGCk-DfaHVzg+oOE(?ue&NuiKIgsn+PGZ zcK6uH<5Q=qhi~7xQay3R{nzKHMQ_b6_z#QycMv|V4C|XS_k8p8?lkesji)o08f*2d za~%&H6d$8P8DdofJGV1Y^ScwZ93C1)jJ*9yvwmo*9X+;1p$swdQXM=#E%v9kXBP?& zjUtA}i-Q+df84(uJvKz43^DRj9Xy8C^-lEAC}McLsx$|w56p>GDMO6BR0oe=HmARF zRvJYNk5*%CkoIA-$~j$Sh>@4-;9)z@KgSJf6fr!WSB3-J0&ubOoI6*B7P=*+JsSX~$t#kW&cxV(cJeF-A7hf+$kDsRa6BWu3BQMp# zW7Fn@Hv$ihA}&1Ew^pw`d=fqE60!535N0`I-K6#N1rl!Cju z3AiarP|VYfOFx0)!m0(uzX;+c&UtfB-g$j13xxwSzd3hi?tPiRb$z*aqq|hS+*`g{ zJ$NkJbR=$SDjwDd8vBrVEC`U8O#2?&=VmlHVp;j8&JSvU!Z>3=>1kIvG-CAq?`I*{-=<(f%KatP~HR_Uf zkB|Me(dUKL%tN!N;c@%^x7iE#HloKTBdnK<&BOe25#=ENXZhYE89q7ofA9ciu!o zBh;u%I`&~6cCSX*xn@zbkCk&n@vwPi1Zputjk=`WGs$Eo zi0B5n^D?0k5PTE7?N0Da=tCp=YWdE~ghq5e+F$Mf4~=NIdfFnP5j~-L7YX%Hx=3u> zP2aoE-v=-eQ??WThO8dRSuYr9TvRA9~p+=U{{`+BHpN!B5HBLpk zw2zcosLL#RVE=xq=Ai!ACzfOcBb*PixPK?|`6j7GxDRCUj+F_Ga33V{Z^@oPy}?uQ zh9ir&1e$N9?4c2E5Lr4At3Lnw1U)nY%_(SqAkI!^r4j8(PwUm`p%FcydKZb^9-L2+ F_y>8sayI|~ diff --git a/src/main/resources/meshes/boatSTLs/catamaran_sail.stl b/src/main/resources/meshes/boatSTLs/catamaran_sail.stl index a2723d980b7b68c4ed654f7d5c4f57f253606439..273b1d5bfe5c205cee453cf2cc1a2ee69467e05c 100644 GIT binary patch literal 1484 zcmb7EJxE(o7=6wz9eiR%Oh!92lms!f#H*GF5etFR7}SD)>0&kds^SuQCnq5p9J>@+ z7l%i9QYaE`%%X)31qX5Hs@4vcDuPAO`@PE-&nqszC5N2veCPXnFS$IIcNTI};Wtix zCfxTnH#?Pc9!Dcx@o>kx#fk8fN7lWbwtBP_1Y1IO<#VPWuD7c|##PF<*OFWe+J1<0CQmSDTAWua5fo;zRYp#(od0 z$&WHyR(@|<4a9f4F$&cu?REt{EX&b~r&@u`u8v|4%tQ`SU1Wy6zvHtmMxh$#W)#0q zhde^aFsAunCW_-nDoiKnDFV6Dg#4mCOci7k5C{hki!U8J&#%IBtj_ zgL!#|xWV8%NDOw%irZ_a%E%2F#;8UQQyp%N6|_P2#qdw95b2NXn9nf zZ8ZpdC-5@vR-9`EGU$PsjK}|-)4g(qh_R30bcw;v8P~r)YURsIua+*lm=`O-3jG@~ literal 1484 zcmb7DJuE{}7`>#cL5PK+lMqqOBhg5>t^b5d2ZIQUv=%?52m^6rZ6YEziJuT*DVlB~ zZxAG6Gc*RNc94kGhH$_4`qe2hcuT+Zob#RU?{+Lqg(I_}pmQ`5o^ZB~hbDueNUh;& z^f;?#=0=?EYVohHBF9!Hg@H?dbIDE2Os7kI99OnSeeO&DIsH$uE&2RhwiJkPoB}mv zB84*BKX&63A&Xi5F)GMZU$SUN0*sc4zlNF|+AcnTUimi`AIPX0Dg)S^L2Gu$pS;*wJ&Pr_1~9 z-N~FFVrY-G-yk8_ zEi1mSop*u=$EZdRt2&8WV+Cz6ke#l*bK=^cl8E$a7VjK0+1&cmA^Cb%An{G$W&Eu` z1U)d5?eVj7x>v3cW9%b;x`bfo9Dl!B{XUG;yQ2>CVkKB1Ri$J@#f^3Ch_D)`YkPbF Di()J} diff --git a/src/main/resources/meshes/boatSTLs/dinghy_hull.stl b/src/main/resources/meshes/boatSTLs/dinghy_hull.stl index 56a443a731a5c5d984fdd3df416d2289b3061e50..9450b75faebce2cfcd42269983ae30f2dc015e00 100644 GIT binary patch literal 14284 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 literal 14284 zcmb7~d016d_s5qY5SBQFNI0N2n5LPUQ*igySNfR)Vp)mVBUxC^il~r~HzISYG&9iD z&@dG!rvf!N=ZfKwQyLMPIb?%cS*Df}+WS5GUM}DBKK=9adDQzn-}6~}@3r?{Ywdkb zOv;qWNy&-NMUF|DJTbEGgv3eDB_?(3(y2$!$ad4FkB;noul&FMG_NDlZ*6zA?Ay?y zZxXtiEyA}u6RspUVrP~*!tmR5`$r|#?=|_$oX+WQl*E75(iC|Z#K)g~P!; z`_7>b>nXOxU2>@%Z?16{e05WmuiT_o-&5+Y++3l5=N{SN?jO2a{}vh5x@?uOK733PE?s#^cQC;zxQ#zFDr;4hxoR4llsC#v=s>oTnKGi#p zWDpHN1b|@Wrz>lnDYs0}G+V0m)j$8tR!ndkcig(fdHSmoZySGBZt7a&D^_xU-0aNx zWz4_yDh<5~aSbxBj9zDKLf>ymD>g0vT*sKU{klo}?F@Q&?)69XZ;>R=IL!JO2P=Cq z+WwuM)HGWXS=w=T@iW8I&ArtP4Zj=t=B|SgZmW$$#|$%fTw}N8-E+}z8^;FTu78Vs z3*uQ2AA+zcKhG<f9mJ#GQV1{lA$ZZ zoV|{mRgdXCcoxL_AaX#k5*wDM-d!$E>nXM*vh|4wl{mPr8o2xplUE<_RNlcNYe8gy z=mUb4h?Kd`4BwuG#< zFF;2hYbEk(=l#JIN9}A_5ssA}5fj~?POj^;q6AwKIZ?FCXjL^;E$!l|OKK_$t~j_o zkUo`4zut(X`yjMhS z1@SV7BOq9L^mrrZpDR71WlJK>L8MJhRd+V-X^V;M=>*WLqCA;eq_L+B`3fU}Rt(d7D{)DW!jxs9Wp$TN`_ z9T(%H%xw*-ZKny&$egJ~VnO@^A`1j7JU2X>B4J-|btI1(V+Ie;G}xo;X>L!Xs$#2S zI*3RRtZ-GsmM~_tF=^Bo6$^qr%AV$Po5&Tkkp#j4f)zdkvL%spquN(radhUYZwRu_ zoooL3mzseUt{>Qv$XlpnCi+b?52KRd^~$j%4OLC!@5SxeACo~$0Z|Hq70$bC38(Co zr_{(f8w#`b`P*&>y2c%Fy7I?4jw04}!f$zHXNmP&(&AH~0S9;QEtS2Gb%TUZMyDE8HGi!hCGcG7eQtQg!+c)%OfF`JA)!_Dw6?&U2N@ zO0%=Oj6w6x>!&z(;l3m@ zz&JW1S$+4)T%$U4ru)S6SM+G-f7#W2WwgJ}YDH)IxI?;}^0qM!#8)6HK(KN=??rdi zro;Lvwj}a@om0)le-?IoEO(r-3m$D&xK_t-_HNvF8{Ihv-}SZ;1Hy_|lR>az{T{h! zzG;n?Er~pUkstbPtaHU zzfF+Iw+4N2Dq22rqn?{_ABH%`CN5Q;IsXyF=OAvh4l-Gp`hC7S`_WGQ6k8HGJn3Rd z-o|7V*lWJQ^IUr0Npp1Rt$NNYD}&r4AOF?c#vdTogJ=MP6`p^#BytJ8+Pz?a>4$M} zHsDHsEPA+V>L%?4k)J{A1yKhCE6-xIcecyaPq8JDzdYkGL(r?e==-j={yO%tN7>UN zKZ4k>G1;sSf|X+!ZA7yZx(&93Gv_-~qQBffS^cnL(qijj!{sN=8i8)Q}slUSDIpC+5#`!$oC~gX3D+pG2ZrBpG5>DG!TqD#aoVGc8 zaaQ9sCUW_$JjZ1aRUla5wZxW0hM@wu8Xu(!Pyw)Aj%s`}B@zeXZxE|Nu)^)JC6Oc5 zrNydWs@W;{1=|fIpIGfPSn+phac>Z_L9kMQy1jFGUA;yd5he3v$Qy>U#c32UhyfOPY^u+B5Q7x7Ds~^27(oyXSO6V z@r!{*(8lRz^j!lD?mM3*cOVZ+{vI8>MCN&kyFswRV`59FMKSU@DJkkcJFS6nA>Pq>F7%Rtlx(H8_OTtBcSk=H$SiCKawgXe(n0PI<9Du^#CCYg;<$*{t6 z!t} z`$hNAQ5!egz3TZ0R$jtW+e&ZO`GYNqbbi0LkKioBk(wj8$oz-i?Pk?JxbZSs>5cp` z;E$8K4Yni_(IQ3@xbZT%%HWEOGqp&oo{N3GV#SsdZI#T`1Mh9E>6I~bnLGQTb-E|T z_zc57#R~V3Er~qw!ul;%8y3Mm;U2Qz@Sf9rz&CPM*gtFuIcom| zAHmfmSD8E}k=c=%zHzX^eP>HJ3Af4d5j<-=n_L-)>^`=`N3gxhTT7O867^lq)-?#CnP?A-10_cdUE1of)_{(smog6)X49Lwo=t00b*+m+wwQ8e}XrcEpc2 z7Y4p&%g!9B?JMy<5QQKzL9oJWmvafuI7zpws`)`hd5hv~Zxs1fjlF<(EFkJF$SK?a zf)(}~znc_U2w!33DhMOzN{=f*o*T?Lhz%et@3O)xgDr_P!N`l_$Ez6_IcGJ_&b*s( zlL}%x2+LQjaAaUhB9rc~t0uNTW7KaMW&6s4XN_kQ6&Z-hAZ`P}3j2*cjdzfH`x`5R zlFW>#S8bIg&l=CB$TSe|fye~G3ddcp=Wr4}{jg(puV>7gcb~MqiR06+eb;sbkqRR0 zo|6VEyzls=Co%yepVa=0!}1l+Gp`I@F(NO3m<1vP1S>rMYzY+^M!qU2NzKN{d7imC z<4lBH>m^b_u)_1tmPEREMy?uSs@~uL{S;dg+1|w8@z|bOX5TOU9Q<~H-#X;_O>}=BcSCvF*x@AxfM8|l-nQ<+ zoo~@?uqBa2ndwTMz4}QXXNZGu%=so=Z7y;z98_R>+E@&t?eCF=T|ltX1y5DZE73h+ zOCpCnBUhs^a{eNv4g6MB=BM9aJq<5>HuAc+jdBn}=clR!5Uhm2qw9VNa9cfLOCl8* z`LI2+)EyW(-#YVKvP5{{(YF71+c*m1aS#C@SSf}_vzz>)pJGcQp?wOBinQm==hw_} z@Rv>_QsbTND*sg0`?_U~Vw^j}f6-pRX#&Ja5WPUKa;^Dm&b$qu=%?6{$c$bWqIb1V zGhc32*TG+*@T~D{ip=p6OF*#l#M#Ye@#%(o&e;;)G&l>4Z_}PvkDylr(f8xaf6#aL z`~}2i^e|yUuGd#LyhI!bR^G&DlTIAhPq8JOywIz%_Gu~|z2Z6GH<&M>hhcqh(X)w+ z1L89fPlI5E=Y}oe+rhi1mTbKz%^cAEZU^r>*N1T>{YQlBJ(x4g}|IM^mOQ5d>tE|T0Dc3?Z{K*Y z*a=p6Pp~CB!S7G`-L}0~3){U}Q|~HP*gtH^-Uj!b-&)yMNeyF-oE07uTdH~9`roDa zy(9O8duS(E;aJO-us;qg@Qs}N&Try)uh`pQg~!B}L>$fxeg3dU&hP8EC)`7vYmG&| zUa`W_hb`HA#c%ugDW>t|zynKkuPpDf!ZC_1iM+k~Tvty^F5CMvehW0}l``k)Ay4af zY^Z(8qH9h?ij}AElxzP7`t2LP{}Q=**xY)i-uoE6OYz$U(Zo!g`dR(NjM67t}o8NQKo{NS&*I6l^n!s-<(99P&< zEn)2s&N#i^&UIcp)LUm92Y%0eRB_%D_&r!ZjmXvJ+w1%iUMz9oBQePcdCfSTo2d^uhjxM$u6NlI?)uJt>l+8pGgq%%aoF2nh3B6w z*$KAG)iR$fMEoyR`h3L-x5t+7Msdtd-#FMVSAAU7+Iz(cx5t)nj#|Ig*9P0=oyt4d z-Uch&9$OOmDfqe(xh_`i?wIf3?9ADK_q@m%5UoL!f?$Pv#gmuKSXtgfZJP3jnj)QE;=PUDLjGVt>rMYzg-aH~Tp%TBfSZcj`EJ zo;f>ne8fF9h@&7r1;Gl>KU>0A_y37C8a0@%Lgx;1a8=BerG2%(=_SHIu)_O}Eg=tL ziRcuO*%}o=v=i1aTF_ToA1A8e>a{C7zL+i!pM(zu;Np*~Hsd5MQ-SHTQvF zg>wm863M~H8#I`1Hp9rddgW@FBN5JOUgACwtZ*!0OCmdt6-O6#Rs2I6;82HuoA2cxm0T8qG(~UkmNr|69l`Y z@FY!62#B{Tc7lzqAQFwnXrUm2jlS9U&F-968AuqIH*emrZ_~PabGCDMYezZPW9iO{BRXuhn{MXNfMSnYcCwVi!(1-9~W2E`)$y#!CWg;QI_kQv8 z+IpqAcYGxQ4&kdQ-bIBn#Ht21k4i21U8!a8&?sW$-QQR~d4BXk^iYK|#K=pvdwiZ> zXj)~thei>@vIo2Fn@$`GsC zJ-*wVe#Kd76frzrtXKNwK2)I$G4fLF9;k>L)F@(joM?>naSOm9d@;pN+_^Hu$V;_* z*j;6IS553(qll6BrS&m)aihE|RFx}~Ax2)R-Q$PN$$ss^LeMB;c$~9+)GuYx1GD-W z70M7JFV*g`?K{ssG>RA=m!}qcqnpp8hbojIMqaAjHG+ChafTDy7=D%3;O zgNkjt^gr?1slYW5qg&l(2wRBW?Jr6hVpaQH*_R=)FGK!nbw0$1Qg!kFBUdOxjH;*} z+DFDH*$)q7B(9;zNx F`~^~AE~5Yd literal 2284 zcmb7FziU%b7`=tp!9hAo7YRsXE47s9GeWQzg%(^CT%D9AQ?-&Rbr2e;j&3eRaH~te zrJxZpPe=a)H>p-dEEL4SL5TOf@1DH#3=VcW^nB+#->>_!c=y(7`*w4=(rT~Xs9acS z-dt|BPuAw@XDicdcdl3FXWW1N&4%cYoA>+sOY0egZ(cp~#~YLVYumG)_}=b=^M|Lm z{fnKX4_sC#L#%3G=MIgh*@q;}Jv53Kc`r^q@zuuGYx6h=(Z8ZX8Diw6+C0989zKU& z(1%75Bk$EmkA3Gvt7aamP=*+JsV+RiycXc0QN-+HuCaBl@Sp;@$Pgnh)zKq#{X0p+ z)T|FESP9kW{N+xvU>-@B?ru~lL#%4^h&#_cG>RB`vHzLIWb{ylGQ`MBwRyY?b2?aB z&pkAX7#?evd(sEy6fQAWC_{|ARGY`xc#;{976W8G?x3S}@KD(Ghli#88sSPAY)s;4^ezwqY7pC?x-lfKH3KqWONGJUlEV#Dx*DVwPl4eTA_NE73%S~n$ayYw DG{7WS diff --git a/src/main/resources/meshes/boatSTLs/dinghy_sail.stl b/src/main/resources/meshes/boatSTLs/dinghy_sail.stl index 12f4b334f02ac125751455011a26506b5572ca9c..f10f0c78b44cd8a21cfd023801ed7bc929444dce 100644 GIT binary patch literal 1484 zcmb7^ze`(D6vv;7*g+9uveY4qU=Y)i0EFTQ3-@rn|q-c6laM>-Er%Yj9(b%aeY0eu2#db_4Ld$j-1%6s)h00smj9^ zq2Y(ho|pMKXgcFRnmLQJRnB6X=jMpq zWF&y%h-l1*D!51xHiTuvBO20a*pYK0^E?J0#?LL;hSq06NTsJ%O;aex?dxhTbbY+g0DuU3FuH^{N zhvxon<9_0=B{;$!T&d6zl=P1KDjl-sbKIUTB0{rvUmrUoWB(t)qc6o-uFIWp Vhv-F{^50eY+s+Z8;UU_2{0Fs~HD>?- literal 1484 zcmb7^%PT~26vxjb8cQ2lkl82}#CTnK{E(qU{sDQ;*m#UCYBq99HYmwTHda=WiG{po zN@Ar@tYo9Hx1enJo!`A@<~w%o;&$qs&-Xm<4aH`o_IxB9n6RVMfzGMOOgLg!2CEva zK>6IlSfILs{`C}_Xh#V&bbO%tuKQa@nr_?0UO#W{V7uP4XvQ6B6A=OeUK$T@shD|+W;@9sW| zT3&(@#h!iIR1IDfDiPhK+*xs5G84QjsZjbOI`L-pWY^bVy*M9KBI+r$&CcHz_u8;q z+#1pu;#Cvq!F;Ghv<;Uio#PJp`Y<2SeJXS9=s{gnGMiJS!=vdhiZ4TQ$dw4;Ui;6_ zl46b@^oWf#+a}O^ISRKX1aFgV&gbqt!#D~(O!s;IP)p|Ch#({i69W@ z!5pZ>HD&*=M5_xT0t C4=3sX From 0e829874c236ea6ec52496f9a824738d1c5f5b4a Mon Sep 17 00:00:00 2001 From: Calum Date: Wed, 20 Sep 2017 16:43:04 +1200 Subject: [PATCH 11/36] Fixed BoatMeshType enum names. #fix --- .../seng302/visualiser/fxObjects/assets_3D/BoatMeshType.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/seng302/visualiser/fxObjects/assets_3D/BoatMeshType.java b/src/main/java/seng302/visualiser/fxObjects/assets_3D/BoatMeshType.java index dfe3d5e5..f78e7172 100644 --- a/src/main/java/seng302/visualiser/fxObjects/assets_3D/BoatMeshType.java +++ b/src/main/java/seng302/visualiser/fxObjects/assets_3D/BoatMeshType.java @@ -8,7 +8,7 @@ package seng302.visualiser.fxObjects.assets_3D; public enum BoatMeshType { DINGHY ("dinghy_hull.stl", "dinghy_mast.stl", 1.36653, "dinghy_sail.stl", 1.36653), - CATAMARAN ("catamaran_hull.stl", "catamaran_mast.stl", 0.997, "catamaran_sail.stl", 0.997); + CAT_ATE_A_MERINGUE ("catamaran_hull.stl", "catamaran_mast.stl", 0.997, "catamaran_sail.stl", 0.997); final String hullFile, mastFile, sailFile; final double mastOffset, sailOffset; From fba522d0c343528161d946cf76cba1720b5805f3 Mon Sep 17 00:00:00 2001 From: Calum Date: Wed, 20 Sep 2017 16:44:38 +1200 Subject: [PATCH 12/36] Fixed BoatMeshType enum names. #fix --- .../java/seng302/visualiser/controllers/cells/PlayerCell.java | 2 +- .../java/seng302/visualiser/fxObjects/assets_3D/BoatObject.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/seng302/visualiser/controllers/cells/PlayerCell.java b/src/main/java/seng302/visualiser/controllers/cells/PlayerCell.java index 7af80e04..09976927 100644 --- a/src/main/java/seng302/visualiser/controllers/cells/PlayerCell.java +++ b/src/main/java/seng302/visualiser/controllers/cells/PlayerCell.java @@ -37,7 +37,7 @@ public class PlayerCell { // Add Rotating Boat to Player Cell with players color on it. Group group = new Group(); boatPane.getChildren().add(group); - BoatModel bo = ModelFactory.boatIconView(BoatMeshType.CATAMARAN, this.boatColor); + BoatModel bo = ModelFactory.boatIconView(BoatMeshType.CAT_ATE_A_MERINGUE, this.boatColor); group.getChildren().add(bo.getAssets()); } diff --git a/src/main/java/seng302/visualiser/fxObjects/assets_3D/BoatObject.java b/src/main/java/seng302/visualiser/fxObjects/assets_3D/BoatObject.java index 30820660..30f49692 100644 --- a/src/main/java/seng302/visualiser/fxObjects/assets_3D/BoatObject.java +++ b/src/main/java/seng302/visualiser/fxObjects/assets_3D/BoatObject.java @@ -36,7 +36,7 @@ public class BoatObject extends Group { * Creates a BoatGroup with the default triangular boat polygon. */ public BoatObject() { - boatAssets = ModelFactory.boatGameView(BoatMeshType.CATAMARAN, colour); + boatAssets = ModelFactory.boatGameView(BoatMeshType.CAT_ATE_A_MERINGUE, colour); boatAssets.hideSail(); boatAssets.getAssets().getTransforms().addAll( rotation From 7197bc2bee0034485f50f0ea310fd6d020399ba5 Mon Sep 17 00:00:00 2001 From: Peter Galloway Date: Wed, 20 Sep 2017 17:33:32 +1200 Subject: [PATCH 13/36] created meshes for pirate ship #story[1274] --- .../meshes/boatSTLs/pirateship_frontsail.stl | Bin 0 -> 4484 bytes .../meshes/boatSTLs/pirateship_hull.stl | Bin 0 -> 23684 bytes .../meshes/boatSTLs/pirateship_mainsail.stl | Bin 0 -> 1884 bytes .../meshes/boatSTLs/pirateship_mast.stl | Bin 0 -> 2284 bytes 4 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 src/main/resources/meshes/boatSTLs/pirateship_frontsail.stl create mode 100644 src/main/resources/meshes/boatSTLs/pirateship_hull.stl create mode 100644 src/main/resources/meshes/boatSTLs/pirateship_mainsail.stl create mode 100644 src/main/resources/meshes/boatSTLs/pirateship_mast.stl diff --git a/src/main/resources/meshes/boatSTLs/pirateship_frontsail.stl b/src/main/resources/meshes/boatSTLs/pirateship_frontsail.stl new file mode 100644 index 0000000000000000000000000000000000000000..b344e825d6457179e5430342121dc9f6f39cbe51 GIT binary patch literal 4484 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 MxuYJcZA&8hKTHVu!~g&Q literal 0 HcmV?d00001 diff --git a/src/main/resources/meshes/boatSTLs/pirateship_mainsail.stl b/src/main/resources/meshes/boatSTLs/pirateship_mainsail.stl new file mode 100644 index 0000000000000000000000000000000000000000..c421901a447db4532ff5e4911bfb2a4777ca6ee4 GIT binary patch literal 1884 zcmb7_JugI25QdM!FW3qR8zG?}qOnW3OQI#A(ur6VOBRVl;-l3_bfQxF2NK!68kIyZ zQTPuEojC7V&)&KBR8()wJnzh$JLl~3$-#c}sJ>m^Y3}cpmv-xo?Rs-!dUB>x9y>hV zDo>5OfBlVw?28oW?xy;D)wpgi%=auxKW>!Lub=*)FZ+6fR&JgkBBJt9@6tGR+&5oO zlePECLNN>a_NH1xXT*vpY((1DK!>i94(FWBD$>jp6GTMNyLIYzmHIi_#VlxhZW-a{ zXxoUit$}8O&|Rt;@;&=ptwE!8R?>MwSwuuzjZ=goS^!ba#&S=OmT3_YEv z1FgAvMKs~V;ayGoes;ZG`hE*Dp)+FG6RJT(+R|td7tuGT#!Iz7)Ufqpf*QpRwO4Wy z;hdi%@pH7)2@z>q1Dz3mj+T6hNLv~$B7dWpuy_hM#RQRJhd9Lq+aQ80OUDHLDvQ06 z#z};8y60@W&4RY4kP+M{n`LRVi2OGvVtu8VDJF<0i{7Pi>UO1j9^NYmJFTTNg7?b$ zS{mIUbU#M_wxqa;yul)*Gh*;>6N#uROQS{P&x$Qk?>cGuO5+q0M3jZEG)~>F5KIwS!>EfU&lM6tFC6}+eSo#do(u~2&8-0z)t-@EVc*=v^z#jCmT)I_mx zDRt&zEjKQjf`@AA@gGAj>P-;YD6;<>QG}{(w_0zh{bYc1Q}XI%|6oacgGA6E0Mrj zbf~c|Y0qd|*S`ja?3}$15ZnoAbbe!GU(8TK9craLW8J!59-Z3E&?;*5aew~z;G>88 zW5$}_`6i(bHP$8V8E>p>JK-Jz4hdwOua8x4cKUd2L^~4dP%G^j)_Im^rB&3(Xyj(A zr#kncggVq%m$YZJY)88)e&G1GY; zHdonCkx+*k>yq{i%#;6=dfpmtjc;4uJgf1ylvO8hx3)cg4VZ@=hA=lh{Dc|ma3}ru z@pAgv90{HYs(1&`Ix${LLLE*Y2)-`p5SFHgPmoZD?~X+G>vOx&daMK;Jq7JAgnNzF zaT4liPr6$W6P?c0(H%lF+gJZr##XvZ{IvJ+J$^;GD@+45I@j9_Va}=(%p6w T?8}g-qdU~>UP3c^Y3<`LVyx}y literal 0 HcmV?d00001 From ea0be5e9529521db4ae78b4d506952bb22cacdbb Mon Sep 17 00:00:00 2001 From: Peter Galloway Date: Wed, 20 Sep 2017 17:56:07 +1200 Subject: [PATCH 14/36] Added pirate ship meshes to application. Updated boat model to allow for jib sails and a fixed sail. #story[1274] --- .../controllers/cells/PlayerCell.java | 2 +- .../fxObjects/assets_3D/BoatMeshType.java | 17 ++++++++++++----- .../fxObjects/assets_3D/BoatModel.java | 14 ++++++++------ .../fxObjects/assets_3D/BoatObject.java | 2 +- .../fxObjects/assets_3D/ModelFactory.java | 11 ++++++++++- 5 files changed, 32 insertions(+), 14 deletions(-) diff --git a/src/main/java/seng302/visualiser/controllers/cells/PlayerCell.java b/src/main/java/seng302/visualiser/controllers/cells/PlayerCell.java index 09976927..a8051f44 100644 --- a/src/main/java/seng302/visualiser/controllers/cells/PlayerCell.java +++ b/src/main/java/seng302/visualiser/controllers/cells/PlayerCell.java @@ -37,7 +37,7 @@ public class PlayerCell { // Add Rotating Boat to Player Cell with players color on it. Group group = new Group(); boatPane.getChildren().add(group); - BoatModel bo = ModelFactory.boatIconView(BoatMeshType.CAT_ATE_A_MERINGUE, this.boatColor); + BoatModel bo = ModelFactory.boatIconView(BoatMeshType.PIRATE_SHIP, this.boatColor); group.getChildren().add(bo.getAssets()); } diff --git a/src/main/java/seng302/visualiser/fxObjects/assets_3D/BoatMeshType.java b/src/main/java/seng302/visualiser/fxObjects/assets_3D/BoatMeshType.java index f78e7172..290916a5 100644 --- a/src/main/java/seng302/visualiser/fxObjects/assets_3D/BoatMeshType.java +++ b/src/main/java/seng302/visualiser/fxObjects/assets_3D/BoatMeshType.java @@ -2,22 +2,29 @@ package seng302.visualiser.fxObjects.assets_3D; /** * Enum for boat meshes. Enum values should be of the form : - * ENUM_VALUE (hull file, mast file, Y offset of mast CoR from origin, sail file, Y offset of sail CoR from origin) + * ENUM_VALUE (hull file, mast file, Y offset of mast CoR from origin, sail file, Y offset of sail CoR from origin, jib file, fixed sail) * Files must be valid .stl files. */ public enum BoatMeshType { - DINGHY ("dinghy_hull.stl", "dinghy_mast.stl", 1.36653, "dinghy_sail.stl", 1.36653), - CAT_ATE_A_MERINGUE ("catamaran_hull.stl", "catamaran_mast.stl", 0.997, "catamaran_sail.stl", 0.997); + DINGHY("dinghy_hull.stl", "dinghy_mast.stl", 1.36653, "dinghy_sail.stl", 1.36653, null, false), + CAT_ATE_A_MERINGUE("catamaran_hull.stl", "catamaran_mast.stl", 0.997, "catamaran_sail.stl", + 0.997, null, false), + PIRATE_SHIP("pirateship_hull.stl", "pirateship_mast.stl", -0.5415, "pirateship_mainsail.stl", + -0.5415, "pirateship_frontsail.stl", true); - final String hullFile, mastFile, sailFile; + final String hullFile, mastFile, sailFile, jibFile; final double mastOffset, sailOffset; + final boolean fixedSail; - BoatMeshType(String hullFile, String mastFile, double mastOffset, String sailFile, double sailOffset) { + BoatMeshType(String hullFile, String mastFile, double mastOffset, String sailFile, + double sailOffset, String jibFile, boolean fixedSail) { this.hullFile = hullFile; this.mastFile = mastFile; this.mastOffset = mastOffset; this.sailFile = sailFile; this.sailOffset = sailOffset; + this.jibFile = jibFile; + this.fixedSail = fixedSail; } } diff --git a/src/main/java/seng302/visualiser/fxObjects/assets_3D/BoatModel.java b/src/main/java/seng302/visualiser/fxObjects/assets_3D/BoatModel.java index 78d2c837..0562d4f7 100644 --- a/src/main/java/seng302/visualiser/fxObjects/assets_3D/BoatModel.java +++ b/src/main/java/seng302/visualiser/fxObjects/assets_3D/BoatModel.java @@ -34,14 +34,16 @@ public class BoatModel extends Model { * @param degrees The rotation of the sail in degrees */ public void rotateSail(double degrees) { - MeshView mast = getMeshViewChild(MAST_INDEX); - MeshView sail = getMeshViewChild(SAIL_INDEX); - mast.getTransforms().setAll( + if (!meshType.fixedSail) { + MeshView mast = getMeshViewChild(MAST_INDEX); + MeshView sail = getMeshViewChild(SAIL_INDEX); + mast.getTransforms().setAll( new Rotate(degrees, 0, -meshType.mastOffset, 0, new Point3D(0, 0, 1)) - ); - sail.getTransforms().setAll( + ); + sail.getTransforms().setAll( new Rotate(degrees, 0, -meshType.sailOffset,0, new Point3D(0, 0, 1)) - ); + ); + } } public void hideSail() { diff --git a/src/main/java/seng302/visualiser/fxObjects/assets_3D/BoatObject.java b/src/main/java/seng302/visualiser/fxObjects/assets_3D/BoatObject.java index 30f49692..596a1401 100644 --- a/src/main/java/seng302/visualiser/fxObjects/assets_3D/BoatObject.java +++ b/src/main/java/seng302/visualiser/fxObjects/assets_3D/BoatObject.java @@ -36,7 +36,7 @@ public class BoatObject extends Group { * Creates a BoatGroup with the default triangular boat polygon. */ public BoatObject() { - boatAssets = ModelFactory.boatGameView(BoatMeshType.CAT_ATE_A_MERINGUE, colour); + boatAssets = ModelFactory.boatGameView(BoatMeshType.PIRATE_SHIP, colour); boatAssets.hideSail(); boatAssets.getAssets().getTransforms().addAll( rotation diff --git a/src/main/java/seng302/visualiser/fxObjects/assets_3D/ModelFactory.java b/src/main/java/seng302/visualiser/fxObjects/assets_3D/ModelFactory.java index 86c7f7f0..f0b0f70f 100644 --- a/src/main/java/seng302/visualiser/fxObjects/assets_3D/ModelFactory.java +++ b/src/main/java/seng302/visualiser/fxObjects/assets_3D/ModelFactory.java @@ -84,6 +84,7 @@ public class ModelFactory { } private static Group getUnmodifiedBoatModel(BoatMeshType boatType, Color primaryColour) { + Group boatAssets = new Group(); MeshView hull = importSTL(boatType.hullFile); hull.setMaterial(new PhongMaterial(primaryColour)); @@ -91,7 +92,15 @@ public class ModelFactory { mast.setMaterial(new PhongMaterial(primaryColour)); MeshView sail = importSTL(boatType.sailFile); sail.setMaterial(new PhongMaterial(Color.WHITE)); - boatAssets.getChildren().addAll(hull, mast, sail); + + if (boatType.jibFile != null) { + MeshView jib = importSTL(boatType.jibFile); + sail.setMaterial(new PhongMaterial(Color.WHITE)); + boatAssets.getChildren().addAll(hull, mast, sail, jib); + } else { + boatAssets.getChildren().addAll(hull, mast, sail); + } + return boatAssets; } From 307e79ecfc149cf0b3396c06bda29957e541ade0 Mon Sep 17 00:00:00 2001 From: Kusal Ekanayake Date: Wed, 20 Sep 2017 20:46:23 +1200 Subject: [PATCH 15/36] Completed working boat selection screen. When a user selects a different boat, it is sent to all other clients and updates accordingly. Boats are all shown with their correct models in game. #story[1274] --- src/main/java/seng302/model/ServerYacht.java | 4 ++ .../java/seng302/utilities/XMLParser.java | 4 +- .../java/seng302/visualiser/GameView3D.java | 3 +- .../controllers/LobbyController.java | 5 ++- .../visualiser/controllers/ViewManager.java | 2 + .../controllers/cells/PlayerCell.java | 6 ++- .../dialogs/BoatCustomizeController.java | 21 ++++++++-- .../fxObjects/assets_3D/BoatMeshType.java | 38 +++++++++++++++++++ .../fxObjects/assets_3D/BoatObject.java | 6 +-- .../fxObjects/assets_3D/ModelFactory.java | 5 ++- .../server_config/xml_templates/boats.ftlh | 2 +- .../seng302/utilities/BoatMeshTypeTest.java | 35 +++++++++++++++++ 12 files changed, 114 insertions(+), 17 deletions(-) create mode 100644 src/test/java/seng302/utilities/BoatMeshTypeTest.java diff --git a/src/main/java/seng302/model/ServerYacht.java b/src/main/java/seng302/model/ServerYacht.java index da5aa37b..80566afd 100644 --- a/src/main/java/seng302/model/ServerYacht.java +++ b/src/main/java/seng302/model/ServerYacht.java @@ -424,4 +424,8 @@ public class ServerYacht { public void setBoatType(String boatType) { this.boatType = boatType; } + + public String getBoatType() { + return boatType; + } } diff --git a/src/main/java/seng302/utilities/XMLParser.java b/src/main/java/seng302/utilities/XMLParser.java index a903daaf..7a8bbac4 100644 --- a/src/main/java/seng302/utilities/XMLParser.java +++ b/src/main/java/seng302/utilities/XMLParser.java @@ -146,9 +146,7 @@ public class XMLParser { XMLParser.getNodeAttributeString(currentBoat, "BoatName"), XMLParser.getNodeAttributeString(currentBoat, "Country")); yacht.setColour(Color.web(getNodeAttributeString(currentBoat, "Color"))); - if (yacht.getBoatType().equals("Yacht")) { - competingBoats.put(yacht.getSourceId(), yacht); - } + competingBoats.put(yacht.getSourceId(), yacht); } } return competingBoats; diff --git a/src/main/java/seng302/visualiser/GameView3D.java b/src/main/java/seng302/visualiser/GameView3D.java index c5b52286..8cc6bb9b 100644 --- a/src/main/java/seng302/visualiser/GameView3D.java +++ b/src/main/java/seng302/visualiser/GameView3D.java @@ -30,6 +30,7 @@ import seng302.model.token.Token; import seng302.utilities.GeoUtility; import seng302.utilities.Sounds; import seng302.visualiser.fxObjects.MarkArrowFactory; +import seng302.visualiser.fxObjects.assets_3D.BoatMeshType; import seng302.visualiser.fxObjects.assets_3D.BoatObject; import seng302.visualiser.fxObjects.assets_3D.Marker3D; import seng302.visualiser.fxObjects.assets_3D.ModelFactory; @@ -459,7 +460,7 @@ public class GameView3D { final List wakes = new ArrayList<>(); for (ClientYacht clientYacht : yachts) { Color colour = clientYacht.getColour(); - newBoat = new BoatObject(); + newBoat = new BoatObject(BoatMeshType.getBoatMeshType(clientYacht.getBoatType())); newBoat.setFill(colour); boatObjects.put(clientYacht, newBoat); wakesGroup.getChildren().add(newBoat.getWake()); diff --git a/src/main/java/seng302/visualiser/controllers/LobbyController.java b/src/main/java/seng302/visualiser/controllers/LobbyController.java index a292fc8a..03af2d3a 100644 --- a/src/main/java/seng302/visualiser/controllers/LobbyController.java +++ b/src/main/java/seng302/visualiser/controllers/LobbyController.java @@ -130,7 +130,8 @@ public class LobbyController implements Initializable { controller.setPlayerName(this.playerBoats .get(ViewManager.getInstance().getGameClient().getServerThread().getClientId()) .getBoatName()); - controller.setCurrentBoat(BoatMeshType.DINGHY); + controller.setCurrentBoat(this.playerBoats.get(ViewManager.getInstance().getGameClient().getServerThread().getClientId()) + .getBoatType()); return customizationDialog; } @@ -204,7 +205,7 @@ public class LobbyController implements Initializable { FXMLLoader loader = new FXMLLoader( getClass().getResource("/views/cells/PlayerCell.fxml")); - loader.setController(new PlayerCell(playerId, yacht.getBoatName(), yacht.getColour())); + loader.setController(new PlayerCell(playerId, yacht.getBoatName(), yacht.getColour(), yacht.getBoatType())); try { pane = loader.load(); diff --git a/src/main/java/seng302/visualiser/controllers/ViewManager.java b/src/main/java/seng302/visualiser/controllers/ViewManager.java index 165d0c39..8e966813 100644 --- a/src/main/java/seng302/visualiser/controllers/ViewManager.java +++ b/src/main/java/seng302/visualiser/controllers/ViewManager.java @@ -278,6 +278,8 @@ public class ViewManager { stage.setMinHeight(500); stage.setMinWidth(800); + stage.setTitle("Party Parrots At Sea"); + stage.getIcons().add(new Image(getClass().getResourceAsStream("/PP.png"))); stage.setOnCloseRequest(e -> closeAll()); stage.setScene(scene); stage.show(); diff --git a/src/main/java/seng302/visualiser/controllers/cells/PlayerCell.java b/src/main/java/seng302/visualiser/controllers/cells/PlayerCell.java index a8051f44..3f434a7f 100644 --- a/src/main/java/seng302/visualiser/controllers/cells/PlayerCell.java +++ b/src/main/java/seng302/visualiser/controllers/cells/PlayerCell.java @@ -24,11 +24,13 @@ public class PlayerCell { private String name; private Color boatColor; private Integer playerId; + private BoatMeshType boatype; - public PlayerCell(Integer playerId, String playerName, Color color) { + public PlayerCell(Integer playerId, String playerName, Color color, String boatType) { this.playerId = playerId; this.name = playerName; this.boatColor = color; + this.boatype = BoatMeshType.getBoatMeshType(boatType); } public void initialize() { @@ -37,7 +39,7 @@ public class PlayerCell { // Add Rotating Boat to Player Cell with players color on it. Group group = new Group(); boatPane.getChildren().add(group); - BoatModel bo = ModelFactory.boatIconView(BoatMeshType.PIRATE_SHIP, this.boatColor); + BoatModel bo = ModelFactory.boatIconView(this.boatype, this.boatColor); group.getChildren().add(bo.getAssets()); } diff --git a/src/main/java/seng302/visualiser/controllers/dialogs/BoatCustomizeController.java b/src/main/java/seng302/visualiser/controllers/dialogs/BoatCustomizeController.java index 5690dc35..a418fe41 100644 --- a/src/main/java/seng302/visualiser/controllers/dialogs/BoatCustomizeController.java +++ b/src/main/java/seng302/visualiser/controllers/dialogs/BoatCustomizeController.java @@ -11,6 +11,7 @@ import javafx.fxml.FXML; import javafx.fxml.Initializable; import javafx.geometry.Insets; import javafx.scene.Group; +import javafx.scene.PointLight; import javafx.scene.layout.Background; import javafx.scene.layout.BackgroundFill; import javafx.scene.layout.CornerRadii; @@ -111,21 +112,35 @@ public class BoatCustomizeController implements Initializable{ this.lobbyController = lobbyController; } - public void setCurrentBoat(BoatMeshType boatType) { + public void setCurrentBoat(String boatType) { Group group = new Group(); - this.currentBoat = boatType; + this.currentBoat = BoatMeshType.getBoatMeshType(boatType); System.out.println(boatType.toString()); boatPane.setBackground(new Background(new BackgroundFill(Color.SKYBLUE, CornerRadii.EMPTY, Insets.EMPTY))); boatPane.getChildren().add(group); - BoatModel bo = ModelFactory.boatCustomiseView(boatType, colorPicker.getValue()); + BoatModel bo = ModelFactory.boatCustomiseView(currentBoat, colorPicker.getValue()); group.getChildren().add(bo.getAssets()); + group.getChildren().add(new PointLight()); } public void nextBoat(ActionEvent actionEvent) { boatPane.getChildren().clear(); + Group group = new Group(); + boatPane.getChildren().add(group); + currentBoat = BoatMeshType.getNextBoatType(currentBoat); + BoatModel bo = ModelFactory.boatCustomiseView(currentBoat, colorPicker.getValue()); + group.getChildren().add(bo.getAssets()); + group.getChildren().add(new PointLight()); } public void prevBoat(ActionEvent actionEvent) { + boatPane.getChildren().clear(); + Group group = new Group(); + boatPane.getChildren().add(group); + currentBoat = BoatMeshType.getPrevBoatType(currentBoat); + BoatModel bo = ModelFactory.boatCustomiseView(currentBoat, colorPicker.getValue()); + group.getChildren().add(bo.getAssets()); + group.getChildren().add(new PointLight()); } private void RefreshBoat() { diff --git a/src/main/java/seng302/visualiser/fxObjects/assets_3D/BoatMeshType.java b/src/main/java/seng302/visualiser/fxObjects/assets_3D/BoatMeshType.java index 290916a5..947a63f5 100644 --- a/src/main/java/seng302/visualiser/fxObjects/assets_3D/BoatMeshType.java +++ b/src/main/java/seng302/visualiser/fxObjects/assets_3D/BoatMeshType.java @@ -16,6 +16,7 @@ public enum BoatMeshType { final String hullFile, mastFile, sailFile, jibFile; final double mastOffset, sailOffset; final boolean fixedSail; + final static BoatMeshType[] boatTypes = new BoatMeshType[]{DINGHY, CAT_ATE_A_MERINGUE, PIRATE_SHIP}; BoatMeshType(String hullFile, String mastFile, double mastOffset, String sailFile, double sailOffset, String jibFile, boolean fixedSail) { @@ -27,4 +28,41 @@ public enum BoatMeshType { this.jibFile = jibFile; this.fixedSail = fixedSail; } + + public static BoatMeshType getBoatMeshType(String boatType) { + switch (boatType){ + case "DINGHY": + return DINGHY; + case "CAT_ATE_A_MERINGUE": + return CAT_ATE_A_MERINGUE; + case "PIRATE_SHIP": + return PIRATE_SHIP; + default: + return DINGHY; + } + } + + + //TODO kre39 make something not terrible to cycle through boat types + public static BoatMeshType getNextBoatType(BoatMeshType boatType) { + for (int i = 0; i < boatTypes.length; i++) { + if (i == boatTypes.length -1) { + return boatTypes[0]; + } else if (boatType == boatTypes[i]) { + return boatTypes[i+1]; + } + } + return boatType; + } + + public static BoatMeshType getPrevBoatType(BoatMeshType boatType) { + for (int i = 0; i < boatTypes.length; i++) { + if (i == 0 && boatType == boatTypes[i]) { + return boatTypes[boatTypes.length -1]; + } else if (boatType == boatTypes[i]) { + return boatTypes[i-1]; + } + } + return boatType; + } } diff --git a/src/main/java/seng302/visualiser/fxObjects/assets_3D/BoatObject.java b/src/main/java/seng302/visualiser/fxObjects/assets_3D/BoatObject.java index 596a1401..abf969a8 100644 --- a/src/main/java/seng302/visualiser/fxObjects/assets_3D/BoatObject.java +++ b/src/main/java/seng302/visualiser/fxObjects/assets_3D/BoatObject.java @@ -11,7 +11,7 @@ import javafx.scene.transform.Rotate; /** * BoatGroup is a javafx group that by default contains a graphical objects for representing a 2 * dimensional boat. It contains a single polygon for the boat, a group of lines to show it's path, - * a wake object and two text labels to annotate the boat teams name and the boats velocity. The + * a wake object and two text labels to annotate the boat teams name and the boatTypes velocity. The * boat will update it's position onscreen everytime UpdatePosition is called unless the window is * minimized in which case it attempts to store animations and apply them when the window is * maximised. @@ -35,8 +35,8 @@ public class BoatObject extends Group { /** * Creates a BoatGroup with the default triangular boat polygon. */ - public BoatObject() { - boatAssets = ModelFactory.boatGameView(BoatMeshType.PIRATE_SHIP, colour); + public BoatObject(BoatMeshType boatMeshType) { + boatAssets = ModelFactory.boatGameView(boatMeshType, colour); boatAssets.hideSail(); boatAssets.getAssets().getTransforms().addAll( rotation diff --git a/src/main/java/seng302/visualiser/fxObjects/assets_3D/ModelFactory.java b/src/main/java/seng302/visualiser/fxObjects/assets_3D/ModelFactory.java index 502fa3c4..91f832ad 100644 --- a/src/main/java/seng302/visualiser/fxObjects/assets_3D/ModelFactory.java +++ b/src/main/java/seng302/visualiser/fxObjects/assets_3D/ModelFactory.java @@ -7,6 +7,7 @@ import javafx.geometry.Point3D; import javafx.scene.AmbientLight; import javafx.scene.CacheHint; import javafx.scene.Group; +import javafx.scene.PointLight; import javafx.scene.paint.Color; import javafx.scene.paint.PhongMaterial; import javafx.scene.shape.Circle; @@ -18,7 +19,7 @@ import javafx.scene.transform.Translate; /** - * Factory class for creating 3D models of boats. + * Factory class for creating 3D models of boatTypes. */ public class ModelFactory { @@ -57,7 +58,7 @@ public class ModelFactory { boatAssets.getTransforms().addAll( new Scale(8.0, 8.0, 8.0), new Rotate(-70, new Point3D(1,0,0)), - new Translate(16,50, 0), + new Translate(16,50, 1), animationRotate ); diff --git a/src/main/resources/server_config/xml_templates/boats.ftlh b/src/main/resources/server_config/xml_templates/boats.ftlh index 8186e000..26fae383 100644 --- a/src/main/resources/server_config/xml_templates/boats.ftlh +++ b/src/main/resources/server_config/xml_templates/boats.ftlh @@ -12,7 +12,7 @@ <#list boats as boat> - diff --git a/src/test/java/seng302/utilities/BoatMeshTypeTest.java b/src/test/java/seng302/utilities/BoatMeshTypeTest.java new file mode 100644 index 00000000..baca1b14 --- /dev/null +++ b/src/test/java/seng302/utilities/BoatMeshTypeTest.java @@ -0,0 +1,35 @@ +package seng302.utilities; + +import org.junit.Assert; +import org.junit.Test; +import seng302.visualiser.fxObjects.assets_3D.BoatMeshType; + +/** + * Basic tests for the next and previous methods + * Created by kre39 on 20/09/17. + */ +public class BoatMeshTypeTest { + + + @Test + public void testNextBoatMeshType() { + BoatMeshType currentBoat = BoatMeshType.DINGHY; + BoatMeshType nextBoat = BoatMeshType.getNextBoatType(currentBoat); + Assert.assertEquals(BoatMeshType.CAT_ATE_A_MERINGUE, nextBoat); + } + + @Test + public void testPreviousBoatMeshType() { + BoatMeshType currentBoat = BoatMeshType.CAT_ATE_A_MERINGUE; + BoatMeshType prevBoat = BoatMeshType.getPrevBoatType(currentBoat); + Assert.assertEquals(BoatMeshType.DINGHY, prevBoat); + } + + @Test + public void testGetBoatMeshType() { + BoatMeshType currentBoat = BoatMeshType.getBoatMeshType("DINGHY"); + Assert.assertEquals(BoatMeshType.DINGHY, currentBoat); + BoatMeshType wrongBoat = BoatMeshType.getBoatMeshType("NOT A REAL BOAT"); + Assert.assertEquals(BoatMeshType.DINGHY, wrongBoat); + } +} From c4a6113f6cb74bd00d3fc167d9c24c3269a3cead Mon Sep 17 00:00:00 2001 From: Kusal Ekanayake Date: Wed, 20 Sep 2017 21:07:49 +1200 Subject: [PATCH 16/36] Minor bug fixes (like all enemy sails being toggled in when they should be out) #story[1274] --- src/main/java/seng302/model/ClientYacht.java | 2 +- src/main/java/seng302/visualiser/GameView3D.java | 1 + .../visualiser/controllers/dialogs/BoatCustomizeController.java | 1 - 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/seng302/model/ClientYacht.java b/src/main/java/seng302/model/ClientYacht.java index 89715852..1ebaa3fc 100644 --- a/src/main/java/seng302/model/ClientYacht.java +++ b/src/main/java/seng302/model/ClientYacht.java @@ -46,7 +46,7 @@ public class ClientYacht extends Observable { private Integer position; private Long estimateTimeAtFinish; - private Boolean sailIn = false; + private Boolean sailIn = true; private Integer currentMarkSeqID = 0; private Long markRoundTime; private Long timeTillNext; diff --git a/src/main/java/seng302/visualiser/GameView3D.java b/src/main/java/seng302/visualiser/GameView3D.java index 8cc6bb9b..73815023 100644 --- a/src/main/java/seng302/visualiser/GameView3D.java +++ b/src/main/java/seng302/visualiser/GameView3D.java @@ -569,6 +569,7 @@ public class GameView3D { } public void setBoatAsPlayer (ClientYacht playerYacht) { + playerYacht.toggleSail(); playerBoatAnimationTimer = new AnimationTimer() { double count = 60; diff --git a/src/main/java/seng302/visualiser/controllers/dialogs/BoatCustomizeController.java b/src/main/java/seng302/visualiser/controllers/dialogs/BoatCustomizeController.java index a418fe41..55f0b7e6 100644 --- a/src/main/java/seng302/visualiser/controllers/dialogs/BoatCustomizeController.java +++ b/src/main/java/seng302/visualiser/controllers/dialogs/BoatCustomizeController.java @@ -115,7 +115,6 @@ public class BoatCustomizeController implements Initializable{ public void setCurrentBoat(String boatType) { Group group = new Group(); this.currentBoat = BoatMeshType.getBoatMeshType(boatType); - System.out.println(boatType.toString()); boatPane.setBackground(new Background(new BackgroundFill(Color.SKYBLUE, CornerRadii.EMPTY, Insets.EMPTY))); boatPane.getChildren().add(group); BoatModel bo = ModelFactory.boatCustomiseView(currentBoat, colorPicker.getValue()); From faeece27ff508bac94aa5ac39a1fc8154672c512 Mon Sep 17 00:00:00 2001 From: Kusal Ekanayake Date: Fri, 22 Sep 2017 13:52:35 +1200 Subject: [PATCH 17/36] Started working on individual boat stats. Already modified turning rate. Need to add a vsual component. #story[1274] --- .../java/seng302/gameServer/GameState.java | 1 + src/main/java/seng302/model/ServerYacht.java | 45 ++++++++++--------- 2 files changed, 26 insertions(+), 20 deletions(-) diff --git a/src/main/java/seng302/gameServer/GameState.java b/src/main/java/seng302/gameServer/GameState.java index 41c619b7..4a93f0d5 100644 --- a/src/main/java/seng302/gameServer/GameState.java +++ b/src/main/java/seng302/gameServer/GameState.java @@ -453,6 +453,7 @@ public class GameState implements Runnable { if (yacht.getPowerUp() != null) { if (yacht.getPowerUp().equals(TokenType.BOOST)) { // TODO: 11/09/17 wmu16 CHANGE THIS TO MAGIC NUMBER + // TODO 22/09/17 kre39 change this magic number to a variable maxBoatSpeed *= 2; } } diff --git a/src/main/java/seng302/model/ServerYacht.java b/src/main/java/seng302/model/ServerYacht.java index 80566afd..f9e028d4 100644 --- a/src/main/java/seng302/model/ServerYacht.java +++ b/src/main/java/seng302/model/ServerYacht.java @@ -8,10 +8,9 @@ import seng302.gameServer.messages.BoatStatus; import seng302.model.mark.Mark; import seng302.model.token.TokenType; import seng302.utilities.GeoUtility; +import seng302.visualiser.fxObjects.assets_3D.BoatMeshType; import java.util.HashMap; -import java.util.Observable; -import java.util.Observer; /** * Yacht class for the racing boat.

Class created to store more variables (eg. boat statuses) @@ -22,10 +21,9 @@ public class ServerYacht { private Logger logger = LoggerFactory.getLogger(ClientYacht.class); - public static final Double TURN_STEP = 5.0; - //Boat info private String boatType; + private Double turn_step; private Integer sourceId; private String hullID; //matches HullNum in the XML spec. private String shortName; @@ -59,7 +57,7 @@ public class ServerYacht { public ServerYacht(String boatType, Integer sourceId, String hullID, String shortName, String boatName, String country) { - this.boatType = boatType; + setBoatType(boatType); this.boatStatus = BoatStatus.PRESTART; this.sourceId = sourceId; this.hullID = hullID; @@ -174,7 +172,7 @@ public class ServerYacht { if (isAuto) { turnTowardsHeading(autoHeading); if (Math.abs(heading - autoHeading) - <= TURN_STEP) { //Cancel when within 1 turn step of target. + <= turn_step) { //Cancel when within 1 turn step of target. isAuto = false; } } @@ -189,20 +187,20 @@ public class ServerYacht { Double normalizedHeading = normalizeHeading(); if (normalizedHeading == 0) { if (lastHeading < 180) { - adjustHeading(-TURN_STEP); + adjustHeading(-turn_step); } else { - adjustHeading(TURN_STEP); + adjustHeading(turn_step); } } else if (normalizedHeading == 180) { if (lastHeading < 180) { - adjustHeading(TURN_STEP); + adjustHeading(turn_step); } else { - adjustHeading(-TURN_STEP); + adjustHeading(-turn_step); } } else if (normalizedHeading < 180) { - adjustHeading(-TURN_STEP); + adjustHeading(-turn_step); } else { - adjustHeading(TURN_STEP); + adjustHeading(turn_step); } } @@ -211,20 +209,20 @@ public class ServerYacht { Double normalizedHeading = normalizeHeading(); if (normalizedHeading == 0) { if (lastHeading < 180) { - adjustHeading(TURN_STEP); + adjustHeading(turn_step); } else { - adjustHeading(-TURN_STEP); + adjustHeading(-turn_step); } } else if (normalizedHeading == 180) { if (lastHeading < 180) { - adjustHeading(-TURN_STEP); + adjustHeading(-turn_step); } else { - adjustHeading(TURN_STEP); + adjustHeading(turn_step); } } else if (normalizedHeading < 180) { - adjustHeading(TURN_STEP); + adjustHeading(turn_step); } else { - adjustHeading(-TURN_STEP); + adjustHeading(-turn_step); } } @@ -268,9 +266,9 @@ public class ServerYacht { private void turnTowardsHeading(Double newHeading) { Double newVal = heading - newHeading; if (Math.floorMod(newVal.longValue(), 360L) > 180) { - adjustHeading(TURN_STEP / 5); + adjustHeading(turn_step / 5); } else { - adjustHeading(-TURN_STEP / 5); + adjustHeading(-turn_step / 5); } } @@ -422,6 +420,13 @@ public class ServerYacht { } public void setBoatType(String boatType) { + if (boatType == BoatMeshType.DINGHY.toString()) { + turn_step = 5.0; + } else if (boatType == BoatMeshType.CAT_ATE_A_MERINGUE.toString()){ + turn_step = 10.0; + } else { + turn_step = 7.0; + } this.boatType = boatType; } From c20c6fb264ff8e3d12f8fdc7b0cff15fe702d23c Mon Sep 17 00:00:00 2001 From: Haoming Yin Date: Fri, 22 Sep 2017 13:53:36 +1200 Subject: [PATCH 18/36] [WIP] Added new toggle for steer turning mode and submit and reset button (restore the setting to default) - minor fix of UI elements to make the font smaller - centred labels and buttons tags: #story[1246] --- .../css/dialogs/KeyBindingDialog.css | 23 +++-- .../views/dialogs/KeyBindingDialog.fxml | 97 ++++++++++++++----- 2 files changed, 88 insertions(+), 32 deletions(-) diff --git a/src/main/resources/css/dialogs/KeyBindingDialog.css b/src/main/resources/css/dialogs/KeyBindingDialog.css index 33a239d3..6f85fd91 100644 --- a/src/main/resources/css/dialogs/KeyBindingDialog.css +++ b/src/main/resources/css/dialogs/KeyBindingDialog.css @@ -6,24 +6,35 @@ JFXButton { -fx-background-color: -fx-pp-light-text-color; -fx-text-fill: -fx-pp-theme-color; - -fx-font-size: 17px; - -fx-effect: -fx-pp-dropshadow-dark; + -fx-font-size: 15px; + -fx-effect: -fx-pp-dropshadow-light; } Label { - -fx-font-size: 25px; + -fx-font-size: 20px; -fx-text-fill: -fx-pp-theme-color; - /*-fx-effect: -fx-pp-dropshadow-dark;*/ + -fx-effect: -fx-pp-dropshadow-light; } JFXButton:hover { - -fx-font-size: 20px; + -fx-font-size: 18px; -fx-background-color: -fx-pp-light-theme-color; -fx-text-fill: -fx-pp-light-text-color; } JFXButton:focused { - -fx-font-size: 20px; + -fx-font-size: 18px; -fx-background-color: -fx-pp-theme-color; -fx-text-fill: -fx-pp-light-text-color; +} + +JFXToggleButton { + -jfx-toggle-color: -fx-pp-theme-color; + -fx-text-fill: -fx-pp-theme-color; +} + +#resetBtn, #confirmBtn { + -fx-background-color: -fx-pp-theme-color; + -fx-text-fill: -fx-pp-front-color; + -fx-effect: -fx-pp-dropshadow-light; } \ No newline at end of file diff --git a/src/main/resources/views/dialogs/KeyBindingDialog.fxml b/src/main/resources/views/dialogs/KeyBindingDialog.fxml index 55a4c44f..29eaa1b3 100644 --- a/src/main/resources/views/dialogs/KeyBindingDialog.fxml +++ b/src/main/resources/views/dialogs/KeyBindingDialog.fxml @@ -2,25 +2,25 @@ + - - - + + - + @@ -29,44 +29,89 @@ + From b05580f018a94b74780e39f4b6e58d31ae4b9d9e Mon Sep 17 00:00:00 2001 From: Kusal Ekanayake Date: Fri, 22 Sep 2017 16:45:10 +1200 Subject: [PATCH 19/36] Worked on making a visual component to the stats. Need to implement acceleration. #story[1274] --- .../java/seng302/gameServer/GameState.java | 3 +- src/main/java/seng302/model/ServerYacht.java | 50 +++++++++++-------- .../dialogs/BoatCustomizeController.java | 39 ++++++++++++++- .../fxObjects/assets_3D/BoatMeshType.java | 14 ++++-- .../fxObjects/assets_3D/BoatModel.java | 7 +++ .../views/dialogs/BoatCustomizeDialog.fxml | 27 ++++++++-- 6 files changed, 108 insertions(+), 32 deletions(-) diff --git a/src/main/java/seng302/gameServer/GameState.java b/src/main/java/seng302/gameServer/GameState.java index 4a93f0d5..cb6d4958 100644 --- a/src/main/java/seng302/gameServer/GameState.java +++ b/src/main/java/seng302/gameServer/GameState.java @@ -449,11 +449,10 @@ public class GameState implements Runnable { private void updateVelocity(ServerYacht yacht) { Double trueWindAngle = Math.abs(windDirection - yacht.getHeading()); Double boatSpeedInKnots = PolarTable.getBoatSpeed(getWindSpeedKnots(), trueWindAngle); - Double maxBoatSpeed = GeoUtility.knotsToMMS(boatSpeedInKnots) * speedMultiplier; + Double maxBoatSpeed = GeoUtility.knotsToMMS(boatSpeedInKnots) * speedMultiplier * yacht.getMaxSpeedMultiplier(); if (yacht.getPowerUp() != null) { if (yacht.getPowerUp().equals(TokenType.BOOST)) { // TODO: 11/09/17 wmu16 CHANGE THIS TO MAGIC NUMBER - // TODO 22/09/17 kre39 change this magic number to a variable maxBoatSpeed *= 2; } } diff --git a/src/main/java/seng302/model/ServerYacht.java b/src/main/java/seng302/model/ServerYacht.java index f9e028d4..6c3ca3dd 100644 --- a/src/main/java/seng302/model/ServerYacht.java +++ b/src/main/java/seng302/model/ServerYacht.java @@ -23,7 +23,8 @@ public class ServerYacht { //Boat info private String boatType; - private Double turn_step; + private Double turnStep = 10.0; + private Double maxSpeedMultiplier = 1.0; private Integer sourceId; private String hullID; //matches HullNum in the XML spec. private String shortName; @@ -172,7 +173,7 @@ public class ServerYacht { if (isAuto) { turnTowardsHeading(autoHeading); if (Math.abs(heading - autoHeading) - <= turn_step) { //Cancel when within 1 turn step of target. + <= turnStep) { //Cancel when within 1 turn step of target. isAuto = false; } } @@ -187,20 +188,20 @@ public class ServerYacht { Double normalizedHeading = normalizeHeading(); if (normalizedHeading == 0) { if (lastHeading < 180) { - adjustHeading(-turn_step); + adjustHeading(-turnStep); } else { - adjustHeading(turn_step); + adjustHeading(turnStep); } } else if (normalizedHeading == 180) { if (lastHeading < 180) { - adjustHeading(turn_step); + adjustHeading(turnStep); } else { - adjustHeading(-turn_step); + adjustHeading(-turnStep); } } else if (normalizedHeading < 180) { - adjustHeading(-turn_step); + adjustHeading(-turnStep); } else { - adjustHeading(turn_step); + adjustHeading(turnStep); } } @@ -209,20 +210,20 @@ public class ServerYacht { Double normalizedHeading = normalizeHeading(); if (normalizedHeading == 0) { if (lastHeading < 180) { - adjustHeading(turn_step); + adjustHeading(turnStep); } else { - adjustHeading(-turn_step); + adjustHeading(-turnStep); } } else if (normalizedHeading == 180) { if (lastHeading < 180) { - adjustHeading(-turn_step); + adjustHeading(-turnStep); } else { - adjustHeading(turn_step); + adjustHeading(turnStep); } } else if (normalizedHeading < 180) { - adjustHeading(turn_step); + adjustHeading(turnStep); } else { - adjustHeading(-turn_step); + adjustHeading(-turnStep); } } @@ -266,9 +267,9 @@ public class ServerYacht { private void turnTowardsHeading(Double newHeading) { Double newVal = heading - newHeading; if (Math.floorMod(newVal.longValue(), 360L) > 180) { - adjustHeading(turn_step / 5); + adjustHeading(turnStep / 5); } else { - adjustHeading(-turn_step / 5); + adjustHeading(-turnStep / 5); } } @@ -420,16 +421,21 @@ public class ServerYacht { } public void setBoatType(String boatType) { - if (boatType == BoatMeshType.DINGHY.toString()) { - turn_step = 5.0; - } else if (boatType == BoatMeshType.CAT_ATE_A_MERINGUE.toString()){ - turn_step = 10.0; - } else { - turn_step = 7.0; + BoatMeshType boatMeshType; + for (BoatMeshType boatMesh: BoatMeshType.values()) { + if (boatType == boatMesh.toString()) { + boatMeshType = boatMesh; + turnStep = boatMeshType.turnStep; + maxSpeedMultiplier = boatMeshType.maxSpeedMultiplier; + } } this.boatType = boatType; } + public Double getMaxSpeedMultiplier() { + return maxSpeedMultiplier; + } + public String getBoatType() { return boatType; } diff --git a/src/main/java/seng302/visualiser/controllers/dialogs/BoatCustomizeController.java b/src/main/java/seng302/visualiser/controllers/dialogs/BoatCustomizeController.java index 55f0b7e6..83b1e520 100644 --- a/src/main/java/seng302/visualiser/controllers/dialogs/BoatCustomizeController.java +++ b/src/main/java/seng302/visualiser/controllers/dialogs/BoatCustomizeController.java @@ -12,6 +12,7 @@ import javafx.fxml.Initializable; import javafx.geometry.Insets; import javafx.scene.Group; import javafx.scene.PointLight; +import javafx.scene.control.ProgressBar; import javafx.scene.layout.Background; import javafx.scene.layout.BackgroundFill; import javafx.scene.layout.CornerRadii; @@ -34,6 +35,12 @@ public class BoatCustomizeController implements Initializable{ @FXML private JFXColorPicker colorPicker; @FXML + private ProgressBar speedBar; + @FXML + private ProgressBar accelBar; + @FXML + private ProgressBar handleBar; + @FXML private JFXButton submitBtn; @FXML private JFXTextField boatName; @@ -49,12 +56,15 @@ public class BoatCustomizeController implements Initializable{ private ClientToServerThread socketThread; private LobbyController lobbyController; private BoatMeshType currentBoat; + private static Double maxSpeedMultiplier = 1.0; + private static Double maxTurnRate = 10.0; + private static Double maxAcceleration = 2.0; @Override public void initialize(URL location, ResourceBundle resources) { socketThread = ViewManager.getInstance().getGameClient().getServerThread(); - + generateMaxStats(); RequiredFieldValidator playerNameReqValidator = new RequiredFieldValidator(); playerNameReqValidator.setMessage("Player name required."); @@ -120,6 +130,8 @@ public class BoatCustomizeController implements Initializable{ BoatModel bo = ModelFactory.boatCustomiseView(currentBoat, colorPicker.getValue()); group.getChildren().add(bo.getAssets()); group.getChildren().add(new PointLight()); + refreshStatBars(bo); + } public void nextBoat(ActionEvent actionEvent) { @@ -130,6 +142,8 @@ public class BoatCustomizeController implements Initializable{ BoatModel bo = ModelFactory.boatCustomiseView(currentBoat, colorPicker.getValue()); group.getChildren().add(bo.getAssets()); group.getChildren().add(new PointLight()); + refreshStatBars(bo); + } public void prevBoat(ActionEvent actionEvent) { @@ -140,6 +154,8 @@ public class BoatCustomizeController implements Initializable{ BoatModel bo = ModelFactory.boatCustomiseView(currentBoat, colorPicker.getValue()); group.getChildren().add(bo.getAssets()); group.getChildren().add(new PointLight()); + refreshStatBars(bo); + } private void RefreshBoat() { @@ -148,5 +164,26 @@ public class BoatCustomizeController implements Initializable{ boatPane.getChildren().add(group); BoatModel bo = ModelFactory.boatCustomiseView(currentBoat, colorPicker.getValue()); group.getChildren().add(bo.getAssets()); + refreshStatBars(bo); + } + + private void generateMaxStats() { + for (BoatMeshType bmt: BoatMeshType.values()) { + if (bmt.turnStep > maxTurnRate) { + maxTurnRate = bmt.turnStep; + } + if (bmt.maxSpeedMultiplier > maxSpeedMultiplier) { + maxSpeedMultiplier = bmt.maxSpeedMultiplier; + } + if (bmt.accelerationMultiplier > maxAcceleration) { + maxAcceleration = bmt.accelerationMultiplier; + } + } + } + + private void refreshStatBars(BoatModel bo) { + speedBar.setProgress((bo.getMeshType().maxSpeedMultiplier) / maxSpeedMultiplier); + accelBar.setProgress(bo.getMeshType().accelerationMultiplier / maxAcceleration); + handleBar.setProgress(bo.getMeshType().turnStep / maxTurnRate); } } diff --git a/src/main/java/seng302/visualiser/fxObjects/assets_3D/BoatMeshType.java b/src/main/java/seng302/visualiser/fxObjects/assets_3D/BoatMeshType.java index 947a63f5..e7c375e5 100644 --- a/src/main/java/seng302/visualiser/fxObjects/assets_3D/BoatMeshType.java +++ b/src/main/java/seng302/visualiser/fxObjects/assets_3D/BoatMeshType.java @@ -7,19 +7,22 @@ package seng302.visualiser.fxObjects.assets_3D; */ public enum BoatMeshType { - DINGHY("dinghy_hull.stl", "dinghy_mast.stl", 1.36653, "dinghy_sail.stl", 1.36653, null, false), + DINGHY("dinghy_hull.stl", "dinghy_mast.stl", 1.36653, "dinghy_sail.stl", 1.36653, null, false, 1.5, 1.0, 5.0), CAT_ATE_A_MERINGUE("catamaran_hull.stl", "catamaran_mast.stl", 0.997, "catamaran_sail.stl", - 0.997, null, false), + 0.997, null, false, 1.0, 1.0, 10.0), PIRATE_SHIP("pirateship_hull.stl", "pirateship_mast.stl", -0.5415, "pirateship_mainsail.stl", - -0.5415, "pirateship_frontsail.stl", true); + -0.5415, "pirateship_frontsail.stl", true, 1.2, 1.0, 7.0); final String hullFile, mastFile, sailFile, jibFile; final double mastOffset, sailOffset; + public final double maxSpeedMultiplier; + public final double accelerationMultiplier; + public final double turnStep; final boolean fixedSail; final static BoatMeshType[] boatTypes = new BoatMeshType[]{DINGHY, CAT_ATE_A_MERINGUE, PIRATE_SHIP}; BoatMeshType(String hullFile, String mastFile, double mastOffset, String sailFile, - double sailOffset, String jibFile, boolean fixedSail) { + double sailOffset, String jibFile, boolean fixedSail, double maxSpeedMultiplier, double accelerationMultiplier, double turnStep) { this.hullFile = hullFile; this.mastFile = mastFile; this.mastOffset = mastOffset; @@ -27,6 +30,9 @@ public enum BoatMeshType { this.sailOffset = sailOffset; this.jibFile = jibFile; this.fixedSail = fixedSail; + this.maxSpeedMultiplier = maxSpeedMultiplier; + this.accelerationMultiplier = accelerationMultiplier; + this.turnStep = turnStep; } public static BoatMeshType getBoatMeshType(String boatType) { diff --git a/src/main/java/seng302/visualiser/fxObjects/assets_3D/BoatModel.java b/src/main/java/seng302/visualiser/fxObjects/assets_3D/BoatModel.java index 0562d4f7..960ceacf 100644 --- a/src/main/java/seng302/visualiser/fxObjects/assets_3D/BoatModel.java +++ b/src/main/java/seng302/visualiser/fxObjects/assets_3D/BoatModel.java @@ -18,6 +18,9 @@ public class BoatModel extends Model { private static final int SAIL_INDEX = 2; private BoatMeshType meshType; + private Double maxSpeedMultiplier; + private Double turnStep; + private Double accelerationMultiplier; /** * Stores a model and it's optional animation. @@ -71,4 +74,8 @@ public class BoatModel extends Model { private MeshView getMeshViewChild(int index) { return (MeshView) assets.getChildren().get(index); } + + public BoatMeshType getMeshType() { + return meshType; + } } \ No newline at end of file diff --git a/src/main/resources/views/dialogs/BoatCustomizeDialog.fxml b/src/main/resources/views/dialogs/BoatCustomizeDialog.fxml index 1d355a33..809b96a2 100644 --- a/src/main/resources/views/dialogs/BoatCustomizeDialog.fxml +++ b/src/main/resources/views/dialogs/BoatCustomizeDialog.fxml @@ -1,5 +1,6 @@ + @@ -24,6 +25,7 @@ + @@ -31,12 +33,12 @@ + + + + + + + + + + + + + + + + + + + From 9f64b2380d4236d948aef9952f1e308b51b2fe0e Mon Sep 17 00:00:00 2001 From: Kusal Ekanayake Date: Fri, 22 Sep 2017 17:28:42 +1200 Subject: [PATCH 20/36] Implemented acceleration and full loading bars. #story[1274] --- src/main/java/seng302/gameServer/GameState.java | 10 +++++----- src/main/java/seng302/model/ServerYacht.java | 9 ++++++++- .../controllers/dialogs/BoatCustomizeController.java | 6 +++--- .../visualiser/fxObjects/assets_3D/BoatMeshType.java | 6 +++--- 4 files changed, 19 insertions(+), 12 deletions(-) diff --git a/src/main/java/seng302/gameServer/GameState.java b/src/main/java/seng302/gameServer/GameState.java index cb6d4958..5818eb66 100644 --- a/src/main/java/seng302/gameServer/GameState.java +++ b/src/main/java/seng302/gameServer/GameState.java @@ -461,17 +461,17 @@ public class GameState implements Runnable { // TODO: 15/08/17 remove magic numbers from these equations. if (yacht.getSailIn()) { if (currentVelocity < maxBoatSpeed - 500) { - yacht.changeVelocity(maxBoatSpeed / 100); + yacht.changeVelocity((maxBoatSpeed / 100) * yacht.getAcceleration()); } else if (currentVelocity > maxBoatSpeed + 500) { - yacht.changeVelocity(-currentVelocity / 200); + yacht.changeVelocity((-currentVelocity / 200) * yacht.getAcceleration()); } else { - yacht.setCurrentVelocity(maxBoatSpeed); + yacht.setCurrentVelocity((maxBoatSpeed) * yacht.getAcceleration()); } } else { if (currentVelocity > 3000) { - yacht.changeVelocity(-currentVelocity / 200); + yacht.changeVelocity((-currentVelocity / 200) * yacht.getAcceleration()); } else if (currentVelocity > 100) { - yacht.changeVelocity(-currentVelocity / 50); + yacht.changeVelocity((-currentVelocity / 50) * yacht.getAcceleration()); } else if (currentVelocity <= 100) { yacht.setCurrentVelocity(0d); } diff --git a/src/main/java/seng302/model/ServerYacht.java b/src/main/java/seng302/model/ServerYacht.java index 6c3ca3dd..29f7eecc 100644 --- a/src/main/java/seng302/model/ServerYacht.java +++ b/src/main/java/seng302/model/ServerYacht.java @@ -11,6 +11,7 @@ import seng302.utilities.GeoUtility; import seng302.visualiser.fxObjects.assets_3D.BoatMeshType; import java.util.HashMap; +import java.util.Objects; /** * Yacht class for the racing boat.

Class created to store more variables (eg. boat statuses) @@ -25,6 +26,7 @@ public class ServerYacht { private String boatType; private Double turnStep = 10.0; private Double maxSpeedMultiplier = 1.0; + private Double acceleration = 1.0; private Integer sourceId; private String hullID; //matches HullNum in the XML spec. private String shortName; @@ -423,10 +425,11 @@ public class ServerYacht { public void setBoatType(String boatType) { BoatMeshType boatMeshType; for (BoatMeshType boatMesh: BoatMeshType.values()) { - if (boatType == boatMesh.toString()) { + if (Objects.equals(boatType, boatMesh.toString())) { boatMeshType = boatMesh; turnStep = boatMeshType.turnStep; maxSpeedMultiplier = boatMeshType.maxSpeedMultiplier; + acceleration = boatMeshType.accelerationMultiplier; } } this.boatType = boatType; @@ -436,6 +439,10 @@ public class ServerYacht { return maxSpeedMultiplier; } + public Double getAcceleration(){ + return acceleration; + } + public String getBoatType() { return boatType; } diff --git a/src/main/java/seng302/visualiser/controllers/dialogs/BoatCustomizeController.java b/src/main/java/seng302/visualiser/controllers/dialogs/BoatCustomizeController.java index 83b1e520..3a71422a 100644 --- a/src/main/java/seng302/visualiser/controllers/dialogs/BoatCustomizeController.java +++ b/src/main/java/seng302/visualiser/controllers/dialogs/BoatCustomizeController.java @@ -56,9 +56,9 @@ public class BoatCustomizeController implements Initializable{ private ClientToServerThread socketThread; private LobbyController lobbyController; private BoatMeshType currentBoat; - private static Double maxSpeedMultiplier = 1.0; - private static Double maxTurnRate = 10.0; - private static Double maxAcceleration = 2.0; + private Double maxSpeedMultiplier = 1.0; + private Double maxTurnRate = 10.0; + private Double maxAcceleration = 1.0; @Override public void initialize(URL location, ResourceBundle resources) { diff --git a/src/main/java/seng302/visualiser/fxObjects/assets_3D/BoatMeshType.java b/src/main/java/seng302/visualiser/fxObjects/assets_3D/BoatMeshType.java index e7c375e5..2dc55d30 100644 --- a/src/main/java/seng302/visualiser/fxObjects/assets_3D/BoatMeshType.java +++ b/src/main/java/seng302/visualiser/fxObjects/assets_3D/BoatMeshType.java @@ -7,11 +7,11 @@ package seng302.visualiser.fxObjects.assets_3D; */ public enum BoatMeshType { - DINGHY("dinghy_hull.stl", "dinghy_mast.stl", 1.36653, "dinghy_sail.stl", 1.36653, null, false, 1.5, 1.0, 5.0), + DINGHY("dinghy_hull.stl", "dinghy_mast.stl", 1.36653, "dinghy_sail.stl", 1.36653, null, false, 1.7, 1.0, 5.0), CAT_ATE_A_MERINGUE("catamaran_hull.stl", "catamaran_mast.stl", 0.997, "catamaran_sail.stl", - 0.997, null, false, 1.0, 1.0, 10.0), + 0.997, null, false, 1.0, 1.4, 10.0), PIRATE_SHIP("pirateship_hull.stl", "pirateship_mast.stl", -0.5415, "pirateship_mainsail.stl", - -0.5415, "pirateship_frontsail.stl", true, 1.2, 1.0, 7.0); + -0.5415, "pirateship_frontsail.stl", true, 1.2, 1.6, 6.0); final String hullFile, mastFile, sailFile, jibFile; final double mastOffset, sailOffset; From 52dc7a956d482dc2459b3b8584a9db3a218eb975 Mon Sep 17 00:00:00 2001 From: Kusal Ekanayake Date: Fri, 22 Sep 2017 17:42:32 +1200 Subject: [PATCH 21/36] Turned handling into a multiplier. #story[1274] --- src/main/java/seng302/model/ServerYacht.java | 4 ++-- .../controllers/dialogs/BoatCustomizeController.java | 2 +- .../visualiser/fxObjects/assets_3D/BoatMeshType.java | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/java/seng302/model/ServerYacht.java b/src/main/java/seng302/model/ServerYacht.java index 29f7eecc..f2965673 100644 --- a/src/main/java/seng302/model/ServerYacht.java +++ b/src/main/java/seng302/model/ServerYacht.java @@ -24,7 +24,7 @@ public class ServerYacht { //Boat info private String boatType; - private Double turnStep = 10.0; + private Double turnStep = 5.0; private Double maxSpeedMultiplier = 1.0; private Double acceleration = 1.0; private Integer sourceId; @@ -427,7 +427,7 @@ public class ServerYacht { for (BoatMeshType boatMesh: BoatMeshType.values()) { if (Objects.equals(boatType, boatMesh.toString())) { boatMeshType = boatMesh; - turnStep = boatMeshType.turnStep; + turnStep = turnStep * boatMeshType.turnStep; maxSpeedMultiplier = boatMeshType.maxSpeedMultiplier; acceleration = boatMeshType.accelerationMultiplier; } diff --git a/src/main/java/seng302/visualiser/controllers/dialogs/BoatCustomizeController.java b/src/main/java/seng302/visualiser/controllers/dialogs/BoatCustomizeController.java index 3a71422a..b587b62d 100644 --- a/src/main/java/seng302/visualiser/controllers/dialogs/BoatCustomizeController.java +++ b/src/main/java/seng302/visualiser/controllers/dialogs/BoatCustomizeController.java @@ -57,7 +57,7 @@ public class BoatCustomizeController implements Initializable{ private LobbyController lobbyController; private BoatMeshType currentBoat; private Double maxSpeedMultiplier = 1.0; - private Double maxTurnRate = 10.0; + private Double maxTurnRate = 1.0; private Double maxAcceleration = 1.0; @Override diff --git a/src/main/java/seng302/visualiser/fxObjects/assets_3D/BoatMeshType.java b/src/main/java/seng302/visualiser/fxObjects/assets_3D/BoatMeshType.java index 2dc55d30..7dc25d38 100644 --- a/src/main/java/seng302/visualiser/fxObjects/assets_3D/BoatMeshType.java +++ b/src/main/java/seng302/visualiser/fxObjects/assets_3D/BoatMeshType.java @@ -7,11 +7,11 @@ package seng302.visualiser.fxObjects.assets_3D; */ public enum BoatMeshType { - DINGHY("dinghy_hull.stl", "dinghy_mast.stl", 1.36653, "dinghy_sail.stl", 1.36653, null, false, 1.7, 1.0, 5.0), + DINGHY("dinghy_hull.stl", "dinghy_mast.stl", 1.36653, "dinghy_sail.stl", 1.36653, null, false, 1.7, 1.0, 1.0), CAT_ATE_A_MERINGUE("catamaran_hull.stl", "catamaran_mast.stl", 0.997, "catamaran_sail.stl", - 0.997, null, false, 1.0, 1.4, 10.0), + 0.997, null, false, 1.0, 1.4, 2.0), PIRATE_SHIP("pirateship_hull.stl", "pirateship_mast.stl", -0.5415, "pirateship_mainsail.stl", - -0.5415, "pirateship_frontsail.stl", true, 1.2, 1.6, 6.0); + -0.5415, "pirateship_frontsail.stl", true, 1.2, 1.6, 1.2); final String hullFile, mastFile, sailFile, jibFile; final double mastOffset, sailOffset; From da8c91f5c1d31bdc0a1eed05cb024705417d7274 Mon Sep 17 00:00:00 2001 From: William Muir Date: Fri, 22 Sep 2017 20:44:06 +1200 Subject: [PATCH 22/36] Review fixes for merge request. PlayerCell now takes in the yacht for construction rather than taking in a whole lot of values extracted from the yacht Reduced boiler plate in BoatCustomizeController #story[1274] --- src/main/java/seng302/model/ServerYacht.java | 2 +- .../controllers/LobbyController.java | 2 +- .../controllers/cells/PlayerCell.java | 13 ++++--- .../dialogs/BoatCustomizeController.java | 37 ++++++++----------- 4 files changed, 24 insertions(+), 30 deletions(-) diff --git a/src/main/java/seng302/model/ServerYacht.java b/src/main/java/seng302/model/ServerYacht.java index 80566afd..99314776 100644 --- a/src/main/java/seng302/model/ServerYacht.java +++ b/src/main/java/seng302/model/ServerYacht.java @@ -20,7 +20,7 @@ import java.util.Observer; */ public class ServerYacht { - private Logger logger = LoggerFactory.getLogger(ClientYacht.class); + private Logger logger = LoggerFactory.getLogger(ServerYacht.class); public static final Double TURN_STEP = 5.0; diff --git a/src/main/java/seng302/visualiser/controllers/LobbyController.java b/src/main/java/seng302/visualiser/controllers/LobbyController.java index 03af2d3a..67b1dfbd 100644 --- a/src/main/java/seng302/visualiser/controllers/LobbyController.java +++ b/src/main/java/seng302/visualiser/controllers/LobbyController.java @@ -205,7 +205,7 @@ public class LobbyController implements Initializable { FXMLLoader loader = new FXMLLoader( getClass().getResource("/views/cells/PlayerCell.fxml")); - loader.setController(new PlayerCell(playerId, yacht.getBoatName(), yacht.getColour(), yacht.getBoatType())); + loader.setController(new PlayerCell(playerId, yacht)); try { pane = loader.load(); diff --git a/src/main/java/seng302/visualiser/controllers/cells/PlayerCell.java b/src/main/java/seng302/visualiser/controllers/cells/PlayerCell.java index 3f434a7f..adba9968 100644 --- a/src/main/java/seng302/visualiser/controllers/cells/PlayerCell.java +++ b/src/main/java/seng302/visualiser/controllers/cells/PlayerCell.java @@ -6,6 +6,7 @@ import javafx.scene.control.Label; import javafx.scene.layout.GridPane; import javafx.scene.layout.Pane; import javafx.scene.paint.Color; +import seng302.model.ClientYacht; import seng302.visualiser.fxObjects.assets_3D.BoatMeshType; import seng302.visualiser.fxObjects.assets_3D.BoatModel; import seng302.visualiser.fxObjects.assets_3D.ModelFactory; @@ -24,13 +25,13 @@ public class PlayerCell { private String name; private Color boatColor; private Integer playerId; - private BoatMeshType boatype; + private BoatMeshType boatType; - public PlayerCell(Integer playerId, String playerName, Color color, String boatType) { + public PlayerCell(Integer playerId, ClientYacht yacht) { this.playerId = playerId; - this.name = playerName; - this.boatColor = color; - this.boatype = BoatMeshType.getBoatMeshType(boatType); + this.name = yacht.getBoatName(); + this.boatColor = yacht.getColour(); + this.boatType = BoatMeshType.getBoatMeshType(yacht.getBoatType()); } public void initialize() { @@ -39,7 +40,7 @@ public class PlayerCell { // Add Rotating Boat to Player Cell with players color on it. Group group = new Group(); boatPane.getChildren().add(group); - BoatModel bo = ModelFactory.boatIconView(this.boatype, this.boatColor); + BoatModel bo = ModelFactory.boatIconView(boatType, boatColor); group.getChildren().add(bo.getAssets()); } diff --git a/src/main/java/seng302/visualiser/controllers/dialogs/BoatCustomizeController.java b/src/main/java/seng302/visualiser/controllers/dialogs/BoatCustomizeController.java index 55f0b7e6..9926cc27 100644 --- a/src/main/java/seng302/visualiser/controllers/dialogs/BoatCustomizeController.java +++ b/src/main/java/seng302/visualiser/controllers/dialogs/BoatCustomizeController.java @@ -6,7 +6,6 @@ import com.jfoenix.controls.JFXTextField; import com.jfoenix.validation.RequiredFieldValidator; import java.net.URL; import java.util.ResourceBundle; -import javafx.event.ActionEvent; import javafx.fxml.FXML; import javafx.fxml.Initializable; import javafx.geometry.Insets; @@ -40,9 +39,8 @@ public class BoatCustomizeController implements Initializable{ @FXML private Pane boatPane; @FXML - void colorChanged(ActionEvent event) { - Color color = colorPicker.getValue(); - RefreshBoat(); + void colorChanged() { + refreshBoat(); } //---------FXML END---------// @@ -62,6 +60,8 @@ public class BoatCustomizeController implements Initializable{ playerNameLengthValidator.setMessage("Player name too long."); boatName.setValidators(playerNameLengthValidator, playerNameReqValidator); + boatPane.setBackground( + new Background(new BackgroundFill(Color.SKYBLUE, CornerRadii.EMPTY, Insets.EMPTY))); submitBtn.setOnMouseReleased(event -> { Sounds.playButtonClick(); @@ -69,7 +69,6 @@ public class BoatCustomizeController implements Initializable{ }); submitBtn.setOnMouseEntered(e -> Sounds.playHoverSound()); - } /** @@ -113,36 +112,30 @@ public class BoatCustomizeController implements Initializable{ } public void setCurrentBoat(String boatType) { - Group group = new Group(); - this.currentBoat = BoatMeshType.getBoatMeshType(boatType); - boatPane.setBackground(new Background(new BackgroundFill(Color.SKYBLUE, CornerRadii.EMPTY, Insets.EMPTY))); - boatPane.getChildren().add(group); - BoatModel bo = ModelFactory.boatCustomiseView(currentBoat, colorPicker.getValue()); - group.getChildren().add(bo.getAssets()); - group.getChildren().add(new PointLight()); + currentBoat = BoatMeshType.getBoatMeshType(boatType); + displayCurrentBoat(); } - public void nextBoat(ActionEvent actionEvent) { - boatPane.getChildren().clear(); - Group group = new Group(); - boatPane.getChildren().add(group); + public void nextBoat() { currentBoat = BoatMeshType.getNextBoatType(currentBoat); - BoatModel bo = ModelFactory.boatCustomiseView(currentBoat, colorPicker.getValue()); - group.getChildren().add(bo.getAssets()); - group.getChildren().add(new PointLight()); + displayCurrentBoat(); } - public void prevBoat(ActionEvent actionEvent) { + public void prevBoat() { + currentBoat = BoatMeshType.getPrevBoatType(currentBoat); + displayCurrentBoat(); + } + + private void displayCurrentBoat() { boatPane.getChildren().clear(); Group group = new Group(); boatPane.getChildren().add(group); - currentBoat = BoatMeshType.getPrevBoatType(currentBoat); BoatModel bo = ModelFactory.boatCustomiseView(currentBoat, colorPicker.getValue()); group.getChildren().add(bo.getAssets()); group.getChildren().add(new PointLight()); } - private void RefreshBoat() { + private void refreshBoat() { boatPane.getChildren().clear(); Group group = new Group(); boatPane.getChildren().add(group); From 22fdf1e4ac29237751557387b12b8ab78e542223 Mon Sep 17 00:00:00 2001 From: William Muir Date: Fri, 22 Sep 2017 21:00:28 +1200 Subject: [PATCH 23/36] Changed the boatType attribute from all around the place from String lit to enum #story[1274] --- src/main/java/seng302/gameServer/GameState.java | 3 ++- .../seng302/gameServer/ServerToClientThread.java | 3 ++- src/main/java/seng302/model/ClientYacht.java | 7 ++++--- src/main/java/seng302/model/ServerYacht.java | 9 +++++---- src/main/java/seng302/utilities/XMLParser.java | 3 ++- src/main/java/seng302/visualiser/GameView3D.java | 2 +- .../visualiser/controllers/cells/PlayerCell.java | 2 +- .../dialogs/BoatCustomizeController.java | 4 ++-- .../fxObjects/assets_3D/BoatMeshType.java | 13 ------------- src/test/java/seng302/model/UpdateYachtTest.java | 7 +++++-- src/test/java/seng302/models/YachtTest.java | 3 ++- .../java/seng302/utilities/BoatMeshTypeTest.java | 7 ------- .../visualiser/map/BoatSailAnimationToggleTest.java | 3 ++- 13 files changed, 28 insertions(+), 38 deletions(-) diff --git a/src/main/java/seng302/gameServer/GameState.java b/src/main/java/seng302/gameServer/GameState.java index 41c619b7..8ff2556c 100644 --- a/src/main/java/seng302/gameServer/GameState.java +++ b/src/main/java/seng302/gameServer/GameState.java @@ -18,6 +18,7 @@ import seng302.utilities.XMLParser; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import java.util.*; +import seng302.visualiser.fxObjects.assets_3D.BoatMeshType; /** * A Static class to hold information about the current state of the game (model) @@ -704,7 +705,7 @@ public class GameState implements Runnable { playerYacht.setBoatColor(yachtColor); } else if (requestType.equals(CustomizeRequestType.SHAPE)) { String type = new String(customizeData); - playerYacht.setBoatType(type); + playerYacht.setBoatType(BoatMeshType.valueOf(type)); } } diff --git a/src/main/java/seng302/gameServer/ServerToClientThread.java b/src/main/java/seng302/gameServer/ServerToClientThread.java index 728e6adb..eb5a9ad0 100644 --- a/src/main/java/seng302/gameServer/ServerToClientThread.java +++ b/src/main/java/seng302/gameServer/ServerToClientThread.java @@ -33,6 +33,7 @@ import seng302.model.stream.packets.PacketType; import seng302.model.stream.packets.StreamPacket; import seng302.model.stream.xml.generator.RaceXMLTemplate; import seng302.utilities.XMLGenerator; +import seng302.visualiser.fxObjects.assets_3D.BoatMeshType; /** * A class describing a single connection to a Client for the purposes of sending and receiving on @@ -125,7 +126,7 @@ public class ServerToClientThread implements Runnable { lName = all.get(ThreadLocalRandom.current().nextInt(0, all.size())); ServerYacht yacht = new ServerYacht( - "DINGHY", sourceId, sourceId.toString(), fName, fName + " " + lName, "NZ" + BoatMeshType.DINGHY, sourceId, sourceId.toString(), fName, fName + " " + lName, "NZ" ); player = new Player(socket, yacht); diff --git a/src/main/java/seng302/model/ClientYacht.java b/src/main/java/seng302/model/ClientYacht.java index 1ebaa3fc..2bc1ed91 100644 --- a/src/main/java/seng302/model/ClientYacht.java +++ b/src/main/java/seng302/model/ClientYacht.java @@ -15,6 +15,7 @@ import javafx.beans.property.ReadOnlyLongWrapper; import javafx.scene.paint.Color; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import seng302.visualiser.fxObjects.assets_3D.BoatMeshType; /** * Yacht class for the racing boat.

Class created to store more variables (eg. boat statuses) @@ -37,7 +38,7 @@ public class ClientYacht extends Observable { private Logger logger = LoggerFactory.getLogger(ClientYacht.class); - private String boatType; + private BoatMeshType boatType; private Integer sourceId; private String hullID; //matches HullNum in the XML spec. private String shortName; @@ -64,7 +65,7 @@ public class ClientYacht extends Observable { private ReadOnlyIntegerWrapper placingProperty = new ReadOnlyIntegerWrapper(); private Color colour; - public ClientYacht(String boatType, Integer sourceId, String hullID, String shortName, + public ClientYacht(BoatMeshType boatType, Integer sourceId, String hullID, String shortName, String boatName, String country) { this.boatType = boatType; this.sourceId = sourceId; @@ -88,7 +89,7 @@ public class ClientYacht extends Observable { super.addObserver(o); } - public String getBoatType() { + public BoatMeshType getBoatType() { return boatType; } diff --git a/src/main/java/seng302/model/ServerYacht.java b/src/main/java/seng302/model/ServerYacht.java index 99314776..e7d936ca 100644 --- a/src/main/java/seng302/model/ServerYacht.java +++ b/src/main/java/seng302/model/ServerYacht.java @@ -12,6 +12,7 @@ import seng302.utilities.GeoUtility; import java.util.HashMap; import java.util.Observable; import java.util.Observer; +import seng302.visualiser.fxObjects.assets_3D.BoatMeshType; /** * Yacht class for the racing boat.

Class created to store more variables (eg. boat statuses) @@ -25,7 +26,7 @@ public class ServerYacht { public static final Double TURN_STEP = 5.0; //Boat info - private String boatType; + private BoatMeshType boatType; private Integer sourceId; private String hullID; //matches HullNum in the XML spec. private String shortName; @@ -57,7 +58,7 @@ public class ServerYacht { private Long powerUpStartTime; - public ServerYacht(String boatType, Integer sourceId, String hullID, String shortName, + public ServerYacht(BoatMeshType boatType, Integer sourceId, String hullID, String shortName, String boatName, String country) { this.boatType = boatType; this.boatStatus = BoatStatus.PRESTART; @@ -421,11 +422,11 @@ public class ServerYacht { return boatColor; } - public void setBoatType(String boatType) { + public void setBoatType(BoatMeshType boatType) { this.boatType = boatType; } - public String getBoatType() { + public BoatMeshType getBoatType() { return boatType; } } diff --git a/src/main/java/seng302/utilities/XMLParser.java b/src/main/java/seng302/utilities/XMLParser.java index 7a8bbac4..71da1248 100644 --- a/src/main/java/seng302/utilities/XMLParser.java +++ b/src/main/java/seng302/utilities/XMLParser.java @@ -18,6 +18,7 @@ import seng302.model.stream.xml.parser.RaceXMLData; import seng302.model.stream.xml.parser.RegattaXMLData; import seng302.model.token.Token; import seng302.model.token.TokenType; +import seng302.visualiser.fxObjects.assets_3D.BoatMeshType; /** * Utilities for parsing XML documents @@ -139,7 +140,7 @@ public class XMLParser { if (currentBoat.getNodeName().equals("Boat")) { // Boat boat = new Boat(currentBoat); ClientYacht yacht = new ClientYacht( - XMLParser.getNodeAttributeString(currentBoat, "Type"), + BoatMeshType.valueOf(XMLParser.getNodeAttributeString(currentBoat, "Type")), XMLParser.getNodeAttributeInt(currentBoat, "SourceID"), XMLParser.getNodeAttributeString(currentBoat, "HullNum"), XMLParser.getNodeAttributeString(currentBoat, "ShortName"), diff --git a/src/main/java/seng302/visualiser/GameView3D.java b/src/main/java/seng302/visualiser/GameView3D.java index 73815023..63d0203d 100644 --- a/src/main/java/seng302/visualiser/GameView3D.java +++ b/src/main/java/seng302/visualiser/GameView3D.java @@ -460,7 +460,7 @@ public class GameView3D { final List wakes = new ArrayList<>(); for (ClientYacht clientYacht : yachts) { Color colour = clientYacht.getColour(); - newBoat = new BoatObject(BoatMeshType.getBoatMeshType(clientYacht.getBoatType())); + newBoat = new BoatObject(clientYacht.getBoatType()); newBoat.setFill(colour); boatObjects.put(clientYacht, newBoat); wakesGroup.getChildren().add(newBoat.getWake()); diff --git a/src/main/java/seng302/visualiser/controllers/cells/PlayerCell.java b/src/main/java/seng302/visualiser/controllers/cells/PlayerCell.java index adba9968..21bd6644 100644 --- a/src/main/java/seng302/visualiser/controllers/cells/PlayerCell.java +++ b/src/main/java/seng302/visualiser/controllers/cells/PlayerCell.java @@ -31,7 +31,7 @@ public class PlayerCell { this.playerId = playerId; this.name = yacht.getBoatName(); this.boatColor = yacht.getColour(); - this.boatType = BoatMeshType.getBoatMeshType(yacht.getBoatType()); + this.boatType = yacht.getBoatType(); } public void initialize() { diff --git a/src/main/java/seng302/visualiser/controllers/dialogs/BoatCustomizeController.java b/src/main/java/seng302/visualiser/controllers/dialogs/BoatCustomizeController.java index 9926cc27..4b02ac9a 100644 --- a/src/main/java/seng302/visualiser/controllers/dialogs/BoatCustomizeController.java +++ b/src/main/java/seng302/visualiser/controllers/dialogs/BoatCustomizeController.java @@ -111,8 +111,8 @@ public class BoatCustomizeController implements Initializable{ this.lobbyController = lobbyController; } - public void setCurrentBoat(String boatType) { - currentBoat = BoatMeshType.getBoatMeshType(boatType); + public void setCurrentBoat(BoatMeshType boatType) { + currentBoat = boatType; displayCurrentBoat(); } diff --git a/src/main/java/seng302/visualiser/fxObjects/assets_3D/BoatMeshType.java b/src/main/java/seng302/visualiser/fxObjects/assets_3D/BoatMeshType.java index 947a63f5..65c9714c 100644 --- a/src/main/java/seng302/visualiser/fxObjects/assets_3D/BoatMeshType.java +++ b/src/main/java/seng302/visualiser/fxObjects/assets_3D/BoatMeshType.java @@ -29,19 +29,6 @@ public enum BoatMeshType { this.fixedSail = fixedSail; } - public static BoatMeshType getBoatMeshType(String boatType) { - switch (boatType){ - case "DINGHY": - return DINGHY; - case "CAT_ATE_A_MERINGUE": - return CAT_ATE_A_MERINGUE; - case "PIRATE_SHIP": - return PIRATE_SHIP; - default: - return DINGHY; - } - } - //TODO kre39 make something not terrible to cycle through boat types public static BoatMeshType getNextBoatType(BoatMeshType boatType) { diff --git a/src/test/java/seng302/model/UpdateYachtTest.java b/src/test/java/seng302/model/UpdateYachtTest.java index 7eaaf990..79c02cb2 100644 --- a/src/test/java/seng302/model/UpdateYachtTest.java +++ b/src/test/java/seng302/model/UpdateYachtTest.java @@ -5,6 +5,7 @@ import org.junit.Before; import org.junit.Test; import seng302.gameServer.GameState; import seng302.utilities.GeoUtility; +import seng302.visualiser.fxObjects.assets_3D.BoatMeshType; import static seng302.gameServer.GameState.checkCollision; @@ -14,8 +15,10 @@ import static seng302.gameServer.GameState.checkCollision; */ public class UpdateYachtTest { - private ServerYacht yacht1 = new ServerYacht("Yacht", 1, "1", "Yacht" + 1, "Yacht" + 1, "Test1"); - private ServerYacht yacht2 = new ServerYacht("Yacht", 2, "2", "Yacht" + 2, "Yacht" + 2, "Test2"); + private ServerYacht yacht1 = new ServerYacht(BoatMeshType.DINGHY, 1, "1", "Yacht" + 1, + "Yacht" + 1, "Test1"); + private ServerYacht yacht2 = new ServerYacht(BoatMeshType.DINGHY, 2, "2", "Yacht" + 2, + "Yacht" + 2, "Test2"); private GeoPoint geoPoint1 = new GeoPoint(50.0, 50.0); private GeoPoint geoPoint2 = GeoUtility.getGeoCoordinate(geoPoint1, 90.0, 50.0); diff --git a/src/test/java/seng302/models/YachtTest.java b/src/test/java/seng302/models/YachtTest.java index 3f342ff5..b73dc61c 100644 --- a/src/test/java/seng302/models/YachtTest.java +++ b/src/test/java/seng302/models/YachtTest.java @@ -4,6 +4,7 @@ import org.junit.AfterClass; import org.junit.BeforeClass; import seng302.gameServer.GameState; import seng302.model.ServerYacht; +import seng302.visualiser.fxObjects.assets_3D.BoatMeshType; public class YachtTest { @@ -17,7 +18,7 @@ public class YachtTest { @BeforeClass public static void setUp() { new GameState("localhost"); - y1 = new ServerYacht("Yacht", 1, "Y1", "Y1", "Yacht 1", "C1"); + y1 = new ServerYacht(BoatMeshType.DINGHY, 1, "Y1", "Y1", "Yacht 1", "C1"); gs = new GameState("localhost"); } diff --git a/src/test/java/seng302/utilities/BoatMeshTypeTest.java b/src/test/java/seng302/utilities/BoatMeshTypeTest.java index baca1b14..743c7f1e 100644 --- a/src/test/java/seng302/utilities/BoatMeshTypeTest.java +++ b/src/test/java/seng302/utilities/BoatMeshTypeTest.java @@ -25,11 +25,4 @@ public class BoatMeshTypeTest { Assert.assertEquals(BoatMeshType.DINGHY, prevBoat); } - @Test - public void testGetBoatMeshType() { - BoatMeshType currentBoat = BoatMeshType.getBoatMeshType("DINGHY"); - Assert.assertEquals(BoatMeshType.DINGHY, currentBoat); - BoatMeshType wrongBoat = BoatMeshType.getBoatMeshType("NOT A REAL BOAT"); - Assert.assertEquals(BoatMeshType.DINGHY, wrongBoat); - } } diff --git a/src/test/java/seng302/visualiser/map/BoatSailAnimationToggleTest.java b/src/test/java/seng302/visualiser/map/BoatSailAnimationToggleTest.java index 70c5c80b..9e95f169 100644 --- a/src/test/java/seng302/visualiser/map/BoatSailAnimationToggleTest.java +++ b/src/test/java/seng302/visualiser/map/BoatSailAnimationToggleTest.java @@ -6,6 +6,7 @@ import static org.junit.Assert.assertTrue; import org.junit.Before; import org.junit.Test; import seng302.model.ClientYacht; +import seng302.visualiser.fxObjects.assets_3D.BoatMeshType; /** * Created by kre39 on 6/08/17. @@ -16,7 +17,7 @@ public class BoatSailAnimationToggleTest { @Before public void setup() throws Exception{ - yacht = new ClientYacht("Yacht", 1, "YACHT", "YAC", "Test Yacht", "NZ"); + yacht = new ClientYacht(BoatMeshType.DINGHY, 1, "YACHT", "YAC", "Test Yacht", "NZ"); } @Test From 957821f1f2d272b0ab19c052ccee733c6a06c0cb Mon Sep 17 00:00:00 2001 From: Zhi You Tan Date: Sat, 23 Sep 2017 01:39:26 +1200 Subject: [PATCH 24/36] [WIP] Created a snackbar for notification. Currently used for keybinding success/fail. Need to show red if fails. #story[1278] --- .../visualiser/controllers/ViewManager.java | 26 ++++++++++++++++++- .../dialogs/KeyBindingDialogController.java | 22 +++++++++++++--- src/main/resources/css/Master.css | 15 +++++++++++ .../views/dialogs/KeyBindingDialog.fxml | 25 +++++++++--------- 4 files changed, 71 insertions(+), 17 deletions(-) diff --git a/src/main/java/seng302/visualiser/controllers/ViewManager.java b/src/main/java/seng302/visualiser/controllers/ViewManager.java index 60e181ae..13fcdd3f 100644 --- a/src/main/java/seng302/visualiser/controllers/ViewManager.java +++ b/src/main/java/seng302/visualiser/controllers/ViewManager.java @@ -4,6 +4,7 @@ import com.jfoenix.controls.JFXButton; import com.jfoenix.controls.JFXDecorator; import com.jfoenix.controls.JFXDialog; import com.jfoenix.controls.JFXDialog.DialogTransition; +import com.jfoenix.controls.JFXSnackbar; import com.jfoenix.svg.SVGGlyph; import java.io.IOException; import java.util.HashMap; @@ -37,6 +38,7 @@ public class ViewManager { private ObservableList playerList; private Logger logger = LoggerFactory.getLogger(ViewManager.class); private Stage stage; + private JFXSnackbar jfxSnackbar; private ViewManager() { properties = new HashMap<>(); @@ -98,6 +100,10 @@ public class ViewManager { gameClient.stopGame(); System.exit(0); }); + + jfxSnackbar = new JFXSnackbar(); + decorator.getChildren().add(jfxSnackbar); + jfxSnackbar.registerSnackbarContainer(decorator); } /** @@ -210,13 +216,22 @@ public class ViewManager { DialogTransition.CENTER); KeyBindingDialogController keyBindingDialogController = dialogContent .getController(); - keyBindingDialogController.init(gameClient.getKeyBind()); + keyBindingDialogController.init(gameClient.getKeyBind(), this); dialog.show(); Sounds.playButtonClick(); } } } + /** + * Show a snackbar at the bottom of the app for 1 second. + * + * @param snackbarText text to be displayed. + */ + public void showSnackbar(String snackbarText) { + jfxSnackbar.show(snackbarText, 1000); + } + /** * Determines if a PC has compatibility with the bonjour protocol for server detection. */ @@ -362,4 +377,13 @@ public class ViewManager { public Stage getStage() { return stage; } + + /** + * Getter to return snackbar object. + * + * @return snackbar object. + */ + public JFXSnackbar getJfxSnackbar() { + return jfxSnackbar; + } } diff --git a/src/main/java/seng302/visualiser/controllers/dialogs/KeyBindingDialogController.java b/src/main/java/seng302/visualiser/controllers/dialogs/KeyBindingDialogController.java index 114b2f74..62be7b1f 100644 --- a/src/main/java/seng302/visualiser/controllers/dialogs/KeyBindingDialogController.java +++ b/src/main/java/seng302/visualiser/controllers/dialogs/KeyBindingDialogController.java @@ -1,20 +1,28 @@ package seng302.visualiser.controllers.dialogs; import com.jfoenix.controls.JFXButton; +import com.jfoenix.controls.JFXDialogLayout; +import java.net.URL; +import java.util.ArrayList; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.ResourceBundle; import javafx.fxml.FXML; import javafx.fxml.Initializable; import javafx.scene.control.Label; import javafx.scene.input.KeyCode; import javafx.scene.input.KeyEvent; - -import java.net.URL; -import java.util.*; import seng302.model.GameClientAction; +import seng302.visualiser.controllers.ViewManager; public class KeyBindingDialogController implements Initializable { //--------FXML BEGIN--------// @FXML + private JFXDialogLayout keyBindDialog; + @FXML private Label keyBindingDialogHeader; @FXML private JFXButton zoomInbtn; @@ -32,6 +40,8 @@ public class KeyBindingDialogController implements Initializable { private JFXButton downwindBtn; //---------FXML END---------// + private ViewManager viewManager; // added viewManager to access snackbar. To be removed. + private Map keys; private List buttons = new ArrayList<>(); private Map keyBind; @@ -48,8 +58,9 @@ public class KeyBindingDialogController implements Initializable { * * @param keyBind a map with GameClientAction and KeyCode pair to be used in GameClient. */ - public void init(Map keyBind) { + public void init(Map keyBind, ViewManager viewManager) { this.keyBind = keyBind; + this.viewManager = viewManager; buttons = new ArrayList<>(); Collections @@ -130,10 +141,13 @@ public class KeyBindingDialogController implements Initializable { keys.replace(button, null); keyBind.replace(buttonAndGameClientActionMap.get(button), null); button.setText(""); + viewManager + .showSnackbar(button.getId() + " can't be set to " + event.getCode().getName()); } else { keys.replace(button, event.getCode()); keyBind.replace(buttonAndGameClientActionMap.get(button), event.getCode()); button.setText(event.getCode().getName()); + viewManager.showSnackbar(button.getId() + " is set to " + event.getCode().getName()); } } } diff --git a/src/main/resources/css/Master.css b/src/main/resources/css/Master.css index 8636a88a..c1d97ddd 100644 --- a/src/main/resources/css/Master.css +++ b/src/main/resources/css/Master.css @@ -99,4 +99,19 @@ .slider .track { -fx-background-color: -fx-pp-dark-text-color; +} + +.jfx-snackbar-content { + -fx-background-color: WHITE; + -fx-padding: 0 5 0 5; + -fx-spacing: 0 5 0 5; + -fx-font-size: 18px; +} + +.jfx-snackbar-toast { + -fx-text-fill: -fx-pp-theme-color; +} + +.jfx-snackbar-action { + -fx-text-fill: #ff4081; } \ No newline at end of file diff --git a/src/main/resources/views/dialogs/KeyBindingDialog.fxml b/src/main/resources/views/dialogs/KeyBindingDialog.fxml index 29eaa1b3..f22f17dc 100644 --- a/src/main/resources/views/dialogs/KeyBindingDialog.fxml +++ b/src/main/resources/views/dialogs/KeyBindingDialog.fxml @@ -9,9 +9,10 @@ - @@ -68,31 +69,31 @@ - - - - - - - From 364264377a0454bde02de48fdb473f75cf175e76 Mon Sep 17 00:00:00 2001 From: Kusal Ekanayake Date: Sat, 23 Sep 2017 15:04:11 +1200 Subject: [PATCH 25/36] Fixed merge errors and reimplemented handling multiplier #story[1274] --- src/main/java/seng302/gameServer/GameState.java | 10 +++++----- src/main/java/seng302/model/ServerYacht.java | 14 +++++++++----- .../visualiser/controllers/LobbyController.java | 2 +- .../dialogs/BoatCustomizeController.java | 12 ++++++------ src/test/java/steps/ToggleSailSteps.java | 1 + 5 files changed, 22 insertions(+), 17 deletions(-) diff --git a/src/main/java/seng302/gameServer/GameState.java b/src/main/java/seng302/gameServer/GameState.java index 9735b0c0..4efb1d23 100644 --- a/src/main/java/seng302/gameServer/GameState.java +++ b/src/main/java/seng302/gameServer/GameState.java @@ -462,17 +462,17 @@ public class GameState implements Runnable { // TODO: 15/08/17 remove magic numbers from these equations. if (yacht.getSailIn()) { if (currentVelocity < maxBoatSpeed - 500) { - yacht.changeVelocity((maxBoatSpeed / 100) * yacht.getAcceleration()); + yacht.changeVelocity((maxBoatSpeed / 100) * yacht.getAccelerationMultiplier()); } else if (currentVelocity > maxBoatSpeed + 500) { - yacht.changeVelocity((-currentVelocity / 200) * yacht.getAcceleration()); + yacht.changeVelocity((-currentVelocity / 200) * yacht.getAccelerationMultiplier()); } else { - yacht.setCurrentVelocity((maxBoatSpeed) * yacht.getAcceleration()); + yacht.setCurrentVelocity((maxBoatSpeed) * yacht.getAccelerationMultiplier()); } } else { if (currentVelocity > 3000) { - yacht.changeVelocity((-currentVelocity / 200) * yacht.getAcceleration()); + yacht.changeVelocity((-currentVelocity / 200) * yacht.getAccelerationMultiplier()); } else if (currentVelocity > 100) { - yacht.changeVelocity((-currentVelocity / 50) * yacht.getAcceleration()); + yacht.changeVelocity((-currentVelocity / 50) * yacht.getAccelerationMultiplier()); } else if (currentVelocity <= 100) { yacht.setCurrentVelocity(0d); } diff --git a/src/main/java/seng302/model/ServerYacht.java b/src/main/java/seng302/model/ServerYacht.java index 73628e33..37065649 100644 --- a/src/main/java/seng302/model/ServerYacht.java +++ b/src/main/java/seng302/model/ServerYacht.java @@ -29,7 +29,8 @@ public class ServerYacht { private BoatMeshType boatType; private Double turnStep = 5.0; private Double maxSpeedMultiplier = 1.0; - private Double acceleration = 1.0; + private Double turnStepMultiplier = 1.0; + private Double accelerationMultiplier = 1.0; private Integer sourceId; private String hullID; //matches HullNum in the XML spec. private String shortName; @@ -133,7 +134,7 @@ public class ServerYacht { * @param amount the amount by which to adjust the boat heading. */ public void adjustHeading(Double amount) { - Double newVal = heading + amount; + Double newVal = heading + (amount * turnStepMultiplier); lastHeading = heading; heading = (double) Math.floorMod(newVal.longValue(), 360L); } @@ -272,7 +273,7 @@ public class ServerYacht { private void turnTowardsHeading(Double newHeading) { Double newVal = heading - newHeading; if (Math.floorMod(newVal.longValue(), 360L) > 180) { - adjustHeading(turnStep / 5); + adjustHeading(turnStep / 5); } else { adjustHeading(-turnStep / 5); } @@ -426,6 +427,9 @@ public class ServerYacht { } public void setBoatType(BoatMeshType boatType) { + this.accelerationMultiplier = boatType.accelerationMultiplier; + this.maxSpeedMultiplier = boatType.maxSpeedMultiplier; + this.turnStepMultiplier = boatType.turnStep; this.boatType = boatType; } @@ -433,8 +437,8 @@ public class ServerYacht { return maxSpeedMultiplier; } - public Double getAcceleration(){ - return acceleration; + public Double getAccelerationMultiplier(){ + return accelerationMultiplier; } diff --git a/src/main/java/seng302/visualiser/controllers/LobbyController.java b/src/main/java/seng302/visualiser/controllers/LobbyController.java index 67b1dfbd..aa8430b8 100644 --- a/src/main/java/seng302/visualiser/controllers/LobbyController.java +++ b/src/main/java/seng302/visualiser/controllers/LobbyController.java @@ -131,7 +131,7 @@ public class LobbyController implements Initializable { .get(ViewManager.getInstance().getGameClient().getServerThread().getClientId()) .getBoatName()); controller.setCurrentBoat(this.playerBoats.get(ViewManager.getInstance().getGameClient().getServerThread().getClientId()) - .getBoatType()); + .getBoatType().toString()); return customizationDialog; } diff --git a/src/main/java/seng302/visualiser/controllers/dialogs/BoatCustomizeController.java b/src/main/java/seng302/visualiser/controllers/dialogs/BoatCustomizeController.java index 5b0cf70b..321f98dd 100644 --- a/src/main/java/seng302/visualiser/controllers/dialogs/BoatCustomizeController.java +++ b/src/main/java/seng302/visualiser/controllers/dialogs/BoatCustomizeController.java @@ -122,7 +122,7 @@ public class BoatCustomizeController implements Initializable{ } public void setCurrentBoat(String boatType) { - currentBoat = boatType; + currentBoat = BoatMeshType.valueOf(boatType); displayCurrentBoat(); refreshStatBars(currentBoat); } @@ -155,7 +155,7 @@ public class BoatCustomizeController implements Initializable{ boatPane.getChildren().add(group); BoatModel bo = ModelFactory.boatCustomiseView(currentBoat, colorPicker.getValue()); group.getChildren().add(bo.getAssets()); - refreshStatBars(bo); + refreshStatBars(currentBoat); } private void generateMaxStats() { @@ -172,9 +172,9 @@ public class BoatCustomizeController implements Initializable{ } } - private void refreshStatBars(BoatModel bo) { - speedBar.setProgress((bo.getMeshType().maxSpeedMultiplier) / maxSpeedMultiplier); - accelBar.setProgress(bo.getMeshType().accelerationMultiplier / maxAcceleration); - handleBar.setProgress(bo.getMeshType().turnStep / maxTurnRate); + private void refreshStatBars(BoatMeshType bo) { + speedBar.setProgress((bo.maxSpeedMultiplier) / maxSpeedMultiplier); + accelBar.setProgress(bo.accelerationMultiplier / maxAcceleration); + handleBar.setProgress(bo.turnStep / maxTurnRate); } } diff --git a/src/test/java/steps/ToggleSailSteps.java b/src/test/java/steps/ToggleSailSteps.java index 4bf20242..5c82a614 100644 --- a/src/test/java/steps/ToggleSailSteps.java +++ b/src/test/java/steps/ToggleSailSteps.java @@ -13,6 +13,7 @@ import seng302.model.ServerYacht; import seng302.visualiser.ClientToServerThread; /** + * * Created by kre39 on 7/08/17. */ public class ToggleSailSteps { From e9b50038a91c922aa146b5439d199f56721698b3 Mon Sep 17 00:00:00 2001 From: Kusal Ekanayake Date: Sat, 23 Sep 2017 15:09:22 +1200 Subject: [PATCH 26/36] Balance changes. Always wanted to use that as a commit message. #story[1274] --- .../visualiser/fxObjects/assets_3D/BoatMeshType.java | 7 +++---- src/test/java/seng302/utilities/BoatMeshTypeTest.java | 4 ++-- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/main/java/seng302/visualiser/fxObjects/assets_3D/BoatMeshType.java b/src/main/java/seng302/visualiser/fxObjects/assets_3D/BoatMeshType.java index 185503fb..292c636a 100644 --- a/src/main/java/seng302/visualiser/fxObjects/assets_3D/BoatMeshType.java +++ b/src/main/java/seng302/visualiser/fxObjects/assets_3D/BoatMeshType.java @@ -7,8 +7,8 @@ package seng302.visualiser.fxObjects.assets_3D; */ public enum BoatMeshType { - DINGHY("dinghy_hull.stl", "dinghy_mast.stl", 1.36653, "dinghy_sail.stl", 1.36653, null, false, 1.7, 1.0, 1.0), - CAT_ATE_A_MERINGUE("catamaran_hull.stl", "catamaran_mast.stl", 0.997, "catamaran_sail.stl", + DINGHY("dinghy_hull.stl", "dinghy_mast.stl", 1.36653, "dinghy_sail.stl", 1.36653, null, false, 1.8, 1.0, 1.0), + CATAMARAN("catamaran_hull.stl", "catamaran_mast.stl", 0.997, "catamaran_sail.stl", 0.997, null, false, 1.0, 1.4, 2.0), PIRATE_SHIP("pirateship_hull.stl", "pirateship_mast.stl", -0.5415, "pirateship_mainsail.stl", -0.5415, "pirateship_frontsail.stl", true, 1.2, 1.6, 1.2); @@ -19,7 +19,7 @@ public enum BoatMeshType { public final double accelerationMultiplier; public final double turnStep; final boolean fixedSail; - final static BoatMeshType[] boatTypes = new BoatMeshType[]{DINGHY, CAT_ATE_A_MERINGUE, PIRATE_SHIP}; + final static BoatMeshType[] boatTypes = new BoatMeshType[]{DINGHY, CATAMARAN, PIRATE_SHIP}; BoatMeshType(String hullFile, String mastFile, double mastOffset, String sailFile, double sailOffset, String jibFile, boolean fixedSail, double maxSpeedMultiplier, double accelerationMultiplier, double turnStep) { @@ -36,7 +36,6 @@ public enum BoatMeshType { } - //TODO kre39 make something not terrible to cycle through boat types public static BoatMeshType getNextBoatType(BoatMeshType boatType) { for (int i = 0; i < boatTypes.length; i++) { if (i == boatTypes.length -1) { diff --git a/src/test/java/seng302/utilities/BoatMeshTypeTest.java b/src/test/java/seng302/utilities/BoatMeshTypeTest.java index 743c7f1e..8f0d30b9 100644 --- a/src/test/java/seng302/utilities/BoatMeshTypeTest.java +++ b/src/test/java/seng302/utilities/BoatMeshTypeTest.java @@ -15,12 +15,12 @@ public class BoatMeshTypeTest { public void testNextBoatMeshType() { BoatMeshType currentBoat = BoatMeshType.DINGHY; BoatMeshType nextBoat = BoatMeshType.getNextBoatType(currentBoat); - Assert.assertEquals(BoatMeshType.CAT_ATE_A_MERINGUE, nextBoat); + Assert.assertEquals(BoatMeshType.CATAMARAN, nextBoat); } @Test public void testPreviousBoatMeshType() { - BoatMeshType currentBoat = BoatMeshType.CAT_ATE_A_MERINGUE; + BoatMeshType currentBoat = BoatMeshType.CATAMARAN; BoatMeshType prevBoat = BoatMeshType.getPrevBoatType(currentBoat); Assert.assertEquals(BoatMeshType.DINGHY, prevBoat); } From 0a885dd8fd339e80332f396952cb480260b48a49 Mon Sep 17 00:00:00 2001 From: Kusal Ekanayake Date: Sat, 23 Sep 2017 15:37:16 +1200 Subject: [PATCH 27/36] Clean up changes #story[1274] --- .../dialogs/BoatCustomizeController.java | 20 +++++++++---------- .../fxObjects/assets_3D/BoatModel.java | 3 --- 2 files changed, 10 insertions(+), 13 deletions(-) diff --git a/src/main/java/seng302/visualiser/controllers/dialogs/BoatCustomizeController.java b/src/main/java/seng302/visualiser/controllers/dialogs/BoatCustomizeController.java index 321f98dd..67fb089a 100644 --- a/src/main/java/seng302/visualiser/controllers/dialogs/BoatCustomizeController.java +++ b/src/main/java/seng302/visualiser/controllers/dialogs/BoatCustomizeController.java @@ -55,14 +55,14 @@ public class BoatCustomizeController implements Initializable{ private LobbyController lobbyController; private BoatMeshType currentBoat; private Double maxSpeedMultiplier = 1.0; - private Double maxTurnRate = 1.0; - private Double maxAcceleration = 1.0; + private Double maxTurnRateMultiplier = 1.0; + private Double maxAccelerationMultiplier = 1.0; @Override public void initialize(URL location, ResourceBundle resources) { socketThread = ViewManager.getInstance().getGameClient().getServerThread(); - generateMaxStats(); + findMaxStats(); RequiredFieldValidator playerNameReqValidator = new RequiredFieldValidator(); playerNameReqValidator.setMessage("Player name required."); @@ -158,23 +158,23 @@ public class BoatCustomizeController implements Initializable{ refreshStatBars(currentBoat); } - private void generateMaxStats() { + private void findMaxStats() { for (BoatMeshType bmt: BoatMeshType.values()) { - if (bmt.turnStep > maxTurnRate) { - maxTurnRate = bmt.turnStep; + if (bmt.turnStep > maxTurnRateMultiplier) { + maxTurnRateMultiplier = bmt.turnStep; } if (bmt.maxSpeedMultiplier > maxSpeedMultiplier) { maxSpeedMultiplier = bmt.maxSpeedMultiplier; } - if (bmt.accelerationMultiplier > maxAcceleration) { - maxAcceleration = bmt.accelerationMultiplier; + if (bmt.accelerationMultiplier > maxAccelerationMultiplier) { + maxAccelerationMultiplier = bmt.accelerationMultiplier; } } } private void refreshStatBars(BoatMeshType bo) { speedBar.setProgress((bo.maxSpeedMultiplier) / maxSpeedMultiplier); - accelBar.setProgress(bo.accelerationMultiplier / maxAcceleration); - handleBar.setProgress(bo.turnStep / maxTurnRate); + accelBar.setProgress(bo.accelerationMultiplier / maxAccelerationMultiplier); + handleBar.setProgress(bo.turnStep / maxTurnRateMultiplier); } } diff --git a/src/main/java/seng302/visualiser/fxObjects/assets_3D/BoatModel.java b/src/main/java/seng302/visualiser/fxObjects/assets_3D/BoatModel.java index 960ceacf..e056b14d 100644 --- a/src/main/java/seng302/visualiser/fxObjects/assets_3D/BoatModel.java +++ b/src/main/java/seng302/visualiser/fxObjects/assets_3D/BoatModel.java @@ -18,9 +18,6 @@ public class BoatModel extends Model { private static final int SAIL_INDEX = 2; private BoatMeshType meshType; - private Double maxSpeedMultiplier; - private Double turnStep; - private Double accelerationMultiplier; /** * Stores a model and it's optional animation. From 4011295b8b97c658f9e8c3886e08c804eb3775cb Mon Sep 17 00:00:00 2001 From: Haoming Yin Date: Sat, 23 Sep 2017 17:52:48 +1200 Subject: [PATCH 28/36] Slightly optimised code style and add more functionality - optimised UI - check conflicts when change key bind if the key has already been in use - abstract keybind as a separate singleton class so all class can access it - [WIP] turning mode is need to be finished #story[1245] --- src/main/java/seng302/model/GameKeyBind.java | 78 +++++++++ .../{GameClientAction.java => KeyAction.java} | 10 +- .../java/seng302/visualiser/GameClient.java | 40 ++--- .../visualiser/controllers/ViewManager.java | 16 +- .../dialogs/KeyBindingDialogController.java | 163 ++++++++---------- .../css/dialogs/KeyBindingDialog.css | 26 +-- .../views/dialogs/KeyBindingDialog.fxml | 55 +++--- 7 files changed, 200 insertions(+), 188 deletions(-) create mode 100644 src/main/java/seng302/model/GameKeyBind.java rename src/main/java/seng302/model/{GameClientAction.java => KeyAction.java} (61%) diff --git a/src/main/java/seng302/model/GameKeyBind.java b/src/main/java/seng302/model/GameKeyBind.java new file mode 100644 index 00000000..e400e6b5 --- /dev/null +++ b/src/main/java/seng302/model/GameKeyBind.java @@ -0,0 +1,78 @@ +package seng302.model; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; +import javafx.scene.input.KeyCode; + +public class GameKeyBind { + + private static GameKeyBind instance; + private Map keyToActionMap; + private Map actionToKeyMap; + private boolean continuouslyTurning; + + + private GameKeyBind() { + setToDefault(); + } + + public void setToDefault() { + actionToKeyMap = new HashMap<>(); + keyToActionMap = new HashMap<>(); + continuouslyTurning = false; + // default key bindings + ArrayList keys = new ArrayList<>(); + keys.add(KeyCode.Z); + keys.add(KeyCode.X); + keys.add(KeyCode.SPACE); + keys.add(KeyCode.SHIFT); + keys.add(KeyCode.ENTER); + keys.add(KeyCode.PAGE_UP); + keys.add(KeyCode.PAGE_DOWN); + for (int i = 0; i < 7; i++) { + actionToKeyMap.put(KeyAction.getType(i + 1), keys.get(i)); + keyToActionMap.put(keys.get(i), KeyAction.getType(i + 1)); + } + } + + public static GameKeyBind getInstance() { + if (instance == null) { + instance = new GameKeyBind(); + } + return instance; + } + + public KeyCode getKeyCode(KeyAction keyAction) { + return instance.actionToKeyMap.get(keyAction); + } + + /** + * Binds a key to a key action + * + * @return true if successfully bind + */ + public boolean bindKeyToAction(KeyCode keyCode, KeyAction keyAction) { + if (instance.keyToActionMap.containsKey(keyCode)) { + // if the key has been bound to other action, return false + return false; + } else { + instance.keyToActionMap.put(keyCode, keyAction); // add key -> action + KeyCode oldKeyCode = instance.actionToKeyMap + .get(keyAction); // get old key for the action + instance.keyToActionMap.remove(oldKeyCode); // remove the old key -> action + instance.actionToKeyMap + .replace(keyAction, keyCode); // replace the old key by the newer one + return true; + } + } + + public void toggleTurningMode() { + continuouslyTurning = !continuouslyTurning; + } + + public boolean isContinuouslyTurning() { + return continuouslyTurning; + } + +} diff --git a/src/main/java/seng302/model/GameClientAction.java b/src/main/java/seng302/model/KeyAction.java similarity index 61% rename from src/main/java/seng302/model/GameClientAction.java rename to src/main/java/seng302/model/KeyAction.java index 21848e74..1b8c2fa1 100644 --- a/src/main/java/seng302/model/GameClientAction.java +++ b/src/main/java/seng302/model/KeyAction.java @@ -3,7 +3,7 @@ package seng302.model; import java.util.HashMap; import java.util.Map; -public enum GameClientAction { +public enum KeyAction { ZOOM_IN(1), ZOOM_OUT(2), VMG(3), @@ -13,19 +13,19 @@ public enum GameClientAction { DOWNWIND(7); private final int type; - private static final Map intToTypeMap = new HashMap<>(); + private static final Map intToTypeMap = new HashMap<>(); static { - for (GameClientAction type : GameClientAction.values()) { + for (KeyAction type : KeyAction.values()) { intToTypeMap.put(type.getValue(), type); } } - GameClientAction(int type) { + KeyAction(int type) { this.type = type; } - public static GameClientAction getType(int value) { + public static KeyAction getType(int value) { return intToTypeMap.get(value); } diff --git a/src/main/java/seng302/visualiser/GameClient.java b/src/main/java/seng302/visualiser/GameClient.java index 9019b53e..d6227d98 100644 --- a/src/main/java/seng302/visualiser/GameClient.java +++ b/src/main/java/seng302/visualiser/GameClient.java @@ -7,7 +7,6 @@ import java.time.ZoneOffset; import java.util.ArrayList; import java.util.Collections; import java.util.Date; -import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.TimeZone; @@ -29,7 +28,8 @@ import seng302.gameServer.messages.BoatAction; import seng302.gameServer.messages.BoatStatus; import seng302.gameServer.messages.YachtEventType; import seng302.model.ClientYacht; -import seng302.model.GameClientAction; +import seng302.model.GameKeyBind; +import seng302.model.KeyAction; import seng302.model.RaceState; import seng302.model.stream.packets.StreamPacket; import seng302.model.stream.parser.MarkRoundingData; @@ -67,7 +67,8 @@ public class GameClient { private RaceViewController raceViewController; private ArrayList finishedBoats = new ArrayList<>(); - private Map keyBind = new HashMap<>(); + + private GameKeyBind gameKeyBind; // all the key binding setting. private ObservableList clientLobbyList = FXCollections.observableArrayList(); @@ -78,21 +79,7 @@ public class GameClient { */ public GameClient(Pane holder) { this.holderPane = holder; - initialiseKeyBind(); - } - - /** - * Initialise default keybind. - */ - private void initialiseKeyBind() { - keyBind = new HashMap<>(); - keyBind.put(GameClientAction.ZOOM_IN, KeyCode.Z); - keyBind.put(GameClientAction.ZOOM_OUT, KeyCode.X); - keyBind.put(GameClientAction.VMG, KeyCode.SPACE); - keyBind.put(GameClientAction.SAILS_STATE, KeyCode.SHIFT); - keyBind.put(GameClientAction.TACK_GYBE, KeyCode.ENTER); - keyBind.put(GameClientAction.UPWIND, KeyCode.PAGE_UP); - keyBind.put(GameClientAction.DOWNWIND, KeyCode.PAGE_DOWN); + this.gameKeyBind = GameKeyBind.getInstance(); } /** @@ -392,13 +379,13 @@ public class GameClient { return; } - if (keyBind.get(GameClientAction.VMG) == e.getCode()) { // align with vmg + if (gameKeyBind.getKeyCode(KeyAction.VMG) == e.getCode()) { // align with vmg socketThread.sendBoatAction(BoatAction.VMG); - } else if (keyBind.get(GameClientAction.UPWIND) == e.getCode()) { // upwind + } else if (gameKeyBind.getKeyCode(KeyAction.UPWIND) == e.getCode()) { // upwind socketThread.sendBoatAction(BoatAction.UPWIND); - } else if (keyBind.get(GameClientAction.DOWNWIND) == e.getCode()) { // downwind + } else if (gameKeyBind.getKeyCode(KeyAction.DOWNWIND) == e.getCode()) { // downwind socketThread.sendBoatAction(BoatAction.DOWNWIND); - } else if (keyBind.get(GameClientAction.TACK_GYBE) == e.getCode()) { // tack/gybe + } else if (gameKeyBind.getKeyCode(KeyAction.TACK_GYBE) == e.getCode()) { // tack/gybe // if chat box is active take whatever is in there and send it to server socketThread.sendBoatAction(BoatAction.TACK_GYBE); } @@ -410,11 +397,11 @@ public class GameClient { return; } - if (keyBind.get(GameClientAction.SAILS_STATE) == e.getCode()) { // sails in/sails out + if (gameKeyBind.getKeyCode(KeyAction.SAILS_STATE) == e.getCode()) { // sails in/sails out socketThread.sendBoatAction(BoatAction.SAILS_IN); allBoatsMap.get(socketThread.getClientId()).toggleSail(); - } else if (keyBind.get(GameClientAction.UPWIND) == e.getCode() - || keyBind.get(GameClientAction.DOWNWIND) == e.getCode()) { + } else if (gameKeyBind.getKeyCode(KeyAction.UPWIND) == e.getCode() + || gameKeyBind.getKeyCode(KeyAction.DOWNWIND) == e.getCode()) { socketThread.sendBoatAction(BoatAction.MAINTAIN_HEADING); } } @@ -473,7 +460,4 @@ public class GameClient { return allBoatsMap; } - public Map getKeyBind() { - return keyBind; - } } diff --git a/src/main/java/seng302/visualiser/controllers/ViewManager.java b/src/main/java/seng302/visualiser/controllers/ViewManager.java index 13fcdd3f..49f76953 100644 --- a/src/main/java/seng302/visualiser/controllers/ViewManager.java +++ b/src/main/java/seng302/visualiser/controllers/ViewManager.java @@ -27,7 +27,6 @@ import seng302.gameServer.ServerAdvertiser; import seng302.utilities.BonjourInstallChecker; import seng302.utilities.Sounds; import seng302.visualiser.GameClient; -import seng302.visualiser.controllers.dialogs.KeyBindingDialogController; public class ViewManager { @@ -137,7 +136,7 @@ public class ViewManager { showKeyBindingDialog(); } } catch (IOException e) { - logger.warn("Could not create Key Binding Dialog."); + logger.warn("Something went wrong when opening key bind dialog"); } })); @@ -214,9 +213,6 @@ public class ViewManager { JFXDialog dialog = new JFXDialog((StackPane) node, dialogContent.load(), DialogTransition.CENTER); - KeyBindingDialogController keyBindingDialogController = dialogContent - .getController(); - keyBindingDialogController.init(gameClient.getKeyBind(), this); dialog.show(); Sounds.playButtonClick(); } @@ -229,7 +225,7 @@ public class ViewManager { * @param snackbarText text to be displayed. */ public void showSnackbar(String snackbarText) { - jfxSnackbar.show(snackbarText, 1000); + jfxSnackbar.show(snackbarText, 1500); } /** @@ -378,12 +374,4 @@ public class ViewManager { return stage; } - /** - * Getter to return snackbar object. - * - * @return snackbar object. - */ - public JFXSnackbar getJfxSnackbar() { - return jfxSnackbar; - } } diff --git a/src/main/java/seng302/visualiser/controllers/dialogs/KeyBindingDialogController.java b/src/main/java/seng302/visualiser/controllers/dialogs/KeyBindingDialogController.java index 62be7b1f..8621fd5b 100644 --- a/src/main/java/seng302/visualiser/controllers/dialogs/KeyBindingDialogController.java +++ b/src/main/java/seng302/visualiser/controllers/dialogs/KeyBindingDialogController.java @@ -2,19 +2,21 @@ package seng302.visualiser.controllers.dialogs; import com.jfoenix.controls.JFXButton; import com.jfoenix.controls.JFXDialogLayout; +import com.jfoenix.controls.JFXToggleButton; import java.net.URL; import java.util.ArrayList; import java.util.Collections; -import java.util.LinkedHashMap; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.ResourceBundle; import javafx.fxml.FXML; import javafx.fxml.Initializable; +import javafx.scene.control.Button; import javafx.scene.control.Label; -import javafx.scene.input.KeyCode; import javafx.scene.input.KeyEvent; -import seng302.model.GameClientAction; +import seng302.model.GameKeyBind; +import seng302.model.KeyAction; import seng302.visualiser.controllers.ViewManager; public class KeyBindingDialogController implements Initializable { @@ -38,116 +40,87 @@ public class KeyBindingDialogController implements Initializable { private JFXButton upwindBtn; @FXML private JFXButton downwindBtn; + @FXML + private JFXButton resetBtn; + @FXML + private JFXButton confirmBtn; + @FXML + private JFXToggleButton turningToggle; //---------FXML END---------// - private ViewManager viewManager; // added viewManager to access snackbar. To be removed. - - private Map keys; + private GameKeyBind gameKeyBind; private List buttons = new ArrayList<>(); - private Map keyBind; - private LinkedHashMap buttonAndGameClientActionMap; + private Map buttonActionMap; @Override public void initialize(URL location, ResourceBundle resources) { - } - - /** - * HAOMING HELP!!! CHANGE FUNCTION NAME PLS :)) - * - * Takes in a map from GameClient and initialise button mapping to the keys. - * - * @param keyBind a map with GameClientAction and KeyCode pair to be used in GameClient. - */ - public void init(Map keyBind, ViewManager viewManager) { - this.keyBind = keyBind; - this.viewManager = viewManager; - + gameKeyBind = GameKeyBind.getInstance(); buttons = new ArrayList<>(); - Collections - .addAll(buttons, zoomInbtn, zoomOutBtn, vmgBtn, sailInOutBtn, tackGybeBtn, upwindBtn, - downwindBtn); + Collections.addAll(buttons, + zoomInbtn, zoomOutBtn, vmgBtn, sailInOutBtn, tackGybeBtn, upwindBtn, downwindBtn); + bindButtonWithAction(); + loadKeyBind(); - initializeKeys(); - initializeButtons(); + buttons.forEach(button -> { + button.setOnMouseEntered(event -> mouseEnter(button)); + button.setOnMousePressed(event -> buttonPressed(button)); + button.setOnMouseExited(event -> mouseExit(button)); + button.setOnKeyPressed(event -> keyPressed(event, button)); + }); + + resetBtn.setOnMouseClicked(event -> { + gameKeyBind.setToDefault(); + loadKeyBind(); + }); } /** - * Initialise default button-keybinding pair if not exist, else rebind the existing keybinding - * to the new button which is created when javafx reinitialise a new controller. + * Set buttons' label according to GameKeyBind settings */ - private void initializeKeys() { - initButtonAndGameClientActionMap(); - initializeDefaultKeys(); + private void loadKeyBind() { + buttons.forEach( + button -> button + .setText(gameKeyBind.getKeyCode(buttonActionMap.get(button)).getName())); } - /** - * HAOMING CHANGE FUNCTION NAME HERE TOO :) OR BETTER, REMOVE THIS FUNCTION - * - * Link buttons and the GameClientAction to be used in accessing keys. - */ - private void initButtonAndGameClientActionMap() { - buttonAndGameClientActionMap = new LinkedHashMap<>(); - buttonAndGameClientActionMap.put(zoomInbtn, GameClientAction.ZOOM_IN); - buttonAndGameClientActionMap.put(zoomOutBtn, GameClientAction.ZOOM_OUT); - buttonAndGameClientActionMap.put(vmgBtn, GameClientAction.VMG); - buttonAndGameClientActionMap.put(sailInOutBtn, GameClientAction.SAILS_STATE); - buttonAndGameClientActionMap.put(tackGybeBtn, GameClientAction.TACK_GYBE); - buttonAndGameClientActionMap.put(upwindBtn, GameClientAction.UPWIND); - buttonAndGameClientActionMap.put(downwindBtn, GameClientAction.DOWNWIND); - } - - /** - * Initialise default keybinding to a button. - */ - private void initializeDefaultKeys() { - keys = new LinkedHashMap<>(); - keys.put(zoomInbtn, keyBind.get(GameClientAction.ZOOM_IN)); - keys.put(zoomOutBtn, keyBind.get(GameClientAction.ZOOM_OUT)); - keys.put(vmgBtn, keyBind.get(GameClientAction.VMG)); - keys.put(sailInOutBtn, keyBind.get(GameClientAction.SAILS_STATE)); - keys.put(tackGybeBtn, keyBind.get(GameClientAction.TACK_GYBE)); - keys.put(upwindBtn, keyBind.get(GameClientAction.UPWIND)); - keys.put(downwindBtn, keyBind.get(GameClientAction.DOWNWIND)); - } - - /** - * Change button text to match current keybinding. Adds focusedProperty and keyPressed listener - * to each buttons. - */ - private void initializeButtons() { - for (JFXButton jfxButton : buttons) { - if (keys.get(jfxButton) != null) { - jfxButton.setText(keys.get(jfxButton).getName()); - } else { - jfxButton.setText(""); - } - jfxButton.focusedProperty().addListener((observable, oldValue, newValue) -> { - jfxButton.setOnKeyPressed(event -> { - event.consume(); - doSomething(event, jfxButton); - }); - }); + private void bindButtonWithAction() { + buttonActionMap = new HashMap<>(); + for (int i = 0; i < 7; i++) { + buttonActionMap.put(buttons.get(i), KeyAction.getType(i + 1)); } } - /** - * HAOMING PLEASE CHANGE THIS DOCSTRING AND THE FUNCTION NAME!!! - * - * @param event BLAH - * @param button BLAH - */ - private void doSomething(KeyEvent event, JFXButton button) { - if (keys.containsValue(event.getCode())) { - keys.replace(button, null); - keyBind.replace(buttonAndGameClientActionMap.get(button), null); - button.setText(""); - viewManager - .showSnackbar(button.getId() + " can't be set to " + event.getCode().getName()); + private void showSnackBar(String message) { + ViewManager.getInstance().showSnackbar(message); + } + + private void mouseEnter(Button button) { + button.setStyle("" + + "-fx-background-color: -fx-pp-theme-color;" + + "-fx-text-fill: -fx-pp-front-color;" + + "-fx-font-size: 15;"); + } + + private void buttonPressed(Button button) { + button.setText("PRESS KEY..."); + } + + private void mouseExit(Button button) { + button.setText(GameKeyBind.getInstance().getKeyCode(buttonActionMap.get(button)).getName()); + button.setStyle("" + + "-fx-background-color: -fx-pp-front-color; " + + "-fx-text-fill: -fx-pp-theme-color; " + + "-fx-font-size: 13;"); + } + + private void keyPressed(KeyEvent event, Button button) { + KeyAction buttonAction = buttonActionMap.get(button); + if (gameKeyBind.bindKeyToAction(event.getCode(), buttonAction)) { + showSnackBar(button.getId() + " is set to " + event.getCode().getName()); + button.setText(gameKeyBind.getKeyCode(buttonAction).getName()); } else { - keys.replace(button, event.getCode()); - keyBind.replace(buttonAndGameClientActionMap.get(button), event.getCode()); - button.setText(event.getCode().getName()); - viewManager.showSnackbar(button.getId() + " is set to " + event.getCode().getName()); + showSnackBar(event.getCode().getName() + " is already in use"); } + event.consume(); } } diff --git a/src/main/resources/css/dialogs/KeyBindingDialog.css b/src/main/resources/css/dialogs/KeyBindingDialog.css index 6f85fd91..51c147f1 100644 --- a/src/main/resources/css/dialogs/KeyBindingDialog.css +++ b/src/main/resources/css/dialogs/KeyBindingDialog.css @@ -1,40 +1,32 @@ #keyBindingDialogHeader { - -fx-font-size: 30px; + -fx-font-size: 27px; -fx-text-fill: -fx-pp-dark-text-color; } JFXButton { -fx-background-color: -fx-pp-light-text-color; -fx-text-fill: -fx-pp-theme-color; - -fx-font-size: 15px; - -fx-effect: -fx-pp-dropshadow-light; + -fx-font-size: 13px; } Label { - -fx-font-size: 20px; + -fx-font-size: 15px; -fx-text-fill: -fx-pp-theme-color; -fx-effect: -fx-pp-dropshadow-light; } -JFXButton:hover { - -fx-font-size: 18px; - -fx-background-color: -fx-pp-light-theme-color; - -fx-text-fill: -fx-pp-light-text-color; -} - -JFXButton:focused { - -fx-font-size: 18px; - -fx-background-color: -fx-pp-theme-color; - -fx-text-fill: -fx-pp-light-text-color; -} - JFXToggleButton { -jfx-toggle-color: -fx-pp-theme-color; -fx-text-fill: -fx-pp-theme-color; } -#resetBtn, #confirmBtn { +#resetBtn { -fx-background-color: -fx-pp-theme-color; -fx-text-fill: -fx-pp-front-color; -fx-effect: -fx-pp-dropshadow-light; + -fx-font-size: 18; +} + +#resetBtn:hover { + -fx-font-size: 20; } \ No newline at end of file diff --git a/src/main/resources/views/dialogs/KeyBindingDialog.fxml b/src/main/resources/views/dialogs/KeyBindingDialog.fxml index f22f17dc..9d7c503a 100644 --- a/src/main/resources/views/dialogs/KeyBindingDialog.fxml +++ b/src/main/resources/views/dialogs/KeyBindingDialog.fxml @@ -9,10 +9,9 @@ - @@ -21,16 +20,17 @@ - - - - - - - - - + + + + + + + + + - + - + maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="45.0" + prefWidth="150.0" text="RESET" GridPane.columnSpan="2" GridPane.halignment="CENTER" + GridPane.rowIndex="9" GridPane.valignment="CENTER"/> From 066557584f3cc7f0d5dd380ab4a3e3d00ec2d621 Mon Sep 17 00:00:00 2001 From: Haoming Yin Date: Sat, 23 Sep 2017 19:37:13 +1200 Subject: [PATCH 29/36] Implemented turning mode toggle - when the mode is toggled, a boat action package will be sent to notify server to change the boat's turning mode - turning mode toggle is now fully functional #story[1245] --- .../java/seng302/gameServer/GameState.java | 37 +++++++-- .../gameServer/messages/BoatAction.java | 4 +- src/main/java/seng302/model/GameKeyBind.java | 4 +- src/main/java/seng302/model/ServerYacht.java | 81 +++++++++++-------- .../java/seng302/visualiser/GameClient.java | 7 ++ .../visualiser/controllers/ViewManager.java | 13 +-- .../dialogs/KeyBindingDialogController.java | 60 ++++++++++++-- .../views/dialogs/KeyBindingDialog.fxml | 8 +- 8 files changed, 152 insertions(+), 62 deletions(-) diff --git a/src/main/java/seng302/gameServer/GameState.java b/src/main/java/seng302/gameServer/GameState.java index 8ff2556c..5e8992ad 100644 --- a/src/main/java/seng302/gameServer/GameState.java +++ b/src/main/java/seng302/gameServer/GameState.java @@ -1,12 +1,35 @@ package seng302.gameServer; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Random; +import java.util.Set; import javafx.scene.paint.Color; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.w3c.dom.Document; import org.xml.sax.InputSource; -import seng302.gameServer.messages.*; -import seng302.model.*; +import seng302.gameServer.messages.BoatAction; +import seng302.gameServer.messages.BoatStatus; +import seng302.gameServer.messages.ChatterMessage; +import seng302.gameServer.messages.CustomizeRequestType; +import seng302.gameServer.messages.MarkRoundingMessage; +import seng302.gameServer.messages.MarkType; +import seng302.gameServer.messages.Message; +import seng302.gameServer.messages.RoundingBoatStatus; +import seng302.gameServer.messages.YachtEventCodeMessage; +import seng302.gameServer.messages.YachtEventType; +import seng302.model.GeoPoint; +import seng302.model.Limit; +import seng302.model.Player; +import seng302.model.PolarTable; +import seng302.model.ServerYacht; import seng302.model.mark.CompoundMark; import seng302.model.mark.Mark; import seng302.model.mark.MarkOrder; @@ -14,10 +37,6 @@ import seng302.model.token.Token; import seng302.model.token.TokenType; import seng302.utilities.GeoUtility; import seng302.utilities.XMLParser; - -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import java.util.*; import seng302.visualiser.fxObjects.assets_3D.BoatMeshType; /** @@ -272,6 +291,12 @@ public class GameState implements Runnable { case DOWNWIND: playerYacht.turnDownwind(); break; + case CONTINUOUSLY_TURNING: + playerYacht.setContinuouslyTurning(true); + break; + case DEFAULT_TURNING: + playerYacht.setContinuouslyTurning(false); + break; } } diff --git a/src/main/java/seng302/gameServer/messages/BoatAction.java b/src/main/java/seng302/gameServer/messages/BoatAction.java index 9003958a..9bd2131f 100644 --- a/src/main/java/seng302/gameServer/messages/BoatAction.java +++ b/src/main/java/seng302/gameServer/messages/BoatAction.java @@ -14,7 +14,9 @@ public enum BoatAction { TACK_GYBE(4), UPWIND(5), DOWNWIND(6), - MAINTAIN_HEADING(7); + MAINTAIN_HEADING(7), + CONTINUOUSLY_TURNING(8), + DEFAULT_TURNING(9); private final int type; private static final Map intToTypeMap = new HashMap<>(); diff --git a/src/main/java/seng302/model/GameKeyBind.java b/src/main/java/seng302/model/GameKeyBind.java index e400e6b5..1c765adc 100644 --- a/src/main/java/seng302/model/GameKeyBind.java +++ b/src/main/java/seng302/model/GameKeyBind.java @@ -10,7 +10,7 @@ public class GameKeyBind { private static GameKeyBind instance; private Map keyToActionMap; private Map actionToKeyMap; - private boolean continuouslyTurning; + private Boolean continuouslyTurning; private GameKeyBind() { @@ -71,7 +71,7 @@ public class GameKeyBind { continuouslyTurning = !continuouslyTurning; } - public boolean isContinuouslyTurning() { + public Boolean isContinuouslyTurning() { return continuouslyTurning; } diff --git a/src/main/java/seng302/model/ServerYacht.java b/src/main/java/seng302/model/ServerYacht.java index e7d936ca..7dce048c 100644 --- a/src/main/java/seng302/model/ServerYacht.java +++ b/src/main/java/seng302/model/ServerYacht.java @@ -1,5 +1,6 @@ package seng302.model; +import java.util.HashMap; import javafx.scene.paint.Color; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -8,10 +9,6 @@ import seng302.gameServer.messages.BoatStatus; import seng302.model.mark.Mark; import seng302.model.token.TokenType; import seng302.utilities.GeoUtility; - -import java.util.HashMap; -import java.util.Observable; -import java.util.Observer; import seng302.visualiser.fxObjects.assets_3D.BoatMeshType; /** @@ -57,6 +54,8 @@ public class ServerYacht { private TokenType powerUp; private Long powerUpStartTime; + //turning mode + private Boolean continuouslyTurning; public ServerYacht(BoatMeshType boatType, Integer sourceId, String hullID, String shortName, String boatName, String country) { @@ -81,6 +80,8 @@ public class ServerYacht { this.hasEnteredRoundingZone = false; this.hasPassedLine = false; this.hasPassedThroughGate = false; + + this.continuouslyTurning = false; } @@ -188,44 +189,52 @@ public class ServerYacht { public void turnUpwind() { disableAutoPilot(); Double normalizedHeading = normalizeHeading(); - if (normalizedHeading == 0) { - if (lastHeading < 180) { - adjustHeading(-TURN_STEP); - } else { - adjustHeading(TURN_STEP); - } - } else if (normalizedHeading == 180) { - if (lastHeading < 180) { - adjustHeading(TURN_STEP); - } else { - adjustHeading(-TURN_STEP); - } - } else if (normalizedHeading < 180) { - adjustHeading(-TURN_STEP); - } else { + if (continuouslyTurning) { adjustHeading(TURN_STEP); + } else { + if (normalizedHeading == 0) { + if (lastHeading < 180) { + adjustHeading(-TURN_STEP); + } else { + adjustHeading(TURN_STEP); + } + } else if (normalizedHeading == 180) { + if (lastHeading < 180) { + adjustHeading(TURN_STEP); + } else { + adjustHeading(-TURN_STEP); + } + } else if (normalizedHeading < 180) { + adjustHeading(-TURN_STEP); + } else { + adjustHeading(TURN_STEP); + } } } public void turnDownwind() { disableAutoPilot(); Double normalizedHeading = normalizeHeading(); - if (normalizedHeading == 0) { - if (lastHeading < 180) { - adjustHeading(TURN_STEP); - } else { - adjustHeading(-TURN_STEP); - } - } else if (normalizedHeading == 180) { - if (lastHeading < 180) { - adjustHeading(-TURN_STEP); - } else { - adjustHeading(TURN_STEP); - } - } else if (normalizedHeading < 180) { - adjustHeading(TURN_STEP); - } else { + if (continuouslyTurning) { adjustHeading(-TURN_STEP); + } else { + if (normalizedHeading == 0) { + if (lastHeading < 180) { + adjustHeading(TURN_STEP); + } else { + adjustHeading(-TURN_STEP); + } + } else if (normalizedHeading == 180) { + if (lastHeading < 180) { + adjustHeading(-TURN_STEP); + } else { + adjustHeading(TURN_STEP); + } + } else if (normalizedHeading < 180) { + adjustHeading(TURN_STEP); + } else { + adjustHeading(-TURN_STEP); + } } } @@ -429,4 +438,8 @@ public class ServerYacht { public BoatMeshType getBoatType() { return boatType; } + + public void setContinuouslyTurning(Boolean continuouslyTurning) { + this.continuouslyTurning = continuouslyTurning; + } } diff --git a/src/main/java/seng302/visualiser/GameClient.java b/src/main/java/seng302/visualiser/GameClient.java index d6227d98..72da551e 100644 --- a/src/main/java/seng302/visualiser/GameClient.java +++ b/src/main/java/seng302/visualiser/GameClient.java @@ -460,4 +460,11 @@ public class GameClient { return allBoatsMap; } + public void sendToggleTurningModePacket() { + if (gameKeyBind.isContinuouslyTurning()) { + socketThread.sendBoatAction(BoatAction.CONTINUOUSLY_TURNING); + } else { + socketThread.sendBoatAction(BoatAction.DEFAULT_TURNING); + } + } } diff --git a/src/main/java/seng302/visualiser/controllers/ViewManager.java b/src/main/java/seng302/visualiser/controllers/ViewManager.java index 49f76953..603e2295 100644 --- a/src/main/java/seng302/visualiser/controllers/ViewManager.java +++ b/src/main/java/seng302/visualiser/controllers/ViewManager.java @@ -27,6 +27,7 @@ import seng302.gameServer.ServerAdvertiser; import seng302.utilities.BonjourInstallChecker; import seng302.utilities.Sounds; import seng302.visualiser.GameClient; +import seng302.visualiser.controllers.dialogs.KeyBindingDialogController; public class ViewManager { @@ -213,6 +214,9 @@ public class ViewManager { JFXDialog dialog = new JFXDialog((StackPane) node, dialogContent.load(), DialogTransition.CENTER); + KeyBindingDialogController keyBindingDialogController = dialogContent + .getController(); + keyBindingDialogController.setGameClient(this.gameClient); dialog.show(); Sounds.playButtonClick(); } @@ -338,15 +342,6 @@ public class ViewManager { scene.setOnKeyPressed(gameClient::keyPressed); scene.setOnKeyReleased(gameClient::keyReleased); - // uncomment to make it full screen -// Rectangle2D visualBounds = Screen.getPrimary().getVisualBounds(); -// stage.setX(visualBounds.getMinX()); -// stage.setY(visualBounds.getMinY()); -// stage.setWidth(visualBounds.getWidth()); -// stage.setHeight(visualBounds.getHeight()); -// stage.setMaximized(true); -// stage.setFullScreen(true); - stage.setMinHeight(500); stage.setMinWidth(800); stage.setTitle("Party Parrots At Sea"); diff --git a/src/main/java/seng302/visualiser/controllers/dialogs/KeyBindingDialogController.java b/src/main/java/seng302/visualiser/controllers/dialogs/KeyBindingDialogController.java index 8621fd5b..7a372d4a 100644 --- a/src/main/java/seng302/visualiser/controllers/dialogs/KeyBindingDialogController.java +++ b/src/main/java/seng302/visualiser/controllers/dialogs/KeyBindingDialogController.java @@ -1,7 +1,6 @@ package seng302.visualiser.controllers.dialogs; import com.jfoenix.controls.JFXButton; -import com.jfoenix.controls.JFXDialogLayout; import com.jfoenix.controls.JFXToggleButton; import java.net.URL; import java.util.ArrayList; @@ -17,16 +16,13 @@ import javafx.scene.control.Label; import javafx.scene.input.KeyEvent; import seng302.model.GameKeyBind; import seng302.model.KeyAction; +import seng302.visualiser.GameClient; import seng302.visualiser.controllers.ViewManager; public class KeyBindingDialogController implements Initializable { //--------FXML BEGIN--------// @FXML - private JFXDialogLayout keyBindDialog; - @FXML - private Label keyBindingDialogHeader; - @FXML private JFXButton zoomInbtn; @FXML private JFXButton zoomOutBtn; @@ -43,7 +39,9 @@ public class KeyBindingDialogController implements Initializable { @FXML private JFXButton resetBtn; @FXML - private JFXButton confirmBtn; + private Label upwindLabel; + @FXML + private Label downwindLabel; @FXML private JFXToggleButton turningToggle; //---------FXML END---------// @@ -51,6 +49,7 @@ public class KeyBindingDialogController implements Initializable { private GameKeyBind gameKeyBind; private List buttons = new ArrayList<>(); private Map buttonActionMap; + private GameClient gameClient; // to send turning mode packet @Override public void initialize(URL location, ResourceBundle resources) { @@ -68,6 +67,8 @@ public class KeyBindingDialogController implements Initializable { button.setOnKeyPressed(event -> keyPressed(event, button)); }); + turningToggle.setOnMouseClicked(event -> toggleTurningMode()); + resetBtn.setOnMouseClicked(event -> { gameKeyBind.setToDefault(); loadKeyBind(); @@ -81,8 +82,19 @@ public class KeyBindingDialogController implements Initializable { buttons.forEach( button -> button .setText(gameKeyBind.getKeyCode(buttonActionMap.get(button)).getName())); + turningToggle.setSelected(gameKeyBind.isContinuouslyTurning()); + if (gameKeyBind.isContinuouslyTurning()) { + upwindLabel.setText("ClOCKWISE TURNING"); + downwindLabel.setText("ANTICLOCKWISE TURNING"); + } else { + upwindLabel.setText("UPWIND"); + downwindLabel.setText("DOWNWIND"); + } } + /** + * Bind buttons with specific action in a map. + */ private void bindButtonWithAction() { buttonActionMap = new HashMap<>(); for (int i = 0; i < 7; i++) { @@ -90,10 +102,17 @@ public class KeyBindingDialogController implements Initializable { } } + /** + * Prompt success / failure message for reassigning key action + */ private void showSnackBar(String message) { ViewManager.getInstance().showSnackbar(message); } + /** + * When a mouse enters the button, the color and font size should change to highlight + * @param button + */ private void mouseEnter(Button button) { button.setStyle("" + "-fx-background-color: -fx-pp-theme-color;" @@ -101,10 +120,20 @@ public class KeyBindingDialogController implements Initializable { + "-fx-font-size: 15;"); } + /** + * Prompt "press key..." to inform users assign a new key bind by pressing a key + * @param button + */ private void buttonPressed(Button button) { button.setText("PRESS KEY..."); } + + /** + * When mouse leaves the button, return the button to the normal state in terms of text, + * color and font size + * @param button + */ private void mouseExit(Button button) { button.setText(GameKeyBind.getInstance().getKeyCode(buttonActionMap.get(button)).getName()); button.setStyle("" @@ -113,6 +142,12 @@ public class KeyBindingDialogController implements Initializable { + "-fx-font-size: 13;"); } + /** + * When a key is pressed, check if the new binding conflicts to any existed settings, if not + * assign the selected action with the new key binding to GameKeyBind. + * @param event + * @param button + */ private void keyPressed(KeyEvent event, Button button) { KeyAction buttonAction = buttonActionMap.get(button); if (gameKeyBind.bindKeyToAction(event.getCode(), buttonAction)) { @@ -123,4 +158,17 @@ public class KeyBindingDialogController implements Initializable { } event.consume(); } + + /** + * When the turning mode is toggled, update gameKeyBind and send out packet to notify the server + */ + private void toggleTurningMode() { + gameKeyBind.toggleTurningMode(); + gameClient.sendToggleTurningModePacket(); + loadKeyBind(); + } + + public void setGameClient(GameClient gameClient) { + this.gameClient = gameClient; + } } diff --git a/src/main/resources/views/dialogs/KeyBindingDialog.fxml b/src/main/resources/views/dialogs/KeyBindingDialog.fxml index 9d7c503a..44c2cfbf 100644 --- a/src/main/resources/views/dialogs/KeyBindingDialog.fxml +++ b/src/main/resources/views/dialogs/KeyBindingDialog.fxml @@ -59,13 +59,13 @@ -

Class created to store more variables (eg. boat statuses) * compared to the XMLParser boat class, also done outside Boat class because some old variables are @@ -197,44 +191,52 @@ public class ServerYacht { public void turnUpwind() { disableAutoPilot(); Double normalizedHeading = normalizeHeading(); - if (normalizedHeading == 0) { - if (lastHeading < 180) { - adjustHeading(-turnStep); - } else { - adjustHeading(turnStep); - } - } else if (normalizedHeading == 180) { - if (lastHeading < 180) { - adjustHeading(turnStep); - } else { - adjustHeading(-turnStep); - } - } else if (normalizedHeading < 180) { - adjustHeading(-turnStep); - } else { + if (continuouslyTurning) { adjustHeading(turnStep); + } else { + if (normalizedHeading == 0) { + if (lastHeading < 180) { + adjustHeading(-turnStep); + } else { + adjustHeading(turnStep); + } + } else if (normalizedHeading == 180) { + if (lastHeading < 180) { + adjustHeading(turnStep); + } else { + adjustHeading(-turnStep); + } + } else if (normalizedHeading < 180) { + adjustHeading(-turnStep); + } else { + adjustHeading(turnStep); + } } } public void turnDownwind() { disableAutoPilot(); Double normalizedHeading = normalizeHeading(); - if (normalizedHeading == 0) { - if (lastHeading < 180) { - adjustHeading(turnStep); - } else { - adjustHeading(-turnStep); - } - } else if (normalizedHeading == 180) { - if (lastHeading < 180) { - adjustHeading(-turnStep); - } else { - adjustHeading(turnStep); - } - } else if (normalizedHeading < 180) { - adjustHeading(turnStep); - } else { + if (continuouslyTurning) { adjustHeading(-turnStep); + } else { + if (normalizedHeading == 0) { + if (lastHeading < 180) { + adjustHeading(turnStep); + } else { + adjustHeading(-turnStep); + } + } else if (normalizedHeading == 180) { + if (lastHeading < 180) { + adjustHeading(-turnStep); + } else { + adjustHeading(turnStep); + } + } else if (normalizedHeading < 180) { + adjustHeading(turnStep); + } else { + adjustHeading(-turnStep); + } } } From 191b818e38c3bf9acdb06754718f63c1066bdcf8 Mon Sep 17 00:00:00 2001 From: Zhi You Tan Date: Mon, 25 Sep 2017 16:31:28 +1300 Subject: [PATCH 34/36] Added close button for keyBindingDialog. - fixed that you cannot bind the key you are using. #story[1278] #pair[hyi25, zyt10] --- src/main/java/seng302/model/GameKeyBind.java | 3 +- .../visualiser/controllers/ViewManager.java | 28 ++++++++++++------- .../dialogs/KeyBindingDialogController.java | 5 ++++ src/main/resources/css/Master.css | 5 ++++ src/main/resources/css/StartScreenView.css | 1 + .../css/dialogs/KeyBindingDialog.css | 10 +++++++ .../views/dialogs/KeyBindingDialog.fxml | 2 ++ 7 files changed, 43 insertions(+), 11 deletions(-) diff --git a/src/main/java/seng302/model/GameKeyBind.java b/src/main/java/seng302/model/GameKeyBind.java index 1c765adc..84ed789e 100644 --- a/src/main/java/seng302/model/GameKeyBind.java +++ b/src/main/java/seng302/model/GameKeyBind.java @@ -53,7 +53,8 @@ public class GameKeyBind { * @return true if successfully bind */ public boolean bindKeyToAction(KeyCode keyCode, KeyAction keyAction) { - if (instance.keyToActionMap.containsKey(keyCode)) { + if (instance.keyToActionMap.containsKey(keyCode) && !(instance.keyToActionMap.get(keyCode) + == keyAction)) { // if the key has been bound to other action, return false return false; } else { diff --git a/src/main/java/seng302/visualiser/controllers/ViewManager.java b/src/main/java/seng302/visualiser/controllers/ViewManager.java index 463b88a5..43f10fb1 100644 --- a/src/main/java/seng302/visualiser/controllers/ViewManager.java +++ b/src/main/java/seng302/visualiser/controllers/ViewManager.java @@ -39,6 +39,7 @@ public class ViewManager { private Logger logger = LoggerFactory.getLogger(ViewManager.class); private Stage stage; private JFXSnackbar jfxSnackbar; + private JFXDialog keyBindingDialog; private ViewManager() { properties = new HashMap<>(); @@ -123,13 +124,14 @@ public class ViewManager { HBox btns = (HBox) decorator.getChildren().get(0); //Create settings button -- [WIP] - JFXButton btnSettings = new JFXButton(); - btnSettings.setText(" Key Bindings"); - btnSettings.setStyle("-fx-text-fill:#fff"); - btnSettings.getStyleClass().add("jfx-decorator-button"); - btnSettings.setCursor(Cursor.HAND); + JFXButton btnKeyBinding = new JFXButton(); + btnKeyBinding.setText(" Key Bindings"); + btnKeyBinding.setStyle("-fx-text-fill:#fff"); + btnKeyBinding.getStyleClass().add("jfx-decorator-button"); + btnKeyBinding.setCursor(Cursor.HAND); + btnKeyBinding.setFocusTraversable(false); - btnSettings.setOnMouseClicked(event -> Platform.runLater(() -> { + btnKeyBinding.setOnMouseClicked(event -> Platform.runLater(() -> { try { if (!checkDialogOpened(decorator.getChildren())) { showKeyBindingDialog(); @@ -145,6 +147,7 @@ public class ViewManager { btnMute.setStyle("-fx-text-fill:#fff"); btnMute.getStyleClass().add("jfx-decorator-button"); btnMute.setCursor(Cursor.HAND); + btnMute.setFocusTraversable(false); //Create Graphics SVGGlyph spacer = new SVGGlyph(0, "SPACER", "", Color.WHITE); @@ -169,12 +172,12 @@ public class ViewManager { btnMute.setGraphic(volumeOn); } - btnSettings.setGraphic(keyBindingGlyph); + btnKeyBinding.setGraphic(keyBindingGlyph); // Add Buttons btns.getChildren().add(0, spacer); btns.getChildren().add(0, btnMute); - btns.getChildren().add(0, btnSettings); + btns.getChildren().add(0, btnKeyBinding); btnMute.setOnAction((action) -> { Sounds.toggleAllSounds(); if (btnMute.getGraphic().equals(volumeOff)) { @@ -209,18 +212,23 @@ public class ViewManager { "/views/dialogs/KeyBindingDialog.fxml")); for (Node node : decorator.getChildren()) { if (node instanceof StackPane) { - JFXDialog dialog = new JFXDialog((StackPane) node, + keyBindingDialog = new JFXDialog((StackPane) node, dialogContent.load(), DialogTransition.CENTER); + KeyBindingDialogController keyBindingDialogController = dialogContent .getController(); keyBindingDialogController.setGameClient(this.gameClient); - dialog.show(); + keyBindingDialog.show(); Sounds.playButtonClick(); } } } + public void closeKeyBindingDialog() { + keyBindingDialog.close(); + } + /** * Show a snackbar at the bottom of the app for 1 second. * diff --git a/src/main/java/seng302/visualiser/controllers/dialogs/KeyBindingDialogController.java b/src/main/java/seng302/visualiser/controllers/dialogs/KeyBindingDialogController.java index 5aa7a097..8b40acea 100644 --- a/src/main/java/seng302/visualiser/controllers/dialogs/KeyBindingDialogController.java +++ b/src/main/java/seng302/visualiser/controllers/dialogs/KeyBindingDialogController.java @@ -23,6 +23,8 @@ public class KeyBindingDialogController implements Initializable { //--------FXML BEGIN--------// @FXML + private Label closeLabel; + @FXML private JFXButton zoomInbtn; @FXML private JFXButton zoomOutBtn; @@ -73,6 +75,8 @@ public class KeyBindingDialogController implements Initializable { gameKeyBind.setToDefault(); loadKeyBind(); }); + + closeLabel.setOnMouseClicked(event -> ViewManager.getInstance().closeKeyBindingDialog()); } /** @@ -171,4 +175,5 @@ public class KeyBindingDialogController implements Initializable { public void setGameClient(GameClient gameClient) { this.gameClient = gameClient; } + } diff --git a/src/main/resources/css/Master.css b/src/main/resources/css/Master.css index 47dd9e83..cb50a645 100644 --- a/src/main/resources/css/Master.css +++ b/src/main/resources/css/Master.css @@ -44,6 +44,11 @@ -fx-border-color: -fx-decorator-color; -fx-border-width: 0 4 4 4; } + +.jfx-decorator-button { + -fx-focus-traversable: false; /* so decorator button will not be focused */ +} + /********* customised scroll bar for scroll pane ***********/ /* The main scrollbar **track** CSS class */ diff --git a/src/main/resources/css/StartScreenView.css b/src/main/resources/css/StartScreenView.css index 04338028..bffc296f 100644 --- a/src/main/resources/css/StartScreenView.css +++ b/src/main/resources/css/StartScreenView.css @@ -2,6 +2,7 @@ -fx-font-size: 20px; -fx-text-fill: -fx-pp-light-text-color; -fx-background-color: -fx-pp-theme-color; + -fx-focus-traversable: false; } .jfx-rippler { diff --git a/src/main/resources/css/dialogs/KeyBindingDialog.css b/src/main/resources/css/dialogs/KeyBindingDialog.css index 3c417968..8d09e130 100644 --- a/src/main/resources/css/dialogs/KeyBindingDialog.css +++ b/src/main/resources/css/dialogs/KeyBindingDialog.css @@ -3,6 +3,16 @@ -fx-text-fill: -fx-pp-dark-text-color; } +#closeLabel { + -fx-font-size: 30; + -fx-text-fill: -fx-pp-dark-text-color; +} + +#closeLabel:hover { + -fx-text-fill: -fx-pp-theme-color; + -fx-font-size: 33; +} + JFXButton { -fx-background-color: -fx-pp-light-text-color; -fx-text-fill: -fx-pp-theme-color; diff --git a/src/main/resources/views/dialogs/KeyBindingDialog.fxml b/src/main/resources/views/dialogs/KeyBindingDialog.fxml index 44c2cfbf..4a677797 100644 --- a/src/main/resources/views/dialogs/KeyBindingDialog.fxml +++ b/src/main/resources/views/dialogs/KeyBindingDialog.fxml @@ -110,6 +110,8 @@ maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="45.0" prefWidth="150.0" text="RESET" GridPane.columnSpan="2" GridPane.halignment="CENTER" GridPane.rowIndex="9" GridPane.valignment="CENTER"/> +