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

This commit is contained in:
hba56
2017-09-27 13:21:41 +13:00
16 changed files with 412 additions and 114 deletions
@@ -4,6 +4,8 @@ import javafx.application.Platform;
import javafx.fxml.FXML;
import javafx.scene.control.Alert;
import javafx.scene.control.ButtonType;
import javafx.scene.control.Label;
import javafx.scene.control.Slider;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import mock.app.Event;
@@ -28,8 +30,12 @@ import java.util.logging.Logger;
*/
public class HostGameController extends Controller {
private @FXML ImageView mapImage;
private @FXML Slider sliderLength;
private @FXML Label lblLength;
private ArrayList<Image> listOfMaps;
private int currentMapIndex = 0;
private int selectedRaceLength; // in minutes
private final int MAX_RACE_LENGTH = 30; // in minutes
private DatagramSocket udpSocket;
private MatchBrowserInterface matchBrowserInterface;
@@ -37,8 +43,33 @@ public class HostGameController extends Controller {
loadMaps();
this.udpSocket = MatchBrowserSingleton.getInstance().getUdpSocket();
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() {
try {
App.game = new Event(false, currentMapIndex);
App.game = new Event(false, currentMapIndex,
selectedRaceLength*60*1000);
App.gameType = currentMapIndex;
HttpMatchBrowserHost matchBrowserHost = new HttpMatchBrowserHost();
@@ -40,7 +40,7 @@ public class LobbyController extends Controller {
private @FXML TextField addressFld;
private @FXML TextField portFld;
private ObservableList<RaceConnection> connections;
private ObservableList<RaceConnection> allConnections;
private ObservableList<RaceConnection> customConnections;
private AudioClip sound;
@@ -51,12 +51,20 @@ public class LobbyController extends Controller {
public void initialize() {
httpMatchBrowserClient = new HttpMatchBrowserClient();
httpMatchBrowserClient.connections.addListener(new ListChangeListener<RaceConnection>() {
@Override
public void onChanged(Change<? extends RaceConnection> c) {
refreshTable();
}
});
new Thread(httpMatchBrowserClient, "Match Client").start();
// set up the connection table
customConnections = FXCollections.observableArrayList();
allConnections = FXCollections.observableArrayList();
//connections.add(new RaceConnection("localhost", 4942, "Local Game"));
lobbyTable.setItems(httpMatchBrowserClient.connections);
lobbyTable.setItems(allConnections);
gameNameColumn.setCellValueFactory(cellData -> cellData.getValue().gamenameProperty());
hostNameColumn.setCellValueFactory(cellData -> cellData.getValue().hostnameProperty());
statusColumn.setCellValueFactory(cellData -> cellData.getValue().statusProperty());
@@ -82,8 +90,14 @@ public class LobbyController extends Controller {
public void refreshBtnPressed(){
sound = new AudioClip(this.getClass().getResource("/visualiser/sounds/buttonpress.wav").toExternalForm());
sound.play();
refreshTable();
}
private void refreshTable() {
allConnections.clear();
addCustomGames();
addServerGames();
for(RaceConnection connection: connections) {
for(RaceConnection connection: allConnections) {
connection.check();
}
try {
@@ -144,9 +158,9 @@ public class LobbyController extends Controller {
try {
int port = Integer.parseInt(portString);
customConnections.add(new RaceConnection(hostName, port, "Boat Game"));
connections.addAll(customConnections);
addressFld.clear();
portFld.clear();
refreshTable();
} catch (NumberFormatException e) {
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
*/
private void addServerGames() {
httpMatchBrowserClient.connections.addAll(customConnections);
httpMatchBrowserClient.connections.addListener(new ListChangeListener<RaceConnection>() {
@Override
public void onChanged(Change<? extends RaceConnection> c) {
refreshBtnPressed();
}
});
allConnections.addAll(httpMatchBrowserClient.connections);
/*
for (HostGame game : matchBrowserLobbyInterface.getGames()) {
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));
}
}
@@ -17,10 +17,12 @@ import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Pane;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.paint.Material;
import javafx.scene.paint.PhongMaterial;
import javafx.scene.shape.Cylinder;
import javafx.scene.paint.Stop;
import javafx.scene.shape.MeshView;
import javafx.scene.shape.Shape3D;
@@ -80,10 +82,12 @@ public class RaceViewController extends Controller {
// note: it says it's not used but it is! do not remove :)
private @FXML ArrowController arrowController;
private @FXML NextMarkController nextMarkController;
private @FXML GridPane canvasBase;
private @FXML GridPane canvasBase1;
private @FXML SplitPane racePane;
private @FXML StackPane arrowPane;
private @FXML Pane nextMarkPane;
private @FXML Label timer;
private @FXML Label FPS;
private @FXML Label timeZone;
@@ -285,19 +289,6 @@ 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();
@@ -306,6 +297,7 @@ public class RaceViewController extends Controller {
initialiseSpeedometer();
initialiseRaceCanvas();
raceTimer(); // start the timer
nextMarkPane.toFront();
speedometerLoop();
new Sparkline(this.raceState, this.sparklineChart);
timeZone.setText(this.raceState.getRaceClock().getTimeZone());
@@ -315,6 +307,12 @@ public class RaceViewController extends Controller {
private void initialiseView3D(VisualiserRaceEvent race) {
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.setTranslateX(250);
ambientLight.setTranslateZ(210);
@@ -385,11 +383,29 @@ public class RaceViewController extends Controller {
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()) {
// Add player boat highlight
Shockwave boatHighlight = new Shockwave(10);
boatHighlight.getMesh().setMaterial(new PhongMaterial(new Color(1, 1, 0, 0.1)));
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() {
@Override
public void handle(long now) {
@@ -398,28 +414,23 @@ public class RaceViewController extends Controller {
}
};
highlightTrack.start();
// Highlight next mark only for player boat
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);
}
boat.legProperty().addListener((o, prev, curr) -> Platform.runLater(() -> swapColours(curr)));
} else {
viewSubjects.add(boatModel);
}
}
// Position and add each boat to view
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());
// }
Shape3D mesh = Assets3D.getBoat();
PhongMaterial boatColorMat = new PhongMaterial(boat.getColor());
//mesh.setMaterial(boatColorMat);
Subject3D boatModel = new Subject3D(mesh, boat.getSourceID());
viewSubjects.add(boatModel);
//add sail
Sails3D sails3D = new Sails3D();
Subject3D sailsSubject = new Subject3D(sails3D, 0);
sails3D.setMouseTransparent(true);
sails3D.setMaterial(boatColorMat);
sailsSubject.setXRot(0d);
sailsSubject.setHeading(visualiserRace.getVisualiserRaceState().getWindDirection().degrees());
@@ -500,17 +511,9 @@ public class RaceViewController extends Controller {
};
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);
viewSubjects.add(shockwave);
boat.legProperty().addListener((o, prev, curr) -> Platform.runLater(() -> swapColours(curr)));
boat.hasCollidedProperty().addListener((o, prev, curr) -> Platform.runLater(() -> showCollision(boat, shockwave)));
}
// Fix initial bird's-eye position
@@ -595,37 +598,32 @@ public class RaceViewController extends Controller {
}
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();
if (target != null) {
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();
nextMarkController.show3d();
// 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();
}
private void removeThirdPersonAnnotations() {
viewSubjects.remove(nextMarkArrow);
if (arrowToNextMark != null) {
arrowToNextMark.stop();
}
nextMarkController.show2d();
}
/**
@@ -52,7 +52,7 @@ public class Assets3D {
windArrow = new Annotation3D(loadX3d(arrowPath));
}
private static Shape3D loadX3d(String path){
public static Shape3D loadX3d(String path){
X3dModelImporter x3dModelImporter = new X3dModelImporter();
URL asset = Assets3D.class.getClassLoader().getResource(path);
x3dModelImporter.read(asset);
@@ -81,7 +81,7 @@ public class View3D extends Pane {
/**
* 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 MAX_ZOOM_LIMIT = 1500;
private final double MAX_PITCH = 60; // birds eye view