diff --git a/src/main/java/seng302/gameServer/messages/BoatActionMessage.java b/src/main/java/seng302/gameServer/messages/BoatActionMessage.java
index 419bf72e..8fa78195 100644
--- a/src/main/java/seng302/gameServer/messages/BoatActionMessage.java
+++ b/src/main/java/seng302/gameServer/messages/BoatActionMessage.java
@@ -5,19 +5,19 @@ package seng302.gameServer.messages;
*/
public class BoatActionMessage extends Message{
private final MessageType MESSAGE_TYPE = MessageType.BOAT_ACTION;
- private final int MESSAGE_SIZE = 1;
+ private final int MESSAGE_SIZE = 5;
private BoatAction actionType;
- public BoatActionMessage(BoatAction actionType) {
+ public BoatActionMessage(BoatAction actionType, int sourceId) {
this.actionType = actionType;
- setHeader(new Header(MessageType.BOAT_ACTION, 0, (short) 1)); // the second variable is the source id
+ setHeader(new Header(MessageType.BOAT_ACTION, sourceId, (short) MESSAGE_SIZE)); // the second variable is the source id
allocateBuffer();
writeHeaderToBuffer();
// Write message fields
putInt(actionType.getValue(), 1);
+ putInt(sourceId, 4);
writeCRC();
rewind();
-
}
@Override
diff --git a/src/main/java/seng302/gameServer/messages/RegistrationRequestMessage.java b/src/main/java/seng302/gameServer/messages/RegistrationRequestMessage.java
index c7b2a1db..6a8e76ad 100644
--- a/src/main/java/seng302/gameServer/messages/RegistrationRequestMessage.java
+++ b/src/main/java/seng302/gameServer/messages/RegistrationRequestMessage.java
@@ -4,8 +4,8 @@ package seng302.gameServer.messages;
public class RegistrationRequestMessage extends Message {
private static int MESSAGE_LENGTH = 2;
- public RegistrationRequestMessage(ClientType type){
- setHeader(new Header(MessageType.REGISTRATION_REQUEST, 1, (short) getSize()));
+ public RegistrationRequestMessage(ClientType type, int clientID){
+ setHeader(new Header(MessageType.REGISTRATION_REQUEST, clientID, (short) getSize()));
allocateBuffer();
writeHeaderToBuffer();
diff --git a/src/main/java/seng302/model/ClientYacht.java b/src/main/java/seng302/model/ClientYacht.java
index 0b5449ae..06cc1e11 100644
--- a/src/main/java/seng302/model/ClientYacht.java
+++ b/src/main/java/seng302/model/ClientYacht.java
@@ -6,6 +6,7 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Observable;
import java.util.Observer;
+import java.util.Timer;
import javafx.beans.property.ReadOnlyDoubleProperty;
import javafx.beans.property.ReadOnlyDoubleWrapper;
import javafx.beans.property.ReadOnlyIntegerProperty;
@@ -20,6 +21,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import seng302.model.token.TokenType;
import seng302.visualiser.fxObjects.assets_3D.BoatMeshType;
+import seng302.visualiser.fxObjects.assets_3D.BoatObject;
/**
* Yacht class for the racing boat.
Class created to store more variables (eg. boat statuses)
@@ -82,6 +84,10 @@ public class ClientYacht extends Observable {
private Integer boatStatus;
private Double currentVelocity;
+ Timer t;
+
+ private BoatObject boatObject;
+
private List locationListeners = new ArrayList<>();
private List markRoundingListeners = new ArrayList<>();
private List powerUpListeners = new ArrayList<>();
@@ -92,6 +98,7 @@ public class ClientYacht extends Observable {
private ReadOnlyLongWrapper timeTillNextProperty = new ReadOnlyLongWrapper();
private ReadOnlyLongWrapper timeSinceLastMarkProperty = new ReadOnlyLongWrapper();
private ReadOnlyIntegerWrapper placingProperty = new ReadOnlyIntegerWrapper();
+ private ReadOnlyDoubleWrapper headingProperty = new ReadOnlyDoubleWrapper();
private Color colour;
public ClientYacht(BoatMeshType boatType, Integer sourceId, String hullID, String shortName,
@@ -104,6 +111,7 @@ public class ClientYacht extends Observable {
this.country = country;
this.location = new GeoPoint(57.670341, 11.826856);
this.heading = 120.0; //In degrees
+ this.headingProperty.set(this.heading);
this.currentVelocity = 0d;
this.boatStatus = 1;
this.colour = Color.rgb(0, 0, 0, 1.0);
@@ -277,6 +285,7 @@ public class ClientYacht extends Observable {
public void setHeading(Double heading) {
this.heading = heading;
+ setHeadingProperty();
}
@Override
@@ -308,10 +317,10 @@ public class ClientYacht extends Observable {
}
}
-
public void updateLocation(double lat, double lng, double heading, double velocity) {
setLocation(lat, lng);
this.heading = heading;
+ setHeadingProperty();
this.currentVelocity = velocity;
updateVelocityProperty(velocity);
for (YachtLocationListener yll : locationListeners) {
@@ -319,6 +328,10 @@ public class ClientYacht extends Observable {
}
}
+ private void setHeadingProperty() {
+ headingProperty.set(heading);
+ }
+
public void addLocationListener(YachtLocationListener listener) {
locationListeners.add(listener);
}
@@ -359,4 +372,17 @@ public class ClientYacht extends Observable {
public Double getCurrentVelocity() {
return currentVelocity;
}
+
+ public void setBoatObject(BoatObject newBoatObject) {
+ this.boatObject = newBoatObject;
+ }
+
+ public BoatObject getBoatObject() {
+ return this.boatObject;
+ }
+
+ public ReadOnlyDoubleWrapper getHeadingProperty() {
+ return headingProperty;
+ }
+
}
diff --git a/src/main/java/seng302/model/GameKeyBind.java b/src/main/java/seng302/model/GameKeyBind.java
index 1c765adc..5627625c 100644
--- a/src/main/java/seng302/model/GameKeyBind.java
+++ b/src/main/java/seng302/model/GameKeyBind.java
@@ -30,7 +30,12 @@ public class GameKeyBind {
keys.add(KeyCode.ENTER);
keys.add(KeyCode.PAGE_UP);
keys.add(KeyCode.PAGE_DOWN);
- for (int i = 0; i < 7; i++) {
+ keys.add(KeyCode.F1);
+ keys.add(KeyCode.D);
+ keys.add(KeyCode.A);
+ keys.add(KeyCode.W);
+ keys.add(KeyCode.S);
+ for (int i = 0; i < 12; i++) {
actionToKeyMap.put(KeyAction.getType(i + 1), keys.get(i));
keyToActionMap.put(keys.get(i), KeyAction.getType(i + 1));
}
@@ -47,6 +52,10 @@ public class GameKeyBind {
return instance.actionToKeyMap.get(keyAction);
}
+ public KeyAction getKeyAction(KeyCode keyCode) {
+ return instance.keyToActionMap.get(keyCode);
+ }
+
/**
* Binds a key to a key action
*
diff --git a/src/main/java/seng302/model/KeyAction.java b/src/main/java/seng302/model/KeyAction.java
index 1b8c2fa1..51509027 100644
--- a/src/main/java/seng302/model/KeyAction.java
+++ b/src/main/java/seng302/model/KeyAction.java
@@ -10,7 +10,12 @@ public enum KeyAction {
SAILS_STATE(4),
TACK_GYBE(5),
UPWIND(6),
- DOWNWIND(7);
+ DOWNWIND(7),
+ VIEW(8),
+ RIGHT(9),
+ LEFT(10),
+ FORWARD(11),
+ BACKWARD(12);
private final int type;
private static final Map intToTypeMap = new HashMap<>();
diff --git a/src/main/java/seng302/model/ServerYacht.java b/src/main/java/seng302/model/ServerYacht.java
index 7dccdc09..8d77dbda 100644
--- a/src/main/java/seng302/model/ServerYacht.java
+++ b/src/main/java/seng302/model/ServerYacht.java
@@ -160,11 +160,11 @@ public class ServerYacht {
/**
* Enables the boats auto pilot feature, which will move the boat towards a given heading.
*
- * @param thisHeading The heading to move the boat towards.
+ * @param newHeading The heading to move the boat towards.
*/
- private void setAutoPilot(Double thisHeading) {
+ private void setAutoPilot(Double newHeading) {
isAuto = true;
- autoHeading = thisHeading;
+ autoHeading = newHeading;
}
/**
@@ -182,8 +182,9 @@ public class ServerYacht {
if (isAuto) {
turnTowardsHeading(autoHeading);
if (Math.abs(heading - autoHeading)
- <= turnStep) { //Cancel when within 1 turn step of target.
+ <= turnStep*1.5) {
isAuto = false;
+ setHeading(autoHeading);
}
}
}
@@ -269,7 +270,7 @@ public class ServerYacht {
// Take optimal heading and turn into a boat heading rather than a wind heading.
optimalHeading =
- optimalHeading + GameState.getWindDirection();
+ (optimalHeading + GameState.getWindDirection()) % 360;
setAutoPilot(optimalHeading);
}
diff --git a/src/main/java/seng302/utilities/XMLParser.java b/src/main/java/seng302/utilities/XMLParser.java
index 71da1248..912708df 100644
--- a/src/main/java/seng302/utilities/XMLParser.java
+++ b/src/main/java/seng302/utilities/XMLParser.java
@@ -4,12 +4,14 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.Random;
import javafx.scene.paint.Color;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import seng302.model.ClientYacht;
+import seng302.model.Colors;
import seng302.model.Limit;
import seng302.model.mark.CompoundMark;
import seng302.model.mark.Corner;
@@ -139,14 +141,26 @@ public class XMLParser {
Node currentBoat = boatsList.item(i);
if (currentBoat.getNodeName().equals("Boat")) {
// Boat boat = new Boat(currentBoat);
+ BoatMeshType boatMeshType;
+ try {
+ boatMeshType = BoatMeshType.valueOf(XMLParser.getNodeAttributeString(currentBoat, "Type"));
+ } catch (IllegalArgumentException e){
+ boatMeshType = BoatMeshType.DINGHY;
+ }
+ Color color;
+ try {
+ color = Color.web(getNodeAttributeString(currentBoat, "Color"));
+ } catch (NullPointerException npe) {
+ color = Colors.getColor(new Random().nextInt(8));
+ }
ClientYacht yacht = new ClientYacht(
- BoatMeshType.valueOf(XMLParser.getNodeAttributeString(currentBoat, "Type")),
+ boatMeshType,
XMLParser.getNodeAttributeInt(currentBoat, "SourceID"),
XMLParser.getNodeAttributeString(currentBoat, "HullNum"),
XMLParser.getNodeAttributeString(currentBoat, "ShortName"),
XMLParser.getNodeAttributeString(currentBoat, "BoatName"),
XMLParser.getNodeAttributeString(currentBoat, "Country"));
- yacht.setColour(Color.web(getNodeAttributeString(currentBoat, "Color")));
+ yacht.setColour(color);
competingBoats.put(yacht.getSourceId(), yacht);
}
}
@@ -195,17 +209,20 @@ public class XMLParser {
*/
private static List extractTokens(Element docEle) {
List tokens = new ArrayList<>();
- NodeList tokenList = docEle.getElementsByTagName("Tokens").item(0).getChildNodes();
- for (int i = 0; i < tokenList.getLength(); i++) {
- Node tokenNode = tokenList.item(i);
- if (tokenNode.getNodeName().equals("Token")) {
- String tokenType = getNodeAttributeString(tokenNode, "TokenType");
- Double lat = getNodeAttributeDouble(tokenNode, "TargetLat");
- Double lng = getNodeAttributeDouble(tokenNode, "TargetLng");
- tokens.add(new Token(TokenType.valueOf(tokenType), lat, lng));
+ try {
+ NodeList tokenList = docEle.getElementsByTagName("Tokens").item(0).getChildNodes();
+ for (int i = 0; i < tokenList.getLength(); i++) {
+ Node tokenNode = tokenList.item(i);
+ if (tokenNode.getNodeName().equals("Token")) {
+ String tokenType = getNodeAttributeString(tokenNode, "TokenType");
+ Double lat = getNodeAttributeDouble(tokenNode, "TargetLat");
+ Double lng = getNodeAttributeDouble(tokenNode, "TargetLng");
+ tokens.add(new Token(TokenType.valueOf(tokenType), lat, lng));
+ }
}
+ } catch (NullPointerException npe) {
+ return new ArrayList<>();
}
-
return tokens;
}
diff --git a/src/main/java/seng302/visualiser/ClientToServerThread.java b/src/main/java/seng302/visualiser/ClientToServerThread.java
index e53aed22..fe32ed85 100644
--- a/src/main/java/seng302/visualiser/ClientToServerThread.java
+++ b/src/main/java/seng302/visualiser/ClientToServerThread.java
@@ -175,7 +175,7 @@ public class ClientToServerThread implements Runnable {
* Sends a request to the server asking for a source ID
*/
private void sendRegistrationRequest() {
- RegistrationRequestMessage requestMessage = new RegistrationRequestMessage(ClientType.PLAYER);
+ RegistrationRequestMessage requestMessage = new RegistrationRequestMessage(ClientType.PLAYER, clientId);
try {
os.write(requestMessage.getBuffer());
@@ -193,7 +193,6 @@ public class ClientToServerThread implements Runnable {
private void processRegistrationResponse(StreamPacket packet){
int sourceId = (int) Message.bytesToLong(Arrays.copyOfRange(packet.getPayload(), 0, 3));
int statusCode = (int) Message.bytesToLong(Arrays.copyOfRange(packet.getPayload(), 4,5));
-
RegistrationResponseStatus status = RegistrationResponseStatus.getResponseStatus(statusCode);
if (status.equals(RegistrationResponseStatus.SUCCESS_PLAYING)){
@@ -243,7 +242,7 @@ public class ClientToServerThread implements Runnable {
new TimerTask() {
@Override
public void run() {
- sendBoatActionMessage(new BoatActionMessage(BoatAction.DOWNWIND));
+ sendBoatActionMessage(new BoatActionMessage(BoatAction.DOWNWIND, clientId));
}
}, 0, PACKET_SENDING_INTERVAL_MS
);
@@ -256,14 +255,14 @@ public class ClientToServerThread implements Runnable {
new TimerTask() {
@Override
public void run() {
- sendBoatActionMessage(new BoatActionMessage(BoatAction.UPWIND));
+ sendBoatActionMessage(new BoatActionMessage(BoatAction.UPWIND, clientId));
}
}, 0, PACKET_SENDING_INTERVAL_MS
);
}
break;
default:
- sendBoatActionMessage(new BoatActionMessage(actionType));
+ sendBoatActionMessage(new BoatActionMessage(actionType, clientId));
break;
}
}
diff --git a/src/main/java/seng302/visualiser/GameClient.java b/src/main/java/seng302/visualiser/GameClient.java
index e964914c..a4117d81 100644
--- a/src/main/java/seng302/visualiser/GameClient.java
+++ b/src/main/java/seng302/visualiser/GameClient.java
@@ -16,8 +16,6 @@ import javafx.application.Platform;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXMLLoader;
-import javafx.scene.control.Alert;
-import javafx.scene.control.Alert.AlertType;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.Pane;
@@ -50,6 +48,7 @@ import seng302.utilities.XMLParser;
import seng302.visualiser.controllers.LobbyController;
import seng302.visualiser.controllers.RaceViewController;
import seng302.visualiser.controllers.ViewManager;
+import seng302.visualiser.controllers.dialogs.PopupDialogController;
/**
* This class is a client side instance of a yacht racing game in JavaFX. The game is instantiated
@@ -173,10 +172,12 @@ public class GameClient {
private void showConnectionError (String message) {
Platform.runLater(() -> {
- Alert alert = new Alert(AlertType.ERROR);
- alert.setHeaderText("Connection Error");
- alert.setContentText(message);
- alert.showAndWait();
+ PopupDialogController controller = ViewManager.getInstance().showPopupDialog();
+ controller.setHeader("Oops");
+ controller.setContent(message);
+ controller.setOptionButtonText("GO HOME");
+ controller
+ .setOptionButtonEventHandler(event -> ViewManager.getInstance().goToStartView());
});
}
@@ -397,7 +398,11 @@ public class GameClient {
}
if (gameKeyBind.getKeyCode(KeyAction.SAILS_STATE) == e.getCode()) { // sails in/sails out
- socketThread.sendBoatAction(BoatAction.SAILS_IN);
+ if (allBoatsMap.get(socketThread.getClientId()).getSailIn()) {
+ socketThread.sendBoatAction(BoatAction.SAILS_OUT);
+ } else {
+ socketThread.sendBoatAction(BoatAction.SAILS_IN);
+ }
allBoatsMap.get(socketThread.getClientId()).toggleSail();
} else if (gameKeyBind.getKeyCode(KeyAction.UPWIND) == e.getCode()
|| gameKeyBind.getKeyCode(KeyAction.DOWNWIND) == e.getCode()) {
diff --git a/src/main/java/seng302/visualiser/GameView3D.java b/src/main/java/seng302/visualiser/GameView3D.java
index 3c662dfb..027e92ad 100644
--- a/src/main/java/seng302/visualiser/GameView3D.java
+++ b/src/main/java/seng302/visualiser/GameView3D.java
@@ -1,6 +1,7 @@
package seng302.visualiser;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
@@ -9,6 +10,7 @@ import javafx.animation.AnimationTimer;
import javafx.application.Platform;
import javafx.geometry.Point2D;
import javafx.geometry.Point3D;
+import javafx.scene.Camera;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.PerspectiveCamera;
@@ -21,7 +23,9 @@ import javafx.scene.transform.Scale;
import javafx.scene.transform.Translate;
import seng302.gameServer.messages.RoundingSide;
import seng302.model.ClientYacht;
+import seng302.model.GameKeyBind;
import seng302.model.GeoPoint;
+import seng302.model.KeyAction;
import seng302.model.Limit;
import seng302.model.mark.CompoundMark;
import seng302.model.mark.Corner;
@@ -30,8 +34,12 @@ import seng302.model.token.Token;
import seng302.model.token.TokenType;
import seng302.utilities.GeoUtility;
import seng302.utilities.Sounds;
+import seng302.visualiser.cameras.ChaseCamera;
+import seng302.visualiser.cameras.IsometricCamera;
+import seng302.visualiser.cameras.RaceCamera;
+import seng302.visualiser.cameras.TopDownCamera;
+import seng302.visualiser.controllers.ViewManager;
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;
@@ -43,18 +51,19 @@ import seng302.visualiser.fxObjects.assets_3D.ModelType;
public class GameView3D {
-
private final double FOV = 60;
- private final double DEFAULT_CAMERA_DEPTH = -125;
private final double DEFAULT_CAMERA_X = 0;
private final double DEFAULT_CAMERA_Y = 155;
private Group root3D;
private SubScene view;
- // ParallelCamera camera;
- private PerspectiveCamera camera;
private Group gameObjects;
+ // Cameras
+ private PerspectiveCamera isometricCam;
+ private PerspectiveCamera topDownCam;
+ private PerspectiveCamera chaseCam;
+
private double bufferSize = 0;
private double canvasWidth = 200;
private double canvasHeight = 200;
@@ -89,20 +98,22 @@ public class GameView3D {
}
public GameView3D () {
- camera = new PerspectiveCamera(true);
- camera.getTransforms().addAll(
- new Translate(DEFAULT_CAMERA_X,DEFAULT_CAMERA_Y, DEFAULT_CAMERA_DEPTH)
- );
- camera.setFarClip(600);
- camera.setNearClip(0.1);
- camera.setFieldOfView(FOV);
+ isometricCam = new IsometricCamera(DEFAULT_CAMERA_X, DEFAULT_CAMERA_Y);
+ topDownCam = new TopDownCamera();
+ chaseCam = new ChaseCamera();
+
+ for (PerspectiveCamera pc : Arrays.asList(isometricCam, topDownCam, chaseCam)) {
+ pc.setFarClip(600);
+ pc.setNearClip(0.1);
+ pc.setFieldOfView(FOV);
+ }
+
gameObjects = new Group();
- root3D = new Group(camera, gameObjects);
+ root3D = new Group(isometricCam, gameObjects);
view = new SubScene(
root3D, 1000, 1000, true, SceneAntialiasing.BALANCED
);
- view.setCamera(camera);
- camera.getTransforms().add(new Rotate(30, new Point3D(1,0,0)));
+ view.setCamera(isometricCam);
gameObjects.getChildren().addAll(
ModelFactory.importModel(ModelType.OCEAN).getAssets(),
@@ -337,7 +348,6 @@ public class GameView3D {
* it to distanceScaleFactor Returns the max horizontal distance of the map.
*/
private double scaleRaceExtremities() {
-
double vertAngle = Math.abs(
GeoUtility.getBearingRad(minLatPoint, maxLatPoint)
);
@@ -405,40 +415,45 @@ public class GameView3D {
}
public void cameraMovement(KeyEvent event) {
- switch (event.getCode()) {
- case NUMPAD8:
- camera.getTransforms().addAll(new Rotate(0.5, new Point3D(1,0,0)));
+ GameKeyBind keyBinds = GameKeyBind.getInstance();
+ KeyAction keyPressed = keyBinds.getKeyAction(event.getCode());
+ switch (keyPressed) {
+ case ZOOM_IN:
+ ((RaceCamera) view.getCamera()).zoomIn();
break;
- case NUMPAD2:
- camera.getTransforms().addAll(new Rotate(-0.5, new Point3D(1,0,0)));
+ case ZOOM_OUT:
+ ((RaceCamera) view.getCamera()).zoomOut();
break;
- case NUMPAD4:
- camera.getTransforms().addAll(new Rotate(-0.5, new Point3D(0,1,0)));
+ case FORWARD:
+ ((RaceCamera) view.getCamera()).panUp();
break;
- case NUMPAD6:
- camera.getTransforms().addAll(new Rotate(0.5, new Point3D(0,1,0)));
+ case BACKWARD:
+ ((RaceCamera) view.getCamera()).panDown();
break;
- case Z:
- camera.getTransforms().addAll(new Translate(0, 0, 1.5));
+ case LEFT:
+ ((RaceCamera) view.getCamera()).panLeft();
break;
- case X:
- camera.getTransforms().addAll(new Translate(0, 0, -1.5));
+ case RIGHT:
+ ((RaceCamera) view.getCamera()).panRight();
break;
- case W:
- camera.getTransforms().addAll(new Translate(0, -1, 0));
- break;
- case S:
- camera.getTransforms().addAll(new Translate(0, 1, 0));
- break;
- case A:
- camera.getTransforms().addAll(new Translate(-1, 0, 0));
- break;
- case D:
- camera.getTransforms().addAll(new Translate(1, 0, 0));
+ case VIEW:
+ toggleCamera();
break;
}
}
+ private void toggleCamera() {
+ Camera currCamera = view.getCamera();
+
+ if (currCamera.equals(isometricCam)) {
+ view.setCamera(topDownCam);
+ } else if (currCamera.equals(topDownCam)) {
+ view.setCamera(chaseCam);
+ } else {
+ view.setCamera(isometricCam);
+ }
+ }
+
/**
* Rescales the race to the size of the window.
*
@@ -469,6 +484,12 @@ public class GameView3D {
boatObjectGroup.getChildren().add(newBoat);
clientYacht.addLocationListener(this::updateBoatLocation);
clientYacht.addColorChangeListener(this::updateBoatColor);
+
+ if (clientYacht.getSourceId().equals(
+ ViewManager.getInstance().getGameClient().getServerThread().getClientId())) {
+ ((ChaseCamera) chaseCam).setPlayerBoat(newBoat);
+ ((TopDownCamera) topDownCam).setPlayerBoat(newBoat);
+ }
}
Platform.runLater(() -> {
gameObjects.getChildren().addAll(wakes);
diff --git a/src/main/java/seng302/visualiser/cameras/ChaseCamera.java b/src/main/java/seng302/visualiser/cameras/ChaseCamera.java
new file mode 100644
index 00000000..0647a473
--- /dev/null
+++ b/src/main/java/seng302/visualiser/cameras/ChaseCamera.java
@@ -0,0 +1,130 @@
+package seng302.visualiser.cameras;
+
+import java.util.Arrays;
+import javafx.beans.property.DoubleProperty;
+import javafx.collections.ObservableList;
+import javafx.geometry.Point3D;
+import javafx.scene.PerspectiveCamera;
+import javafx.scene.transform.Rotate;
+import javafx.scene.transform.Transform;
+import javafx.scene.transform.Translate;
+import seng302.visualiser.fxObjects.assets_3D.BoatObject;
+
+
+public class ChaseCamera extends PerspectiveCamera implements RaceCamera {
+
+ private final Double VERTICAL_PAN_LIMIT = 20.0;
+ private final Double NEAR_ZOOM_LIMIT = -15.0;
+ private final Double FAR_ZOOM_LIMIT = -125.0;
+
+ private final Double ZOOM_STEP = 2.5;
+ private final Double PAN_STEP = 2.5;
+
+ private ObservableList transforms;
+ private BoatObject playerBoat;
+
+ private Double zoomFactor;
+ private Double horizontalPan;
+ private Double verticalPan;
+
+
+ public ChaseCamera() {
+ super(true);
+ transforms = this.getTransforms();
+
+ zoomFactor = (FAR_ZOOM_LIMIT + NEAR_ZOOM_LIMIT) / 2.0;
+ this.horizontalPan = 0.0;
+ this.verticalPan = 0.0;
+ }
+
+ /**
+ * Sets a player boat object to observe and update the camera with.
+ *
+ * @param playerBoat The player boat to be observed.
+ */
+ public void setPlayerBoat(BoatObject playerBoat) {
+ this.playerBoat = playerBoat;
+
+ for (DoubleProperty o : Arrays
+ .asList(playerBoat.getRotationProperty(), playerBoat.layoutYProperty(),
+ playerBoat.layoutXProperty())) {
+ o.addListener((obs, oldVal, newVal) -> repositionCamera());
+ }
+ }
+
+ /**
+ * Moves the camera to a new position after some change (Zooming or Panning)
+ */
+ private void repositionCamera() {
+ transforms.clear();
+ transforms.addAll(
+ new Translate(playerBoat.getLayoutX(), playerBoat.getLayoutY(), 0),
+ new Rotate(playerBoat.getRotationProperty().getValue() + horizontalPan,
+ new Point3D(0, 0, 1)),
+ new Rotate(60 + verticalPan, new Point3D(1, 0, 0)),
+ new Translate(0, 0, zoomFactor)
+ );
+ }
+
+ /**
+ * Adjusts the zoom amount (camera depth) by some adjustment value
+ * @param adjustment the adjustment to be made to the camera
+ */
+ private void adjustZoomFactor(Double adjustment) {
+ if (zoomFactor + adjustment < NEAR_ZOOM_LIMIT && zoomFactor + adjustment > FAR_ZOOM_LIMIT) {
+ zoomFactor = zoomFactor + adjustment;
+ repositionCamera();
+ }
+ }
+
+ /**
+ * Adjusts the Vertical Panning of the Camera
+ * @param adjustment the adjustment to be made to the camera
+ */
+ private void adjustVerticalPan(Double adjustment) {
+ if (verticalPan + adjustment >= -VERTICAL_PAN_LIMIT
+ && verticalPan + adjustment <= VERTICAL_PAN_LIMIT) {
+ verticalPan += adjustment;
+ repositionCamera();
+ }
+ }
+
+ /**
+ * Adjusts the Horizontal Panning of the Camera.
+ * @param adjustment the adjustment to be made to the camera
+ */
+ private void adjustHorizontalPan(Double adjustment) {
+ this.horizontalPan += adjustment;
+ repositionCamera();
+ }
+
+ @Override
+ public void zoomIn() {
+ adjustZoomFactor(ZOOM_STEP);
+ }
+
+ @Override
+ public void zoomOut() {
+ adjustZoomFactor(-ZOOM_STEP);
+ }
+
+ @Override
+ public void panLeft() {
+ adjustHorizontalPan(-PAN_STEP);
+ }
+
+ @Override
+ public void panRight() {
+ adjustHorizontalPan(PAN_STEP);
+ }
+
+ @Override
+ public void panUp() {
+ adjustVerticalPan(-PAN_STEP);
+ }
+
+ @Override
+ public void panDown() {
+ adjustVerticalPan(PAN_STEP);
+ }
+}
diff --git a/src/main/java/seng302/visualiser/cameras/IsometricCamera.java b/src/main/java/seng302/visualiser/cameras/IsometricCamera.java
new file mode 100644
index 00000000..85a0e502
--- /dev/null
+++ b/src/main/java/seng302/visualiser/cameras/IsometricCamera.java
@@ -0,0 +1,113 @@
+package seng302.visualiser.cameras;
+
+import javafx.collections.ObservableList;
+import javafx.geometry.Point3D;
+import javafx.scene.PerspectiveCamera;
+import javafx.scene.transform.Rotate;
+import javafx.scene.transform.Transform;
+import javafx.scene.transform.Translate;
+
+public class IsometricCamera extends PerspectiveCamera implements RaceCamera {
+
+ private final Double MIN_X = -120.0;
+ private final Double MAX_X = 125.0;
+
+ private final Double MIN_Y = 40.0;
+ private final Double MAX_Y = 170.0;
+
+ private final Double PAN_LIMIT = 160.0;
+ private final Double NEAR_ZOOM_LIMIT = -50.0;
+ private final Double FAR_ZOOM_LIMIT = -160.0;
+
+ private Double horizontalPan;
+ private Double verticalPan;
+ private Double zoomFactor;
+
+ private ObservableList transforms;
+
+ public IsometricCamera(Double cameraStartX, Double cameraStartY) {
+ super(true);
+ transforms = this.getTransforms();
+
+ zoomFactor = (FAR_ZOOM_LIMIT + NEAR_ZOOM_LIMIT) / 2.0;
+ horizontalPan = cameraStartX;
+ verticalPan = cameraStartY;
+
+ updateCamera();
+ }
+
+ /**
+ * Moves the camera to a new position after some change (Zooming or Panning)
+ */
+ private void updateCamera() {
+ transforms.clear();
+ transforms.addAll(
+ new Translate(horizontalPan, verticalPan, zoomFactor),
+ new Rotate(30, new Point3D(1, 0, 0))
+ );
+ }
+
+ /**
+ * Adjusts the zoom amount (camera depth) by some adjustment value
+ *
+ * @param adjustment the adjustment to be made to the camera
+ */
+ private void adjustZoomFactor(Double adjustment) {
+ if (zoomFactor + adjustment < NEAR_ZOOM_LIMIT && zoomFactor + adjustment > FAR_ZOOM_LIMIT) {
+ zoomFactor = zoomFactor + adjustment;
+ updateCamera();
+ }
+ }
+
+ /**
+ * Adjusts the Vertical Panning of the Camera
+ * @param adjustment the adjustment to be made to the camera
+ */
+ private void adjustVerticalPan(Double adjustment) {
+ if (verticalPan + adjustment >= MIN_Y && verticalPan + adjustment <= MAX_Y) {
+ verticalPan += adjustment;
+ updateCamera();
+ }
+ }
+
+ /**
+ * Adjusts the Horizontal Panning of the Camera.
+ * @param adjustment the adjustment to be made to the camera
+ */
+ private void adjustHorizontalPan(Double adjustment) {
+ if (horizontalPan + adjustment >= MIN_X && horizontalPan + adjustment <= MIN_Y) {
+ this.horizontalPan += adjustment;
+ updateCamera();
+ }
+ }
+
+ @Override
+ public void zoomIn() {
+ adjustZoomFactor(-2.5);
+ }
+
+ @Override
+ public void zoomOut() {
+ adjustZoomFactor(2.5);
+ }
+
+ @Override
+ public void panLeft() {
+ adjustHorizontalPan(-2.5);
+ }
+
+ @Override
+ public void panRight() {
+ adjustHorizontalPan(2.5);
+ }
+
+ @Override
+ public void panUp() {
+ adjustVerticalPan(-2.5);
+ }
+
+ @Override
+ public void panDown() {
+ adjustVerticalPan(2.5);
+ }
+}
diff --git a/src/main/java/seng302/visualiser/cameras/RaceCamera.java b/src/main/java/seng302/visualiser/cameras/RaceCamera.java
new file mode 100644
index 00000000..7416ae4a
--- /dev/null
+++ b/src/main/java/seng302/visualiser/cameras/RaceCamera.java
@@ -0,0 +1,18 @@
+package seng302.visualiser.cameras;
+
+
+public interface RaceCamera {
+
+ void zoomIn();
+
+ void zoomOut();
+
+ void panLeft();
+
+ void panRight();
+
+ void panUp();
+
+ void panDown();
+
+}
diff --git a/src/main/java/seng302/visualiser/cameras/TopDownCamera.java b/src/main/java/seng302/visualiser/cameras/TopDownCamera.java
new file mode 100644
index 00000000..72d58707
--- /dev/null
+++ b/src/main/java/seng302/visualiser/cameras/TopDownCamera.java
@@ -0,0 +1,123 @@
+package seng302.visualiser.cameras;
+
+
+import java.util.Arrays;
+import javafx.beans.property.DoubleProperty;
+import javafx.collections.ObservableList;
+import javafx.scene.PerspectiveCamera;
+import javafx.scene.transform.Transform;
+import javafx.scene.transform.Translate;
+import seng302.visualiser.fxObjects.assets_3D.BoatObject;
+
+public class TopDownCamera extends PerspectiveCamera implements RaceCamera {
+
+ private final Double PAN_LIMIT = 30.0;
+ private final Double NEAR_ZOOM_LIMIT = -30.0;
+ private final Double FAR_ZOOM_LIMIT = -130.0;
+ private final Double ZOOM_STEP = 2.5;
+
+ private ObservableList transforms;
+ private BoatObject playerBoat;
+
+ private Double zoomFactor;
+ private Double horizontalPan;
+ private Double verticalPan;
+
+ public TopDownCamera() {
+ super(true);
+ transforms = this.getTransforms();
+
+ zoomFactor = (FAR_ZOOM_LIMIT + NEAR_ZOOM_LIMIT) / 2.0;
+ horizontalPan = 0.0;
+ verticalPan = 0.0;
+ }
+
+ /**
+ * Sets a player boat object to observe and update the camera with.
+ *
+ * @param playerBoat The player boat to be observed.
+ */
+ public void setPlayerBoat(BoatObject playerBoat) {
+ this.playerBoat = playerBoat;
+
+ for (DoubleProperty o : Arrays
+ .asList(playerBoat.layoutXProperty(), playerBoat.layoutYProperty())) {
+ o.addListener((obs, oldVal, newVal) -> updateCamera());
+ }
+ }
+
+ /**
+ * Moves the camera to a new position after some change (Zooming or Panning)
+ */
+ private void updateCamera() {
+ transforms.clear();
+ transforms.addAll(
+ new Translate(playerBoat.getLayoutX() + horizontalPan,
+ playerBoat.getLayoutY() + verticalPan, zoomFactor)
+ );
+ }
+
+ /**
+ * Adjusts the zoom amount (camera depth) by some adjustment value
+ * @param adjustment the adjustment to be made to the camera
+ */
+ private void adjustZoomFactor(Double adjustment) {
+ if (zoomFactor + adjustment < NEAR_ZOOM_LIMIT && zoomFactor + adjustment > FAR_ZOOM_LIMIT) {
+ zoomFactor = zoomFactor + adjustment;
+ updateCamera();
+ }
+ }
+
+ /**
+ * Adjusts the Vertical Panning of the Camera
+ * @param adjustment the adjustment to be made to the camera
+ */
+ private void adjustVerticalPan(Double adjustment) {
+ if (verticalPan + adjustment >= -PAN_LIMIT && verticalPan + adjustment <= PAN_LIMIT) {
+ verticalPan += adjustment;
+ updateCamera();
+ }
+ }
+
+ /**
+ * Adjusts the Horizontal Panning of the Camera.
+ * @param adjustment the adjustment to be made to the camera
+ */
+ private void adjustHorizontalPan(Double adjustment) {
+ if (horizontalPan + adjustment >= -PAN_LIMIT && horizontalPan + adjustment <= PAN_LIMIT) {
+ horizontalPan += adjustment;
+ updateCamera();
+ }
+ }
+
+ @Override
+ public void zoomIn() {
+ adjustZoomFactor(ZOOM_STEP);
+ }
+
+ @Override
+ public void zoomOut() {
+ adjustZoomFactor(-ZOOM_STEP);
+ }
+
+ @Override
+ public void panLeft() {
+ adjustHorizontalPan(-1.0);
+ }
+
+ @Override
+ public void panRight() {
+ adjustHorizontalPan(1.0);
+ }
+
+ @Override
+ public void panUp() {
+ adjustVerticalPan(-1.0);
+ }
+
+ @Override
+ public void panDown() {
+ adjustVerticalPan(1.0);
+ }
+
+}
diff --git a/src/main/java/seng302/visualiser/controllers/FinishScreenViewController.java b/src/main/java/seng302/visualiser/controllers/FinishScreenViewController.java
index 7eb9b4fd..86e39ead 100644
--- a/src/main/java/seng302/visualiser/controllers/FinishScreenViewController.java
+++ b/src/main/java/seng302/visualiser/controllers/FinishScreenViewController.java
@@ -88,7 +88,6 @@ public class FinishScreenViewController implements Initializable {
public void switchToStartScreenView() {
Sounds.playButtonClick();
- //TODO merge fix
setContentPane("/views/StartScreenView.fxml");
}
diff --git a/src/main/java/seng302/visualiser/controllers/ViewManager.java b/src/main/java/seng302/visualiser/controllers/ViewManager.java
index 8f98824c..5e3d6748 100644
--- a/src/main/java/seng302/visualiser/controllers/ViewManager.java
+++ b/src/main/java/seng302/visualiser/controllers/ViewManager.java
@@ -28,6 +28,7 @@ import seng302.utilities.BonjourInstallChecker;
import seng302.utilities.Sounds;
import seng302.visualiser.GameClient;
import seng302.visualiser.controllers.dialogs.KeyBindingDialogController;
+import seng302.visualiser.controllers.dialogs.PopupDialogController;
public class ViewManager {
@@ -229,6 +230,26 @@ public class ViewManager {
keyBindingDialog.close();
}
+ public PopupDialogController showPopupDialog() {
+ FXMLLoader dialogContent = new FXMLLoader(
+ getClass().getResource("/views/dialogs/PopupDialog.fxml"));
+ for (Node node : decorator.getChildren()) {
+ if (node instanceof StackPane) {
+ try {
+ JFXDialog dialog = new JFXDialog((StackPane) node, dialogContent.load(),
+ DialogTransition.CENTER);
+ PopupDialogController popupDialogController = dialogContent.getController();
+ popupDialogController.setPopupDialog(dialog);
+ dialog.show();
+ return popupDialogController;
+ } catch (IOException e) {
+ logger.error("Cannot load Popup dialog");
+ }
+ }
+ }
+ return null;
+ }
+
/**
* 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 2a286ec4..c650bc59 100644
--- a/src/main/java/seng302/visualiser/controllers/dialogs/KeyBindingDialogController.java
+++ b/src/main/java/seng302/visualiser/controllers/dialogs/KeyBindingDialogController.java
@@ -48,6 +48,16 @@ public class KeyBindingDialogController implements Initializable {
private Label downwindLabel;
@FXML
private JFXToggleButton turningToggle;
+ @FXML
+ private JFXButton viewButton;
+ @FXML
+ private JFXButton rightButton;
+ @FXML
+ private JFXButton leftButton;
+ @FXML
+ private JFXButton forwardButton;
+ @FXML
+ private JFXButton backwardButton;
//---------FXML END---------//
private GameKeyBind gameKeyBind;
@@ -60,7 +70,9 @@ public class KeyBindingDialogController implements Initializable {
gameKeyBind = GameKeyBind.getInstance();
buttons = new ArrayList<>();
Collections.addAll(buttons,
- zoomInbtn, zoomOutBtn, vmgBtn, sailInOutBtn, tackGybeBtn, upwindBtn, downwindBtn);
+ zoomInbtn, zoomOutBtn, vmgBtn, sailInOutBtn, tackGybeBtn, upwindBtn, downwindBtn,
+ viewButton,
+ rightButton, leftButton, forwardButton, backwardButton);
bindButtonWithAction();
loadKeyBind();
@@ -106,7 +118,7 @@ public class KeyBindingDialogController implements Initializable {
*/
private void bindButtonWithAction() {
buttonActionMap = new HashMap<>();
- for (int i = 0; i < 7; i++) {
+ for (int i = 0; i < 12; i++) {
buttonActionMap.put(buttons.get(i), KeyAction.getType(i + 1));
}
}
diff --git a/src/main/java/seng302/visualiser/controllers/dialogs/PopupDialogController.java b/src/main/java/seng302/visualiser/controllers/dialogs/PopupDialogController.java
new file mode 100644
index 00000000..6d294e50
--- /dev/null
+++ b/src/main/java/seng302/visualiser/controllers/dialogs/PopupDialogController.java
@@ -0,0 +1,56 @@
+package seng302.visualiser.controllers.dialogs;
+
+import com.jfoenix.controls.JFXButton;
+import com.jfoenix.controls.JFXDialog;
+import java.net.URL;
+import java.util.ResourceBundle;
+import javafx.event.EventHandler;
+import javafx.fxml.FXML;
+import javafx.fxml.Initializable;
+import javafx.scene.control.Label;
+import javafx.scene.input.MouseEvent;
+
+public class PopupDialogController implements Initializable {
+
+ @FXML
+ private Label headerLabel;
+ @FXML
+ private Label contentLabel;
+ @FXML
+ private Label closeLabel;
+ @FXML
+ private JFXButton optionButton;
+
+ @FXML
+ private JFXDialog popupDialog;
+
+ @Override
+ public void initialize(URL location, ResourceBundle resources) {
+
+ }
+
+ public void setContent(String content) {
+ this.contentLabel.setText(content);
+ }
+
+ public void setHeader(String header) {
+ this.headerLabel.setText(header);
+ }
+
+ public void setOptionButton(JFXButton jfxButton) {
+ this.optionButton = jfxButton;
+ }
+
+ public void setOptionButtonText(String text) {
+ this.optionButton.setText(text);
+ }
+
+ public void setOptionButtonEventHandler(EventHandler super MouseEvent> eventHandler) {
+ this.optionButton.setOnMouseClicked(eventHandler);
+ }
+
+ public void setPopupDialog(JFXDialog popupDialog) {
+ this.popupDialog = popupDialog;
+ this.closeLabel.setOnMouseClicked(event -> this.popupDialog.close());
+ }
+}
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 abf969a8..025ab820 100644
--- a/src/main/java/seng302/visualiser/fxObjects/assets_3D/BoatObject.java
+++ b/src/main/java/seng302/visualiser/fxObjects/assets_3D/BoatObject.java
@@ -3,6 +3,7 @@ package seng302.visualiser.fxObjects.assets_3D;
import java.util.ArrayList;
import java.util.List;
import javafx.application.Platform;
+import javafx.beans.property.ReadOnlyDoubleWrapper;
import javafx.geometry.Point3D;
import javafx.scene.Group;
import javafx.scene.paint.Color;
@@ -30,12 +31,15 @@ public class BoatObject extends Group {
private Boolean isSelected = false;
private Rotate rotation = new Rotate(0, new Point3D(0,0,1));
+ private ReadOnlyDoubleWrapper rotationProperty;
+
private List selectedBoatListenerListeners = new ArrayList<>();
/**
* Creates a BoatGroup with the default triangular boat polygon.
*/
public BoatObject(BoatMeshType boatMeshType) {
+ rotationProperty = new ReadOnlyDoubleWrapper(0.0);
boatAssets = ModelFactory.boatGameView(boatMeshType, colour);
boatAssets.hideSail();
boatAssets.getAssets().getTransforms().addAll(
@@ -83,6 +87,7 @@ public class BoatObject extends Group {
private void rotateTo(double heading, boolean sailsIn, double windDir) {
+ rotationProperty.set(heading);
rotation.setAngle(heading);
wake.getTransforms().setAll(new Rotate(heading, new Point3D(0,0,1)));
if (sailsIn) {
@@ -130,4 +135,8 @@ public class BoatObject extends Group {
public void addSelectedBoatListener(SelectedBoatListener sbl) {
selectedBoatListenerListeners.add(sbl);
}
+
+ public ReadOnlyDoubleWrapper getRotationProperty() {
+ return rotationProperty;
+ }
}
\ No newline at end of file
diff --git a/src/main/resources/css/Master.css b/src/main/resources/css/Master.css
index cb50a645..478d7cf0 100644
--- a/src/main/resources/css/Master.css
+++ b/src/main/resources/css/Master.css
@@ -51,6 +51,11 @@
/********* customised scroll bar for scroll pane ***********/
+.scroll-pane {
+ -fx-focus-traversable: false;
+ -fx-border-style: none;
+}
+
/* The main scrollbar **track** CSS class */
.scroll-bar:horizontal .track,
.scroll-bar:vertical .track {
diff --git a/src/main/resources/css/dialogs/KeyBindingDialog.css b/src/main/resources/css/dialogs/KeyBindingDialog.css
index 8d09e130..6c7bff26 100644
--- a/src/main/resources/css/dialogs/KeyBindingDialog.css
+++ b/src/main/resources/css/dialogs/KeyBindingDialog.css
@@ -9,8 +9,13 @@
}
#closeLabel:hover {
- -fx-text-fill: -fx-pp-theme-color;
- -fx-font-size: 33;
+ -fx-text-fill: red;
+ -fx-font-size: 33px;
+}
+
+.sectionLabel {
+ -fx-text-fill: -fx-pp-dark-text-color;
+ -fx-font-size: 20px;
}
JFXButton {
diff --git a/src/main/resources/css/dialogs/Popup.css b/src/main/resources/css/dialogs/Popup.css
new file mode 100644
index 00000000..d0dd364b
--- /dev/null
+++ b/src/main/resources/css/dialogs/Popup.css
@@ -0,0 +1,33 @@
+#headerLabel {
+ -fx-font-size: 20px;
+ -fx-text-fill: -fx-pp-dark-text-color;
+}
+
+#closeLabel {
+ -fx-font-size: 22px;
+ -fx-text-fill: -fx-pp-dark-text-color;
+}
+
+#closeLabel:hover {
+ -fx-font-size: 24px;
+ -fx-text-fill: red;
+}
+
+#contentLabel {
+ -fx-font-size: 22px;
+ -fx-text-fill: -fx-pp-dark-text-color;
+}
+
+#optionButton {
+ -fx-background-color: -fx-pp-theme-color;
+ -fx-text-fill: -fx-pp-light-text-color;
+ -fx-font-size: 18px;
+ -fx-effect: -fx-pp-dropshadow-light;
+ -fx-max-height: 55;
+ -fx-focus-traversable: false;
+}
+
+#optionButton:hover {
+ -fx-font-size: 20px !important;
+ -fx-background-color: -fx-pp-light-theme-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 4a677797..7fcf2e7f 100644
--- a/src/main/resources/views/dialogs/KeyBindingDialog.fxml
+++ b/src/main/resources/views/dialogs/KeyBindingDialog.fxml
@@ -6,117 +6,226 @@
+
+
+
+
+
+
-
-
+
-
-
-
-
-
-
-
-
-
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+ GridPane.rowIndex="2" GridPane.valignment="CENTER"/>
-
-
-
-
diff --git a/src/main/resources/views/dialogs/PopupDialog.fxml b/src/main/resources/views/dialogs/PopupDialog.fxml
new file mode 100644
index 00000000..00574bc4
--- /dev/null
+++ b/src/main/resources/views/dialogs/PopupDialog.fxml
@@ -0,0 +1,47 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+