mirror of
https://github.com/michaelrausch/Party-Parrots-At-Sea.git
synced 2026-05-09 06:18:44 +00:00
Merge remote-tracking branch 'origin/story1266_3d_model_factory' into NewUI_merge
# Conflicts: # pom.xml # src/main/java/seng302/App.java # src/main/java/seng302/gameServer/GameState.java # src/main/java/seng302/gameServer/MainServerThread.java # src/main/java/seng302/gameServer/ServerToClientThread.java # src/main/java/seng302/utilities/XMLGenerator.java # src/main/java/seng302/visualiser/GameClient.java # src/main/java/seng302/visualiser/controllers/RaceViewController.java # src/main/resources/views/RaceView.fxml # src/main/resources/views/StartScreenView.fxml
This commit is contained in:
@@ -33,8 +33,6 @@ import seng302.model.stream.packets.StreamPacket;
|
||||
*/
|
||||
public class ClientToServerThread implements Runnable {
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Functional interface for receiving packets from client socket.
|
||||
*/
|
||||
@@ -95,7 +93,7 @@ public class ClientToServerThread implements Runnable {
|
||||
|
||||
sendRegistrationRequest();
|
||||
|
||||
thread = new Thread(this);
|
||||
thread = new Thread(this, "ClientToServer");
|
||||
thread.start();
|
||||
}
|
||||
|
||||
|
||||
@@ -146,13 +146,15 @@ public class GameClient {
|
||||
return new ServerDescription(serverName, regattaData.getCourseName(), GameState.getNumberOfPlayers(), GameState.getCapacity(), ipAddress, 4942);
|
||||
}
|
||||
|
||||
private void loadStartScreen() {
|
||||
|
||||
private void tearDownConnection() {
|
||||
socketThread.setSocketToClose();
|
||||
if (server != null) {
|
||||
server.terminate();
|
||||
server = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void loadStartScreen() {
|
||||
FXMLLoader fxmlLoader = new FXMLLoader(
|
||||
getClass().getResource("/views/StartScreenView.fxml"));
|
||||
try {
|
||||
@@ -250,11 +252,14 @@ public class GameClient {
|
||||
break;
|
||||
|
||||
case RACE_XML:
|
||||
courseData = XMLParser.parseRace(
|
||||
RaceXMLData raceXMLData = XMLParser.parseRace(
|
||||
StreamParser.extractXmlMessage(packet)
|
||||
);
|
||||
if (courseData == null) { //workaround for object comparisons. Avoid recreating
|
||||
courseData = raceXMLData;
|
||||
}
|
||||
if (raceView != null) {
|
||||
raceView.updateRaceData(courseData);
|
||||
raceView.updateRaceData(raceXMLData);
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
@@ -13,8 +13,7 @@ import javafx.animation.Timeline;
|
||||
import javafx.application.Platform;
|
||||
import javafx.collections.ObservableList;
|
||||
import javafx.geometry.Point2D;
|
||||
import javafx.scene.Group;
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.*;
|
||||
import javafx.scene.image.ImageView;
|
||||
import javafx.scene.input.KeyCode;
|
||||
import javafx.scene.input.KeyEvent;
|
||||
@@ -26,22 +25,23 @@ import javafx.scene.shape.Circle;
|
||||
import javafx.scene.shape.Polygon;
|
||||
import javafx.scene.text.Text;
|
||||
import javafx.util.Duration;
|
||||
import seng302.model.ClientYacht;
|
||||
import seng302.gameServer.messages.RoundingSide;
|
||||
import seng302.model.ClientYacht;
|
||||
import seng302.model.Colors;
|
||||
import seng302.model.GeoPoint;
|
||||
import seng302.model.Limit;
|
||||
import seng302.model.mark.CompoundMark;
|
||||
import seng302.model.mark.Corner;
|
||||
import seng302.model.mark.Mark;
|
||||
import seng302.model.token.Token;
|
||||
import seng302.utilities.GeoUtility;
|
||||
import seng302.visualiser.fxObjects.AnnotationBox;
|
||||
import seng302.visualiser.fxObjects.BoatObject;
|
||||
import seng302.visualiser.fxObjects.CourseBoundary;
|
||||
import seng302.visualiser.fxObjects.Gate;
|
||||
import seng302.visualiser.fxObjects.MarkArrowFactory;
|
||||
import seng302.visualiser.fxObjects.Marker;
|
||||
import seng302.visualiser.fxObjects.assets_2D.AnnotationBox;
|
||||
import seng302.visualiser.fxObjects.assets_2D.BoatObject;
|
||||
import seng302.visualiser.fxObjects.assets_2D.CourseBoundary;
|
||||
import seng302.visualiser.fxObjects.assets_2D.Gate;
|
||||
import seng302.visualiser.fxObjects.assets_2D.MarkArrowFactory;
|
||||
import seng302.visualiser.fxObjects.assets_2D.Marker;
|
||||
import seng302.visualiser.fxObjects.assets_3D.ModelFactory;
|
||||
import seng302.visualiser.fxObjects.assets_3D.ModelType;
|
||||
import seng302.visualiser.map.Boundary;
|
||||
import seng302.visualiser.map.CanvasMap;
|
||||
|
||||
@@ -82,9 +82,12 @@ public class GameView extends Pane {
|
||||
private Group boatObjectGroup = new Group();
|
||||
private Group trails = new Group();
|
||||
private Group markers = new Group();
|
||||
private Group tokens = new Group();
|
||||
private List<CompoundMark> course = new ArrayList<>();
|
||||
private List<Node> mapTokens;
|
||||
|
||||
private ImageView mapImage = new ImageView();
|
||||
private Camera camera;
|
||||
|
||||
//FRAME RATE
|
||||
|
||||
@@ -142,11 +145,26 @@ public class GameView extends Pane {
|
||||
|
||||
public GameView () {
|
||||
gameObjects = this.getChildren();
|
||||
// AmbientLight ambientLight = new AmbientLight(new Color(1,1,1,0.4));
|
||||
// ambientLight.setOpacity(0.5);
|
||||
// gameObjects.add(ambientLight);
|
||||
// create image view for map, bind panel size to image
|
||||
gameObjects.add(mapImage);
|
||||
gameObjects.add(raceBorder);
|
||||
gameObjects.add(markers);
|
||||
camera = new ParallelCamera();
|
||||
camera.setTranslateZ(-500);
|
||||
camera.setFarClip(Double.MAX_VALUE);
|
||||
camera.setNearClip(0.1);
|
||||
PointLight pl = new PointLight();
|
||||
pl.setLightOn(true);
|
||||
pl.layoutYProperty().bind(camera.layoutYProperty());
|
||||
pl.layoutXProperty().bind(camera.layoutXProperty());
|
||||
// gameObjects.add(camera);
|
||||
this.sceneProperty().addListener((obs, oldValue, scene) -> {
|
||||
if (scene != null) {
|
||||
scene.setCamera(camera);
|
||||
}
|
||||
});
|
||||
initializeTimer();
|
||||
gameObjects.addAll(mapImage, raceBorder, markers, tokens, pl);
|
||||
}
|
||||
|
||||
private void initializeTimer() {
|
||||
@@ -185,7 +203,7 @@ public class GameView extends Pane {
|
||||
lastTime = now;
|
||||
}
|
||||
}
|
||||
boatObjects.forEach((boat, boatObject) -> boatObject.updateLocation());
|
||||
// boatObjects.forEach((boat, boatObject) -> boatObject.updateLocation());
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -311,18 +329,16 @@ public class GameView extends Pane {
|
||||
for (int i=1; i < sequence.size()-1; i++) { //General case.
|
||||
double averageLat = 0;
|
||||
double averageLng = 0;
|
||||
int numMarks = 0;
|
||||
int numMarks = course.get(i-1).getMarks().size();
|
||||
for (Mark mark : course.get(i-1).getMarks()) {
|
||||
numMarks += 1;
|
||||
averageLat += mark.getLat();
|
||||
averageLng += mark.getLng();
|
||||
}
|
||||
GeoPoint lastMarkAv = new GeoPoint(averageLat / numMarks, averageLng / numMarks);
|
||||
numMarks = 0;
|
||||
numMarks = course.get(i+1).getMarks().size();
|
||||
averageLat = 0;
|
||||
averageLng = 0;
|
||||
for (Mark mark : course.get(i+1).getMarks()) {
|
||||
numMarks += 1;
|
||||
averageLat += mark.getLat();
|
||||
averageLng += mark.getLng();
|
||||
}
|
||||
@@ -440,6 +456,40 @@ public class GameView extends Pane {
|
||||
raceBorder.getPoints().setAll(boundaryPoints);
|
||||
}
|
||||
|
||||
/**
|
||||
* Rescales the race to the size of the window.
|
||||
*
|
||||
* @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();
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces all tokens in the course with those passed in
|
||||
*
|
||||
* @param newTokens the tokens to be put on the course.
|
||||
*/
|
||||
public void updateTokens(List<Token> newTokens) {
|
||||
mapTokens = new ArrayList<>();
|
||||
for (Token token : newTokens) {
|
||||
Point2D location = findScaledXY(token.getLat(), token.getLng());
|
||||
Node tokenObject = ModelFactory.importModel(ModelType.VELOCITY_PICKUP).getAssets();
|
||||
tokenObject.setLayoutX(location.getX());
|
||||
tokenObject.setLayoutY(location.getY());
|
||||
mapTokens.add(tokenObject);
|
||||
}
|
||||
|
||||
Platform.runLater(() -> {
|
||||
tokens.getChildren().clear();
|
||||
tokens.getChildren().addAll(mapTokens);
|
||||
});
|
||||
}
|
||||
|
||||
// TODO: 16/08/17 initialize zooming internal to GameView only
|
||||
/**
|
||||
* Enables zoom. Has to be called after this is added to a scene.
|
||||
@@ -455,18 +505,6 @@ public class GameView extends Pane {
|
||||
});
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Rescales the race to the size of the window.
|
||||
*
|
||||
* @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();
|
||||
}
|
||||
|
||||
private void setSelectedBoat(BoatObject bo, Boolean isSelected) {
|
||||
if (this.selectedBoat == bo && !isSelected) {
|
||||
@@ -492,7 +530,7 @@ public class GameView extends Pane {
|
||||
BoatObject newBoat;
|
||||
final List<Group> wakes = new ArrayList<>();
|
||||
for (ClientYacht clientYacht : yachts) {
|
||||
Paint colour = clientYacht.getColour();
|
||||
Color colour = clientYacht.getColour();
|
||||
newBoat = new BoatObject();
|
||||
newBoat.addSelectedBoatListener(this::setSelectedBoat);
|
||||
newBoat.setFill(colour);
|
||||
@@ -502,7 +540,7 @@ public class GameView extends Pane {
|
||||
wakes.add(newBoat.getWake());
|
||||
boatObjectGroup.getChildren().add(newBoat);
|
||||
trails.getChildren().add(newBoat.getTrail());
|
||||
// TODO: 1/08/17 Make this less vile to look at.
|
||||
|
||||
clientYacht.addLocationListener((boat, lat, lon, heading, sailIn, velocity) -> {
|
||||
BoatObject bo = boatObjects.get(boat);
|
||||
Point2D p2d = findScaledXY(lat, lon);
|
||||
@@ -789,8 +827,10 @@ public class GameView extends Pane {
|
||||
|
||||
private void updateMarkArrows (ClientYacht yacht, CompoundMark compoundMark, int legNumber) {
|
||||
//Only show arrows for this and next leg.
|
||||
// System.out.println(markerObjects);
|
||||
if (compoundMark != null) {
|
||||
for (Mark mark : compoundMark.getMarks()) {
|
||||
// System.out.println("markerObjects.get(mark) = " + markerObjects.get(mark));
|
||||
markerObjects.get(mark).showNextExitArrow();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,642 @@
|
||||
package seng302.visualiser;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import javafx.animation.AnimationTimer;
|
||||
import javafx.application.Platform;
|
||||
import javafx.geometry.Point2D;
|
||||
import javafx.geometry.Point3D;
|
||||
import javafx.scene.*;
|
||||
import javafx.scene.image.ImageView;
|
||||
import javafx.scene.input.KeyEvent;
|
||||
import javafx.scene.paint.Color;
|
||||
import javafx.scene.paint.PhongMaterial;
|
||||
import javafx.scene.shape.Sphere;
|
||||
import javafx.scene.text.Text;
|
||||
import javafx.scene.transform.Rotate;
|
||||
import javafx.scene.transform.Scale;
|
||||
import javafx.scene.transform.Translate;
|
||||
import seng302.gameServer.messages.RoundingSide;
|
||||
import seng302.model.ClientYacht;
|
||||
import seng302.model.GeoPoint;
|
||||
import seng302.model.Limit;
|
||||
import seng302.model.mark.CompoundMark;
|
||||
import seng302.model.mark.Corner;
|
||||
import seng302.model.mark.Mark;
|
||||
import seng302.model.token.Token;
|
||||
import seng302.utilities.GeoUtility;
|
||||
import seng302.visualiser.fxObjects.assets_2D.*;
|
||||
import seng302.visualiser.fxObjects.assets_3D.ModelFactory;
|
||||
import seng302.visualiser.fxObjects.assets_3D.ModelType;
|
||||
|
||||
/**
|
||||
* Collection of animated3D assets that displays a race.
|
||||
*/
|
||||
|
||||
public class GameView3D {
|
||||
|
||||
private final double FOV = 60;
|
||||
private final double DEFAULT_CAMERA_DEPTH = 100;
|
||||
|
||||
private Group root3D;
|
||||
private SubScene view;
|
||||
// ParallelCamera camera;
|
||||
private PerspectiveCamera camera;
|
||||
private Group gameObjects;
|
||||
|
||||
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 double metersPerPixelX, metersPerPixelY;
|
||||
|
||||
final double SCALE_DELTA = 1.1;
|
||||
|
||||
private Text fpsDisplay = new Text();
|
||||
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, Group> markerObjects;
|
||||
|
||||
private Map<ClientYacht, BoatObject> boatObjects = new HashMap<>();
|
||||
private Map<ClientYacht, AnnotationBox> annotations = new HashMap<>();
|
||||
private BoatObject selectedBoat = null;
|
||||
private Group annotationsGroup = new Group();
|
||||
private Group wakesGroup = new Group();
|
||||
private Group boatObjectGroup = new Group();
|
||||
private Group trails = new Group();
|
||||
private Group markers = new Group();
|
||||
private Group tokens = new Group();
|
||||
private List<CompoundMark> course = new ArrayList<>();
|
||||
private List<Node> mapTokens;
|
||||
|
||||
private ImageView mapImage = new ImageView();
|
||||
|
||||
//FRAME RATE
|
||||
|
||||
private AnimationTimer timer;
|
||||
private int NUM_SAMPLES = 10;
|
||||
private final long[] frameTimes = new long[NUM_SAMPLES];
|
||||
private Double frameRate = 60.0;
|
||||
private int frameTimeIndex = 0;
|
||||
private boolean arrayFilled = false;
|
||||
private ClientYacht playerYacht;
|
||||
private double windDir = 0.0;
|
||||
|
||||
double scaleFactor = 1;
|
||||
|
||||
private enum ScaleDirection {
|
||||
HORIZONTAL,
|
||||
VERTICAL
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public GameView3D () {
|
||||
camera = new PerspectiveCamera(true);
|
||||
// camera = new ParallelCamera();
|
||||
// gameObjects.getTransforms().add(new Scale(4,4,4));
|
||||
// camera.setLayoutX(camera.getLayoutX()-400);
|
||||
// camera.setLayoutY(camera.getLayoutY()-400);
|
||||
camera.getTransforms().addAll(
|
||||
new Translate(0,0, -DEFAULT_CAMERA_DEPTH)
|
||||
);
|
||||
camera.setFarClip(Double.MAX_VALUE);
|
||||
camera.setNearClip(0.1);
|
||||
camera.setFieldOfView(FOV);
|
||||
gameObjects = new Group();
|
||||
root3D = new Group(camera, gameObjects);
|
||||
view = new SubScene(
|
||||
root3D, 1000, 1000, true, SceneAntialiasing.BALANCED
|
||||
);
|
||||
view.setCamera(camera);
|
||||
view.setFill(Color.SKYBLUE);
|
||||
camera.getTransforms().add(new Rotate(30, new Point3D(1,0,0)));
|
||||
// gameObjects.getChildren().addAll(raceBorder, markers, tokens);
|
||||
|
||||
Sphere red = new Sphere(1);
|
||||
red.setMaterial(new PhongMaterial(Color.RED));
|
||||
red.setLayoutX(0);
|
||||
red.setLayoutY(0);
|
||||
|
||||
Sphere blue = new Sphere(1);
|
||||
blue.setMaterial(new PhongMaterial(Color.BLUE));
|
||||
blue.setLayoutX(1);
|
||||
blue.setLayoutY(0);
|
||||
|
||||
Sphere green = new Sphere(1);
|
||||
green.setMaterial(new PhongMaterial(Color.GREEN));
|
||||
green.setLayoutX(-.5);
|
||||
green.setLayoutY(0);
|
||||
|
||||
Sphere white = new Sphere(1);
|
||||
white.setMaterial(new PhongMaterial(Color.WHITE));
|
||||
white.setLayoutX(-.25);
|
||||
white.setLayoutY(0);
|
||||
|
||||
Sphere black = new Sphere(1);
|
||||
black.setMaterial(new PhongMaterial(Color.BLACK));
|
||||
black.setLayoutX(-.125);
|
||||
black.setLayoutY(0);
|
||||
|
||||
gameObjects.getChildren().addAll(
|
||||
ModelFactory.importModel(ModelType.OCEAN).getAssets(),
|
||||
raceBorder, markers, tokens,
|
||||
white, blue, green, black, red
|
||||
);
|
||||
|
||||
// Sphere s = new Sphere(1);
|
||||
// s.setMaterial(new PhongMaterial(Color.RED));
|
||||
// Sphere left = new Sphere(1);
|
||||
// left.setMaterial(new PhongMaterial(Color.LEMONCHIFFON));
|
||||
// left.getTransforms().add(new Translate(-Math.tan(Math.toRadians(FOV / 2)) * DEFAULT_CAMERA_DEPTH, 0, 0));
|
||||
// Sphere right = new Sphere(1);
|
||||
// right.setMaterial(new PhongMaterial(Color.ROSYBROWN));
|
||||
// right.getTransforms().add(new Translate(Math.tan(Math.toRadians(FOV / 2)) * DEFAULT_CAMERA_DEPTH, 0, 0));
|
||||
// Sphere top = new Sphere(1);
|
||||
// top.setMaterial(new PhongMaterial(Color.TEAL));
|
||||
// top.getTransforms().add(new Translate(0,-Math.tan(Math.toRadians(FOV / 2)) * DEFAULT_CAMERA_DEPTH, 0));
|
||||
// Sphere bottom = new Sphere(1);
|
||||
// bottom.setMaterial(new PhongMaterial(Color.BLANCHEDALMOND));
|
||||
// bottom.getTransforms().add(new Translate(0, Math.tan(Math.toRadians(FOV / 2)) * DEFAULT_CAMERA_DEPTH, 0));
|
||||
//
|
||||
// Node boat = ModelFactory.boatGameView(BoatMeshType.DINGHY, Color.BLUE).getAssets();
|
||||
// Node boat2 = ModelFactory.boatGameView(BoatMeshType.DINGHY, Color.BROWN).getAssets();
|
||||
// boat2.getTransforms().add(new Translate(0,20, 0));
|
||||
// Node boat3 = ModelFactory.boatGameView(BoatMeshType.DINGHY, Color.RED).getAssets();
|
||||
// boat3.getTransforms().add(new Translate(0,-20, 0));
|
||||
//
|
||||
// Node sMarker = ModelFactory.importModel(ModelType.START_MARKER).getAssets();
|
||||
// sMarker.getTransforms().add(0, new Translate(30, 30, 0));
|
||||
//
|
||||
// Node fMarker = ModelFactory.importModel(ModelType.FINISH_MARKER).getAssets();
|
||||
// fMarker.getTransforms().add(0, new Translate(30, -30, 0));
|
||||
//
|
||||
// Node marker = ModelFactory.importModel(ModelType.PLAIN_MARKER).getAssets();
|
||||
// marker.getTransforms().add(0, new Translate(30, 0, 0));
|
||||
//
|
||||
// Node coin = ModelFactory.importModel(ModelType.VELOCITY_PICKUP).getAssets();
|
||||
// coin.setTranslateX(coin.getTranslateX() - 30);
|
||||
//
|
||||
// gameObjects.getChildren().addAll(
|
||||
// ModelFactory.importModel(ModelType.OCEAN).getAssets(),
|
||||
// s, left, right, top, bottom,
|
||||
// boat, boat2, boat3,
|
||||
// sMarker, fMarker, marker,
|
||||
// coin
|
||||
// );
|
||||
|
||||
view.sceneProperty().addListener((obs, old, scene) -> {
|
||||
if (scene != null) {
|
||||
scene.addEventHandler(KeyEvent.KEY_PRESSED, this::cameraMovement);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void updateCourse(List<CompoundMark> newCourse, List<Corner> sequence) {
|
||||
markerObjects = new HashMap<>();
|
||||
|
||||
for (Corner corner : sequence) { //Makes course out of all compound marks.
|
||||
for (CompoundMark compoundMark : newCourse) {
|
||||
if (corner.getCompoundMarkID() == compoundMark.getId()) {
|
||||
course.add(compoundMark);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: 16/08/17 Updating mark roundings here. It should not happen here. Nor should it be done this way.
|
||||
for (Corner corner : sequence){
|
||||
CompoundMark compoundMark = course.get(corner.getSeqID() - 1);
|
||||
compoundMark.setRoundingSide(
|
||||
RoundingSide.getRoundingSide(corner.getRounding())
|
||||
);
|
||||
}
|
||||
|
||||
final List<Group> gates = new ArrayList<>();
|
||||
|
||||
//Creates new markers
|
||||
for (CompoundMark cMark : newCourse) {
|
||||
for (Mark mark : cMark.getMarks()) {
|
||||
if (cMark.getId() == sequence.get(0).getCompoundMarkID()) {
|
||||
makeAndBindMarker(mark, ModelType.START_MARKER);
|
||||
} else if (cMark.getId() == sequence.get(sequence.size() - 1).getCompoundMarkID()) {
|
||||
makeAndBindMarker(mark, ModelType.FINISH_MARKER);
|
||||
} else {
|
||||
makeAndBindMarker(mark, ModelType.PLAIN_MARKER);
|
||||
}
|
||||
}
|
||||
//Create gate line
|
||||
if (cMark.isGate()) {
|
||||
ModelType gateType;
|
||||
if (cMark.getId() == sequence.get(0).getCompoundMarkID()) {
|
||||
gateType = ModelType.START_LINE;
|
||||
} else if (cMark.getId() == sequence.get(sequence.size() - 1).getCompoundMarkID()) {
|
||||
gateType = ModelType.FINISH_LINE;
|
||||
} else {
|
||||
gateType = ModelType.GATE_LINE;
|
||||
}
|
||||
gates.add(makeGate(
|
||||
cMark.getSubMark(1), cMark.getSubMark(2), gateType
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
//Scale race to markers if there is no border.
|
||||
if (borderPoints == null) {
|
||||
rescaleRace(new ArrayList<>(markerObjects.keySet()));
|
||||
}
|
||||
//Move the Markers to initial position.
|
||||
markerObjects.forEach(((mark, marker) -> {
|
||||
Point2D p2d = findScaledXY(mark.getLat(), mark.getLng());
|
||||
System.out.println(mark.toString() + " " + p2d.toString());
|
||||
marker.setLayoutX(p2d.getX());
|
||||
marker.setLayoutY(p2d.getY());
|
||||
}));
|
||||
Platform.runLater(() -> {
|
||||
markers.getChildren().clear();
|
||||
markers.getChildren().addAll(gates);
|
||||
markers.getChildren().addAll(markerObjects.values());
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new Marker and binds it's position to the given Mark.
|
||||
*
|
||||
* @param observableMark The mark to bind the marker to.
|
||||
* @param markerType the type of marker as a ModelType. Should be PLAIN_MARKER, START_MARKER or END_MARKER
|
||||
*/
|
||||
private void makeAndBindMarker(Mark observableMark, ModelType markerType) {
|
||||
|
||||
Group marker = ModelFactory.importModel(markerType).getAssets();
|
||||
|
||||
markerObjects.put(observableMark, marker);
|
||||
observableMark.addPositionListener((mark, lat, lon) -> {
|
||||
Point2D p2d = findScaledXY(lat, lon);
|
||||
markerObjects.get(mark).setLayoutX(p2d.getX());
|
||||
markerObjects.get(mark).setLayoutY(p2d.getY());
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new gate connecting the given marks.
|
||||
*
|
||||
* @param m1 The first Mark of the gate.
|
||||
* @param m2 The second Mark of the gate.
|
||||
* @param gateType The type of model for the gate.
|
||||
* @return the new gate.
|
||||
*/
|
||||
private Group makeGate(Mark m1, Mark m2, ModelType gateType) {
|
||||
Point2D m1Location = findScaledXY(m1);
|
||||
Point2D m2Location = findScaledXY(m2);
|
||||
|
||||
Group barrier = ModelFactory.importModel(gateType).getAssets();
|
||||
barrier.getTransforms().addAll(
|
||||
new Rotate(
|
||||
Math.toDegrees(
|
||||
Math.atan2(m2Location.getY() - m1Location.getY(), m2Location.getX() - m1Location.getX())
|
||||
) + 90,
|
||||
new Point3D(0,0,1)
|
||||
),
|
||||
new Scale(1, m1Location.distance(m2Location) / 10, 1)
|
||||
);
|
||||
|
||||
Point2D midPoint = m2Location.midpoint(m1Location);
|
||||
barrier.setLayoutX(midPoint.getX());
|
||||
barrier.setLayoutY(midPoint.getY());
|
||||
return barrier;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
switch (event.getCode()) {
|
||||
case NUMPAD8:
|
||||
camera.getTransforms().addAll(new Rotate(0.5, new Point3D(1,0,0)));
|
||||
break;
|
||||
case NUMPAD2:
|
||||
camera.getTransforms().addAll(new Rotate(-0.5, new Point3D(1,0,0)));
|
||||
break;
|
||||
case NUMPAD4:
|
||||
camera.getTransforms().addAll(new Rotate(-0.5, new Point3D(0,1,0)));
|
||||
break;
|
||||
case NUMPAD6:
|
||||
camera.getTransforms().addAll(new Rotate(0.5, new Point3D(0,1,0)));
|
||||
break;
|
||||
case X:
|
||||
camera.getTransforms().addAll(new Translate(0, 0, 1.5));
|
||||
break;
|
||||
case Z:
|
||||
camera.getTransforms().addAll(new Translate(0, 0, -1.5));
|
||||
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));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Rescales the race to the size of the window.
|
||||
*
|
||||
* @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
|
||||
*/
|
||||
public void setBoats(List<ClientYacht> yachts) {
|
||||
BoatObject newBoat;
|
||||
final List<Group> wakes = new ArrayList<>();
|
||||
for (ClientYacht clientYacht : yachts) {
|
||||
Color colour = clientYacht.getColour();
|
||||
newBoat = new BoatObject();
|
||||
// newBoat.addSelectedBoatListener(this::setSelectedBoat);
|
||||
newBoat.setFill(colour);
|
||||
boatObjects.put(clientYacht, newBoat);
|
||||
// createAndBindAnnotationBox(clientYacht, colour);
|
||||
wakesGroup.getChildren().add(newBoat.getWake());
|
||||
wakes.add(newBoat.getWake());
|
||||
boatObjectGroup.getChildren().add(newBoat);
|
||||
// trails.getChildren().add(newBoat.getTrail());
|
||||
|
||||
clientYacht.addLocationListener((boat, lat, lon, heading, sailIn, velocity) -> {
|
||||
BoatObject bo = boatObjects.get(boat);
|
||||
Point2D p2d = findScaledXY(lat, lon);
|
||||
bo.moveTo(p2d.getX(), p2d.getY(), heading, velocity, sailIn, windDir);
|
||||
// annotations.get(boat).setLocation(p2d.getX(), p2d.getY());
|
||||
bo.setTrajectory(
|
||||
heading,
|
||||
velocity,
|
||||
metersPerPixelX,
|
||||
metersPerPixelY);
|
||||
});
|
||||
}
|
||||
// annotationsGroup.getChildren().addAll(annotations.values());
|
||||
Platform.runLater(() -> {
|
||||
|
||||
// gameObjects.addAll(trails);
|
||||
gameObjects.getChildren().addAll(wakes);
|
||||
gameObjects.getChildren().addAll(boatObjectGroup);
|
||||
// gameObjects.addAll(annotationsGroup);
|
||||
// gameObjects.addAll(boatObjectGroup);
|
||||
});
|
||||
}
|
||||
|
||||
public Node getAssets () {
|
||||
return view;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @param border the race border to be drawn.
|
||||
*/
|
||||
public void updateBorder(List<Limit> border) {
|
||||
if (borderPoints == null) {
|
||||
borderPoints = border;
|
||||
rescaleRace(new ArrayList<>(borderPoints));
|
||||
}
|
||||
List<Node> boundaryAssets = new ArrayList<>();
|
||||
|
||||
Point2D lastLocation = 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());
|
||||
pylon = ModelFactory.importModel(ModelType.BORDER_PYLON).getAssets();
|
||||
pylon.setLayoutX(location.getX());
|
||||
pylon.setLayoutY(location.getY());
|
||||
|
||||
Group barrier = ModelFactory.importModel(ModelType.BORDER_BARRIER).getAssets();
|
||||
barrier.getTransforms().addAll(
|
||||
new Rotate(
|
||||
Math.toDegrees(
|
||||
Math.atan2(location.getY() - lastLocation.getY(), location.getX() - lastLocation.getX())
|
||||
),
|
||||
new Point3D(0,0,1)
|
||||
),
|
||||
new Scale((lastLocation.distance(location) / 15)-0.2, 1, 1)
|
||||
);
|
||||
|
||||
Point2D midPoint = location.midpoint(lastLocation);
|
||||
barrier.setLayoutX(midPoint.getX());
|
||||
barrier.setLayoutY(midPoint.getY());
|
||||
|
||||
lastLocation = location;
|
||||
|
||||
boundaryAssets.add(barrier);
|
||||
boundaryAssets.add(pylon);
|
||||
}
|
||||
|
||||
Point2D firstLocation = findScaledXY(border.get(0).getLat(), border.get(0).getLng());
|
||||
Group barrier = ModelFactory.importModel(ModelType.BORDER_BARRIER).getAssets();
|
||||
barrier.getTransforms().addAll(
|
||||
new Rotate(
|
||||
Math.toDegrees(
|
||||
Math.atan2(lastLocation.getY() - firstLocation.getY(), lastLocation.getX() - firstLocation.getX())
|
||||
),
|
||||
new Point3D(0,0,1)
|
||||
),
|
||||
new Scale((firstLocation.distance(lastLocation) / 15)-0.2, 1, 1)
|
||||
);
|
||||
|
||||
Point2D midPoint = lastLocation.midpoint(firstLocation);
|
||||
barrier.setLayoutX(midPoint.getX());
|
||||
barrier.setLayoutY(midPoint.getY());
|
||||
boundaryAssets.add(barrier);
|
||||
|
||||
Platform.runLater(() -> raceBorder.getChildren().setAll(boundaryAssets));
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces all tokens in the course with those passed in
|
||||
*
|
||||
* @param newTokens the tokens to be put on the course.
|
||||
*/
|
||||
public void updateTokens(List<Token> newTokens) {
|
||||
mapTokens = new ArrayList<>();
|
||||
for (Token token : newTokens) {
|
||||
Point2D location = findScaledXY(token.getLat(), token.getLng());
|
||||
Node tokenObject = ModelFactory.importModel(ModelType.VELOCITY_PICKUP).getAssets();
|
||||
tokenObject.setLayoutX(location.getX());
|
||||
tokenObject.setLayoutY(location.getY());
|
||||
mapTokens.add(tokenObject);
|
||||
}
|
||||
|
||||
Platform.runLater(() -> {
|
||||
tokens.getChildren().setAll(mapTokens);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -32,6 +32,7 @@ import javafx.scene.layout.VBox;
|
||||
import javafx.scene.paint.Color;
|
||||
import javafx.scene.paint.Paint;
|
||||
import javafx.scene.shape.Line;
|
||||
import javafx.scene.shape.Polyline;
|
||||
import javafx.scene.text.Text;
|
||||
import javafx.stage.Stage;
|
||||
import javafx.stage.StageStyle;
|
||||
@@ -42,12 +43,12 @@ import seng302.model.RaceState;
|
||||
import seng302.model.mark.CompoundMark;
|
||||
import seng302.model.mark.Mark;
|
||||
import seng302.model.stream.xml.parser.RaceXMLData;
|
||||
import seng302.visualiser.GameView;
|
||||
import seng302.visualiser.controllers.annotations.Annotation;
|
||||
import seng302.visualiser.GameView3D;
|
||||
import seng302.visualiser.controllers.annotations.ImportantAnnotationController;
|
||||
import seng302.visualiser.controllers.annotations.ImportantAnnotationDelegate;
|
||||
import seng302.visualiser.controllers.annotations.ImportantAnnotationsState;
|
||||
import seng302.visualiser.fxObjects.BoatObject;
|
||||
import seng302.visualiser.fxObjects.assets_2D.BoatObject;
|
||||
import seng302.visualiser.fxObjects.assets_2D.WindArrow;
|
||||
|
||||
/**
|
||||
* Controller class that manages the display of a race
|
||||
@@ -69,7 +70,9 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
||||
@FXML
|
||||
private AnchorPane rvAnchorPane;
|
||||
@FXML
|
||||
private Text windArrowText, windDirectionText;
|
||||
private Text windDirectionText;
|
||||
@FXML
|
||||
private AnchorPane windArrowHolder;
|
||||
@FXML
|
||||
private Slider annotationSlider;
|
||||
@FXML
|
||||
@@ -85,13 +88,14 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
||||
private Map<Integer, ClientYacht> participants;
|
||||
private Map<Integer, CompoundMark> markers;
|
||||
private RaceXMLData courseData;
|
||||
private GameView gameView;
|
||||
private GameView3D gameView;
|
||||
private RaceState raceState;
|
||||
|
||||
private Timeline timerTimeline;
|
||||
private Timer timer = new Timer();
|
||||
private List<Series<String, Double>> sparkLineData = new ArrayList<>();
|
||||
private ImportantAnnotationsState importantAnnotations;
|
||||
private Polyline windArrow = new WindArrow(Color.LIGHTGRAY);
|
||||
|
||||
public void initialize() {
|
||||
// Load a default important annotation state
|
||||
@@ -110,6 +114,11 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
||||
//selectAnnotationBtn.setOnAction(event -> loadSelectAnnotationView());
|
||||
rvAnchorPane.prefWidthProperty().bind(ViewManager.getInstance().getDecorator().widthProperty());
|
||||
rvAnchorPane.prefHeightProperty().bind(ViewManager.getInstance().getDecorator().heightProperty());
|
||||
selectAnnotationBtn.setOnAction(event -> loadSelectAnnotationView());
|
||||
windArrowHolder.getChildren().addAll(windArrow);
|
||||
windArrow.setLayoutX(windArrowHolder.getWidth() / 2);
|
||||
windArrow.setLayoutY(windArrowHolder.getHeight() / 2);
|
||||
|
||||
}
|
||||
|
||||
public void loadRace (
|
||||
@@ -137,29 +146,32 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
||||
});
|
||||
|
||||
updateOrder(raceState.getPlayerPositions());
|
||||
gameView = new GameView();
|
||||
//gameView.setFrameRateFXText(fpsDisplay);
|
||||
Platform.runLater(() -> contentAnchorPane.getChildren().add(gameView));
|
||||
gameView.setBoats(new ArrayList<>(participants.values()));
|
||||
gameView.updateBorder(raceData.getCourseLimit());
|
||||
gameView.updateCourse(
|
||||
new ArrayList<>(raceData.getCompoundMarks().values()), raceData.getMarkSequence()
|
||||
gameView = new GameView3D();
|
||||
// gameView.setFrameRateFXText(fpsDisplay);
|
||||
Platform.runLater(() -> contentAnchorPane.getChildren().add(0, gameView.getAssets()));
|
||||
gameView.setBoats(new ArrayList<>(participants.values()));
|
||||
gameView.updateBorder(raceData.getCourseLimit());
|
||||
gameView.updateTokens(raceData.getTokens());
|
||||
gameView.updateCourse(
|
||||
new ArrayList<>(raceData.getCompoundMarks().values()), raceData.getMarkSequence()
|
||||
);
|
||||
gameView.enableZoom();
|
||||
gameView.setBoatAsPlayer(player);
|
||||
gameView.startRace();
|
||||
// gameView.enableZoom();
|
||||
// gameView.setBoatAsPlayer(player);
|
||||
// gameView.startRace();
|
||||
|
||||
raceState.addCollisionListener(gameView::drawCollision);
|
||||
raceState.windDirectionProperty().addListener((obs, oldDirection, newDirection) -> {
|
||||
gameView.setWindDir(newDirection.doubleValue());
|
||||
updateWindDirection(newDirection.doubleValue());
|
||||
});
|
||||
raceState.windSpeedProperty().addListener((obs, oldSpeed, newSpeed) -> {
|
||||
updateWindSpeed(newSpeed.doubleValue());
|
||||
});
|
||||
updateWindDirection(raceState.windDirectionProperty().doubleValue());
|
||||
updateWindSpeed(raceState.getWindSpeed());
|
||||
gameView.setWindDir(raceState.windDirectionProperty().doubleValue());
|
||||
// raceState.addCollisionListener(gameView::drawCollision);
|
||||
// raceState.windDirectionProperty().addListener((obs, oldDirection, newDirection) -> {
|
||||
// gameView.setWindDir(newDirection.doubleValue());
|
||||
// Platform.runLater(() -> updateWindDirection(newDirection.doubleValue()));
|
||||
// });
|
||||
// raceState.windSpeedProperty().addListener((obs, oldSpeed, newSpeed) ->
|
||||
// Platform.runLater(() -> updateWindSpeed(newSpeed.doubleValue()))
|
||||
// );
|
||||
// Platform.runLater(() -> {
|
||||
// updateWindDirection(raceState.windDirectionProperty().doubleValue());
|
||||
// updateWindSpeed(raceState.getWindSpeed());
|
||||
// });
|
||||
// gameView.setWindDir(raceState.windDirectionProperty().doubleValue());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -576,31 +588,31 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
||||
}
|
||||
|
||||
private void setAnnotations(Integer annotationLevel) {
|
||||
switch (annotationLevel) {
|
||||
// No Annotations
|
||||
case 0:
|
||||
gameView.setAnnotationVisibilities(
|
||||
false, false, false, false, false, false
|
||||
);
|
||||
break;
|
||||
// Important Annotations
|
||||
case 1:
|
||||
gameView.setAnnotationVisibilities(
|
||||
importantAnnotations.getAnnotationState(Annotation.NAME),
|
||||
importantAnnotations.getAnnotationState(Annotation.SPEED),
|
||||
importantAnnotations.getAnnotationState(Annotation.ESTTIMETONEXTMARK),
|
||||
importantAnnotations.getAnnotationState(Annotation.LEGTIME),
|
||||
importantAnnotations.getAnnotationState(Annotation.TRACK),
|
||||
importantAnnotations.getAnnotationState(Annotation.WAKE)
|
||||
);
|
||||
break;
|
||||
// All Annotations
|
||||
case 2:
|
||||
gameView.setAnnotationVisibilities(
|
||||
true, true, true, true, true, true
|
||||
);
|
||||
break;
|
||||
}
|
||||
// switch (annotationLevel) {
|
||||
// // No Annotations
|
||||
// case 0:
|
||||
// gameView.setAnnotationVisibilities(
|
||||
// false, false, false, false, false, false
|
||||
// );
|
||||
// break;
|
||||
// // Important Annotations
|
||||
// case 1:
|
||||
// gameView.setAnnotationVisibilities(
|
||||
// importantAnnotations.getAnnotationState(Annotation.NAME),
|
||||
// importantAnnotations.getAnnotationState(Annotation.SPEED),
|
||||
// importantAnnotations.getAnnotationState(Annotation.ESTTIMETONEXTMARK),
|
||||
// importantAnnotations.getAnnotationState(Annotation.LEGTIME),
|
||||
// importantAnnotations.getAnnotationState(Annotation.TRACK),
|
||||
// importantAnnotations.getAnnotationState(Annotation.WAKE)
|
||||
// );
|
||||
// break;
|
||||
// // All Annotations
|
||||
// case 2:
|
||||
// gameView.setAnnotationVisibilities(
|
||||
// true, true, true, true, true, true
|
||||
// );
|
||||
// break;
|
||||
// }
|
||||
}
|
||||
|
||||
|
||||
@@ -624,7 +636,7 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
||||
}
|
||||
|
||||
public void updateRaceData (RaceXMLData raceData) {
|
||||
this.courseData = raceData;
|
||||
gameView.updateBorder(raceData.getCourseLimit());
|
||||
gameView.updateTokens(raceData.getTokens());
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package seng302.visualiser.fxObjects;
|
||||
package seng302.visualiser.fxObjects.assets_2D;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
+153
-72
@@ -1,16 +1,25 @@
|
||||
package seng302.visualiser.fxObjects;
|
||||
package seng302.visualiser.fxObjects.assets_2D;
|
||||
|
||||
import javafx.application.Platform;
|
||||
import javafx.geometry.Point2D;
|
||||
import javafx.geometry.Point3D;
|
||||
import javafx.scene.AmbientLight;
|
||||
import javafx.scene.Group;
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.PointLight;
|
||||
import javafx.scene.paint.Color;
|
||||
import javafx.scene.paint.Paint;
|
||||
import javafx.scene.paint.PhongMaterial;
|
||||
import javafx.scene.shape.Line;
|
||||
import javafx.scene.shape.Polygon;
|
||||
import javafx.scene.shape.Polyline;
|
||||
import javafx.scene.shape.StrokeLineCap;
|
||||
import javafx.scene.shape.Shape3D;
|
||||
import javafx.scene.transform.Rotate;
|
||||
import javafx.scene.transform.Scale;
|
||||
import javafx.scene.transform.Translate;
|
||||
import seng302.visualiser.fxObjects.assets_3D.BoatMeshType;
|
||||
import seng302.visualiser.fxObjects.assets_3D.BoatModel;
|
||||
import seng302.visualiser.fxObjects.assets_3D.ModelFactory;
|
||||
import seng302.visualiser.fxObjects.assets_3D.ModelType;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -25,6 +34,17 @@ import java.util.List;
|
||||
*/
|
||||
public class BoatObject extends Group {
|
||||
|
||||
|
||||
private static final double MODEL_SCALE_FACTOR = 400;
|
||||
private static final double MODEL_X_OFFSET = 0; // standard
|
||||
private static final double MODEL_Y_OFFSET = 0; // standard
|
||||
|
||||
private static final int VIEWPORT_SIZE = 800;
|
||||
|
||||
private static final Color lightColor = Color.rgb(244, 255, 250);
|
||||
private static final Color jewelColor = Color.rgb(0, 190, 222);
|
||||
|
||||
|
||||
@FunctionalInterface
|
||||
public interface SelectedBoatListener {
|
||||
|
||||
@@ -32,8 +52,8 @@ public class BoatObject extends Group {
|
||||
}
|
||||
|
||||
//Constants for drawing
|
||||
private static final double BOAT_HEIGHT = 15d;
|
||||
private static final double BOAT_WIDTH = 10d;
|
||||
private static final float BOAT_HEIGHT = 15f;
|
||||
private static final float BOAT_WIDTH = 10f;
|
||||
|
||||
private double xVelocity;
|
||||
private double yVelocity;
|
||||
@@ -41,16 +61,18 @@ public class BoatObject extends Group {
|
||||
private double sailState;
|
||||
//Graphical objects
|
||||
private Polyline trail = new Polyline();
|
||||
private Polygon boatPoly;
|
||||
// private Polygon boatPoly;
|
||||
private BoatModel boatPoly;
|
||||
private Polygon sail;
|
||||
private Wake wake;
|
||||
private Group wake;
|
||||
private Line leftLayLine;
|
||||
private Line rightLayline;
|
||||
private double distanceTravelled, lastRotation;
|
||||
private Point2D lastPoint;
|
||||
private Paint colour = Color.BLACK;
|
||||
private Color colour = Color.BLACK;
|
||||
private Boolean isSelected = false, destinationSet; //All boats are initialised as selected
|
||||
private boolean isPlayer = false;
|
||||
private Rotate rotation = new Rotate(0,0,1);
|
||||
|
||||
private List<SelectedBoatListener> selectedBoatListenerListeners = new ArrayList<>();
|
||||
|
||||
@@ -81,20 +103,30 @@ public class BoatObject extends Group {
|
||||
* polygon.
|
||||
*/
|
||||
private void initChildren(double... points) {
|
||||
boatPoly = new Polygon(points);
|
||||
boatPoly.setFill(colour);
|
||||
boatPoly.setFill(this.colour);
|
||||
boatPoly.setOnMouseEntered(event -> {
|
||||
boatPoly.setFill(Color.FLORALWHITE);
|
||||
boatPoly.setStroke(Color.RED);
|
||||
boatPoly = makeBoatPolygon();
|
||||
boatPoly.getAssets().getTransforms().addAll(
|
||||
// new Rotate(-40, new Point3D(1,0,0)),
|
||||
rotation
|
||||
// new Rotate(-90, new Point3D(0,0,1))
|
||||
);
|
||||
boatPoly.getAssets().getTransforms().add(new Scale(5, 5, 5));
|
||||
// boatPoly.setDrawMode(DrawMode.FILL);
|
||||
// boatPoly.setFill(colour);
|
||||
// boatPoly.setFill(this.colour);
|
||||
// boatPoly.setMaterial(new PhongMaterial(this.colour));
|
||||
boatPoly.getAssets().setOnMouseEntered(event -> {
|
||||
// boatPoly.setFill(Color.FLORALWHITE);
|
||||
// boatPoly.setStroke(Color.RED);
|
||||
// boatPoly.setMaterial(new PhongMaterial(Color.FLORALWHITE));
|
||||
});
|
||||
boatPoly.setOnMouseExited(event -> {
|
||||
boatPoly.setFill(colour);
|
||||
boatPoly.setFill(this.colour);
|
||||
boatPoly.setStroke(Color.BLACK);
|
||||
boatPoly.getAssets().setOnMouseExited(event -> {
|
||||
// boatPoly.setMaterial(new PhongMaterial(this.colour));
|
||||
// boatPoly.setFill(colour);
|
||||
// boatPoly.setFill(this.colour);
|
||||
// boatPoly.setStroke(Color.BLACK);
|
||||
});
|
||||
boatPoly.setOnMouseClicked(event -> setIsSelected(!isSelected));
|
||||
boatPoly.setCache(true);
|
||||
boatPoly.getAssets().setOnMouseClicked(event -> setIsSelected(!isSelected));
|
||||
boatPoly.getAssets().setCache(true);
|
||||
// boatPoly.setCacheHint(CacheHint.SPEED);
|
||||
|
||||
// annotationBox = new AnnotationBox();
|
||||
@@ -104,8 +136,8 @@ public class BoatObject extends Group {
|
||||
rightLayline = new Line();
|
||||
trail.getStrokeDashArray().setAll(5d, 10d);
|
||||
trail.setCache(true);
|
||||
wake = new Wake(0, -BOAT_HEIGHT);
|
||||
wake.setVisible(true);
|
||||
|
||||
wake = ModelFactory.importModel(ModelType.WAKE).getAssets();
|
||||
|
||||
sail = new Polygon(0.0,BOAT_HEIGHT / 4,
|
||||
0.0, BOAT_HEIGHT);
|
||||
@@ -115,15 +147,65 @@ public class BoatObject extends Group {
|
||||
sail.setFill(Color.TRANSPARENT);
|
||||
sail.setCache(true);
|
||||
super.getChildren().clear();
|
||||
super.getChildren().addAll(boatPoly, sail);
|
||||
PointLight pointLight = new PointLight(Color.WHITE);
|
||||
// pointLight.setLightOn(true);
|
||||
pointLight.getTransforms().add(new Translate(0, 0, -30));
|
||||
super.getChildren().add(pointLight);
|
||||
// pointLight = new PointLight(Color.WHITE);
|
||||
//// pointLight.setLightOn(true);
|
||||
// pointLight.getTransforms().add(new Translate(50, 50, -20));
|
||||
// super.getChildren().add(pointLight);
|
||||
// pointLight = new PointLight(Color.WHITE);
|
||||
//// pointLight.setLightOn(true);
|
||||
// pointLight.getTransforms().add(new Translate(50, -50, -20));
|
||||
// super.getChildren().add(pointLight);
|
||||
// pointLight = new PointLight(Color.WHITE);
|
||||
//// pointLight.setLightOn(true);
|
||||
// pointLight.getTransforms().add(new Translate(-50, -50, -20));
|
||||
// super.getChildren().add(pointLight);
|
||||
AmbientLight light = new AmbientLight(new Color(0.5,0.5,0.5,1));
|
||||
super.getChildren().add(light);
|
||||
super.getChildren().addAll(boatPoly.getAssets());
|
||||
}
|
||||
|
||||
public void setFill (Paint value) {
|
||||
public void setFill (Color value) {
|
||||
this.colour = value;
|
||||
boatPoly.setFill(colour);
|
||||
PhongMaterial pm = new PhongMaterial(this.colour);
|
||||
for (int i=0;i<2;i++) {
|
||||
Shape3D s = (Shape3D) boatPoly.getAssets().getChildren().get(i);
|
||||
s.setMaterial(pm);
|
||||
}
|
||||
trail.setStroke(colour);
|
||||
}
|
||||
|
||||
public BoatModel makeBoatPolygon () {
|
||||
// StlMeshImporter importer = new StlMeshImporter();
|
||||
// importer.read(getClass().getResource("/meshes/hollow_simple_boat.stl").toString());
|
||||
// importer.read(getClass().getResource("/cube.stl").toString());
|
||||
// importer.read(getClass().getResource("/meshes/simple_yacht.stl").toString());
|
||||
// ObjModelImporter importer = new ObjModelImporter();
|
||||
// ColModelImporter importer = new ColModelImporter();
|
||||
// ColModelImporter importer = new ColModelImporter();
|
||||
// importer.read(getClass().getResource("/meshes/hollow_simple_boat.dae"));
|
||||
// MeshView mesh = importer.getImport()[0];
|
||||
// FileInputStream inputStream = null;
|
||||
// try{
|
||||
// inputStream = new FileInputStream(getClass().getResource("/meshes/simple_yacht.stl").toString());
|
||||
// Obj obj = ObjUtils.convertToRenderable(
|
||||
// ObjReader.read(inputStream));
|
||||
//
|
||||
// IntBuffer indices = ObjData.getFaceVertexIndices(obj);
|
||||
// FloatBuffer vertices = ObjData.getVertices(obj);
|
||||
// FloatBuffer texCoords = ObjData.getTexCoords(obj);
|
||||
// MeshView
|
||||
// FloatBuffer normals = ObjData.getNormals(obj);
|
||||
return ModelFactory.boatGameView(BoatMeshType.DINGHY, colour);
|
||||
// } catch (Exception e) {
|
||||
// e.printStackTrace();
|
||||
// return null;
|
||||
// }
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves the boat and its children annotations to coordinates specified
|
||||
* @param x The X coordinate to move the boat to
|
||||
@@ -134,27 +216,27 @@ public class BoatObject extends Group {
|
||||
* @param windDir .
|
||||
*/
|
||||
public void moveTo(double x, double y, double rotation, double velocity, Boolean sailIn, double windDir) {
|
||||
Double dx = Math.abs(boatPoly.getLayoutX() - x);
|
||||
Double dy = Math.abs(boatPoly.getLayoutY() - y);
|
||||
Double dx = Math.abs(boatPoly.getAssets().getLayoutX() - x);
|
||||
Double dy = Math.abs(boatPoly.getAssets().getLayoutY() - y);
|
||||
Platform.runLater(() -> {
|
||||
rotateTo(rotation, sailIn, windDir);
|
||||
boatPoly.setLayoutX(x);
|
||||
boatPoly.setLayoutY(y);
|
||||
if (sailIn) {
|
||||
// sail.getPoints().clear();
|
||||
// sail.getPoints().addAll(0.0, 0.0, 4.0, 1.5, 8.0, 3.0, 12.0, 3.5, 16.0, 3.0, 20.0, 1.5, 24.0, 0.0);
|
||||
// sail.getPoints().addAll(0.0, 0.0, 24.0, 0.0);
|
||||
sail.setLayoutX(x);
|
||||
sail.setLayoutY(y);
|
||||
} else {
|
||||
animateSail();
|
||||
sail.setLayoutX(x);
|
||||
sail.setLayoutY(y);
|
||||
}
|
||||
boatPoly.getAssets().setLayoutX(x);
|
||||
boatPoly.getAssets().setLayoutY(y);
|
||||
// if (sailIn) {
|
||||
//// sail.getPoints().clear();
|
||||
//// sail.getPoints().addAll(0.0, 0.0, 4.0, 1.5, 8.0, 3.0, 12.0, 3.5, 16.0, 3.0, 20.0, 1.5, 24.0, 0.0);
|
||||
//// sail.getPoints().addAll(0.0, 0.0, 24.0, 0.0);
|
||||
// sail.setLayoutX(x);
|
||||
// sail.setLayoutY(y);
|
||||
// } else {
|
||||
//// animateSail();
|
||||
// sail.setLayoutX(x);
|
||||
// sail.setLayoutY(y);
|
||||
// }
|
||||
wake.setLayoutX(x);
|
||||
wake.setLayoutY(y);
|
||||
});
|
||||
wake.setRotation(rotation, velocity);
|
||||
// wake.setRotation(rotation, velocity);
|
||||
// rotateTo(rotation);
|
||||
// boatPoly.setLayoutX(x);
|
||||
// boatPoly.setLayoutY(y);
|
||||
@@ -183,35 +265,33 @@ public class BoatObject extends Group {
|
||||
|
||||
|
||||
private void rotateTo(double heading, boolean sailsIn, double windDir) {
|
||||
boatPoly.getTransforms().setAll(new Rotate(heading));
|
||||
if (sailsIn) {
|
||||
rotation.setAngle(heading);
|
||||
wake.getTransforms().setAll(new Rotate(heading, new Point3D(0,0,1)));
|
||||
if (!sailsIn) {
|
||||
boatPoly.showSail();
|
||||
Double sailWindOffset = 30.0;
|
||||
Double upwindAngleLimit = 15.0;
|
||||
Double downwindAngleLimit = 10.0; //Upwind from normalised horizontal
|
||||
Double normalizedHeading = normalizeHeading(heading, windDir);
|
||||
if (normalizedHeading < 180) {
|
||||
sail.getTransforms().setAll(new Rotate(windDir + 90 + sailWindOffset));
|
||||
sail.getPoints().clear();
|
||||
sail.getPoints().addAll(0.0, 0.0, 4.0, -1.5, 8.0, -3.0, 12.0, -3.5, 16.0, -3.0, 20.0, -1.5, 24.0, 0.0);
|
||||
if (normalizedHeading > 90 + sailWindOffset){
|
||||
sail.getTransforms().setAll(new Rotate(heading + downwindAngleLimit));
|
||||
}
|
||||
if (normalizedHeading < sailWindOffset + upwindAngleLimit){
|
||||
sail.getTransforms().setAll(new Rotate(heading + 90 - upwindAngleLimit));
|
||||
boatPoly.rotateSail(90 - upwindAngleLimit);
|
||||
} else if (normalizedHeading > 90 + sailWindOffset){
|
||||
boatPoly.rotateSail(downwindAngleLimit);
|
||||
} else {
|
||||
boatPoly.rotateSail(90 + sailWindOffset);
|
||||
}
|
||||
} else {
|
||||
sail.getTransforms().setAll(new Rotate(windDir + 90 - sailWindOffset));
|
||||
sail.getPoints().clear();
|
||||
sail.getPoints().addAll(0.0, 0.0, 4.0, 1.5, 8.0, 3.0, 12.0, 3.5, 16.0, 3.0, 20.0, 1.5, 24.0, 0.0);
|
||||
if (normalizedHeading < 270 - sailWindOffset){
|
||||
sail.getTransforms().setAll(new Rotate(heading + 180 - downwindAngleLimit));
|
||||
}
|
||||
if (normalizedHeading > 360 - (sailWindOffset + upwindAngleLimit)){
|
||||
sail.getTransforms().setAll(new Rotate(heading + 90 + upwindAngleLimit));
|
||||
boatPoly.rotateSail(90 + upwindAngleLimit);
|
||||
} else if (normalizedHeading < 270 - sailWindOffset){
|
||||
boatPoly.rotateSail(180 - downwindAngleLimit);
|
||||
} else {
|
||||
boatPoly.rotateSail(90 - sailWindOffset);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
sail.getTransforms().setAll(new Rotate(windDir));
|
||||
boatPoly.hideSail();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -222,8 +302,8 @@ public class BoatObject extends Group {
|
||||
double period = 10;
|
||||
for (int i = 0; i < 50; i++) {
|
||||
points[i * 2] = amplitude * Math.sin(((Math.PI * i) / period + sailState));
|
||||
points[i * 2 + 1] = (BOAT_HEIGHT * i) / BOAT_HEIGHT / 2;
|
||||
points[199 - (i * 2)] = (BOAT_HEIGHT * i) / BOAT_HEIGHT / 2;
|
||||
points[i * 2 + 1] = (double) (BOAT_HEIGHT * i) / BOAT_HEIGHT / 2;
|
||||
points[199 - (i * 2)] = (double) (BOAT_HEIGHT * i) / BOAT_HEIGHT / 2;
|
||||
points[199 - (i * 2 + 1)] = amplitude * Math.sin(((Math.PI * i) / period + sailState));
|
||||
}
|
||||
if (sailState == - 2 * Math.PI) {
|
||||
@@ -237,6 +317,7 @@ public class BoatObject extends Group {
|
||||
}
|
||||
|
||||
public void updateLocation() {
|
||||
// boatPoly.getTransforms().add(new Rotate(2, new Point3D(1,1,1)));
|
||||
// double dx = xVelocity / 60;
|
||||
// double dy = yVelocity / 60;
|
||||
//
|
||||
@@ -346,33 +427,33 @@ public class BoatObject extends Group {
|
||||
}
|
||||
|
||||
public Double getBoatLayoutX() {
|
||||
return boatPoly.getLayoutX();
|
||||
return boatPoly.getAssets().getLayoutX();
|
||||
}
|
||||
|
||||
|
||||
public Double getBoatLayoutY() {
|
||||
return boatPoly.getLayoutY();
|
||||
return boatPoly.getAssets().getLayoutY();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets this boat to appear highlighted
|
||||
*/
|
||||
public void setAsPlayer() {
|
||||
boatPoly.getPoints().setAll(
|
||||
-BOAT_WIDTH / 1.75, BOAT_HEIGHT / 1.75,
|
||||
0.0, -BOAT_HEIGHT / 1.75,
|
||||
BOAT_WIDTH / 1.75, BOAT_HEIGHT / 1.75
|
||||
);
|
||||
boatPoly.setStroke(Color.BLACK);
|
||||
boatPoly.setStrokeWidth(2);
|
||||
boatPoly.setStrokeLineCap(StrokeLineCap.ROUND);
|
||||
// boatPoly.getPoints().setAll(
|
||||
// -BOAT_WIDTH / 1.75, BOAT_HEIGHT / 1.75,
|
||||
// 0.0, -BOAT_HEIGHT / 1.75,
|
||||
// BOAT_WIDTH / 1.75, BOAT_HEIGHT / 1.75
|
||||
// );
|
||||
// boatPoly.setStroke(Color.BLACK);
|
||||
// boatPoly.setStrokeWidth(2);
|
||||
// boatPoly.setStrokeLineCap(StrokeLineCap.ROUND);
|
||||
isPlayer = true;
|
||||
animateSail();
|
||||
}
|
||||
|
||||
public void setTrajectory(double heading, double velocity, double windDir) {
|
||||
wake.setRotation(lastHeading - heading, velocity);
|
||||
rotateTo(heading, false, windDir);
|
||||
// wake.r(lastHeading - heading, velocity);
|
||||
// rotateTo(heading, false, windDir);
|
||||
xVelocity = Math.cos(Math.toRadians(heading)) * velocity;
|
||||
yVelocity = Math.sin(Math.toRadians(heading)) * velocity;
|
||||
lastHeading = heading;
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package seng302.visualiser.fxObjects;
|
||||
package seng302.visualiser.fxObjects.assets_2D;
|
||||
|
||||
import javafx.scene.paint.Color;
|
||||
import javafx.scene.shape.Polygon;
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package seng302.visualiser.fxObjects;
|
||||
package seng302.visualiser.fxObjects.assets_2D;
|
||||
|
||||
import javafx.scene.paint.Paint;
|
||||
import javafx.scene.shape.Line;
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package seng302.visualiser.fxObjects;
|
||||
package seng302.visualiser.fxObjects.assets_2D;
|
||||
|
||||
import javafx.scene.Group;
|
||||
import javafx.scene.paint.Color;
|
||||
+14
-8
@@ -1,4 +1,4 @@
|
||||
package seng302.visualiser.fxObjects;
|
||||
package seng302.visualiser.fxObjects.assets_2D;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -7,13 +7,16 @@ import javafx.scene.Group;
|
||||
import javafx.scene.paint.Color;
|
||||
import javafx.scene.paint.Paint;
|
||||
import javafx.scene.shape.Circle;
|
||||
import javafx.scene.transform.Scale;
|
||||
import seng302.visualiser.fxObjects.assets_3D.ModelFactory;
|
||||
import seng302.visualiser.fxObjects.assets_3D.ModelType;
|
||||
|
||||
/**
|
||||
* Visual object for a mark. Contains a coloured circle and any specified arrows.
|
||||
*/
|
||||
public class Marker extends Group {
|
||||
|
||||
private Circle mark = new Circle();
|
||||
private Group mark = ModelFactory.importModel(ModelType.PLAIN_MARKER).getAssets();
|
||||
private Paint colour = Color.BLACK;
|
||||
private List<Group> enterArrows = new ArrayList<>();
|
||||
private List<Group> exitArrows = new ArrayList<>();
|
||||
@@ -24,10 +27,13 @@ public class Marker extends Group {
|
||||
* Creates a new Marker containing only a circle. The default colour is black.
|
||||
*/
|
||||
public Marker() {
|
||||
mark.setRadius(5);
|
||||
mark.setCenterX(0);
|
||||
mark.setCenterY(0);
|
||||
Platform.runLater(() -> this.getChildren().addAll(mark, new Group())); //Empty group placeholder or arrows.
|
||||
// mark.setRadius(5);
|
||||
// mark.setCenterX(0);
|
||||
// mark.setCenterY(0);
|
||||
Platform.runLater(() -> {
|
||||
mark.getTransforms().add(new Scale(5,5,5));
|
||||
this.getChildren().addAll(mark, new Group());
|
||||
}); //Empty group placeholder or arrows.
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -37,7 +43,7 @@ public class Marker extends Group {
|
||||
public Marker(Paint colour) {
|
||||
this();
|
||||
this.colour = colour;
|
||||
mark.setFill(colour);
|
||||
// mark.setFill(colour);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -48,7 +54,7 @@ public class Marker extends Group {
|
||||
* @param exitAngle The angle the arrow wil point from the marker.
|
||||
*/
|
||||
public void addArrows(MarkArrowFactory.RoundingSide roundingSide, double entryAngle,
|
||||
double exitAngle) {
|
||||
double exitAngle) {
|
||||
//Change Color.GRAY to this.colour to revert all gray arrows.
|
||||
enterArrows.add(
|
||||
MarkArrowFactory.constructEntryArrow(roundingSide, entryAngle, exitAngle, Color.GRAY)
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package seng302.visualiser.fxObjects;
|
||||
package seng302.visualiser.fxObjects.assets_2D;
|
||||
|
||||
import javafx.application.Platform;
|
||||
import javafx.scene.CacheHint;
|
||||
@@ -0,0 +1,25 @@
|
||||
package seng302.visualiser.fxObjects.assets_2D;
|
||||
|
||||
import javafx.scene.paint.Paint;
|
||||
import javafx.scene.shape.Polyline;
|
||||
import javafx.scene.shape.StrokeLineCap;
|
||||
import javafx.scene.shape.StrokeLineJoin;
|
||||
|
||||
/**
|
||||
* Created by cir27 on 5/09/17.
|
||||
*/
|
||||
public class WindArrow extends Polyline {
|
||||
public WindArrow(Paint fill) {
|
||||
this.getPoints().addAll(
|
||||
-10d, 15d,
|
||||
0d, 25d,
|
||||
0d, -25d,
|
||||
0d, 25d,
|
||||
10d, 15d
|
||||
);
|
||||
this.setStrokeLineCap(StrokeLineCap.ROUND);
|
||||
this.setStroke(fill);
|
||||
this.setStrokeWidth(5);
|
||||
this.setStrokeLineJoin(StrokeLineJoin.ROUND);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package seng302.visualiser.fxObjects.assets_3D;
|
||||
|
||||
/**
|
||||
* Enum for boat meshes. Enum values should be of the form :
|
||||
* ENUM_VALUE (hull file, mast file, X offset of mast CoR from origin, sail file, X offset of sail CoR from origin)
|
||||
* Files must be valid .stl files.
|
||||
*/
|
||||
public enum BoatMeshType {
|
||||
|
||||
DINGHY ("dinghy_hull.stl", "dinghy_mast.stl", -1.36653, "dinghy_sail.stl", -1.36653);
|
||||
|
||||
final String hullFile, mastFile, sailFile;
|
||||
final double mastOffset, sailOffset;
|
||||
|
||||
BoatMeshType(String hullFile, String mastFile, double mastOffset, String sailFile, double sailOffset) {
|
||||
this.hullFile = hullFile;
|
||||
this.mastFile = mastFile;
|
||||
this.mastOffset = mastOffset;
|
||||
this.sailFile = sailFile;
|
||||
this.sailOffset = sailOffset;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
package seng302.visualiser.fxObjects.assets_3D;
|
||||
|
||||
import javafx.animation.AnimationTimer;
|
||||
import javafx.geometry.Point3D;
|
||||
import javafx.scene.Group;
|
||||
import javafx.scene.paint.Color;
|
||||
import javafx.scene.paint.PhongMaterial;
|
||||
import javafx.scene.shape.MeshView;
|
||||
import javafx.scene.transform.Rotate;
|
||||
|
||||
/**
|
||||
* Container class for a group of 3d objects representing a boat and it's animation.
|
||||
*/
|
||||
public class BoatModel extends Model {
|
||||
|
||||
private static final int HULL_INDEX = 0;
|
||||
private static final int MAST_INDEX = 1;
|
||||
private static final int SAIL_INDEX = 2;
|
||||
|
||||
private BoatMeshType meshType;
|
||||
|
||||
/**
|
||||
* Stores a model and it's optional animation.
|
||||
* @param boatAssets The group with 3d assets for the boat.
|
||||
* @param animation Animation, can be null.
|
||||
*/
|
||||
BoatModel(Group boatAssets, AnimationTimer animation, BoatMeshType meshType) {
|
||||
super(boatAssets, animation);
|
||||
this.meshType = meshType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Rotates the sail of this model by the given amount.
|
||||
* @param degrees The rotation of the sail in degrees
|
||||
*/
|
||||
public void rotateSail(double degrees) {
|
||||
MeshView mast = getMeshViewChild(MAST_INDEX);
|
||||
MeshView sail = getMeshViewChild(SAIL_INDEX);
|
||||
mast.getTransforms().setAll(
|
||||
new Rotate(degrees, -meshType.mastOffset, 0,0, new Point3D(0, 0, 1))
|
||||
);
|
||||
sail.getTransforms().setAll(
|
||||
new Rotate(degrees, -meshType.sailOffset, 0,0, new Point3D(0, 0, 1))
|
||||
);
|
||||
}
|
||||
|
||||
public void hideSail() {
|
||||
getMeshViewChild(SAIL_INDEX).setVisible(false);
|
||||
}
|
||||
|
||||
public void showSail() {
|
||||
getMeshViewChild(SAIL_INDEX).setVisible(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes the colour of the model in this class.
|
||||
* @param newColour the new colour for the boat.
|
||||
*/
|
||||
public void changeColour(Color newColour) {
|
||||
changeColourChild(HULL_INDEX, newColour);
|
||||
changeColourChild(SAIL_INDEX, newColour);
|
||||
}
|
||||
|
||||
private void changeColourChild(int index, Color newColour) {
|
||||
MeshView meshView = getMeshViewChild(index);
|
||||
meshView.setMaterial(new PhongMaterial(newColour));
|
||||
}
|
||||
|
||||
private MeshView getMeshViewChild(int index) {
|
||||
return (MeshView) assets.getChildren().get(index);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package seng302.visualiser.fxObjects.assets_3D;
|
||||
|
||||
import javafx.animation.AnimationTimer;
|
||||
import javafx.scene.Group;
|
||||
|
||||
/**
|
||||
* Created by CJIRWIN on 7/09/2017.
|
||||
*/
|
||||
public class Model {
|
||||
|
||||
AnimationTimer animationTimer;
|
||||
Group assets;
|
||||
|
||||
Model (Group assets, AnimationTimer animation) {
|
||||
this.assets = assets;
|
||||
this.animationTimer = animation;
|
||||
if (animation != null) {
|
||||
animation.start();
|
||||
}
|
||||
}
|
||||
|
||||
void setAnimation(AnimationTimer animation) {
|
||||
animationTimer = animation;
|
||||
if (animation != null) {
|
||||
animation.start();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops the animation of this model.
|
||||
*/
|
||||
public void stopAnimation() {
|
||||
if (animationTimer != null) {
|
||||
animationTimer.stop();
|
||||
animationTimer = null;
|
||||
}
|
||||
}
|
||||
|
||||
public Group getAssets() {
|
||||
return this.assets;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,178 @@
|
||||
package seng302.visualiser.fxObjects.assets_3D;
|
||||
|
||||
import com.interactivemesh.jfx.importer.col.ColModelImporter;
|
||||
import com.interactivemesh.jfx.importer.stl.StlMeshImporter;
|
||||
import javafx.animation.AnimationTimer;
|
||||
import javafx.geometry.Point3D;
|
||||
import javafx.scene.AmbientLight;
|
||||
import javafx.scene.Group;
|
||||
import javafx.scene.paint.Color;
|
||||
import javafx.scene.paint.PhongMaterial;
|
||||
import javafx.scene.shape.Circle;
|
||||
import javafx.scene.shape.MeshView;
|
||||
import javafx.scene.transform.Rotate;
|
||||
import javafx.scene.transform.Scale;
|
||||
import javafx.scene.transform.Translate;
|
||||
|
||||
/**
|
||||
* Factory class for creating 3D models of boats.
|
||||
*/
|
||||
public class ModelFactory {
|
||||
|
||||
public static BoatModel boatIconView(BoatMeshType boatType, Color primaryColour) {
|
||||
Group boatAssets = getUnmodifiedBoatModel(boatType, primaryColour);
|
||||
boatAssets.getTransforms().addAll(
|
||||
new Scale(20, 20, 20),
|
||||
new Rotate(90, new Point3D(0,0,1)),
|
||||
new Rotate(90, new Point3D(0, 1, 0))
|
||||
);
|
||||
boatAssets.getChildren().add(new AmbientLight(new Color(1, 1, 1, 0.01)));
|
||||
return new BoatModel(boatAssets, null, boatType);
|
||||
}
|
||||
|
||||
public static BoatModel boatRotatingView(BoatMeshType boatType, Color primaryColour) {
|
||||
Group boatAssets = getUnmodifiedBoatModel(boatType, primaryColour);
|
||||
boatAssets.getTransforms().addAll(
|
||||
new Scale(40, 40, 40),
|
||||
new Rotate(90, new Point3D(0,0,1)),
|
||||
new Rotate(90, new Point3D(0, 1, 0)),
|
||||
new Rotate(0, new Point3D(1,1,1))
|
||||
);
|
||||
// TODO: 7/09/17 This seems like it will never be garbage claimed. Might have to call BoatModel.stopAnimation();
|
||||
return new BoatModel(boatAssets, new AnimationTimer() {
|
||||
|
||||
private double rotation = 0;
|
||||
private final Group group = boatAssets;
|
||||
|
||||
@Override
|
||||
public void handle(long now) {
|
||||
rotation += 0.5;
|
||||
((Rotate) group.getTransforms().get(3)).setAngle(rotation);
|
||||
}
|
||||
}, boatType);
|
||||
}
|
||||
|
||||
public static BoatModel boatGameView(BoatMeshType boatType, Color primaryColour) {
|
||||
Group boatAssets = getUnmodifiedBoatModel(boatType, primaryColour);
|
||||
boatAssets.getTransforms().setAll(
|
||||
new Rotate(-90, new Point3D(0,0,1)),
|
||||
new Scale(0.05, 0.05, 0.05)
|
||||
);
|
||||
return new BoatModel(boatAssets, null, boatType);
|
||||
}
|
||||
|
||||
private static Group getUnmodifiedBoatModel(BoatMeshType boatType, Color primaryColour) {
|
||||
Group boatAssets = new Group();
|
||||
MeshView hull = importFile(boatType.hullFile);
|
||||
hull.setMaterial(new PhongMaterial(primaryColour));
|
||||
MeshView mast = importFile(boatType.mastFile);
|
||||
mast.setMaterial(new PhongMaterial(primaryColour));
|
||||
MeshView sail = importFile(boatType.sailFile);
|
||||
sail.setMaterial(new PhongMaterial(Color.WHITE));
|
||||
boatAssets.getChildren().addAll(hull, mast, sail);
|
||||
return boatAssets;
|
||||
}
|
||||
|
||||
private static MeshView importFile(String fileName) {
|
||||
StlMeshImporter importer = new StlMeshImporter();
|
||||
importer.read(ModelFactory.class.getResource("/meshes/" + fileName));
|
||||
return new MeshView(importer.getImport());
|
||||
}
|
||||
|
||||
public static Model importModel(ModelType tokenType) {
|
||||
Group assets;
|
||||
if (tokenType.filename == null) {
|
||||
assets = new Group();
|
||||
} else {
|
||||
ColModelImporter importer = new ColModelImporter();
|
||||
importer.read(ModelFactory.class.getResource("/meshes/" + tokenType.filename));
|
||||
assets = new Group(importer.getImport());
|
||||
}
|
||||
switch (tokenType) {
|
||||
case VELOCITY_PICKUP:
|
||||
return makeCoinPickup(assets);
|
||||
case FINISH_MARKER:
|
||||
case PLAIN_MARKER:
|
||||
case START_MARKER:
|
||||
return makeMarker(assets);
|
||||
case OCEAN:
|
||||
return makeOcean(assets);
|
||||
case BORDER_PYLON:
|
||||
case BORDER_BARRIER:
|
||||
return makeBarrier(assets);
|
||||
case FINISH_LINE:
|
||||
case START_LINE:
|
||||
case GATE_LINE:
|
||||
return makeGate(assets);
|
||||
case WAKE:
|
||||
return makeWake(assets);
|
||||
default:
|
||||
return new Model(new Group(assets), null);
|
||||
}
|
||||
}
|
||||
|
||||
private static Model makeCoinPickup(Group assets){
|
||||
assets.setRotationAxis(new Point3D(1,0,0));
|
||||
assets.setRotate(90);
|
||||
assets.setTranslateX(0.2);
|
||||
assets.setTranslateY(1);
|
||||
assets.getTransforms().addAll(
|
||||
new Translate(0,-1,0),
|
||||
new Rotate(0 ,new Point3D(1,1,1))
|
||||
);
|
||||
return new Model(new Group(assets), new AnimationTimer() {
|
||||
|
||||
private double rotation = 0;
|
||||
private Group group = assets;
|
||||
|
||||
@Override
|
||||
public void handle(long now) {
|
||||
rotation += 1;
|
||||
((Rotate) group.getTransforms().get(1)).setAngle(rotation);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static Model makeMarker(Group marker) {
|
||||
ColModelImporter importer = new ColModelImporter();
|
||||
importer.read(ModelFactory.class.getResource("/meshes/" + ModelType.MARK_AREA.filename));
|
||||
Group area = new Group(importer.getImport());
|
||||
area.getChildren().add(marker);
|
||||
area.getTransforms().add(new Rotate(90, new Point3D(1, 0, 0)));
|
||||
return new Model(new Group(area), null);
|
||||
}
|
||||
|
||||
private static Model makeOcean(Group group) {
|
||||
// group.setScaleY(Double.MAX_VALUE);
|
||||
// group.setScaleX(Double.MAX_VALUE);
|
||||
// group.getTransforms().add(new Rotate(90, new Point3D(1, 0, 0)));
|
||||
Circle ocean = new Circle(0,0,1000, Color.DARKSEAGREEN);
|
||||
ocean.setStroke(Color.TRANSPARENT);
|
||||
group.getChildren().add(ocean);
|
||||
return new Model(group, null);
|
||||
}
|
||||
|
||||
private static Model makeBarrier(Group assets) {
|
||||
assets.getTransforms().addAll(
|
||||
new Rotate(90, new Point3D(1,0,0)),
|
||||
new Scale(1.5,1.5,1.5)
|
||||
);
|
||||
return new Model(new Group(assets), null);
|
||||
}
|
||||
|
||||
private static Model makeGate(Group assets) {
|
||||
assets.getTransforms().addAll(
|
||||
new Rotate(90, new Point3D(1,0,0))
|
||||
);
|
||||
return new Model(new Group(assets), null);
|
||||
}
|
||||
|
||||
private static Model makeWake(Group assets) {
|
||||
assets.getTransforms().setAll(
|
||||
new Rotate(-90, new Point3D(0,0,1)),
|
||||
new Rotate(90, new Point3D(1,0,0)),
|
||||
new Scale(0.5, 0.5, 0.5)
|
||||
);
|
||||
return new Model(new Group(assets), null);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package seng302.visualiser.fxObjects.assets_3D;
|
||||
|
||||
/**
|
||||
* Enum for models. Values should be the name of the file and files should be .dae files with texture
|
||||
* information included. Can be null in which case assets are assumed to be empty.
|
||||
*/
|
||||
public enum ModelType {
|
||||
|
||||
VELOCITY_PICKUP("velocity_pickup.dae"),
|
||||
FINISH_MARKER ("finish_marker.dae"),
|
||||
START_MARKER ("start_marker.dae"),
|
||||
PLAIN_MARKER ("plain_marker.dae"),
|
||||
MARK_AREA ("mark_area.dae"),
|
||||
OCEAN (null),
|
||||
BORDER_PYLON ("barrier_pole.dae"),
|
||||
BORDER_BARRIER ("barrier_segment.dae"),
|
||||
FINISH_LINE ("finish_line.dae"),
|
||||
START_LINE ("start_line.dae"),
|
||||
GATE_LINE ("gate_line.dae"),
|
||||
WAKE ("wake.dae");
|
||||
|
||||
final String filename;
|
||||
|
||||
ModelType(String filename) {
|
||||
this.filename = filename;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,108 @@
|
||||
package seng302.visualiser;
|
||||
|
||||
import com.interactivemesh.jfx.importer.stl.StlMeshImporter;
|
||||
import javafx.animation.AnimationTimer;
|
||||
import javafx.application.Application;
|
||||
import javafx.geometry.Point3D;
|
||||
import javafx.scene.Camera;
|
||||
import javafx.scene.Group;
|
||||
import javafx.scene.PerspectiveCamera;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.scene.SceneAntialiasing;
|
||||
import javafx.scene.paint.Color;
|
||||
import javafx.scene.paint.PhongMaterial;
|
||||
import javafx.scene.shape.MeshView;
|
||||
import javafx.scene.transform.Rotate;
|
||||
import javafx.scene.transform.Scale;
|
||||
import javafx.scene.transform.Translate;
|
||||
import javafx.stage.Stage;
|
||||
|
||||
/**
|
||||
* Created by cir27 on 7/09/17.
|
||||
*/
|
||||
public class test3d extends Application {
|
||||
|
||||
Group root = new Group();
|
||||
Scene scene;
|
||||
|
||||
@Override
|
||||
public void start(Stage primaryStage) throws Exception {
|
||||
// camera = new PerspectiveCamera();
|
||||
// gameObjects = new Group();
|
||||
// root3D = new Group(camera, gameObjects);
|
||||
scene = new Scene(
|
||||
root, 1000, 1000, true, SceneAntialiasing.BALANCED
|
||||
);
|
||||
gameView3DTest();
|
||||
primaryStage.setScene(scene);
|
||||
primaryStage.show();
|
||||
// scene.setCamera(camera);
|
||||
// primaryStage.setScene(scene);
|
||||
// primaryStage.show();
|
||||
//
|
||||
// StlMeshImporter importer = new StlMeshImporter();
|
||||
// importer.read(test3d.class.getResource("/meshes/dinghy_hull.stl").toString());
|
||||
// MeshView boat = new MeshView(importer.getImport());
|
||||
// boat.setMaterial(new PhongMaterial(Color.GREENYELLOW));
|
||||
//
|
||||
// importer = new StlMeshImporter();
|
||||
// importer.read(getClass().getResource("/meshes/dinghy_mast.stl").toString());
|
||||
// MeshView mast = new MeshView(importer.getImport());
|
||||
// mast.setMaterial(new PhongMaterial(Color.GREENYELLOW));
|
||||
//
|
||||
// importer = new StlMeshImporter();
|
||||
// importer.read(getClass().getResource("/meshes/dinghy_sail.stl").toString());
|
||||
// MeshView sail = new MeshView(importer.getImport());
|
||||
// sail.setMaterial(new PhongMaterial(Color.LIGHTGREY));
|
||||
//
|
||||
// gameObjects.getChildren().addAll(boat, mast, sail);
|
||||
//
|
||||
// gameObjects.getTransforms().add(new Scale(25, 25,25));
|
||||
// gameObjects.getTransforms().add(new Translate(15, 20,0));
|
||||
// gameObjects.getTransforms().addAll(
|
||||
// new Rotate(90, new Point3D(0,0,1)),
|
||||
// new Rotate(90, new Point3D(0, 1, 0))
|
||||
// );
|
||||
//
|
||||
//// PointLight light = new PointLight();
|
||||
//// light.setLightOn(true);
|
||||
//// light.getTransforms().add(new Translate(15, 20, 0));
|
||||
////
|
||||
//// PointLight light2 = new PointLight();
|
||||
//// light2.setLightOn(true);
|
||||
//// light2.getTransforms().add(new Translate(30, 40, 0));
|
||||
//
|
||||
//// root3D.getChildren().addAll(light);
|
||||
//
|
||||
// scene.setOnKeyPressed(event -> {
|
||||
// switch (event.getCode()) {
|
||||
// case UP:
|
||||
// gameObjects.getTransforms().add(new Rotate(5, new Point3D(0,0,1)));
|
||||
// break;
|
||||
// case DOWN:
|
||||
// gameObjects.getTransforms().add(new Rotate(-5, new Point3D(0,0,1)));
|
||||
// break;
|
||||
// case LEFT:
|
||||
// gameObjects.getTransforms().add(new Rotate(-5, new Point3D(0,1,0)));
|
||||
// break;
|
||||
// case RIGHT:
|
||||
// gameObjects.getTransforms().add(new Rotate(5, new Point3D(0,1,0)));
|
||||
// break;
|
||||
// }
|
||||
// });
|
||||
//
|
||||
// AnimationTimer animationTimer = new AnimationTimer() {
|
||||
// @Override
|
||||
// public void handle(long now) {
|
||||
// sail.getTransforms().add(new Rotate(0.5, 0, -1.36653, 0, new Point3D(0, 0, 1)));
|
||||
// }
|
||||
// };
|
||||
//
|
||||
//// animationTimer.start();
|
||||
}
|
||||
|
||||
private void gameView3DTest() {
|
||||
GameView3D gameView3D = new GameView3D();
|
||||
root.getChildren().add(gameView3D.getAssets());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user