Merge remote-tracking branch 'remotes/origin/master' into scoreTable

This commit is contained in:
hba56
2017-09-14 22:25:33 +12:00
57 changed files with 948 additions and 156 deletions
@@ -80,6 +80,9 @@ public class HostGameController extends Controller {
*/
public void alertMatchBrowser(){
try{
if (matchBrowserInterface == null){
return;//private game
}
matchBrowserInterface.startSendingHostData(App.game.getHostedGameData(), udpSocket);
}catch (IOException e){
System.err.println("failed to send out hosted game info");
@@ -138,11 +138,13 @@ public class InGameLobbyController extends Controller {
playerContainer.add(playerBoatToSet, (count % 3) , row);
playerContainer.setMargin(playerBoatToSet, new Insets(10, 10, 10, 10));
SeaSurface sea = new SeaSurface(750, 200, 250, 0, 210);
subjects.add(sea.getSurface());
SeaSurface sea = new SeaSurface(750, 200);
sea.setX(250);
sea.setZ(210);
subjects.add(sea);
MeshView mesh = new MeshView(importer.getImport());
Subject3D subject = new Subject3D(mesh);
Subject3D subject = new Subject3D(mesh,0);
subjects.add(subject);
playerBoatToSet.setDistance(50);
@@ -321,7 +323,7 @@ public class InGameLobbyController extends Controller {
* @param interval Countdown interval to check
*/
private void countdownText(long interval){
countdownTenPane.setVisible(false);
//Do nothing if 5 seconds or less to go
if (interval <=5000){
countdownTenPane.setVisible(false);
@@ -7,6 +7,8 @@ import javafx.scene.control.Button;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.TextField;
import javafx.scene.layout.AnchorPane;
import javafx.scene.media.AudioClip;
import network.Messages.HostGame;
import visualiser.app.MatchBrowserSingleton;
import visualiser.model.RaceConnection;
@@ -34,6 +36,8 @@ public class LobbyController extends Controller {
private ObservableList<RaceConnection> connections;
private ObservableList<RaceConnection> customConnections;
private AudioClip sound;
//the socket for match browser
private DatagramSocket udpSocket;
private MatchBrowserLobbyInterface matchBrowserLobbyInterface;
@@ -67,6 +71,8 @@ public class LobbyController extends Controller {
* Refreshes the connections in the lobby
*/
public void refreshBtnPressed(){
sound = new AudioClip(this.getClass().getResource("/visualiser/sounds/buttonpress.wav").toExternalForm());
sound.play();
addServerGames();
for(RaceConnection connection: connections) {
connection.check();
@@ -92,6 +98,8 @@ public class LobbyController extends Controller {
}
public void menuBtnPressed() throws IOException {
sound = new AudioClip(this.getClass().getResource("/visualiser/sounds/buttonpress.wav").toExternalForm());
sound.play();
matchBrowserLobbyInterface.closeSocket();
loadScene("title.fxml");
}
@@ -100,6 +108,8 @@ public class LobbyController extends Controller {
* adds a new connection
*/
public void addConnectionPressed(){
sound = new AudioClip(this.getClass().getResource("/visualiser/sounds/buttonpress.wav").toExternalForm());
sound.play();
String hostName = addressFld.getText();
String portString = portFld.getText();
try {
@@ -3,30 +3,38 @@ package visualiser.Controllers;
import com.interactivemesh.jfx.importer.stl.StlMeshImporter;
import javafx.animation.AnimationTimer;
import javafx.application.Platform;
import javafx.beans.value.ChangeListener;
import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
import javafx.collections.transformation.SortedList;
import javafx.fxml.FXML;
import javafx.scene.AmbientLight;
import javafx.scene.PointLight;
import javafx.scene.chart.LineChart;
import javafx.scene.control.*;
import javafx.scene.effect.Light;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.StackPane;
import javafx.scene.shape.MeshView;
import javafx.scene.shape.Sphere;
import javafx.scene.paint.Color;
import javafx.scene.paint.Material;
import javafx.scene.paint.PhongMaterial;
import javafx.scene.shape.*;
import javafx.scene.transform.Translate;
import javafx.util.Callback;
import network.Messages.Enums.RaceStatusEnum;
import shared.dataInput.RaceDataSource;
import shared.model.Leg;
import shared.model.Mark;
import shared.exceptions.BoatNotFoundException;
import shared.model.*;
import visualiser.app.App;
import visualiser.enums.TutorialState;
import visualiser.gameController.ControllerClient;
import visualiser.gameController.Keys.ControlKey;
import visualiser.layout.*;
import visualiser.model.*;
import visualiser.gameController.Keys.KeyFactory;
import visualiser.layout.Subject3D;
import visualiser.layout.View3D;
@@ -62,6 +70,15 @@ public class RaceViewController extends Controller {
private View3D view3D;
private ObservableList<Subject3D> viewSubjects;
/**
* Arrow pointing to next mark in third person
*/
private Subject3D nextMarkArrow;
/**
* Animation loop for rotating mark arrow
*/
private AnimationTimer pointToMark;
// note: it says it's not used but it is! do not remove :)
private @FXML ArrowController arrowController;
private @FXML GridPane canvasBase;
@@ -123,9 +140,8 @@ public class RaceViewController extends Controller {
}
}
/**
* Sets up the listener and actions that occur when a key is pressed.
*/
private AnimationTimer arrowToNextMark;
private void initKeypressHandler() {
newRacePane.addEventFilter(KeyEvent.KEY_PRESSED, event -> {
String codeString = event.getCode().toString();
@@ -191,10 +207,23 @@ public class RaceViewController extends Controller {
* Initialises the various UI components to listen to the {@link #visualiserRace}.
*/
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
initialiseFps();
initialiseInfoTable();
initialiseView3D();
initialiseView3D(this.visualiserRace);
initialiseRaceClock();
raceTimer(); // start the timer
new Sparkline(this.raceState, this.sparklineChart);
@@ -202,55 +231,122 @@ public class RaceViewController extends Controller {
arrowController.setWindProperty(this.raceState.windProperty());
}
private void initialiseView3D() {
private void initialiseView3D(VisualiserRaceEvent race) {
viewSubjects = FXCollections.observableArrayList();
AmbientLight ambientLight = new AmbientLight(Color.web("#CCCCFF"));
ambientLight.setTranslateX(250);
ambientLight.setTranslateZ(210);
ambientLight.setLightOn(true);
PointLight pointLight = new PointLight(Color.web("#AAAAFF"));
pointLight.setTranslateX(250);
pointLight.setTranslateZ(210);
pointLight.setLightOn(true);
// Import boat mesh
URL asset = RaceViewController.class.getClassLoader().getResource("assets/V1.2 " +
"Complete Boat.stl");
URL asset = RaceViewController.class.getClassLoader().getResource("assets/V1.2 Complete Boat.stl");
StlMeshImporter importer = new StlMeshImporter();
importer.read(asset);
// Configure camera angles and control
view3D = new View3D();
URL markerAsset = RaceViewController.class.getClassLoader().getResource("assets/Bouy V1.1.stl");
StlMeshImporter importerMark = new StlMeshImporter();
importerMark.read(markerAsset);
URL alternateBoatAsset = RaceViewController.class.getClassLoader().getResource("assets/V1.3 BurgerBoat.stl");
StlMeshImporter importerBurgerBoat = new StlMeshImporter();
importerBurgerBoat.read(alternateBoatAsset);
view3D = new View3D(false);
view3D.setItems(viewSubjects);
view3D.setDistance(1050);
view3D.setYaw(0);
view3D.setPitch(60);
view3D.setBirdsEye();
view3D.enableTracking();
view3D.addAmbientLight(ambientLight);
view3D.addPointLight(pointLight);
canvasBase.add(view3D, 0, 0);
// Set up projection from GPS to view
RaceDataSource raceData = raceState.getRaceDataSource();
RaceDataSource raceData = visualiserRace.getVisualiserRaceState().getRaceDataSource();
final GPSConverter gpsConverter = new GPSConverter(raceData, 450, 450);
view3D.setItems(viewSubjects);
// Position and add each mark to view
for (Mark mark : raceState.getMarks()) {
Subject3D subject = new Subject3D(new Sphere(2));
subject.setX(gpsConverter.convertGPS(mark.getPosition()).getX());
subject.setZ(gpsConverter.convertGPS(mark.getPosition()).getY());
SkyBox skyBox = new SkyBox(750, 200, 250, 0, 210);
viewSubjects.addAll(skyBox.getSkyBoxPlanes());
viewSubjects.add(subject);
// Set up sea surface
SeaSurface sea = new SeaSurface(750, 200);
sea.setX(250);
sea.setZ(210);
viewSubjects.add(sea);
// Set up sea surface overlay
SeaSurface seaOverlay = new SeaSurface(4000, 200);
seaOverlay.setX(250);
seaOverlay.setZ(210);
viewSubjects.add(seaOverlay);
Boundary3D boundary3D = new Boundary3D(visualiserRace.getVisualiserRaceState().getRaceDataSource().getBoundary(), gpsConverter);
for (Subject3D subject3D: boundary3D.getBoundaryNodes()){
viewSubjects.add(subject3D);
}
// Position and add each mark to view
for(Mark mark: race.getVisualiserRaceState().getMarks()) {
MeshView mesh = new MeshView(importerMark.getImport());
Subject3D markModel = new Subject3D(mesh, mark.getSourceID());
markModel.setX(gpsConverter.convertGPS(mark.getPosition()).getX());
markModel.setZ(gpsConverter.convertGPS(mark.getPosition()).getY());
viewSubjects.add(markModel);
}
// Position and add each boat to view
for (VisualiserBoat boat : raceState.getBoats()) {
MeshView mesh = new MeshView(importer.getImport());
Subject3D subject = new Subject3D(mesh);
viewSubjects.add(subject);
for(VisualiserBoat boat: race.getVisualiserRaceState().getBoats()) {
MeshView mesh;
if(boat.getSourceID() == race.getVisualiserRaceState().getPlayerBoatID()) {
mesh = new MeshView(importer.getImport());
} else {
mesh = new MeshView(importerBurgerBoat.getImport());
}
Subject3D boatModel = new Subject3D(mesh, boat.getSourceID());
viewSubjects.add(boatModel);
// Track this boat's movement with the new subject
AnimationTimer trackBoat = new AnimationTimer() {
@Override public void handle(long now) {
subject.setHeading(boat.getBearing().degrees());
subject.setX(gpsConverter.convertGPS(boat.getPosition()).getX());
subject.setZ(gpsConverter.convertGPS(boat.getPosition()).getY());
@Override
public void handle(long now) {
boatModel.setHeading(boat.getBearing().degrees());
boatModel.setX(gpsConverter.convertGPS(boat.getPosition()).getX());
boatModel.setZ(gpsConverter.convertGPS(boat.getPosition()).getY());
}
};
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()).setMaterial(markColor);
if(nextMark.getMark2() != null) {
view3D.getShape(nextMark.getMark2().getSourceID()).setMaterial(markColor);
}
Subject3D shockwave = new Shockwave(10);
viewSubjects.add(shockwave);
boat.legProperty().addListener((o, prev, curr) -> swapColours(curr));
boat.hasCollidedProperty().addListener((o, prev, curr) -> showCollision(boatModel, shockwave));
}
// Fix initial bird's-eye position
view3D.updatePivot(new Translate(250, 0, 210));
view3D.targetProperty().addListener((o, prev, curr)-> {
if(curr != null && visualiserRace.getVisualiserRaceState().isVisualiserBoat(curr.getSourceID())) {
addThirdPersonAnnotations(curr);
} else {
removeThirdPersonAnnotations(prev);
}
});
// Bind zooming to scrolling
view3D.setOnScroll(e -> {
view3D.updateDistance(e.getDeltaY());
@@ -259,7 +355,7 @@ public class RaceViewController extends Controller {
// Bind zooming to keypress (Z/X default)
newRacePane.addEventFilter(KeyEvent.KEY_PRESSED, e -> {
ControlKey key = keyFactory.getKey(e.getCode().toString());
if (key != null) {
if(key != null) {
switch (key.toString()) {
case "Zoom In":
//Check if race is a tutorial
@@ -296,6 +392,112 @@ public class RaceViewController extends Controller {
});
}
private void showCollision(Subject3D boat, Subject3D shockwave) {
AnimationTimer shockFront = new AnimationTimer() {
double opacity = 1;
@Override
public void handle(long now) {
shockwave.setX(boat.getPosition().getX());
shockwave.setY(boat.getPosition().getY());
shockwave.setZ(boat.getPosition().getZ());
if(opacity <= 0) {
shockwave.getMesh().setMaterial(new PhongMaterial(new Color(1,0,0,0)));
this.stop();
}
else {
shockwave.getMesh().setMaterial(new PhongMaterial(new Color(1,0,0,opacity)));
opacity -= 0.1;
}
}
};
shockFront.start();
}
private void addThirdPersonAnnotations(Subject3D subject3D) {
viewSubjects.add(nextMarkArrow);
final VisualiserBoat boat;
try {
boat = visualiserRace.getVisualiserRaceState().getBoat(subject3D.getSourceID());
} catch (BoatNotFoundException e) {
e.printStackTrace();
return;
}
arrowToNextMark = new AnimationTimer() {
@Override
public void handle(long now) {
CompoundMark target = boat.getCurrentLeg().getEndCompoundMark();
Bearing headingToMark = GPSCoordinate.calculateBearing(boat.getPosition(), target.getAverageGPSCoordinate());
nextMarkArrow.setX(view3D.getPivot().getX());
nextMarkArrow.setY(view3D.getPivot().getY());
nextMarkArrow.setZ(view3D.getPivot().getZ() + 15);
nextMarkArrow.setHeading(headingToMark.degrees());
}
};
arrowToNextMark.start();
/*
try {
VisualiserBoat boat = visualiserRace.getVisualiserRaceState().getBoat(subject3D.getSourceID());
this.pointToMark = new AnimationTimer() {
@Override
public void handle(long now) {
CompoundMark target = boat.getCurrentLeg().getEndCompoundMark();
Bearing headingToMark = GPSCoordinate.calculateBearing(boat.getPosition(), target.getAverageGPSCoordinate());
nextMarkArrow.setX(view3D.getPivot().getX());
nextMarkArrow.setY(view3D.getPivot().getY());
nextMarkArrow.setZ(view3D.getPivot().getZ() + 10);
nextMarkArrow.setHeading(headingToMark.degrees());
}
};
pointToMark.start();
} catch (BoatNotFoundException e) {
e.printStackTrace();
}*/
}
private void removeThirdPersonAnnotations(Subject3D subject3D) {
viewSubjects.remove(nextMarkArrow);
arrowToNextMark.stop();
/*
try {
VisualiserBoat boat = visualiserRace.getVisualiserRaceState().getBoat(subject3D.getSourceID());
boat.positionProperty().removeListener(pointToMark);
} catch (BoatNotFoundException e) {
e.printStackTrace();
}*/
//pointToMark.stop();
}
/**
* Swap the colour of the next mark to pass with the last mark passed
* @param leg boat has started on
*/
private void swapColours(Leg leg) {
CompoundMark start = leg.getStartCompoundMark();
CompoundMark end = leg.getEndCompoundMark();
Shape3D start1 = view3D.getShape(start.getMark1().getSourceID());
Shape3D end1 = view3D.getShape(end.getMark1().getSourceID());
Material nextMark = start1.getMaterial();
Material lastMark = end1.getMaterial();
start1.setMaterial(lastMark);
if(start.getMark2() != null) {
Shape3D start2 = view3D.getShape(start.getMark2().getSourceID());
start2.setMaterial(lastMark);
}
end1.setMaterial(nextMark);
if(end.getMark2() != null) {
Shape3D end2 = view3D.getShape(end.getMark2().getSourceID());
end2.setMaterial(nextMark);
}
}
/**
* Initialises the frame rate functionality. This allows for toggling the
* frame rate, and connect the fps label to the race's fps property.
@@ -6,11 +6,20 @@ import javafx.scene.control.RadioButton;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.Pane;
import javafx.scene.media.AudioClip;
import javafx.scene.media.Media;
import javafx.scene.media.MediaPlayer;
import javafx.stage.Modality;
import mock.exceptions.EventConstructionException;
import visualiser.app.App;
import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.ResourceBundle;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Controller for the opening title window.