Merge remote-tracking branch 'origin/develop' into 1273_Skybox

# Conflicts:
#	src/main/java/seng302/gameServer/GameState.java
#	src/main/java/seng302/gameServer/MainServerThread.java
#	src/main/java/seng302/gameServer/MessageFactory.java
#	src/main/java/seng302/gameServer/ServerToClientThread.java
#	src/main/java/seng302/model/ClientYacht.java
#	src/main/java/seng302/model/mark/MarkOrder.java
#	src/main/java/seng302/visualiser/GameClient.java
#	src/main/java/seng302/visualiser/GameView3D.java
#	src/main/java/seng302/visualiser/controllers/ServerListController.java
#	src/main/java/seng302/visualiser/controllers/dialogs/ServerCreationController.java
#	src/main/resources/icons/bumperIcon.png
#	src/main/resources/icons/handlingIcon.png
#	src/main/resources/icons/velocity.png
#	src/main/resources/icons/windWalkerIcon.png
#	src/main/resources/views/RaceView.fxml
#	src/main/resources/views/dialogs/ServerCreationDialog.fxml
This commit is contained in:
Michael Rausch
2017-09-27 14:23:38 +13:00
41 changed files with 1554 additions and 587 deletions
@@ -1,14 +1,25 @@
package seng302.visualiser;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.TimeZone;
import java.util.Timer;
import java.util.TimerTask;
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;
import javafx.scene.paint.Color;
import javafx.util.Pair;
import seng302.gameServer.GameStages;
import seng302.gameServer.GameState;
@@ -37,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;
import java.io.IOException;
import java.text.SimpleDateFormat;
@@ -166,10 +178,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());
});
}
@@ -413,9 +427,16 @@ public class GameClient {
* @param yachtEventData The YachtEvent data packet
*/
private void processYachtEvent(YachtEventData yachtEventData) {
ClientYacht thisYacht = allBoatsMap.get(yachtEventData.getSubjectId().intValue());
if (yachtEventData.getEventId() == YachtEventType.COLLISION.getCode()) {
showCollisionAlert(yachtEventData);
} else {
showCollisionAlert(thisYacht);
} else if (yachtEventData.getEventId() == YachtEventType.POWER_DOWN.getCode()) {
thisYacht.powerDown();
Sounds.playTokenPickupSound(); // TODO: 23/09/17 This should be power down sound
} else if (yachtEventData.getEventId() == YachtEventType.BUMPER_CRASH.getCode()) {
showDisableAlert(thisYacht);
} else { //Else all token pickup types
TokenType tokenType = null;
if (yachtEventData.getEventId() == YachtEventType.TOKEN_VELOCITY.getCode()) {
tokenType = TokenType.BOOST;
@@ -429,36 +450,36 @@ public class GameClient {
tokenType = TokenType.WIND_WALKER;
}
showTokenPickUp(tokenType);
allBoatsMap.get(yachtEventData.getSubjectId().intValue()).setPowerUp(tokenType);
Sounds.playTokenPickupSound();
thisYacht.setPowerUp(tokenType);
}
}
/**
* Turns a disabled boat black until the bumper affect wears off
*
* @param yacht The yacht to show as disabled
*/
private void showDisableAlert(ClientYacht yacht) {
Color originalColor = yacht.getColour();
yacht.setColour(Color.BLACK);
Timer disableTimer = new Timer("Disable Timer");
disableTimer.schedule(new TimerTask() {
@Override
public void run() {
yacht.setColour(originalColor);
}
}, GameState.BUMPER_DISABLE_TIME);
}
/**
* Tells race view to show a collision animation.
*/
private void showCollisionAlert(YachtEventData yachtEventData) {
private void showCollisionAlert(ClientYacht yacht) {
Sounds.playCrashSound();
raceState.storeCollision(
allBoatsMap.get(
yachtEventData.getSubjectId().intValue()
)
);
}
// TODO: 11/09/17 wmu16 - Add in functionality to viually indicate a pickup to a user
private void showTokenPickUp(TokenType tokenType) {
Sounds.playTokenPickupSound();
switch (tokenType) {
case BOOST:
break;
case HANDLING:
break;
case WIND_WALKER:
break;
case BUMPER:
break;
}
raceState.storeCollision(yacht);
}
private void formatAndSendChatMessage(String rawChat) {
@@ -1,6 +1,8 @@
package seng302.visualiser;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -8,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;
@@ -22,6 +25,9 @@ import javafx.scene.transform.Translate;
import org.fxyz3d.scene.Skybox;
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.ScaledPoint;
import seng302.model.mark.CompoundMark;
@@ -49,17 +55,27 @@ import seng302.visualiser.fxObjects.assets_3D.ModelType;
public class GameView3D extends GameView{
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 = 100;
private Group root3D;
private SubScene view;
private PerspectiveCamera camera;
private PerspectiveCamera camera2;
private PerspectiveCamera camera3;
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;
private boolean horizontalInversion = false;
private double distanceScaleFactor;
private ScaleDirection scaleDirection;
private GeoPoint minLatPoint, minLonPoint, maxLatPoint, maxLonPoint;
private double referencePointX, referencePointY;
private Group raceBorder = new Group();
/* Note that if either of these is null then values for it have not been added and the other
@@ -75,31 +91,28 @@ public class GameView3D extends GameView{
private Double windDir;
private Skybox skybox;
private enum ScaleDirection {
HORIZONTAL,
VERTICAL
}
public GameView3D () {
canvasWidth = canvasHeight = 220;
isometricCam = new IsometricCamera(DEFAULT_CAMERA_X, DEFAULT_CAMERA_Y);
topDownCam = new TopDownCamera();
chaseCam = new ChaseCamera();
camera = new IsometricCamera(DEFAULT_CAMERA_X, DEFAULT_CAMERA_Y, DEFAULT_CAMERA_DEPTH);
camera.setFarClip(100000);
camera.setNearClip(0.1);
camera.setFieldOfView(FOV);
camera2 = new TopDownCamera();
camera2.setFarClip(100000);
camera2.setNearClip(0.1);
camera2.setFieldOfView(FOV);
camera3 = new ChaseCamera();
camera3.setFarClip(100000);
camera3.setNearClip(0.1);
camera3.setFieldOfView(FOV);
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, 5000, 3000, true, SceneAntialiasing.BALANCED
);
view.setCamera(camera);
camera.getTransforms().add(new Rotate(30, new Point3D(1,0,0)));
view.setCamera(isometricCam);
skybox = new Skybox(new Image(getClass().getResourceAsStream("/images/skybox.jpg")), 100000, camera);
skybox.getTransforms().addAll(new Rotate(90, Rotate.X_AXIS));
@@ -274,48 +287,44 @@ public class GameView3D extends GameView{
}
public void cameraMovement(KeyEvent event) {
switch (event.getCode()) {
case NUMPAD8:
view.getCamera().getTransforms().addAll(new Rotate(0.5, new Point3D(1, 0, 0)));
break;
case NUMPAD2:
view.getCamera().getTransforms().addAll(new Rotate(-0.5, new Point3D(1, 0, 0)));
break;
case NUMPAD4:
view.getCamera().getTransforms().addAll(new Rotate(-0.5, new Point3D(0, 1, 0)));
break;
case NUMPAD6:
view.getCamera().getTransforms().addAll(new Rotate(0.5, new Point3D(0, 1, 0)));
break;
case Z:
((RaceCamera) view.getCamera()).zoomIn();
break;
case X:
((RaceCamera) view.getCamera()).zoomOut();
break;
case W:
((RaceCamera) view.getCamera()).panUp();
break;
case S:
((RaceCamera) view.getCamera()).panDown();
break;
case A:
((RaceCamera) view.getCamera()).panLeft();
break;
case D:
((RaceCamera) view.getCamera()).panRight();
break;
case F1:
if (view.getCamera().equals(camera)) {
view.setCamera(camera2);
if (view.getCamera() instanceof TopDownCamera) {
((RaceCamera) view.getCamera()).zoomIn();
}
} else if (view.getCamera().equals(camera2)) {
view.setCamera(camera3);
} else {
view.setCamera(camera);
}
GameKeyBind keyBinds = GameKeyBind.getInstance();
KeyAction keyPressed = keyBinds.getKeyAction(event.getCode());
if (keyPressed != null) {
switch (keyPressed) {
case ZOOM_IN:
((RaceCamera) view.getCamera()).zoomIn();
break;
case ZOOM_OUT:
((RaceCamera) view.getCamera()).zoomOut();
break;
case FORWARD:
((RaceCamera) view.getCamera()).panUp();
break;
case BACKWARD:
((RaceCamera) view.getCamera()).panDown();
break;
case LEFT:
((RaceCamera) view.getCamera()).panLeft();
break;
case RIGHT:
((RaceCamera) view.getCamera()).panRight();
break;
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);
}
}
@@ -334,16 +343,13 @@ public class GameView3D extends GameView{
wakesGroup.getChildren().add(newBoat.getWake());
wakes.add(newBoat.getWake());
boatObjectGroup.getChildren().add(newBoat);
clientYacht.addLocationListener((boat, lat, lon, heading, sailIn, velocity) -> {
BoatObject bo = boatObjects.get(boat);
Point2D p2d = scaledPoint.findScaledXY(lat, lon);
bo.moveTo(p2d.getX(), p2d.getY(), heading, velocity, sailIn, windDir);
});
clientYacht.addLocationListener(this::updateBoatLocation);
clientYacht.addColorChangeListener(this::updateBoatColor);
if (clientYacht.getSourceId().equals(
ViewManager.getInstance().getGameClient().getServerThread().getClientId())) {
((ChaseCamera) camera3).setPlayerBoat(newBoat, clientYacht);
((TopDownCamera) camera2).setPlayerBoat(newBoat);
((ChaseCamera) chaseCam).setPlayerBoat(newBoat);
((TopDownCamera) topDownCam).setPlayerBoat(newBoat);
}
}
Platform.runLater(() -> {
@@ -356,6 +362,23 @@ public class GameView3D extends GameView{
return view;
}
/**
* Updates the boatObjects color with that of the clientYachts object. Used in notification from
* a listener on this attribute in clientYacht to re paint the boat mesh
*
* @param clientYacht The yacht to update the colour for
*/
private void updateBoatColor(ClientYacht clientYacht) {
boatObjects.get(clientYacht).setFill(clientYacht.getColour());
}
private void updateBoatLocation(ClientYacht boat, Double lat, Double lon, Double heading,
Boolean sailIn, Double velocity) {
BoatObject bo = boatObjects.get(boat);
Point2D p2d = findScaledXY(lat, lon);
bo.moveTo(p2d.getX(), p2d.getY(), heading, velocity, sailIn, windDir);
}
/**
* Adds a border to the GameView and rescales to the size of the border, does not rescale if a
* border already exists. Assumes the border is larger than the course.
@@ -1,22 +1,28 @@
package seng302.visualiser.cameras;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
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.model.ClientYacht;
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<Transform> transforms;
private BoatObject playerBoat;
private ClientYacht playerYacht;
private Double zoomFactor;
private Double horizontalPan;
private Double verticalPan;
@@ -25,97 +31,100 @@ public class ChaseCamera extends PerspectiveCamera implements RaceCamera {
public ChaseCamera() {
super(true);
transforms = this.getTransforms();
this.zoomFactor = -75.0;
zoomFactor = (FAR_ZOOM_LIMIT + NEAR_ZOOM_LIMIT) / 2.0;
this.horizontalPan = 0.0;
this.verticalPan = 0.0;
}
public void setPlayerBoat(BoatObject playerBoat, ClientYacht playerYacht) {
/**
* 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;
this.playerYacht = playerYacht;
this.playerYacht.getHeadingProperty().addListener(new ChangeListener<Number>() {
@Override
public void changed(ObservableValue<? extends Number> observable, Number oldValue,
Number newValue) {
repositionCamera();
}
});
this.playerBoat.layoutXProperty().addListener(new ChangeListener<Number>() {
@Override
public void changed(ObservableValue<? extends Number> observable, Number oldValue,
Number newValue) {
repositionCamera();
}
});
this.playerBoat.layoutYProperty().addListener(new ChangeListener<Number>() {
@Override
public void changed(ObservableValue<? extends Number> observable, Number oldValue,
Number newValue) {
repositionCamera();
}
});
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(playerYacht.getHeadingProperty().getValue() + horizontalPan,
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 < -15.0 && zoomFactor + adjustment > -125.0) {
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 >= -20 && verticalPan + adjustment <= 20) {
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(5.0);
adjustZoomFactor(ZOOM_STEP);
}
@Override
public void zoomOut() {
adjustZoomFactor(-5.0);
adjustZoomFactor(-ZOOM_STEP);
}
/*
These have been left intentionally empty for now. it would be cool to be able to pan around the boat and have the camera move around the boat though.
*/
@Override
public void panLeft() {
this.horizontalPan -= 5;
repositionCamera();
adjustHorizontalPan(-PAN_STEP);
}
@Override
public void panRight() {
this.horizontalPan += 5;
repositionCamera();
adjustHorizontalPan(PAN_STEP);
}
@Override
public void panUp() {
adjustVerticalPan(-5.0);
adjustVerticalPan(-PAN_STEP);
}
@Override
public void panDown() {
adjustVerticalPan(5.0);
adjustVerticalPan(PAN_STEP);
}
}
@@ -1,47 +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 {
ObservableList<Transform> transforms;
private final Double MIN_X = -120.0;
private final Double MAX_X = 125.0;
public IsometricCamera(Double cameraStartX, Double cameraStartY, Double cameraDepth) {
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<Transform> transforms;
public IsometricCamera(Double cameraStartX, Double cameraStartY) {
super(true);
transforms = this.getTransforms();
transforms.addAll(new Translate(cameraStartX, cameraStartY, cameraDepth));
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() {
transforms.addAll(new Translate(0, 0, 1.5));
adjustZoomFactor(-2.5);
}
@Override
public void zoomOut() {
transforms.addAll(new Translate(0, 0, -1.5));
adjustZoomFactor(2.5);
}
@Override
public void panLeft() {
transforms.addAll(new Translate(-1, 0, 0));
adjustHorizontalPan(-2.5);
}
@Override
public void panRight() {
transforms.addAll(new Translate(1, 0, 0));
adjustHorizontalPan(2.5);
}
@Override
public void panUp() {
transforms.addAll(new Translate(0, -1, 0));
adjustVerticalPan(-2.5);
}
@Override
public void panDown() {
transforms.addAll(new Translate(0, 1, 0));
adjustVerticalPan(2.5);
}
}
@@ -1,8 +1,8 @@
package seng302.visualiser.cameras;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import java.util.Arrays;
import javafx.beans.property.DoubleProperty;
import javafx.collections.ObservableList;
import javafx.scene.PerspectiveCamera;
import javafx.scene.transform.Transform;
@@ -11,75 +11,113 @@ 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<Transform> transforms;
private BoatObject playerBoat;
private Double zoomFactor;
private Double horizontalPan;
private Double verticalPan;
public TopDownCamera() {
super(true);
transforms = this.getTransforms();
transforms.add(new Translate(0, 0, -125));
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;
this.playerBoat.layoutXProperty().addListener(new ChangeListener<Number>() {
@Override
public void changed(ObservableValue<? extends Number> observable, Number oldValue,
Number newValue) {
updateCameraX((Double) oldValue, (Double) newValue);
}
});
this.playerBoat.layoutYProperty().addListener(new ChangeListener<Number>() {
@Override
public void changed(ObservableValue<? extends Number> observable, Number oldValue,
Number newValue) {
updateCameraY((Double) oldValue, (Double) newValue);
}
});
}
private void updateCameraX(Double oldXValue, Double newXValue) {
if (transforms.size() == 0) { // boat is placed and then moved at start,
transforms.addAll(
new Translate(playerBoat.getLayoutX(), playerBoat.getLayoutY(), -125)
);
} else {
transforms.addAll(new Translate(newXValue - oldXValue, 0, 0));
for (DoubleProperty o : Arrays
.asList(playerBoat.layoutXProperty(), playerBoat.layoutYProperty())) {
o.addListener((obs, oldVal, newVal) -> updateCamera());
}
}
private void updateCameraY(Double oldYValue, Double newYValue) {
transforms.addAll(new Translate(0, (newYValue - oldYValue), 0));
/**
* 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() {
transforms.addAll(new Translate(0, 0, 1.5));
adjustZoomFactor(ZOOM_STEP);
}
@Override
public void zoomOut() {
transforms.addAll(new Translate(0, 0, -1.5));
adjustZoomFactor(-ZOOM_STEP);
}
@Override
public void panLeft() {
transforms.addAll(new Translate(-1, 0, 0));
adjustHorizontalPan(-1.0);
}
@Override
public void panRight() {
transforms.addAll(new Translate(1, 0, 0));
adjustHorizontalPan(1.0);
}
@Override
public void panUp() {
transforms.addAll(new Translate(0, -1, 0));
adjustVerticalPan(-1.0);
}
@Override
public void panDown() {
transforms.addAll(new Translate(0, 1, 0));
adjustVerticalPan(1.0);
}
}
@@ -44,12 +44,14 @@ import javafx.scene.shape.Polyline;
import javafx.scene.text.Text;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
import javax.swing.ImageIcon;
import seng302.model.ClientYacht;
import seng302.model.ClientYacht.PowerUpListener;
import seng302.model.RaceState;
import seng302.model.mark.CompoundMark;
import seng302.model.mark.Mark;
import seng302.model.stream.xml.parser.RaceXMLData;
import seng302.model.token.Token;
import seng302.model.token.TokenType;
import seng302.utilities.Sounds;
import seng302.visualiser.GameView3D;
@@ -115,7 +117,7 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
@FXML
private Label positionLabel, boatSpeedLabel, boatHeadingLabel;
@FXML
private ImageView velocityIcon, handlingIcon, windWalkerIcon, bumperIcon;
private ImageView velocityIcon, handlingIcon, windWalkerIcon, bumperIcon, badRandomIcon;
//Race Data
private Map<Integer, ClientYacht> participants;
@@ -136,6 +138,10 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
private JFXDialog finishScreenDialog;
private FinishDialogController finishDialogController;
//Icon stuff
private Timer blinkingTimer = new Timer();
private ImageView iconToDisplay;
public void initialize() {
Sounds.stopMusic();
Sounds.playRaceMusic();
@@ -213,6 +219,7 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
});
player.addPowerUpListener(this::displayPowerUpIcon);
player.addPowerDownListener(this::removeIcon);
updateOrder(raceState.getPlayerPositions());
gameView = new GameView3D();
@@ -257,7 +264,9 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
*/
private void displayPowerUpIcon(ClientYacht yacht, TokenType tokenType) {
if (yacht == player) {
final ImageView iconToDisplay;
if (iconToDisplay != null) {
iconToDisplay.setVisible(false);
}
switch (tokenType) {
case BOOST:
@@ -272,6 +281,9 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
case BUMPER:
iconToDisplay = bumperIcon;
break;
case RANDOM:
iconToDisplay = badRandomIcon;
break;
default:
iconToDisplay = velocityIcon;
}
@@ -280,7 +292,10 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
iconToDisplay.setVisible(true);
//Start blinking icon towards end
Timer blinkingTimer = new Timer();
if (blinkingTimer != null) {
blinkingTimer.cancel();
}
blinkingTimer = new Timer("Blinking Timer");
blinkingTimer.schedule(new TimerTask() {
Boolean isVisible = true;
@@ -290,16 +305,14 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
iconToDisplay.setVisible(isVisible);
}
}, (int) (tokenType.getTimeout() * ICON_BLINK_TIMEOUT_RATIO), ICON_BLINK_PERIOD);
}
}
//Turn icon off after the time out
Timer switchOffTimer = new Timer();
switchOffTimer.schedule(new TimerTask() {
@Override
public void run() {
blinkingTimer.cancel();
iconToDisplay.setVisible(false);
}
}, tokenType.getTimeout());
public void removeIcon(ClientYacht yacht) {
if (yacht == player) {
blinkingTimer.cancel();
iconToDisplay.setVisible(false);
iconToDisplay = null;
}
}
@@ -5,6 +5,12 @@ import com.jfoenix.controls.JFXDialog;
import com.jfoenix.controls.JFXDialog.DialogTransition;
import com.jfoenix.controls.JFXTextField;
import com.jfoenix.validation.RequiredFieldValidator;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.ResourceBundle;
import javafx.application.Platform;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
@@ -32,6 +38,10 @@ import java.net.URL;
import java.util.Arrays;
import java.util.List;
import java.util.ResourceBundle;
import seng302.visualiser.controllers.dialogs.ServerCreationController;
import seng302.visualiser.validators.HostNameFieldValidator;
import seng302.visualiser.validators.NumberRangeValidator;
import seng302.visualiser.validators.ValidationTools;
public class ServerListController implements Initializable, ServerListenerDelegate {
@@ -63,6 +73,14 @@ public class ServerListController implements Initializable, ServerListenerDelega
private Logger logger = LoggerFactory.getLogger(ServerListController.class);
private JFXDialog directConnectDialog;
private JFXDialog serverCreationDialog;
private List<ServerCreationDialogListener> serverCreationDialogListeners = new ArrayList<>();
@FunctionalInterface
public interface ServerCreationDialogListener {
void notifyClosure();
}
// TODO: 12/09/17 ajm412: break this method down, its way too long.
@Override
@@ -166,6 +184,8 @@ public class ServerListController implements Initializable, ServerListenerDelega
serverListHostButton.setOnAction(action -> {
showServerCreationDialog();
});
addServerCreationDialogListener(this::closeServerCreationDialog);
}
/**
@@ -176,9 +196,11 @@ public class ServerListController implements Initializable, ServerListenerDelega
FXMLLoader dialogContent = new FXMLLoader(getClass().getResource(
"/views/dialogs/ServerCreationDialog.fxml"));
try {
JFXDialog dialog = new JFXDialog(serverListMainStackPane, dialogContent.load(),
serverCreationDialog = new JFXDialog(serverListMainStackPane, dialogContent.load(),
DialogTransition.CENTER);
dialog.show();
ServerCreationController serverCreationController = dialogContent.getController();
serverCreationController.setListener(serverCreationDialogListeners);
serverCreationDialog.show();
Sounds.playButtonClick();
} catch (IOException e) {
e.printStackTrace();
@@ -205,6 +227,10 @@ public class ServerListController implements Initializable, ServerListenerDelega
return dcDialog;
}
private void closeServerCreationDialog() {
serverCreationDialog.close();
}
/**
* Validates the connection and attempts to connect to a given hostname and port number.
*/
@@ -303,4 +329,14 @@ public class ServerListController implements Initializable, ServerListenerDelega
public void serverDetected(ServerDescription serverDescription, List<ServerDescription> servers) {
Platform.runLater(() -> refreshServers(servers));
}
private void addServerCreationDialogListener(
ServerCreationDialogListener serverCreationDialogListener) {
serverCreationDialogListeners.add(serverCreationDialogListener);
}
private void removeServerCreationDialogListener(
ServerCreationDialogListener serverCreationDialogListener) {
serverCreationDialogListeners.remove(serverCreationDialogListener);
}
}
@@ -21,6 +21,7 @@ import seng302.gameServer.ServerAdvertiser;
import seng302.utilities.Sounds;
import seng302.visualiser.GameClient;
import seng302.visualiser.controllers.dialogs.KeyBindingDialogController;
import seng302.visualiser.controllers.dialogs.PopupDialogController;
import java.io.IOException;
import java.util.HashMap;
@@ -97,8 +98,6 @@ public class ViewManager {
gameClient.stopGame();
System.exit(0);
});
jfxSnackbar = new JFXSnackbar(decorator);
}
/**
@@ -183,6 +182,7 @@ public class ViewManager {
}
});
jfxSnackbar = new JFXSnackbar(decorator);
}
/**
@@ -216,6 +216,7 @@ public class ViewManager {
.getController();
keyBindingDialogController.setGameClient(this.gameClient);
keyBindingDialog.show();
decorator.requestFocus();
Sounds.playButtonClick();
}
}
@@ -225,6 +226,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.
*
@@ -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,8 @@ 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();
@@ -76,12 +87,10 @@ public class KeyBindingDialogController implements Initializable {
resetBtn.setOnMouseClicked(event -> {
gameKeyBind.setToDefault();
loadKeyBind();
showSnackBar("All keys reset!", false);
});
closeLabel.setOnMouseClicked(event -> ViewManager.getInstance().closeKeyBindingDialog());
keyBindingDialogHeader.setFocusTraversable(true);
keyBindingDialogHeader.requestFocus();
}
/**
@@ -106,7 +115,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));
}
}
@@ -149,6 +158,7 @@ public class KeyBindingDialogController implements Initializable {
+ "-fx-background-color: -fx-pp-front-color; "
+ "-fx-text-fill: -fx-pp-theme-color; "
+ "-fx-font-size: 13;");
keyBindingDialogHeader.requestFocus();
}
/**
@@ -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());
}
}
@@ -6,6 +6,7 @@ import com.jfoenix.controls.JFXSlider;
import com.jfoenix.controls.JFXTextField;
import com.jfoenix.validation.RequiredFieldValidator;
import java.net.URL;
import java.util.List;
import java.util.ResourceBundle;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
@@ -15,6 +16,7 @@ import javafx.scene.layout.AnchorPane;
import seng302.gameServer.ServerDescription;
import seng302.utilities.Sounds;
import seng302.visualiser.MapMaker;
import seng302.visualiser.controllers.ServerListController.ServerCreationDialogListener;
import seng302.visualiser.controllers.ViewManager;
import seng302.visualiser.validators.FieldLengthValidator;
import seng302.visualiser.validators.ValidationTools;
@@ -31,6 +33,8 @@ public class ServerCreationController implements Initializable {
@FXML
private JFXButton submitBtn;
@FXML
private Label closeLabel;
@FXML
private JFXButton nextMapButton;
@FXML
private JFXButton lastMapButton;
@@ -49,6 +53,8 @@ public class ServerCreationController implements Initializable {
//---------FXML END---------//
private List<ServerCreationDialogListener> serverCreationDialogListeners;
public void initialize(URL location, ResourceBundle resources) {
legsSlider.setMax(10);
legsSlider.setValue(4);
@@ -86,6 +92,7 @@ public class ServerCreationController implements Initializable {
mapHolder.getChildren().setAll(mapMaker.getCurrentGameView());
mapNameLabel.setText(mapMaker.getCurrentRegatta().getCourseName());
closeLabel.setOnMouseClicked(event -> notifyListeners());
}
/**
@@ -144,4 +151,14 @@ public class ServerCreationController implements Initializable {
mapNameLabel.setText(mapMaker.getCurrentRegatta().getCourseName());
}
public void setListener(List<ServerCreationDialogListener> serverCreationDialogListeners) {
this.serverCreationDialogListeners = serverCreationDialogListeners;
}
public void notifyListeners() {
for (ServerCreationDialogListener serverCreationDialogListener : serverCreationDialogListeners) {
serverCreationDialogListener.notifyClosure();
}
}
}
@@ -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<SelectedBoatListener> 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;
}
}