Merge branch 'master' into story1292_hp_punish

main
David Wu 8 years ago
commit 1a672e8ac8

@ -21,7 +21,7 @@ public class App extends Application {
public void start(Stage primaryStage) { public void start(Stage primaryStage) {
try { try {
//TODO should read a configuration file to configure server? //TODO should read a configuration file to configure server?
Event raceEvent = new Event(false, 0); Event raceEvent = new Event(false, 0, 5);
} catch (Exception e) { } catch (Exception e) {

@ -40,24 +40,17 @@ public class Event {
private String raceXML; private String raceXML;
private String regattaXML; private String regattaXML;
private String boatXML; private String boatXML;
private XMLFileType xmlFileType; private XMLFileType xmlFileType;
private Polars boatPolars; private Polars boatPolars;
/** /**
* Data sources containing data from the xml files. * Data sources containing data from the xml files.
*/ */
RaceDataSource raceDataSource; private RaceDataSource raceDataSource;
BoatDataSource boatDataSource; private BoatDataSource boatDataSource;
RegattaDataSource regattaDataSource; private RegattaDataSource regattaDataSource;
private ConnectionAcceptor connectionAcceptor; private ConnectionAcceptor connectionAcceptor;
private LatestMessages latestMessages; private LatestMessages latestMessages;
private CompositeCommand compositeCommand; private CompositeCommand compositeCommand;
/** /**
* This is used to allocate source IDs. * This is used to allocate source IDs.
*/ */
@ -66,22 +59,17 @@ public class Event {
private RaceLogic raceLogic; private RaceLogic raceLogic;
private Thread raceThread; private Thread raceThread;
private Thread connectionThread; private Thread connectionThread;
private int mapIndex; private int mapIndex;
/** /**
* Constructs an event, using various XML files. * Constructs an event, using various XML files.
* @param singlePlayer Whether or not to create a single player event. * @param singlePlayer Whether or not to create a single player event.
* @param mapIndex Specifies which map to use. * @param mapIndex Specifies which map to use.
* @throws EventConstructionException Thrown if we cannot create an Event for any reason. * @throws EventConstructionException Thrown if we cannot create an Event for any reason.
*/ */
public Event(boolean singlePlayer, int mapIndex) throws EventConstructionException { public Event(boolean singlePlayer, int mapIndex, int raceLength) throws
EventConstructionException {
PolarParser.parseNewPolars("mock/polars/acc_polars.csv"); PolarParser.parseNewPolars("mock/polars/acc_polars.csv");
this.mapIndex = mapIndex; this.mapIndex = mapIndex;
String raceXMLFile; String raceXMLFile;
@ -125,8 +113,8 @@ public class Event {
} else { } else {
this.raceXML = Event.setRaceXMLAtCurrentTimeToNow(XMLReader.readXMLFileToString(raceXMLFile, StandardCharsets.UTF_8)); this.raceXML = Event.setRaceXMLAtCurrentTimeToNow(XMLReader.readXMLFileToString(raceXMLFile, StandardCharsets.UTF_8));
this.raceXML = RaceXMLCreator.alterRaceToWind(this.raceXML, XMLFileType.Contents, windAngle); this.raceXML = RaceXMLCreator.alterRaceToWind(this.raceXML, XMLFileType.Contents, windAngle);
this.raceXML = RaceXMLCreator.scaleRaceSize(raceXML, windSpeed, 15 * 60 * 1000); this.raceXML = RaceXMLCreator.scaleRaceSize(raceXML,
windSpeed, raceLength);
} }
this.boatXML = XMLReader.readXMLFileToString(boatsXMLFile, StandardCharsets.UTF_8); this.boatXML = XMLReader.readXMLFileToString(boatsXMLFile, StandardCharsets.UTF_8);

@ -21,6 +21,8 @@ import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatter;
import java.util.Collections; import java.util.Collections;
import java.util.Comparator; import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;
/** /**
* Helper Class for creating a Race XML * Helper Class for creating a Race XML
@ -212,12 +214,16 @@ public class RaceXMLCreator {
double averageSpeed = (bestDownWindSpeed + bestUpWindSpeed) / 2; double averageSpeed = (bestDownWindSpeed + bestUpWindSpeed) / 2;
double raceApproximateTime = getRaceLength(race, averageSpeed); double raceApproximateTime = getRaceLength(race, averageSpeed);
double scale = milliseconds / raceApproximateTime; double scale = milliseconds / raceApproximateTime;
Map<XMLCompoundMark, Boolean> hasBeenScaled = new HashMap<>();
for (XMLCorner cm: race.getCompoundMarkSequence().getCorner()){ for (XMLCorner cm: race.getCompoundMarkSequence().getCorner()){
int index = cm.getCompoundMarkID() - 1; int index = cm.getCompoundMarkID() - 1;
XMLCompoundMark mark = race.getCourse().getCompoundMark().get(index); XMLCompoundMark mark = race.getCourse().getCompoundMark().get(index);
for (XMLMark m: mark.getMark()){ if (!hasBeenScaled.containsKey(mark)) {
scalePoint(m, center, scale); for (XMLMark m : mark.getMark()) {
scalePoint(m, center, scale);
}
} }
hasBeenScaled.put(mark, true);
} }
for (XMLLimit limit: race.getCourseLimit().getLimit()){ for (XMLLimit limit: race.getCourseLimit().getLimit()){
scalePoint(limit, center, scale); scalePoint(limit, center, scale);
@ -319,8 +325,13 @@ public class RaceXMLCreator {
} }
/**
* sets the current race time of the xml
* @param raceXML race xml to alter
* @param racePrestartTime prestart time
* @param racePreparatoryTime preparatory time
* @deprecated this should be used from the RaceXMLCreator not from this function
*/
public static void setRaceXMLAtCurrentTimeToNow(XMLRace raceXML, long racePrestartTime, long racePreparatoryTime){ public static void setRaceXMLAtCurrentTimeToNow(XMLRace raceXML, long racePrestartTime, long racePreparatoryTime){
//The start time is current time + 4 minutes. prestart is 3 minutes, and we add another minute. //The start time is current time + 4 minutes. prestart is 3 minutes, and we add another minute.
long millisecondsToAdd = racePrestartTime + racePreparatoryTime; long millisecondsToAdd = racePrestartTime + racePreparatoryTime;

@ -4,6 +4,8 @@ import javafx.application.Platform;
import javafx.fxml.FXML; import javafx.fxml.FXML;
import javafx.scene.control.Alert; import javafx.scene.control.Alert;
import javafx.scene.control.ButtonType; import javafx.scene.control.ButtonType;
import javafx.scene.control.Label;
import javafx.scene.control.Slider;
import javafx.scene.image.Image; import javafx.scene.image.Image;
import javafx.scene.image.ImageView; import javafx.scene.image.ImageView;
import mock.app.Event; import mock.app.Event;
@ -28,8 +30,12 @@ import java.util.logging.Logger;
*/ */
public class HostGameController extends Controller { public class HostGameController extends Controller {
private @FXML ImageView mapImage; private @FXML ImageView mapImage;
private @FXML Slider sliderLength;
private @FXML Label lblLength;
private ArrayList<Image> listOfMaps; private ArrayList<Image> listOfMaps;
private int currentMapIndex = 0; private int currentMapIndex = 0;
private int selectedRaceLength; // in minutes
private final int MAX_RACE_LENGTH = 30; // in minutes
private DatagramSocket udpSocket; private DatagramSocket udpSocket;
private MatchBrowserInterface matchBrowserInterface; private MatchBrowserInterface matchBrowserInterface;
@ -37,8 +43,33 @@ public class HostGameController extends Controller {
loadMaps(); loadMaps();
this.udpSocket = MatchBrowserSingleton.getInstance().getUdpSocket(); this.udpSocket = MatchBrowserSingleton.getInstance().getUdpSocket();
this.matchBrowserInterface = MatchBrowserSingleton.getInstance().getMatchBrowserInterface(); this.matchBrowserInterface = MatchBrowserSingleton.getInstance().getMatchBrowserInterface();
setRaceLengthSlider();
} }
/**
* Sets up the values and display for a slider object which allows a user
* to select how many minutes long they would like their race to be.
*/
private void setRaceLengthSlider(){
// set the listener to update the label
sliderLength.valueProperty().addListener((ov, old_val, new_val) -> {
selectedRaceLength = new_val.intValue();
if (selectedRaceLength == 1){
lblLength.setText(selectedRaceLength + " minute.");
} else {
lblLength.setText(selectedRaceLength + " minutes.");
}
});
// set values and marks to be displayed
sliderLength.setMin(2);
sliderLength.setMax(MAX_RACE_LENGTH);
sliderLength.setShowTickLabels(true);
sliderLength.setMajorTickUnit(MAX_RACE_LENGTH-1);
sliderLength.setBlockIncrement(1);
sliderLength.getStylesheets().add("/css/slider.css");
}
/** /**
@ -64,7 +95,8 @@ public class HostGameController extends Controller {
*/ */
public void hostGamePressed() { public void hostGamePressed() {
try { try {
App.game = new Event(false, currentMapIndex); App.game = new Event(false, currentMapIndex,
selectedRaceLength*60*1000);
App.gameType = currentMapIndex; App.gameType = currentMapIndex;
HttpMatchBrowserHost matchBrowserHost = new HttpMatchBrowserHost(); HttpMatchBrowserHost matchBrowserHost = new HttpMatchBrowserHost();

@ -40,7 +40,7 @@ public class LobbyController extends Controller {
private @FXML TextField addressFld; private @FXML TextField addressFld;
private @FXML TextField portFld; private @FXML TextField portFld;
private ObservableList<RaceConnection> connections; private ObservableList<RaceConnection> allConnections;
private ObservableList<RaceConnection> customConnections; private ObservableList<RaceConnection> customConnections;
private AudioClip sound; private AudioClip sound;
@ -51,12 +51,20 @@ public class LobbyController extends Controller {
public void initialize() { public void initialize() {
httpMatchBrowserClient = new HttpMatchBrowserClient(); httpMatchBrowserClient = new HttpMatchBrowserClient();
httpMatchBrowserClient.connections.addListener(new ListChangeListener<RaceConnection>() {
@Override
public void onChanged(Change<? extends RaceConnection> c) {
refreshTable();
}
});
new Thread(httpMatchBrowserClient, "Match Client").start(); new Thread(httpMatchBrowserClient, "Match Client").start();
// set up the connection table // set up the connection table
customConnections = FXCollections.observableArrayList(); customConnections = FXCollections.observableArrayList();
allConnections = FXCollections.observableArrayList();
//connections.add(new RaceConnection("localhost", 4942, "Local Game")); //connections.add(new RaceConnection("localhost", 4942, "Local Game"));
lobbyTable.setItems(httpMatchBrowserClient.connections); lobbyTable.setItems(allConnections);
gameNameColumn.setCellValueFactory(cellData -> cellData.getValue().gamenameProperty()); gameNameColumn.setCellValueFactory(cellData -> cellData.getValue().gamenameProperty());
hostNameColumn.setCellValueFactory(cellData -> cellData.getValue().hostnameProperty()); hostNameColumn.setCellValueFactory(cellData -> cellData.getValue().hostnameProperty());
statusColumn.setCellValueFactory(cellData -> cellData.getValue().statusProperty()); statusColumn.setCellValueFactory(cellData -> cellData.getValue().statusProperty());
@ -82,8 +90,14 @@ public class LobbyController extends Controller {
public void refreshBtnPressed(){ public void refreshBtnPressed(){
sound = new AudioClip(this.getClass().getResource("/visualiser/sounds/buttonpress.wav").toExternalForm()); sound = new AudioClip(this.getClass().getResource("/visualiser/sounds/buttonpress.wav").toExternalForm());
sound.play(); sound.play();
refreshTable();
}
private void refreshTable() {
allConnections.clear();
addCustomGames();
addServerGames(); addServerGames();
for(RaceConnection connection: connections) { for(RaceConnection connection: allConnections) {
connection.check(); connection.check();
} }
try { try {
@ -144,9 +158,9 @@ public class LobbyController extends Controller {
try { try {
int port = Integer.parseInt(portString); int port = Integer.parseInt(portString);
customConnections.add(new RaceConnection(hostName, port, "Boat Game")); customConnections.add(new RaceConnection(hostName, port, "Boat Game"));
connections.addAll(customConnections);
addressFld.clear(); addressFld.clear();
portFld.clear(); portFld.clear();
refreshTable();
} catch (NumberFormatException e) { } catch (NumberFormatException e) {
System.err.println("Port number entered is not a number"); System.err.println("Port number entered is not a number");
} }
@ -173,17 +187,14 @@ public class LobbyController extends Controller {
* Adds the games received from the server * Adds the games received from the server
*/ */
private void addServerGames() { private void addServerGames() {
httpMatchBrowserClient.connections.addAll(customConnections); allConnections.addAll(httpMatchBrowserClient.connections);
httpMatchBrowserClient.connections.addListener(new ListChangeListener<RaceConnection>() {
@Override
public void onChanged(Change<? extends RaceConnection> c) {
refreshBtnPressed();
}
});
/* /*
for (HostGame game : matchBrowserLobbyInterface.getGames()) { for (HostGame game : matchBrowserLobbyInterface.getGames()) {
connections.add(new RaceConnection(game.getIp(), 4942, "Boat Game")); connections.add(new RaceConnection(game.getIp(), 4942, "Boat Game"));
}*/ }*/
} }
private void addCustomGames() {
allConnections.addAll(customConnections);
}
} }

@ -0,0 +1,123 @@
package visualiser.Controllers;
import com.interactivemesh.jfx.importer.stl.StlMeshImporter;
import javafx.animation.AnimationTimer;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.geometry.Point3D;
import javafx.scene.AmbientLight;
import javafx.scene.control.Label;
import javafx.scene.layout.Pane;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.paint.PhongMaterial;
import javafx.scene.shape.Cylinder;
import javafx.scene.shape.MeshView;
import javafx.scene.shape.Shape3D;
import javafx.scene.transform.Rotate;
import shared.model.Bearing;
import shared.model.CompoundMark;
import shared.model.GPSCoordinate;
import visualiser.layout.Annotation3D;
import visualiser.layout.Assets3D;
import visualiser.layout.Subject3D;
import visualiser.layout.View3D;
import visualiser.model.VisualiserBoat;
import java.net.URL;
import java.util.Observable;
import java.util.Observer;
public class NextMarkController {
private @FXML StackPane arrowStackPane2d;
private @FXML StackPane arrowStackPane3d;
private @FXML Pane pane2d;
private @FXML Pane pane3d;
private VisualiserBoat boat;
public void initialiseArrowView(VisualiserBoat boat) {
this.boat = boat;
pane2d.setVisible(true);
pane3d.setVisible(false);
initialise2dArrowView();
initialise3dArrowView();
}
private void initialise2dArrowView() {
AnimationTimer arrow2d = new AnimationTimer() {
@Override
public void handle(long now) {
if (boat.getCurrentLeg().getEndCompoundMark() != null) {
CompoundMark target = boat.getCurrentLeg().getEndCompoundMark();
Bearing headingToMark = GPSCoordinate.calculateBearing(boat.getPosition(), target.getAverageGPSCoordinate());
arrowStackPane2d.setRotate(headingToMark.degrees());
} else {
stop();
}
}
};
arrow2d.start();
}
private void initialise3dArrowView() {
ObservableList<Subject3D> viewSubjects = FXCollections.observableArrayList();
String arrowPath = "assets/mark_arrow.x3d";
Shape3D arrow = Assets3D.loadX3d(arrowPath);
arrow.setScaleX(25);
arrow.setScaleY(25);
arrow.setScaleZ(100);
arrow.setRotationAxis(new Point3D(1,0,0));
arrowStackPane3d.getChildren().add(arrow);
AnimationTimer arrow3d = new AnimationTimer() {
@Override
public void handle(long now) {
if (boat.getCurrentLeg().getEndCompoundMark() != null) {
arrow.getTransforms().clear();
double zRotation = calculateZRotate();
arrow.setRotate(calculateXRotate(zRotation));
arrow.getTransforms().add(new Rotate(zRotation, new Point3D(0, 0, 1)));
} else {
stop();
}
}
};
arrow3d.start();
}
public void show2d() {
pane3d.setVisible(false);
pane2d.setVisible(true);
}
public void show3d() {
pane2d.setVisible(false);
pane3d.setVisible(true);
}
private double calculateZRotate() {
CompoundMark target = boat.getCurrentLeg().getEndCompoundMark();
Bearing headingToMark = GPSCoordinate.calculateBearing(boat.getPosition(), target.getAverageGPSCoordinate());
return -headingToMark.degrees() + boat.getBearing().degrees() + 180;
}
private double calculateXRotate(double zRotation) {
// if (zRotation > 360) {
// zRotation -=360;
// } else if (zRotation < 0) {
// zRotation += 360;
// }
//
// if (zRotation > 180) {
// zRotation = 360 - zRotation;
// }
return 70;
//return 90 - 20 * Math.cos(Math.toRadians(zRotation));
}
}

@ -21,11 +21,13 @@ import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent; import javafx.scene.input.KeyEvent;
import javafx.scene.layout.AnchorPane; import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.GridPane; import javafx.scene.layout.GridPane;
import javafx.scene.layout.Pane;
import javafx.scene.layout.StackPane; import javafx.scene.layout.StackPane;
import javafx.scene.media.AudioClip; import javafx.scene.media.AudioClip;
import javafx.scene.paint.Color; import javafx.scene.paint.Color;
import javafx.scene.paint.Material; import javafx.scene.paint.Material;
import javafx.scene.paint.PhongMaterial; import javafx.scene.paint.PhongMaterial;
import javafx.scene.shape.Cylinder;
import javafx.scene.paint.Stop; import javafx.scene.paint.Stop;
import javafx.scene.shape.MeshView; import javafx.scene.shape.MeshView;
import javafx.scene.shape.Shape3D; import javafx.scene.shape.Shape3D;
@ -90,10 +92,12 @@ public class RaceViewController extends Controller {
// note: it says it's not used but it is! do not remove :) // note: it says it's not used but it is! do not remove :)
private @FXML ArrowController arrowController; private @FXML ArrowController arrowController;
private @FXML NextMarkController nextMarkController;
private @FXML GridPane canvasBase; private @FXML GridPane canvasBase;
private @FXML GridPane canvasBase1; private @FXML GridPane canvasBase1;
private @FXML SplitPane racePane; private @FXML SplitPane racePane;
private @FXML StackPane arrowPane; private @FXML StackPane arrowPane;
private @FXML Pane nextMarkPane;
private @FXML Label timer; private @FXML Label timer;
private @FXML Label FPS; private @FXML Label FPS;
private @FXML Label timeZone; private @FXML Label timeZone;
@ -302,19 +306,6 @@ public class RaceViewController extends Controller {
* Initialises the various UI components to listen to the {@link #visualiserRace}. * Initialises the various UI components to listen to the {@link #visualiserRace}.
*/ */
private void initialiseRaceVisuals() { private void initialiseRaceVisuals() {
// Import arrow mesh
URL asset = this.getClass().getClassLoader().getResource("assets/arrow V1.0.4.stl");
StlMeshImporter importer = new StlMeshImporter();
importer.read(asset);
MeshView arrow = new MeshView(importer.getImport());
PhongMaterial arrowMat = new PhongMaterial(Color.RED);
arrow.setMaterial(arrowMat);
this.nextMarkArrow = new Annotation3D(arrow);
this.nextMarkArrow.setScale(0.1);
// initialise displays // initialise displays
initialiseFps(); initialiseFps();
initialiseInfoTable(); initialiseInfoTable();
@ -323,6 +314,7 @@ public class RaceViewController extends Controller {
initialiseRaceClock(); initialiseRaceClock();
initialiseSpeedometer(); initialiseSpeedometer();
raceTimer(); // start the timer raceTimer(); // start the timer
nextMarkPane.toFront();
speedometerLoop(); speedometerLoop();
new Sparkline(this.raceState, this.sparklineChart); new Sparkline(this.raceState, this.sparklineChart);
timeZone.setText(this.raceState.getRaceClock().getTimeZone()); timeZone.setText(this.raceState.getRaceClock().getTimeZone());
@ -349,6 +341,12 @@ public class RaceViewController extends Controller {
private void initialiseView3D(VisualiserRaceEvent race) { private void initialiseView3D(VisualiserRaceEvent race) {
viewSubjects = FXCollections.observableArrayList(); viewSubjects = FXCollections.observableArrayList();
try {
nextMarkController.initialiseArrowView(race.getVisualiserRaceState().getBoat(race.getVisualiserRaceState().getPlayerBoatID()));
} catch (BoatNotFoundException e) {
e.printStackTrace();
}
AmbientLight ambientLight = new AmbientLight(Color.web("#CCCCFF")); AmbientLight ambientLight = new AmbientLight(Color.web("#CCCCFF"));
ambientLight.setTranslateX(250); ambientLight.setTranslateX(250);
ambientLight.setTranslateZ(210); ambientLight.setTranslateZ(210);
@ -419,11 +417,29 @@ public class RaceViewController extends Controller {
viewSubjects.add(markModel); viewSubjects.add(markModel);
} }
for (VisualiserBoat boat: race.getVisualiserRaceState().getBoats()) { // Position and add each boat to view
for(VisualiserBoat boat: race.getVisualiserRaceState().getBoats()) {
Shape3D mesh = Assets3D.getBoat();
PhongMaterial boatColorMat = new PhongMaterial(boat.getColor());
//mesh.setMaterial(boatColorMat);
Subject3D boatModel = new Subject3D(mesh, boat.getSourceID());
// Configure visualiser for client's boat
if (boat.isClientBoat()) { if (boat.isClientBoat()) {
// Add player boat highlight
Shockwave boatHighlight = new Shockwave(10); Shockwave boatHighlight = new Shockwave(10);
boatHighlight.getMesh().setMaterial(new PhongMaterial(new Color(1, 1, 0, 0.1))); boatHighlight.getMesh().setMaterial(new PhongMaterial(new Color(1, 1, 0, 0.1)));
viewSubjects.add(boatHighlight); viewSubjects.add(boatHighlight);
// Track player boat with camera
viewSubjects.add(boatModel);
Platform.runLater(() -> {
view3D.trackSubject(boatModel);
view3D.setThirdPerson();
});
// Track player boat with highlight
AnimationTimer highlightTrack = new AnimationTimer() { AnimationTimer highlightTrack = new AnimationTimer() {
@Override @Override
public void handle(long now) { public void handle(long now) {
@ -432,24 +448,18 @@ public class RaceViewController extends Controller {
} }
}; };
highlightTrack.start(); highlightTrack.start();
}
}
// Position and add each boat to view // Highlight next mark only for player boat
for(VisualiserBoat boat: race.getVisualiserRaceState().getBoats()) { Material markColor = new PhongMaterial(new Color(0.15,0.9,0.2,1));
// MeshView mesh; CompoundMark nextMark = boat.getCurrentLeg().getEndCompoundMark();
// if(boat.getSourceID() == race.getVisualiserRaceState().getPlayerBoatID()) { view3D.getShape(nextMark.getMark1().getSourceID()).getMesh().setMaterial(markColor);
// mesh = new MeshView(importer.getImport()); if(nextMark.getMark2() != null) {
// } else { view3D.getShape(nextMark.getMark2().getSourceID()).getMesh().setMaterial(markColor);
// mesh = new MeshView(importerBurgerBoat.getImport()); }
// } boat.legProperty().addListener((o, prev, curr) -> Platform.runLater(() -> swapColours(curr)));
Shape3D mesh = Assets3D.getBoat(); } else {
viewSubjects.add(boatModel);
PhongMaterial boatColorMat = new PhongMaterial(boat.getColor()); }
//mesh.setMaterial(boatColorMat);
Subject3D boatModel = new Subject3D(mesh, boat.getSourceID());
viewSubjects.add(boatModel);
//Create health effect //Create health effect
HealthEffect healthEffect = new HealthEffect(boat.getSourceID(), System.currentTimeMillis()); HealthEffect healthEffect = new HealthEffect(boat.getSourceID(), System.currentTimeMillis());
@ -459,6 +469,7 @@ public class RaceViewController extends Controller {
//add sail //add sail
Sails3D sails3D = new Sails3D(); Sails3D sails3D = new Sails3D();
Subject3D sailsSubject = new Subject3D(sails3D, 0); Subject3D sailsSubject = new Subject3D(sails3D, 0);
sails3D.setMouseTransparent(true);
sails3D.setMaterial(boatColorMat); sails3D.setMaterial(boatColorMat);
sailsSubject.setXRot(0d); sailsSubject.setXRot(0d);
sailsSubject.setHeading(visualiserRace.getVisualiserRaceState().getWindDirection().degrees()); sailsSubject.setHeading(visualiserRace.getVisualiserRaceState().getWindDirection().degrees());
@ -547,17 +558,9 @@ public class RaceViewController extends Controller {
}; };
trackBoat.start(); trackBoat.start();
Material markColor = new PhongMaterial(new Color(0.15,0.9,0.2,1));
CompoundMark nextMark = boat.getCurrentLeg().getEndCompoundMark();
view3D.getShape(nextMark.getMark1().getSourceID()).getMesh().setMaterial(markColor);
if(nextMark.getMark2() != null) {
view3D.getShape(nextMark.getMark2().getSourceID()).getMesh().setMaterial(markColor);
}
Subject3D shockwave = new Shockwave(10); Subject3D shockwave = new Shockwave(10);
viewSubjects.add(shockwave); viewSubjects.add(shockwave);
boat.legProperty().addListener((o, prev, curr) -> Platform.runLater(() -> swapColours(curr)));
boat.hasCollidedProperty().addListener((o, prev, curr) -> Platform.runLater(() -> showCollision(boat, shockwave))); boat.hasCollidedProperty().addListener((o, prev, curr) -> Platform.runLater(() -> showCollision(boat, shockwave)));
} }
// Fix initial bird's-eye position // Fix initial bird's-eye position
@ -642,37 +645,32 @@ public class RaceViewController extends Controller {
} }
private void addThirdPersonAnnotations(Subject3D subject3D) { private void addThirdPersonAnnotations(Subject3D subject3D) {
viewSubjects.add(nextMarkArrow); nextMarkController.show3d();
final VisualiserBoat boat; // viewSubjects.add(nextMarkArrow);
try { // final VisualiserBoat boat;
boat = visualiserRace.getVisualiserRaceState().getBoat(subject3D.getSourceID()); // try {
} catch (BoatNotFoundException e) { // boat = visualiserRace.getVisualiserRaceState().getBoat(subject3D.getSourceID());
e.printStackTrace(); // } catch (BoatNotFoundException e) {
return; // e.printStackTrace();
} // return;
arrowToNextMark = new AnimationTimer() { // }
@Override // arrowToNextMark = new AnimationTimer() {
public void handle(long now) { // @Override
CompoundMark target = boat.getCurrentLeg().getEndCompoundMark(); // public void handle(long now) {
if (target != null) { // CompoundMark target = boat.getCurrentLeg().getEndCompoundMark();
Bearing headingToMark = GPSCoordinate.calculateBearing(boat.getPosition(), target.getAverageGPSCoordinate()); // Bearing headingToMark = GPSCoordinate.calculateBearing(boat.getPosition(), target.getAverageGPSCoordinate());
//
nextMarkArrow.setX(view3D.getPivot().getX()); // nextMarkArrow.setX(view3D.getPivot().getX());
nextMarkArrow.setY(view3D.getPivot().getY()); // nextMarkArrow.setY(view3D.getPivot().getY());
nextMarkArrow.setZ(view3D.getPivot().getZ() + 15); // nextMarkArrow.setZ(view3D.getPivot().getZ() + 15);
nextMarkArrow.setHeading(headingToMark.degrees()); // nextMarkArrow.setHeading(headingToMark.degrees());
} // }
} // };
}; // arrowToNextMark.start();
arrowToNextMark.start();
} }
private void removeThirdPersonAnnotations() { private void removeThirdPersonAnnotations() {
viewSubjects.remove(nextMarkArrow); nextMarkController.show2d();
if (arrowToNextMark != null) {
arrowToNextMark.stop();
}
} }
/** /**

@ -52,7 +52,7 @@ public class Assets3D {
windArrow = new Annotation3D(loadX3d(arrowPath)); windArrow = new Annotation3D(loadX3d(arrowPath));
} }
private static Shape3D loadX3d(String path){ public static Shape3D loadX3d(String path){
X3dModelImporter x3dModelImporter = new X3dModelImporter(); X3dModelImporter x3dModelImporter = new X3dModelImporter();
URL asset = Assets3D.class.getClassLoader().getResource(path); URL asset = Assets3D.class.getClassLoader().getResource(path);
x3dModelImporter.read(asset); x3dModelImporter.read(asset);

@ -81,7 +81,7 @@ public class View3D extends Pane {
/** /**
* Distance to stop zoom * Distance to stop zoom
*/ */
private final double ZOOM_IN_LIMIT = 30; private final double ZOOM_IN_LIMIT = 3;
private final double ZOOM_OUT_LIMIT = 700; private final double ZOOM_OUT_LIMIT = 700;
private final double MAX_ZOOM_LIMIT = 1500; private final double MAX_ZOOM_LIMIT = 1500;
private final double MAX_PITCH = 60; // birds eye view private final double MAX_PITCH = 60; // birds eye view

@ -0,0 +1,62 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE X3D PUBLIC "ISO//Web3D//DTD X3D 3.0//EN" "http://www.web3d.org/specifications/x3d-3.0.dtd">
<X3D version="3.0" profile="Immersive" xmlns:xsd="http://www.w3.org/2001/XMLSchema-instance" xsd:noNamespaceSchemaLocation="http://www.web3d.org/specifications/x3d-3.0.xsd">
<head>
<meta name="filename" content="Mark Arrow V1.3.x3d" />
<meta name="generator" content="Blender 2.77 (sub 0)" />
</head>
<Scene>
<NavigationInfo headlight="true"
visibilityLimit="0.0"
type='"EXAMINE", "ANY"'
avatarSize="0.25, 1.75, 0.75"
/>
<Background DEF="WO_World"
groundColor="0.051 0.051 0.051"
skyColor="0.051 0.051 0.051"
/>
<Transform DEF="Cube_TRANSFORM"
translation="0.000000 0.000000 0.000000"
scale="1.000000 1.000000 1.000000"
rotation="0.000000 0.707107 0.707107 3.141593"
>
<Transform DEF="Cube_ifs_TRANSFORM"
translation="0.000000 0.000000 0.000000"
scale="1.000000 1.000000 1.000000"
rotation="1.000000 0.000000 0.000000 0.000000"
>
<Group DEF="group_ME_Cube">
<Shape>
<Appearance>
<ImageTexture DEF="IM_Material_Diffuse_Color_002"
url='"textures/Material Diffuse Color.002" "Material Diffuse Color.002" "D:/Storage/3D Models/Misc/SENG302/Mark Arrow/textures/Material Diffuse Color.002"'
/>
<TextureTransform
translation="0.000000 0.000000"
scale="1.000000 1.000000"
rotation="0.000000"
/>
<Material DEF="MA_Material"
diffuseColor="0.800 0.800 0.800"
specularColor="0.401 0.401 0.401"
emissiveColor="0.000 0.000 0.000"
ambientIntensity="0.333"
shininess="0.098"
transparency="0.0"
/>
</Appearance>
<IndexedFaceSet solid="true"
texCoordIndex="0 1 2 -1 3 4 5 -1 6 7 8 9 -1 10 11 12 -1 13 14 15 -1 16 17 18 19 -1 20 21 22 -1 23 24 25 -1 26 27 28 29 -1 30 31 32 -1 33 34 35 -1 36 37 38 39 -1 "
coordIndex="4 1 7 -1 2 0 8 -1 1 0 2 3 -1 1 3 7 -1 8 0 9 -1 0 1 4 9 -1 4 7 6 -1 2 8 5 -1 6 3 2 5 -1 6 7 3 -1 8 9 5 -1 4 6 5 9 -1 "
>
<Coordinate DEF="coords_ME_Cube"
point="1.000000 -0.000000 -0.100000 1.000000 -0.000001 0.100000 0.000000 2.000000 -0.100000 0.000000 2.000000 0.100000 0.000000 -2.000000 0.100000 -1.000000 -0.000000 -0.100000 -1.000000 -0.000001 0.100000 0.000000 -0.000000 0.100000 0.000000 0.000000 -0.100000 0.000000 -2.000000 -0.100000 "
/>
<TextureCoordinate point="0.9999 0.0001 0.7826 0.0001 0.8260 0.0870 0.6522 0.1934 0.7826 0.3673 0.8260 0.2803 0.4348 0.1740 0.4348 0.1934 0.6522 0.1934 0.6522 0.1740 0.7826 0.0001 0.6522 0.1740 0.8260 0.0870 0.8260 0.2803 0.7826 0.3673 0.9999 0.3673 0.4348 0.1934 0.4348 0.1740 0.2174 0.1740 0.2174 0.1934 0.9999 0.0001 0.8260 0.0870 0.8695 0.1740 0.6522 0.1934 0.8260 0.2803 0.8695 0.1934 0.8695 0.1740 0.6522 0.1740 0.6522 0.1934 0.8695 0.1934 0.8695 0.1740 0.8260 0.0870 0.6522 0.1740 0.8260 0.2803 0.9999 0.3673 0.8695 0.1934 0.2174 0.1740 0.0001 0.1740 0.0001 0.1934 0.2174 0.1934 " />
</IndexedFaceSet>
</Shape>
</Group>
</Transform>
</Transform>
</Scene>
</X3D>

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

@ -0,0 +1,16 @@
.slider .thumb {
-fx-background-image: url("/visualiser/images/sun.png");
-fx-background-size: 25px;
-fx-pref-height: 25px;
-fx-pref-width: 25px;
-fx-background-position: top;
-fx-background-repeat: no-repeat;
-fx-focus-color: transparent;
-fx-background-color: transparent;
}
.slider .track {
-fx-control-inner-background: dodgerblue;
-fx-border-color: rgba(30, 144, 255, 0.44);
-fx-border-radius: 0.25em, 0.25em, 0.166667em;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.9 KiB

@ -3,6 +3,7 @@
<?import javafx.geometry.Insets?> <?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?> <?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?> <?import javafx.scene.control.Label?>
<?import javafx.scene.control.Slider?>
<?import javafx.scene.image.ImageView?> <?import javafx.scene.image.ImageView?>
<?import javafx.scene.layout.AnchorPane?> <?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.ColumnConstraints?> <?import javafx.scene.layout.ColumnConstraints?>
@ -12,19 +13,20 @@
<AnchorPane fx:id="hostWrapper" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="600.0" prefWidth="780.0" xmlns="http://javafx.com/javafx/8.0.111" xmlns:fx="http://javafx.com/fxml/1" fx:controller="visualiser.Controllers.HostGameController"> <AnchorPane fx:id="hostWrapper" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="600.0" prefWidth="780.0" xmlns="http://javafx.com/javafx/8.0.111" xmlns:fx="http://javafx.com/fxml/1" fx:controller="visualiser.Controllers.HostGameController">
<children> <children>
<GridPane layoutY="14.0" AnchorPane.bottomAnchor="-14.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="14.0"> <GridPane layoutY="14.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<columnConstraints> <columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" maxWidth="170.0" minWidth="10.0" prefWidth="170.0" /> <ColumnConstraints hgrow="NEVER" prefWidth="170.0" />
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" /> <ColumnConstraints hgrow="NEVER" prefWidth="100.0" />
<ColumnConstraints hgrow="SOMETIMES" maxWidth="170.0" minWidth="10.0" prefWidth="170.0" /> <ColumnConstraints hgrow="NEVER" prefWidth="170.0" />
</columnConstraints> </columnConstraints>
<rowConstraints> <rowConstraints>
<RowConstraints maxHeight="60.0" minHeight="60.0" prefHeight="30.0" vgrow="SOMETIMES" /> <RowConstraints prefHeight="50.0" vgrow="NEVER" />
<RowConstraints minHeight="10.0" prefHeight="435.0" vgrow="SOMETIMES" /> <RowConstraints prefHeight="419.5" vgrow="NEVER" />
<RowConstraints maxHeight="80.0" minHeight="80.0" prefHeight="80.0" vgrow="SOMETIMES" /> <RowConstraints prefHeight="50.0" vgrow="NEVER" />
<RowConstraints prefHeight="80.0" vgrow="NEVER" />
</rowConstraints> </rowConstraints>
<children> <children>
<Button fx:id="hostGameBtn" mnemonicParsing="false" onAction="#hostGamePressed" text="Start Game" GridPane.columnIndex="1" GridPane.halignment="CENTER" GridPane.rowIndex="2" GridPane.valignment="CENTER"> <Button fx:id="hostGameBtn" mnemonicParsing="false" onAction="#hostGamePressed" text="Start Game" GridPane.columnIndex="1" GridPane.halignment="CENTER" GridPane.rowIndex="3" GridPane.valignment="CENTER">
<font> <font>
<Font size="20.0" /> <Font size="20.0" />
</font> </font>
@ -50,6 +52,16 @@
<ImageView fx:id="mapImage" pickOnBounds="true" preserveRatio="true" GridPane.columnIndex="1" GridPane.halignment="CENTER" GridPane.hgrow="ALWAYS" GridPane.rowIndex="1" GridPane.valignment="CENTER" GridPane.vgrow="ALWAYS" /> <ImageView fx:id="mapImage" pickOnBounds="true" preserveRatio="true" GridPane.columnIndex="1" GridPane.halignment="CENTER" GridPane.hgrow="ALWAYS" GridPane.rowIndex="1" GridPane.valignment="CENTER" GridPane.vgrow="ALWAYS" />
<Button fx:id="previousButton" maxHeight="80.0" maxWidth="80.0" mnemonicParsing="false" onAction="#previousImage" GridPane.halignment="CENTER" GridPane.rowIndex="1" GridPane.valignment="CENTER" /> <Button fx:id="previousButton" maxHeight="80.0" maxWidth="80.0" mnemonicParsing="false" onAction="#previousImage" GridPane.halignment="CENTER" GridPane.rowIndex="1" GridPane.valignment="CENTER" />
<Button fx:id="nextButton" maxHeight="80.0" maxWidth="80.0" mnemonicParsing="false" onAction="#nextImage" GridPane.columnIndex="2" GridPane.halignment="CENTER" GridPane.rowIndex="1" GridPane.valignment="CENTER" /> <Button fx:id="nextButton" maxHeight="80.0" maxWidth="80.0" mnemonicParsing="false" onAction="#nextImage" GridPane.columnIndex="2" GridPane.halignment="CENTER" GridPane.rowIndex="1" GridPane.valignment="CENTER" />
<Slider fx:id="sliderLength" prefHeight="14.0" prefWidth="100.0" GridPane.columnIndex="1" GridPane.halignment="CENTER" GridPane.rowIndex="2">
<GridPane.margin>
<Insets left="50.0" right="50.0" />
</GridPane.margin>
</Slider>
<Label fx:id="lblLength" GridPane.columnIndex="1" GridPane.halignment="CENTER" GridPane.rowIndex="2" GridPane.valignment="BOTTOM">
<GridPane.margin>
<Insets />
</GridPane.margin>
</Label>
</children> </children>
</GridPane> </GridPane>
</children> </children>

@ -49,6 +49,13 @@
<rowConstraints> <rowConstraints>
<RowConstraints minHeight="10.0" vgrow="SOMETIMES" /> <RowConstraints minHeight="10.0" vgrow="SOMETIMES" />
</rowConstraints> </rowConstraints>
<children>
<StackPane fx:id="nextMarkPane" alignment="TOP_CENTER" mouseTransparent="true" prefHeight="150.0" prefWidth="150.0" snapToPixel="false">
<children>
<fx:include fx:id="nextMark" source="nextMark.fxml" />
</children>
</StackPane>
</children>
</GridPane> </GridPane>
<Pane prefHeight="200.0" prefWidth="400.0" visible="false"> <Pane prefHeight="200.0" prefWidth="400.0" visible="false">
<children> <children>

@ -0,0 +1,38 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.image.Image?>
<?import javafx.scene.image.ImageView?>
<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.Pane?>
<?import javafx.scene.layout.RowConstraints?>
<?import javafx.scene.layout.StackPane?>
<GridPane fx:id="arrowGridPane" alignment="TOP_CENTER" maxHeight="-Infinity" maxWidth="-Infinity" xmlns="http://javafx.com/javafx/8.0.112" xmlns:fx="http://javafx.com/fxml/1" fx:controller="visualiser.Controllers.NextMarkController">
<children>
<Pane fx:id="pane2d" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="112.0" prefWidth="112.0">
<children>
<StackPane fx:id="arrowStackPane2d" prefHeight="112.0" prefWidth="112.0">
<children>
<ImageView fx:id="arrowImage" fitHeight="75.0" fitWidth="25.0">
<image>
<Image url="@../../images/nextMarkArrow2d.png" />
</image>
</ImageView>
</children>
</StackPane>
</children>
</Pane>
<Pane fx:id="pane3d" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="112.0" prefWidth="112.0">
<children>
<StackPane fx:id="arrowStackPane3d" prefHeight="112.0" prefWidth="112.0" />
</children>
</Pane>
</children>
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="10.0" vgrow="SOMETIMES" />
</rowConstraints>
</GridPane>
Loading…
Cancel
Save