From 2e7487fdfcff2de498a66aa746dad68378bb2dec Mon Sep 17 00:00:00 2001 From: alistairjmcintyre Date: Tue, 26 Sep 2017 15:06:21 +1300 Subject: [PATCH] - Chase Camera: - Has panning bounds, zoom bounds, and general tidy up. - Now correctly observes the boat object rather than getting information from both the boat object AND the client yacht model. Top Down Camera: - Can only pan within certain bounds now, and will continue to follow the boat regardless. - Can only zoom within certain bounds now. Isometric Camera: - Nothing changed. #tags [1273] --- .../java/seng302/visualiser/GameView3D.java | 68 ++++++++------- .../visualiser/cameras/ChaseCamera.java | 66 ++++++-------- .../visualiser/cameras/IsometricCamera.java | 7 ++ .../visualiser/cameras/TopDownCamera.java | 86 +++++++++++-------- .../fxObjects/assets_3D/BoatObject.java | 9 ++ 5 files changed, 130 insertions(+), 106 deletions(-) diff --git a/src/main/java/seng302/visualiser/GameView3D.java b/src/main/java/seng302/visualiser/GameView3D.java index 78e43b9a..5094e41c 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; @@ -53,12 +55,13 @@ public class GameView3D { private Group root3D; private SubScene view; - // ParallelCamera camera; - 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; @@ -93,28 +96,25 @@ public class GameView3D { } public GameView3D () { - camera = new IsometricCamera(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, + DEFAULT_CAMERA_DEPTH); + topDownCam = new TopDownCamera(); + chaseCam = new ChaseCamera(); - camera2 = new TopDownCamera(); - camera2.setFarClip(600); - camera2.setNearClip(0.1); - camera2.setFieldOfView(FOV); - - camera3 = new ChaseCamera(); - camera3.setFarClip(600); - 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, 1000, 1000, true, SceneAntialiasing.BALANCED ); - view.setCamera(camera); - camera.getTransforms().add(new Rotate(30, new Point3D(1,0,0))); + view.setCamera(isometricCam); + isometricCam.getTransforms() + .add(new Rotate(30, new Point3D(1, 0, 0))); //todo: move this into isometric cam? gameObjects.getChildren().addAll( ModelFactory.importModel(ModelType.OCEAN).getAssets(), @@ -449,16 +449,20 @@ public class GameView3D { ((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); - } + 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); } } @@ -498,8 +502,8 @@ public class GameView3D { 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(() -> { diff --git a/src/main/java/seng302/visualiser/cameras/ChaseCamera.java b/src/main/java/seng302/visualiser/cameras/ChaseCamera.java index 6c777f77..daddfaca 100644 --- a/src/main/java/seng302/visualiser/cameras/ChaseCamera.java +++ b/src/main/java/seng302/visualiser/cameras/ChaseCamera.java @@ -1,22 +1,25 @@ 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 ObservableList transforms; private BoatObject playerBoat; - private ClientYacht playerYacht; + private Double zoomFactor; private Double horizontalPan; private Double verticalPan; @@ -25,43 +28,27 @@ 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) { + public void setPlayerBoat(BoatObject playerBoat) { this.playerBoat = playerBoat; - this.playerYacht = playerYacht; - this.playerYacht.getHeadingProperty().addListener(new ChangeListener() { - @Override - public void changed(ObservableValue observable, Number oldValue, - Number newValue) { - repositionCamera(); - } - }); - this.playerBoat.layoutXProperty().addListener(new ChangeListener() { - @Override - public void changed(ObservableValue observable, Number oldValue, - Number newValue) { - repositionCamera(); - } - }); - this.playerBoat.layoutYProperty().addListener(new ChangeListener() { - @Override - public void changed(ObservableValue observable, Number oldValue, - Number newValue) { - repositionCamera(); - } - }); + for (DoubleProperty o : Arrays + .asList(playerBoat.getRotationProperty(), playerBoat.layoutYProperty(), + playerBoat.layoutXProperty())) { + o.addListener((obs, oldVal, newVal) -> repositionCamera()); + } } 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) @@ -69,19 +56,25 @@ public class ChaseCamera extends PerspectiveCamera implements RaceCamera { } 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(); } } 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(); } } + private void adjustHorizontalPan(Double adjustment) { + this.horizontalPan += adjustment; + repositionCamera(); + } + @Override public void zoomIn() { adjustZoomFactor(5.0); @@ -92,21 +85,14 @@ public class ChaseCamera extends PerspectiveCamera implements RaceCamera { adjustZoomFactor(-5.0); } - - /* - 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(-5.0); } @Override public void panRight() { - this.horizontalPan += 5; - repositionCamera(); + adjustHorizontalPan(5.0); } @Override diff --git a/src/main/java/seng302/visualiser/cameras/IsometricCamera.java b/src/main/java/seng302/visualiser/cameras/IsometricCamera.java index a4abeac4..434032b7 100644 --- a/src/main/java/seng302/visualiser/cameras/IsometricCamera.java +++ b/src/main/java/seng302/visualiser/cameras/IsometricCamera.java @@ -7,6 +7,13 @@ import javafx.scene.transform.Translate; public class IsometricCamera extends PerspectiveCamera implements RaceCamera { + private final Double PAN_LIMIT = 50.0; + private final Double NEAR_ZOOM_LIMIT = -15.0; + private final Double FAR_ZOOM_LIMIT = -125.0; + + private Double horizontalAdjustment; + private Double verticalAdjustment; + ObservableList transforms; public IsometricCamera(Double cameraStartX, Double cameraStartY, Double cameraDepth) { diff --git a/src/main/java/seng302/visualiser/cameras/TopDownCamera.java b/src/main/java/seng302/visualiser/cameras/TopDownCamera.java index af17d553..09455345 100644 --- a/src/main/java/seng302/visualiser/cameras/TopDownCamera.java +++ b/src/main/java/seng302/visualiser/cameras/TopDownCamera.java @@ -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,93 @@ 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(); - transforms.add(new Translate(0, 0, -125)); + + zoomFactor = (FAR_ZOOM_LIMIT + NEAR_ZOOM_LIMIT) / 2.0; + horizontalPan = 0.0; + verticalPan = 0.0; } public void setPlayerBoat(BoatObject playerBoat) { this.playerBoat = playerBoat; - this.playerBoat.layoutXProperty().addListener(new ChangeListener() { - @Override - public void changed(ObservableValue observable, Number oldValue, - Number newValue) { - updateCameraX((Double) oldValue, (Double) newValue); - } - }); - this.playerBoat.layoutYProperty().addListener(new ChangeListener() { - @Override - public void changed(ObservableValue 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)); + private void updateCamera() { + transforms.clear(); + transforms.addAll( + new Translate(playerBoat.getLayoutX() + horizontalPan, + playerBoat.getLayoutY() + verticalPan, zoomFactor) + ); + } + + private void adjustZoomFactor(Double adjustment) { + if (zoomFactor + adjustment < NEAR_ZOOM_LIMIT && zoomFactor + adjustment > FAR_ZOOM_LIMIT) { + zoomFactor = zoomFactor + adjustment; + updateCamera(); + } + } + + private void adjustVerticalPan(Double adjustment) { + if (verticalPan + adjustment >= -PAN_LIMIT && verticalPan + adjustment <= PAN_LIMIT) { + verticalPan += adjustment; + updateCamera(); + } + } + + 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); } + } 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