Merge branch 'master' into raceLength

# Conflicts:
#	racevisionGame/src/main/java/mock/app/Event.java
This commit is contained in:
Fan-Wu Yang
2017-09-26 16:40:03 +13:00
105 changed files with 27862 additions and 198 deletions
@@ -10,6 +10,7 @@ import javafx.fxml.FXML;
import javafx.geometry.Insets;
import javafx.scene.Node;
import javafx.scene.control.Alert;
import javafx.scene.control.Button;
import javafx.scene.control.ButtonType;
import javafx.scene.control.Label;
import javafx.scene.image.ImageView;
@@ -18,22 +19,21 @@ import javafx.scene.layout.GridPane;
import javafx.scene.paint.Color;
import javafx.scene.paint.PhongMaterial;
import javafx.scene.shape.MeshView;
import javafx.scene.shape.Shape3D;
import mock.app.Event;
import network.Messages.Enums.RaceStatusEnum;
import network.Messages.Enums.RequestToJoinEnum;
import shared.model.Boat;
import visualiser.app.App;
import visualiser.gameController.ControllerClient;
import visualiser.layout.SeaSurface;
import visualiser.layout.Shockwave;
import visualiser.layout.Subject3D;
import visualiser.layout.View3D;
import visualiser.layout.*;
import visualiser.model.VisualiserBoat;
import visualiser.model.VisualiserRaceEvent;
import visualiser.model.VisualiserRaceState;
import visualiser.network.HttpMatchBrowserHost;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.Socket;
import java.net.URL;
import java.time.temporal.ChronoUnit;
@@ -71,13 +71,10 @@ public class InGameLobbyController extends Controller {
private Label playerLabel6;
@FXML
private Label countdownLabel;
private Button startButton;
@FXML
private AnchorPane countdownTenPane;
@FXML
private Label countdownTenText;
private Button quitButton;
private Event game;
@@ -158,12 +155,22 @@ public class InGameLobbyController extends Controller {
sea.setZ(210);
subjects.add(sea);
MeshView mesh = new MeshView(importer.getImport());
// MeshView mesh = new MeshView(importer.getImport());
// Subject3D subject = new Subject3D(mesh,0);
// subjects.add(subject);
Shape3D mesh = Assets3D.getBoat();
PhongMaterial boatColorMat = new PhongMaterial(boat.getColor());
mesh.setMaterial(boatColorMat);
Subject3D subject = new Subject3D(mesh,0);
Subject3D subject = new Subject3D(mesh, 0);
subjects.add(subject);
Sails3D sails3D = new Sails3D();
Subject3D sailsSubject = new Subject3D(sails3D, 0);
sails3D.setMaterial(boatColorMat);
subjects.add(sailsSubject);
sailsSubject.setXRot(0d);
//sails3D.startLuffing();
playerBoatToSet.setDistance(50);
playerBoatToSet.setYaw(45);
playerBoatToSet.setPitch(20);
@@ -183,6 +190,7 @@ public class InGameLobbyController extends Controller {
@Override
public void handle(long now) {
subject.setHeading(subject.getHeading().getAngle() + 0.1);
sailsSubject.setHeading(subject.getHeading().getAngle() + 0.1);
}
};
rotate.start();
@@ -209,37 +217,13 @@ public class InGameLobbyController extends Controller {
* Starts the race.
*/
private void startRace() {
//Initialises the race clock.
initialiseRaceClock(this.visualiserRaceEvent.getVisualiserRaceState());
//Starts the race countdown timer.
countdownTimer();
}
/**
* Initialises the race clock/timer labels for the start time, current time, and remaining time.
* @param visualiserRace The race to get data from.
*/
private void initialiseRaceClock(VisualiserRaceState visualiserRace) {
//Remaining time.
initialiseRaceClockDuration(visualiserRace);
}
/**
* Initialises the race duration label.
* @param visualiserRace The race to get data from.
*/
private void initialiseRaceClockDuration(VisualiserRaceState visualiserRace) {
visualiserRace.getRaceClock().durationProperty().addListener((observable, oldValue, newValue) -> {
Platform.runLater(() -> {
countdownLabel.setText(newValue);
});
});
}
/**
* Countdown timer until race starts.
*/
@@ -250,19 +234,6 @@ public class InGameLobbyController extends Controller {
//Get the current race status.
RaceStatusEnum raceStatus = visualiserRaceEvent.getVisualiserRaceState().getRaceStatusEnum();
//Try catch for getting interval times
try {
long interval = ChronoUnit.MILLIS.between(visualiserRaceEvent.getVisualiserRaceState().getRaceClock().getCurrentTime(), visualiserRaceEvent.getVisualiserRaceState().getRaceClock().getStartingTime());
if(interval<=10000){
countdownLabel.setVisible(false);
countdownTenPane.setVisible(true);
countdownTenText.setVisible(true);
}
countdownText(interval);
} catch (Exception e){
}
//If the race has reached the preparatory phase, or has started...
if (raceStatus == RaceStatusEnum.PREPARATORY || raceStatus == RaceStatusEnum.STARTED) {
@@ -301,6 +272,8 @@ public class InGameLobbyController extends Controller {
this.visualiserRaceEvent.getVisualiserRaceState().getBoats().addListener(this.lobbyUpdateListener);
enableStartIfHost();
startRace();
} catch (IOException e) {
//TODO should probably let this propagate, so that we only enter this scene if everything works
@@ -308,6 +281,22 @@ public class InGameLobbyController extends Controller {
}
}
/**
* Enables the start button if the client is the host of the game.
*/
private void enableStartIfHost() {
if (isHost) {
startButton.setVisible(true);
startButton.setDisable(false);
} else {
startButton.setVisible(false);
startButton.setDisable(true);
}
}
/**
* Menu button pressed. Prompt alert then return to menu
* @throws IOException socket erro
@@ -335,7 +324,7 @@ public class InGameLobbyController extends Controller {
* Start button pressed. Currently only prints out start
*/
public void startBtnPressed(){
//System.out.println("Should start the race. This button is only visible for the host");
App.game.getRaceLogic().getRace().startRace(App.game.getRaceLogic().getRace().getRacePreparatoryTime(), true);
}
public void joinSpecPressed(){
@@ -346,48 +335,5 @@ public class InGameLobbyController extends Controller {
//System.out.println("Empty race user pane pressed. Joining racers");
}
/**
* Countdown interval checker that updates the countdown text
* @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);
//countdownTenText.setText("5");
return;
}
//6 seconds left. Display 1 second for countdown
if (interval <=6000){
countdownTenText.setText("1");
return;
}
//7 seconds left. Display 2 seconds for countdown
if (interval <=7000){
countdownTenText.setText("2");
return;
}
//8 seconds left. Display 3 seconds for countdown
if (interval <=8000){
countdownTenText.setText("3");
return;
}
//9 seconds left. Display 4 seconds for countdown
if (interval <=9000){
countdownTenText.setText("4");
return;
}
//10 seconds left. Display 5 seconds for countdown
if (interval <=10000){
countdownTenText.setText("5");
return;
}
}
}
@@ -319,19 +319,92 @@ public class RaceViewController extends Controller {
}
// Position and add each boat to view
for (VisualiserBoat boat: race.getVisualiserRaceState().getBoats()) {
MeshView mesh;
if(boat.getSourceID() == race.getVisualiserRaceState().getPlayerBoatID()) {
for(VisualiserBoat boat: race.getVisualiserRaceState().getBoats()) {
/*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.setMaterial(boatColorMat);
sailsSubject.setXRot(0d);
sailsSubject.setHeading(visualiserRace.getVisualiserRaceState().getWindDirection().degrees());
viewSubjects.add(sailsSubject);
AnimationTimer sailsFollowBoat = new AnimationTimer() {
double sailCurrent = visualiserRace.getVisualiserRaceState().getWindDirection().degrees();
boolean canLuff = true;
double turnRate = 5;
@Override
public void handle(long now) {
double sailDir;
//if sails are out etc
if (boat.isSailsOut()) {
double windDir = visualiserRace.getVisualiserRaceState().getWindDirection().degrees();
double windOffset = (360 - windDir + boat.getBearing().degrees()) % 360;
sailDir = windOffset / 180 * 270 + windDir + 180;
boolean leftOfWind = windOffset >= 180;
if (leftOfWind){
sailDir = -sailDir;
} else {
sailDir = windDir - sailDir;
}
} else {
sailDir = visualiserRace.getVisualiserRaceState().getWindDirection().degrees();
}
//get new place to move towards
double compA = ((sailCurrent - sailDir) % 360 + 360) % 360;//degrees right
if (compA > 180) compA = 360 - compA;
double compB = ((sailDir - sailCurrent) % 360 + 360) % 360;//degrees left
if (compB > compA){
if (compA > turnRate){
sailCurrent = ((sailCurrent - turnRate) % 360 + 360) % 360;
canLuff = false;
} else {
sailCurrent = sailDir;
canLuff = true;
}
} else {
if (compB > turnRate){
sailCurrent = ((sailCurrent + turnRate) % 360 + 360) % 360;
canLuff = false;
} else {
sailCurrent = sailDir;
canLuff = true;
}
}
sailsSubject.setHeading(sailCurrent);
if (canLuff) {
if (boat.isSailsOut()) {
if (sails3D.isLuffing()) {
sails3D.stopLuffing();
}
} else {
if (!sails3D.isLuffing()) {
sails3D.startLuffing();
}
}
}
sailsSubject.setX(gpsConverter.convertGPS(boat.getPosition()).getX());
sailsSubject.setZ(gpsConverter.convertGPS(boat.getPosition()).getY());
}
};
sailsFollowBoat.start();
// Track this boat's movement with the new subject
AnimationTimer trackBoat = new AnimationTimer() {
@Override
@@ -390,7 +463,7 @@ public class RaceViewController extends Controller {
}
}
}
view3D.updateDistance(-10);
view3D.zoomIn();
break;
case "Zoom Out":
//Check if race is a tutorial
@@ -405,7 +478,7 @@ public class RaceViewController extends Controller {
}
}
}
view3D.updateDistance(10);
view3D.zoomOut();
break;
}
}
@@ -25,6 +25,7 @@ import javafx.stage.Stage;
import javafx.stage.StageStyle;
import javafx.util.Duration;
import mock.app.Event;
import visualiser.layout.Assets3D;
public class App extends Application {
private static Stage stage;
@@ -113,6 +114,7 @@ public class App extends Application {
}
);
new Thread(boatTask).start();
Assets3D.loadAssets();
}
/**
@@ -0,0 +1,57 @@
package visualiser.layout;
import com.interactivemesh.jfx.importer.obj.ObjModelImporter;
import com.interactivemesh.jfx.importer.x3d.X3dModelImporter;
import javafx.geometry.Point3D;
import javafx.scene.Group;
import javafx.scene.shape.MeshView;
import javafx.scene.shape.Shape3D;
import visualiser.Controllers.HostGameController;
import java.net.URL;
/**
* Created by Gondr on 21/09/2017.
*/
public class Assets3D {
public static MeshView[] sails;
public static void loadAssets(){
loadSails();
}
private static void loadSails(){
sails = new MeshView[40];
ObjModelImporter objModelImporter = new ObjModelImporter();
for (int i = 0; i < sails.length; i++){
String path = String.format("assets/Sails/V1.3 Sail_%06d.obj", i + 1);
URL asset = Assets3D.class.getClassLoader().getResource(path);
objModelImporter.read(asset);
if (objModelImporter.getImport().length > 0) {
sails[i] = objModelImporter.getImport()[0];
/*sails[i].setRotationAxis(new Point3D(1, 0, 0));
sails[i].setRotate(-90);*/
}
}
}
public static Shape3D getBoat(){
X3dModelImporter x3dModelImporter = new X3dModelImporter();
String path = "assets/V1.3 Complete Boat without Sail and Rotated.x3d";
URL asset = Assets3D.class.getClassLoader().getResource(path);
x3dModelImporter.read(asset);
if (x3dModelImporter.getImport().length > 0) {
//if (x3dModelImporter.getImport()[0] instanceof MeshView) {
Group g = (Group)((Group)((Group) x3dModelImporter.getImport()[0]).getChildren().get(0)).getChildren().get(0);
Shape3D boat = (Shape3D)g.getChildren().get(0);
return boat;
/*} else {
System.err.println("Boat is not a Mesh View 0.0");
}*/
}
return null;
}
}
@@ -0,0 +1,40 @@
package visualiser.layout;
import javafx.animation.AnimationTimer;
import javafx.scene.shape.Mesh;
import javafx.scene.shape.MeshView;
/**
* Created by Gondr on 21/09/2017.
*/
public class Sails3D extends MeshView {
private int index = 0;
private boolean isLuffing = false;
public Sails3D() {
setMesh(Assets3D.sails[0].getMesh());
}
private AnimationTimer luff = new AnimationTimer() {
@Override
public void handle(long now) {
setMesh(Assets3D.sails[index].getMesh());
index = (index + 1) % 40;
}
};
public void startLuffing(){
luff.start();
isLuffing = true;
}
public void stopLuffing(){
luff.stop();
isLuffing = false;
setMesh(Assets3D.sails[0].getMesh());
}
public boolean isLuffing() {
return isLuffing;
}
}
@@ -28,8 +28,13 @@ public class Subject3D {
*/
private Rotate heading;
private Rotate xRot;
private Rotate yRot;
private Scale scale;
/**
* Constructor for view subject wrapper
* @param mesh to be rendered
@@ -41,7 +46,9 @@ public class Subject3D {
this.scale = new Scale();
this.position = new Translate();
this.heading = new Rotate(0, Rotate.Y_AXIS);
this.mesh.getTransforms().addAll(position, scale, heading, new Rotate(90, Rotate.X_AXIS), new Rotate(180, Rotate.Y_AXIS));
this.xRot = new Rotate(90, Rotate.X_AXIS);
this.yRot = new Rotate(180, Rotate.Y_AXIS);
this.mesh.getTransforms().addAll(position, scale, heading, xRot, yRot);
}
public Shape3D getMesh() {
@@ -81,4 +88,12 @@ public class Subject3D {
public void setHeading(double angle) {
heading.setAngle(angle);
}
public void setXRot(double angle){
xRot.setAngle(angle);
}
public void setYRot(double angle){
yRot.setAngle(angle);
}
}
@@ -3,7 +3,6 @@ package visualiser.layout;
import javafx.animation.AnimationTimer;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.value.ChangeListener;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
import javafx.scene.*;
@@ -78,11 +77,17 @@ public class View3D extends Pane {
/**
* Distance to switch from third person to bird's eye
*/
private final double THIRD_PERSON_LIMIT = 100;
private final double THIRD_PERSON_LIMIT = 500;
/**
* Distance to stop zoom
*/
private final double FIRST_PERSON_LIMIT = 2;
private final double ZOOM_IN_LIMIT = 30;
private final double ZOOM_OUT_LIMIT = 700;
private final double MAX_ZOOM_LIMIT = 1500;
private final double MAX_PITCH = 60; // birds eye view
private final double MIN_PITCH = 5; // third person view
private final double ZOOM_PER_KEYPRESS = 5; // distance changed per zoom
private double itemScale = 1;
/**
* Default constructor for View3D. Sets up Scene and PerspectiveCamera.
@@ -183,12 +188,9 @@ public class View3D extends Pane {
* Configures camera to third person view
*/
public void setThirdPerson() {
this.setDistance(THIRD_PERSON_LIMIT / 2);
this.setPitch(10);
for(Subject3D item: items) {
item.setScale(0.1);
}
this.setDistance(ZOOM_IN_LIMIT * 2);
adjustPitchForZoom();
adjustScaleForZoom();
}
/**
@@ -196,17 +198,14 @@ public class View3D extends Pane {
*/
public void setBirdsEye() {
this.setYaw(0);
this.setPitch(60);
for(Subject3D item: items) {
item.setScale(1);
}
this.setPitch(MAX_PITCH);
adjustScaleForZoom();
}
/**
* Stop camera from following the last selected subject
*/
private void untrackSubject() {
public void untrackSubject() {
if(target.get() != null) {
trackBoat.stop();
target.setValue(null);
@@ -217,7 +216,7 @@ public class View3D extends Pane {
* Set camera to follow the selected subject
* @param subject to track
*/
private void trackSubject(Subject3D subject) {
public void trackSubject(Subject3D subject) {
target.set(subject);
this.trackBoat = new AnimationTimer() {
@@ -267,17 +266,79 @@ public class View3D extends Pane {
* @param delta amount to change distance by
*/
public void updateDistance(double delta) {
double distance = -this.distance.getZ() + delta;
if(distance <= FIRST_PERSON_LIMIT) {
this.setDistance(FIRST_PERSON_LIMIT);
} else if(distance > THIRD_PERSON_LIMIT) {
this.setDistance(distance);
double newDistance = -this.distance.getZ() + delta;
if (target.get() == null){
if (newDistance > MAX_ZOOM_LIMIT){
setDistance(MAX_ZOOM_LIMIT);
} else {
setDistance(newDistance);
}
} else if(newDistance <= ZOOM_IN_LIMIT) {
setDistance(ZOOM_IN_LIMIT);
} else if (newDistance > ZOOM_OUT_LIMIT){
untrackSubject();
setBirdsEye();
setDistance(1050);
updatePivot(new Translate(250, 0, 210));
setYaw(0);
} else {
this.setDistance(distance);
setDistance(newDistance);
}
adjustPitchForZoom();
adjustScaleForZoom();
}
/**
* Adjusts the scale size of boats and markers as a user zooms in or out,
* to smooth the change between third person to birds eye view.
*/
private void adjustScaleForZoom(){
double itemScale = (((-distance.getZ() - (ZOOM_IN_LIMIT * 2)) /
((THIRD_PERSON_LIMIT - (ZOOM_IN_LIMIT * 2)) /
(1 - 0.1))) + 0.1);
// if zoomed right in
if (itemScale < 0.1){
itemScale = 0.1;
// if zoomed right out
} else if (itemScale > 1) {
itemScale = 1;
}
// update scale
for (Subject3D item : items) {
item.setScale(itemScale);
}
}
/**
* Adjusts the pitch as a user zooms in or out, to smooth the change
* between third person to birds eye view.
*/
private void adjustPitchForZoom(){
double pitch = (((-distance.getZ() - (ZOOM_IN_LIMIT*2)) /
((THIRD_PERSON_LIMIT - (ZOOM_IN_LIMIT*2)) / (MAX_PITCH -
MIN_PITCH))) + MIN_PITCH);
// if pitch is out of bounds, set it to the min/max
if (pitch < MIN_PITCH) {
pitch = MIN_PITCH;
} else if (pitch > MAX_PITCH){
pitch = MAX_PITCH;
}
setPitch(pitch);
}
/**
* Method to be called when the zoom in key is pressed.
*/
public void zoomIn(){
updateDistance(-ZOOM_PER_KEYPRESS);
}
/**
* Method to be called when the zoom out key is pressed.
*/
public void zoomOut(){
updateDistance(ZOOM_PER_KEYPRESS);
}
/**