mirror of
https://github.com/michaelrausch/Party-Parrots-At-Sea.git
synced 2026-05-09 06:18:44 +00:00
Merge branch 'develop' into 1276_Next_Mark_Indicator
# Conflicts: # src/main/java/seng302/visualiser/GameView3D.java # src/main/java/seng302/visualiser/fxObjects/assets_3D/ModelType.java
This commit is contained in:
@@ -17,17 +17,15 @@ import javafx.scene.Node;
|
||||
import javafx.scene.PerspectiveCamera;
|
||||
import javafx.scene.SceneAntialiasing;
|
||||
import javafx.scene.SubScene;
|
||||
import javafx.scene.image.Image;
|
||||
import javafx.scene.input.KeyEvent;
|
||||
import javafx.scene.paint.Color;
|
||||
import javafx.scene.transform.Rotate;
|
||||
import javafx.scene.transform.Scale;
|
||||
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.*;
|
||||
import seng302.model.mark.CompoundMark;
|
||||
import seng302.model.mark.Corner;
|
||||
import seng302.model.mark.Mark;
|
||||
@@ -42,6 +40,7 @@ import seng302.visualiser.controllers.ViewManager;
|
||||
import seng302.visualiser.fxObjects.MarkArrowFactory;
|
||||
import seng302.visualiser.fxObjects.assets_3D.BoatObject;
|
||||
import seng302.visualiser.fxObjects.assets_3D.Marker3D;
|
||||
import seng302.visualiser.fxObjects.assets_3D.Model;
|
||||
import seng302.visualiser.fxObjects.assets_3D.ModelFactory;
|
||||
import seng302.visualiser.fxObjects.assets_3D.ModelType;
|
||||
|
||||
@@ -49,63 +48,45 @@ import seng302.visualiser.fxObjects.assets_3D.ModelType;
|
||||
* Collection of animated3D assets that displays a race.
|
||||
*/
|
||||
|
||||
public class GameView3D {
|
||||
public class GameView3D extends GameView{
|
||||
|
||||
private final double FOV = 60;
|
||||
private final double DEFAULT_CAMERA_X = 0;
|
||||
private final double DEFAULT_CAMERA_Y = 155;
|
||||
private final double DEFAULT_CAMERA_Y = 100;
|
||||
|
||||
private Group root3D;
|
||||
private SubScene view;
|
||||
private Group gameObjects;
|
||||
|
||||
private Group raceBorder = new Group();
|
||||
// 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
|
||||
should be used as the limits of the map. */
|
||||
private List<Limit> borderPoints;
|
||||
private Map<Mark, Marker3D> markerObjects;
|
||||
|
||||
private BoatObject playerBoat;
|
||||
private Map<ClientYacht, BoatObject> boatObjects = new HashMap<>();
|
||||
private BoatObject selectedBoat = null;
|
||||
private Group wakesGroup = new Group();
|
||||
private Group boatObjectGroup = new Group();
|
||||
private Group markers = new Group();
|
||||
private Group tokens = new Group();
|
||||
private List<CompoundMark> course = new ArrayList<>();
|
||||
private List<Node> mapTokens;
|
||||
private AnimationTimer playerBoatAnimationTimer;
|
||||
private Group trail = new Group();
|
||||
private Double windDir;
|
||||
|
||||
|
||||
private enum ScaleDirection {
|
||||
HORIZONTAL,
|
||||
VERTICAL
|
||||
}
|
||||
private Skybox skybox;
|
||||
|
||||
public GameView3D () {
|
||||
isometricCam = new IsometricCamera(DEFAULT_CAMERA_X, DEFAULT_CAMERA_Y);
|
||||
topDownCam = new TopDownCamera();
|
||||
chaseCam = new ChaseCamera();
|
||||
|
||||
canvasWidth = canvasHeight = 300;
|
||||
|
||||
for (PerspectiveCamera pc : Arrays.asList(isometricCam, topDownCam, chaseCam)) {
|
||||
pc.setFarClip(600);
|
||||
pc.setFarClip(100000);
|
||||
pc.setNearClip(0.1);
|
||||
pc.setFieldOfView(FOV);
|
||||
}
|
||||
@@ -113,14 +94,21 @@ public class GameView3D {
|
||||
gameObjects = new Group();
|
||||
root3D = new Group(isometricCam, gameObjects);
|
||||
view = new SubScene(
|
||||
root3D, 1000, 1000, true, SceneAntialiasing.BALANCED
|
||||
root3D, 5000, 3000, true, SceneAntialiasing.BALANCED
|
||||
);
|
||||
view.setCamera(isometricCam);
|
||||
|
||||
skybox = new Skybox(new Image(getClass().getResourceAsStream("/images/skybox.jpg")), 100000, isometricCam);
|
||||
skybox.getTransforms().addAll(new Rotate(90, Rotate.X_AXIS));
|
||||
|
||||
Model land = ModelFactory.importModel(ModelType.LAND_SMOOTH);
|
||||
land.getAssets().getTransforms().add(new Rotate(90, Rotate.X_AXIS));
|
||||
|
||||
gameObjects.getChildren().addAll(
|
||||
ModelFactory.importModel(ModelType.OCEAN).getAssets(),
|
||||
raceBorder, trail, markers, tokens
|
||||
raceBorder, trail, markers, tokens, skybox, land.getAssets()
|
||||
);
|
||||
|
||||
|
||||
view.sceneProperty().addListener((obs, old, scene) -> {
|
||||
if (scene != null) {
|
||||
scene.addEventHandler(KeyEvent.KEY_PRESSED, this::cameraMovement);
|
||||
@@ -128,8 +116,10 @@ public class GameView3D {
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateCourse(List<CompoundMark> newCourse, List<Corner> sequence) {
|
||||
markerObjects = new HashMap<>();
|
||||
compoundMarks = newCourse;
|
||||
|
||||
for (Corner corner : sequence) { //Makes course out of all compound marks.
|
||||
for (CompoundMark compoundMark : newCourse) {
|
||||
@@ -180,11 +170,13 @@ public class GameView3D {
|
||||
|
||||
//Scale race to markers if there is no border.
|
||||
if (borderPoints == null) {
|
||||
rescaleRace(new ArrayList<>(markerObjects.keySet()));
|
||||
scaledPoint = ScaledPoint.makeScaledPoint(
|
||||
canvasWidth, canvasHeight, new ArrayList<>(markerObjects.keySet()), true
|
||||
);
|
||||
}
|
||||
//Move the Markers to initial position.
|
||||
markerObjects.forEach(((mark, marker) -> {
|
||||
Point2D p2d = findScaledXY(mark.getLat(), mark.getLng());
|
||||
Point2D p2d = scaledPoint.findScaledXY(mark.getLat(), mark.getLng());
|
||||
marker.setLayoutX(p2d.getX());
|
||||
marker.setLayoutY(p2d.getY());
|
||||
}));
|
||||
@@ -204,7 +196,7 @@ public class GameView3D {
|
||||
private void makeAndBindMarker(Mark observableMark, ModelType markerType) {
|
||||
markerObjects.put(observableMark, new Marker3D(markerType));
|
||||
observableMark.addPositionListener((mark, lat, lon) -> {
|
||||
Point2D p2d = findScaledXY(lat, lon);
|
||||
Point2D p2d = scaledPoint.findScaledXY(lat, lon);
|
||||
markerObjects.get(mark).setLayoutX(p2d.getX());
|
||||
markerObjects.get(mark).setLayoutY(p2d.getY());
|
||||
});
|
||||
@@ -219,8 +211,8 @@ public class GameView3D {
|
||||
* @return the new gate.
|
||||
*/
|
||||
private Group makeGate(Mark m1, Mark m2, ModelType gateType) {
|
||||
Point2D m1Location = findScaledXY(m1);
|
||||
Point2D m2Location = findScaledXY(m2);
|
||||
Point2D m1Location = scaledPoint.findScaledXY(m1);
|
||||
Point2D m2Location = scaledPoint.findScaledXY(m2);
|
||||
|
||||
Group barrier = ModelFactory.importModel(gateType).getAssets();
|
||||
barrier.getTransforms().addAll(
|
||||
@@ -278,144 +270,6 @@ public class GameView3D {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the class variables minLatPoint, maxLatPoint, minLonPoint, maxLonPoint to the point with
|
||||
* the leftmost point, rightmost point, southern most point and northern most point
|
||||
* respectively.
|
||||
*/
|
||||
private void findMinMaxPoint(List<GeoPoint> points) {
|
||||
List<GeoPoint> sortedPoints = new ArrayList<>(points);
|
||||
sortedPoints.sort(Comparator.comparingDouble(GeoPoint::getLat));
|
||||
minLatPoint = new GeoPoint(sortedPoints.get(0).getLat(), sortedPoints.get(0).getLng());
|
||||
GeoPoint maxLat = sortedPoints.get(sortedPoints.size() - 1);
|
||||
maxLatPoint = new GeoPoint(maxLat.getLat(), maxLat.getLng());
|
||||
|
||||
sortedPoints.sort(Comparator.comparingDouble(GeoPoint::getLng));
|
||||
minLonPoint = new GeoPoint(sortedPoints.get(0).getLat(), sortedPoints.get(0).getLng());
|
||||
GeoPoint maxLon = sortedPoints.get(sortedPoints.size() - 1);
|
||||
maxLonPoint = new GeoPoint(maxLon.getLat(), maxLon.getLng());
|
||||
if (maxLonPoint.getLng() - minLonPoint.getLng() > 180) {
|
||||
horizontalInversion = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the location of a reference point, this is always the point with minimum latitude,
|
||||
* in relation to the canvas.
|
||||
*
|
||||
* @param minLonToMaxLon The horizontal distance between the point of minimum longitude to
|
||||
* maximum longitude.
|
||||
*/
|
||||
private void calculateReferencePointLocation(double minLonToMaxLon) {
|
||||
GeoPoint referencePoint = minLatPoint;
|
||||
double referenceAngle;
|
||||
|
||||
if (scaleDirection == ScaleDirection.HORIZONTAL) {
|
||||
referenceAngle = Math.abs(
|
||||
GeoUtility.getBearingRad(referencePoint, minLonPoint)
|
||||
);
|
||||
referencePointX =
|
||||
-100 + distanceScaleFactor * Math.sin(referenceAngle) * GeoUtility
|
||||
.getDistance(referencePoint, minLonPoint);
|
||||
referenceAngle = Math.abs(GeoUtility.getDistance(referencePoint, maxLatPoint));
|
||||
referencePointY = -100 + canvasHeight - (bufferSize + bufferSize);
|
||||
referencePointY -= distanceScaleFactor * Math.cos(referenceAngle) * GeoUtility
|
||||
.getDistance(referencePoint, maxLatPoint);
|
||||
referencePointY = referencePointY / 2;
|
||||
referencePointY += bufferSize;
|
||||
referencePointY += distanceScaleFactor * Math.cos(referenceAngle) * GeoUtility
|
||||
.getDistance(referencePoint, maxLatPoint);
|
||||
} else {
|
||||
referencePointY = -100 + canvasHeight - bufferSize;
|
||||
referenceAngle = Math.abs(
|
||||
Math.toRadians(
|
||||
GeoUtility.getDistance(referencePoint, minLonPoint)
|
||||
)
|
||||
);
|
||||
referencePointX = -100 + bufferSize;
|
||||
referencePointX += distanceScaleFactor * Math.sin(referenceAngle) * GeoUtility
|
||||
.getDistance(referencePoint, minLonPoint);
|
||||
referencePointX +=
|
||||
((canvasWidth - (bufferSize + bufferSize)) - (minLonToMaxLon * distanceScaleFactor))
|
||||
/ 2;
|
||||
}
|
||||
if (horizontalInversion) {
|
||||
referencePointX = -100 + canvasWidth - bufferSize - (referencePointX - bufferSize);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Finds the scale factor necessary to fit all race markers within the onscreen map and assigns
|
||||
* it to distanceScaleFactor Returns the max horizontal distance of the map.
|
||||
*/
|
||||
private double scaleRaceExtremities() {
|
||||
double vertAngle = Math.abs(
|
||||
GeoUtility.getBearingRad(minLatPoint, maxLatPoint)
|
||||
);
|
||||
double vertDistance =
|
||||
Math.cos(vertAngle) * GeoUtility.getDistance(minLatPoint, maxLatPoint);
|
||||
double horiAngle = Math.abs(
|
||||
GeoUtility.getBearingRad(minLonPoint, maxLonPoint)
|
||||
);
|
||||
if (horiAngle <= (Math.PI / 2)) {
|
||||
horiAngle = (Math.PI / 2) - horiAngle;
|
||||
} else {
|
||||
horiAngle = horiAngle - (Math.PI / 2);
|
||||
}
|
||||
double horiDistance =
|
||||
Math.cos(horiAngle) * GeoUtility.getDistance(minLonPoint, maxLonPoint);
|
||||
|
||||
double vertScale = (canvasHeight - (bufferSize + bufferSize)) / vertDistance;
|
||||
|
||||
if ((horiDistance * vertScale) > (canvasWidth - (bufferSize + bufferSize))) {
|
||||
distanceScaleFactor = (canvasWidth - (bufferSize + bufferSize)) / horiDistance;
|
||||
scaleDirection = ScaleDirection.HORIZONTAL;
|
||||
} else {
|
||||
distanceScaleFactor = vertScale;
|
||||
scaleDirection = ScaleDirection.VERTICAL;
|
||||
}
|
||||
return horiDistance;
|
||||
}
|
||||
|
||||
private Point2D findScaledXY(GeoPoint unscaled) {
|
||||
return findScaledXY(unscaled.getLat(), unscaled.getLng());
|
||||
}
|
||||
|
||||
private Point2D findScaledXY(double unscaledLat, double unscaledLon) {
|
||||
double distanceFromReference;
|
||||
double angleFromReference;
|
||||
double xAxisLocation = referencePointX;
|
||||
double yAxisLocation = referencePointY;
|
||||
|
||||
angleFromReference = GeoUtility.getBearingRad(
|
||||
minLatPoint, new GeoPoint(unscaledLat, unscaledLon)
|
||||
);
|
||||
distanceFromReference = GeoUtility.getDistance(
|
||||
minLatPoint, new GeoPoint(unscaledLat, unscaledLon)
|
||||
);
|
||||
if (angleFromReference >= 0 && angleFromReference <= Math.PI / 2) {
|
||||
xAxisLocation += distanceScaleFactor * Math.sin(angleFromReference) * distanceFromReference;
|
||||
yAxisLocation -= distanceScaleFactor * Math.cos(angleFromReference) * distanceFromReference;
|
||||
} else if (angleFromReference >= 0) {
|
||||
angleFromReference = angleFromReference - Math.PI / 2;
|
||||
xAxisLocation += distanceScaleFactor * Math.cos(angleFromReference) * distanceFromReference;
|
||||
yAxisLocation += distanceScaleFactor * Math.sin(angleFromReference) * distanceFromReference;
|
||||
} else if (angleFromReference < 0 && angleFromReference >= -Math.PI / 2) {
|
||||
angleFromReference = Math.abs(angleFromReference);
|
||||
xAxisLocation -= distanceScaleFactor * Math.sin(angleFromReference) * distanceFromReference;
|
||||
yAxisLocation -= distanceScaleFactor * Math.cos(angleFromReference) * distanceFromReference;
|
||||
} else {
|
||||
angleFromReference = Math.abs(angleFromReference) - Math.PI / 2;
|
||||
xAxisLocation -= distanceScaleFactor * Math.cos(angleFromReference) * distanceFromReference;
|
||||
yAxisLocation += distanceScaleFactor * Math.sin(angleFromReference) * distanceFromReference;
|
||||
}
|
||||
if (horizontalInversion) {
|
||||
xAxisLocation = canvasWidth - bufferSize - (xAxisLocation - bufferSize);
|
||||
}
|
||||
return new Point2D(xAxisLocation, yAxisLocation);
|
||||
}
|
||||
|
||||
public void cameraMovement(KeyEvent event) {
|
||||
GameKeyBind keyBinds = GameKeyBind.getInstance();
|
||||
KeyAction keyPressed = keyBinds.getKeyAction(event.getCode());
|
||||
@@ -458,19 +312,6 @@ public class GameView3D {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Rescales the race to the size of the window.
|
||||
*g
|
||||
* @param limitingCoordinates the set of geo points that contains the extremities of the race.
|
||||
*/
|
||||
private void rescaleRace(List<GeoPoint> limitingCoordinates) {
|
||||
//Check is called once to avoid unnecessarily change the course limits once the race is running
|
||||
findMinMaxPoint(limitingCoordinates);
|
||||
double minLonToMaxLon = scaleRaceExtremities();
|
||||
calculateReferencePointLocation(minLonToMaxLon);
|
||||
// drawGoogleMap();
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws all the boats.
|
||||
* @param yachts The yachts to set in the race
|
||||
@@ -545,7 +386,7 @@ public class GameView3D {
|
||||
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);
|
||||
Point2D p2d = scaledPoint.findScaledXY(lat, lon);
|
||||
bo.moveTo(p2d.getX(), p2d.getY(), heading, velocity, sailIn, windDir);
|
||||
}
|
||||
|
||||
@@ -558,18 +399,20 @@ public class GameView3D {
|
||||
public void updateBorder(List<Limit> border) {
|
||||
if (borderPoints == null) {
|
||||
borderPoints = border;
|
||||
rescaleRace(new ArrayList<>(borderPoints));
|
||||
scaledPoint = ScaledPoint.makeScaledPoint(
|
||||
canvasWidth, canvasHeight, new ArrayList<>(borderPoints), true
|
||||
);
|
||||
}
|
||||
List<Node> boundaryAssets = new ArrayList<>();
|
||||
|
||||
Point2D lastLocation = findScaledXY(border.get(0).getLat(), border.get(0).getLng());
|
||||
Point2D lastLocation = scaledPoint.findScaledXY(border.get(0).getLat(), border.get(0).getLng());
|
||||
Group pylon = ModelFactory.importModel(ModelType.BORDER_PYLON).getAssets();
|
||||
pylon.setLayoutX(lastLocation.getX());
|
||||
pylon.setLayoutY(lastLocation.getY());
|
||||
boundaryAssets.add(pylon);
|
||||
|
||||
for (int i=1; i<border.size(); i++) {
|
||||
Point2D location = findScaledXY(border.get(i).getLat(), border.get(i).getLng());
|
||||
Point2D location = scaledPoint.findScaledXY(border.get(i).getLat(), border.get(i).getLng());
|
||||
pylon = ModelFactory.importModel(ModelType.BORDER_PYLON).getAssets();
|
||||
pylon.setLayoutX(location.getX());
|
||||
pylon.setLayoutY(location.getY());
|
||||
@@ -595,7 +438,7 @@ public class GameView3D {
|
||||
boundaryAssets.add(pylon);
|
||||
}
|
||||
|
||||
Point2D firstLocation = findScaledXY(border.get(0).getLat(), border.get(0).getLng());
|
||||
Point2D firstLocation = scaledPoint.findScaledXY(border.get(0).getLat(), border.get(0).getLng());
|
||||
Group barrier = ModelFactory.importModel(ModelType.BORDER_BARRIER).getAssets();
|
||||
barrier.getTransforms().addAll(
|
||||
new Rotate(
|
||||
@@ -623,7 +466,7 @@ public class GameView3D {
|
||||
public void updateTokens(List<Token> newTokens) {
|
||||
mapTokens = new ArrayList<>();
|
||||
for (Token token : newTokens) {
|
||||
Point2D location = findScaledXY(token.getLat(), token.getLng());
|
||||
Point2D location = scaledPoint.findScaledXY(token.getLat(), token.getLng());
|
||||
|
||||
ModelType modelType = null;
|
||||
switch (token.getTokenType()) {
|
||||
@@ -659,23 +502,17 @@ public class GameView3D {
|
||||
playerYacht.toggleSail();
|
||||
playerBoatAnimationTimer = new AnimationTimer() {
|
||||
|
||||
double count = 60;
|
||||
Point2D lastLocation = findScaledXY(playerYacht.getLocation());
|
||||
Point2D lastLocation = scaledPoint.findScaledXY(playerYacht.getLocation());
|
||||
|
||||
@Override
|
||||
public void handle(long now) {
|
||||
if (--count == 0) {
|
||||
count = 60;
|
||||
|
||||
boatObjects.get(playerYacht);
|
||||
course.get(playerYacht.getLegNumber()).getMidPoint().getLat();
|
||||
|
||||
Point2D location = scaledPoint.findScaledXY(playerYacht.getLocation());
|
||||
if (Math.abs(lastLocation.distance(location)) > 2) {
|
||||
Node segment = ModelFactory.importModel(ModelType.TRAIL_SEGMENT).getAssets();
|
||||
Point2D location = findScaledXY(playerYacht.getLocation());
|
||||
location = scaledPoint.findScaledXY(playerYacht.getLocation());
|
||||
segment.getTransforms().addAll(
|
||||
new Translate(location.getX(), location.getY(), 0),
|
||||
new Rotate(playerYacht.getHeading(), new Point3D(0,0,1)),
|
||||
new Scale(1, lastLocation.distance(location) / 5, 1)
|
||||
new Rotate(playerYacht.getHeading(), new Point3D(0,0,1))
|
||||
);
|
||||
trail.getChildren().add(segment);
|
||||
if (trail.getChildren().size() > 50) {
|
||||
|
||||
Reference in New Issue
Block a user