mirror of
https://github.com/michaelrausch/Party-Parrots-At-Sea.git
synced 2026-05-09 14:28:43 +00:00
Merge remote-tracking branch 'origin/develop' into develop
# Conflicts: # src/main/java/seng302/gameServer/MainServerThread.java # src/main/java/seng302/visualiser/GameClient.java # src/main/java/seng302/visualiser/controllers/dialogs/ServerCreationController.java
This commit is contained in:
@@ -103,7 +103,7 @@ public class App extends Application {
|
|||||||
public void run() {
|
public void run() {
|
||||||
System.gc();
|
System.gc();
|
||||||
}
|
}
|
||||||
}, 0, 1200);
|
}, 0, 1_000);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
parseArgs(args);
|
parseArgs(args);
|
||||||
|
|||||||
@@ -238,7 +238,7 @@ public class GameState implements Runnable {
|
|||||||
if (System.currentTimeMillis() > startTime) {
|
if (System.currentTimeMillis() > startTime) {
|
||||||
startSpawningTokens();
|
startSpawningTokens();
|
||||||
startUpdatingWind();
|
startUpdatingWind();
|
||||||
GameState.setCurrentStage(GameStages.RACING);
|
GameState.currentStage = GameStages.RACING;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (currentStage == GameStages.RACING) {
|
if (currentStage == GameStages.RACING) {
|
||||||
@@ -299,8 +299,8 @@ public class GameState implements Runnable {
|
|||||||
windSpeed += random.nextInt(500);
|
windSpeed += random.nextInt(500);
|
||||||
}
|
}
|
||||||
|
|
||||||
GameState.setWindSpeed(Double.valueOf(windSpeed));
|
GameState.windSpeed = Double.valueOf(windSpeed);
|
||||||
GameState.setWindDirection(direction.doubleValue());
|
GameState.windDirection = direction.doubleValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import java.net.ServerSocket;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Random;
|
|
||||||
import java.util.Timer;
|
import java.util.Timer;
|
||||||
import java.util.TimerTask;
|
import java.util.TimerTask;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
@@ -19,12 +18,6 @@ import seng302.model.stream.xml.parser.RaceXMLData;
|
|||||||
import seng302.model.stream.xml.parser.RegattaXMLData;
|
import seng302.model.stream.xml.parser.RegattaXMLData;
|
||||||
import seng302.utilities.GeoUtility;
|
import seng302.utilities.GeoUtility;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.net.ServerSocket;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Random;
|
|
||||||
import java.util.Timer;
|
|
||||||
import java.util.TimerTask;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A class describing the overall server, which creates and collects server threads for each client
|
* A class describing the overall server, which creates and collects server threads for each client
|
||||||
@@ -32,23 +25,32 @@ import java.util.TimerTask;
|
|||||||
*/
|
*/
|
||||||
public class MainServerThread implements Runnable, ClientConnectionDelegate {
|
public class MainServerThread implements Runnable, ClientConnectionDelegate {
|
||||||
|
|
||||||
private Logger logger = LoggerFactory.getLogger(MainServerThread.class);
|
|
||||||
|
|
||||||
private static final int PORT = 4942;
|
private static final int PORT = 4942;
|
||||||
private static int selectedPort = PORT;
|
private static int selectedPort = PORT;
|
||||||
private static final Integer CLIENT_UPDATES_PER_SECOND = 60;
|
private static final Integer CLIENT_UPDATES_PER_SECOND = 60;
|
||||||
|
private Logger logger = LoggerFactory.getLogger(MainServerThread.class);
|
||||||
private boolean terminated;
|
private boolean terminated;
|
||||||
|
|
||||||
private Thread thread;
|
|
||||||
private boolean hasStarted = false;
|
private boolean hasStarted = false;
|
||||||
|
|
||||||
private ServerSocket serverSocket = null;
|
private ServerSocket serverSocket = null;
|
||||||
private ArrayList<ServerToClientThread> serverToClientThreads = new ArrayList<>();
|
private ArrayList<ServerToClientThread> serverToClientThreads = new ArrayList<>();
|
||||||
private static Integer capacity;
|
|
||||||
private RaceXMLData raceXMLData;
|
private RaceXMLData raceXMLData;
|
||||||
private RegattaXMLData regattaXMLData;
|
private RegattaXMLData regattaXMLData;
|
||||||
private boolean serverStarted = false;
|
|
||||||
|
public MainServerThread() {
|
||||||
|
new GameState();
|
||||||
|
try {
|
||||||
|
serverSocket = new ServerSocket(0);
|
||||||
|
selectedPort = serverSocket.getLocalPort();
|
||||||
|
} catch (IOException e) {
|
||||||
|
logger.trace("IO error in server thread handler upon trying to make new server socket",
|
||||||
|
0);
|
||||||
|
}
|
||||||
|
terminated = false;
|
||||||
|
Thread thread = new Thread(this, "MainServer");
|
||||||
|
thread.start();
|
||||||
|
}
|
||||||
|
|
||||||
private void startAdvertisingServer() {
|
private void startAdvertisingServer() {
|
||||||
Integer capacity = GameState.getCapacity();
|
Integer capacity = GameState.getCapacity();
|
||||||
@@ -72,22 +74,6 @@ public class MainServerThread implements Runnable, ClientConnectionDelegate {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public MainServerThread() {
|
|
||||||
new GameState();
|
|
||||||
try {
|
|
||||||
serverSocket = new ServerSocket(0);
|
|
||||||
selectedPort = serverSocket.getLocalPort();
|
|
||||||
System.out.println("selectedPort = " + selectedPort);
|
|
||||||
|
|
||||||
} catch (IOException e) {
|
|
||||||
logger.trace("IO error in server thread handler upon trying to make new server socket",
|
|
||||||
0);
|
|
||||||
}
|
|
||||||
terminated = false;
|
|
||||||
thread = new Thread(this, "MainServer");
|
|
||||||
thread.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void startServer() {
|
private void startServer() {
|
||||||
PolarTable.parsePolarFile(getClass().getResourceAsStream("/server_config/acc_polars.csv"));
|
PolarTable.parsePolarFile(getClass().getResourceAsStream("/server_config/acc_polars.csv"));
|
||||||
MessageFactory.updateXMLGenerator(raceXMLData, regattaXMLData);
|
MessageFactory.updateXMLGenerator(raceXMLData, regattaXMLData);
|
||||||
@@ -126,7 +112,8 @@ public class MainServerThread implements Runnable, ClientConnectionDelegate {
|
|||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
logger.trace("Interrupted exception in Main Server Thread thread sleep", 1);
|
logger.trace("Interrupted exception in Main Server Thread thread sleep", 1);
|
||||||
}
|
}
|
||||||
if (GameState.getCurrentStage() == GameStages.LOBBYING && GameState.getCustomizationFlag()) {
|
if (GameState.getCurrentStage() == GameStages.LOBBYING && GameState
|
||||||
|
.getCustomizationFlag()) {
|
||||||
MessageFactory.updateBoats(new ArrayList<>(GameState.getYachts().values()));
|
MessageFactory.updateBoats(new ArrayList<>(GameState.getYachts().values()));
|
||||||
sendSetupMessages();
|
sendSetupMessages();
|
||||||
GameState.resetCustomizationFlag();
|
GameState.resetCustomizationFlag();
|
||||||
@@ -145,7 +132,8 @@ public class MainServerThread implements Runnable, ClientConnectionDelegate {
|
|||||||
else if (GameState.getCurrentStage() == GameStages.FINISHED) {
|
else if (GameState.getCurrentStage() == GameStages.FINISHED) {
|
||||||
broadcastMessage(MessageFactory.getRaceStatusMessage());
|
broadcastMessage(MessageFactory.getRaceStatusMessage());
|
||||||
try {
|
try {
|
||||||
Thread.sleep(1000); //Hackish fix to make sure all threads have sent closing RaceStatus
|
Thread.sleep(
|
||||||
|
1000); //Hackish fix to make sure all threads have sent closing RaceStatus
|
||||||
terminate();
|
terminate();
|
||||||
} catch (InterruptedException ie) {
|
} catch (InterruptedException ie) {
|
||||||
logger.trace("Thread interrupted while waiting to terminate clients", 1);
|
logger.trace("Thread interrupted while waiting to terminate clients", 1);
|
||||||
@@ -209,9 +197,8 @@ public class MainServerThread implements Runnable, ClientConnectionDelegate {
|
|||||||
startServer();
|
startServer();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
|
||||||
//serverToClientThread.addConnectionListener(this::sendSetupMessages);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
serverToClientThreads.add(serverToClientThread);
|
serverToClientThreads.add(serverToClientThread);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -259,8 +246,10 @@ public class MainServerThread implements Runnable, ClientConnectionDelegate {
|
|||||||
logger.warn("Couldn't update advertisement");
|
logger.warn("Couldn't update advertisement");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (closedConnection != null) {
|
||||||
closedConnection.terminate();
|
closedConnection.terminate();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void startGame() {
|
public void startGame() {
|
||||||
try {
|
try {
|
||||||
@@ -283,10 +272,6 @@ public class MainServerThread implements Runnable, ClientConnectionDelegate {
|
|||||||
}
|
}
|
||||||
}, 0, 500);
|
}, 0, 500);
|
||||||
|
|
||||||
|
|
||||||
// if (GameState.getCurrentStage() == GameStages.LOBBYING) {
|
|
||||||
// sendSetupMessages();
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void terminate() {
|
public void terminate() {
|
||||||
@@ -297,108 +282,6 @@ public class MainServerThread implements Runnable, ClientConnectionDelegate {
|
|||||||
* Initialise boats to specific spaced out geopoints behind starting line.
|
* Initialise boats to specific spaced out geopoints behind starting line.
|
||||||
*/
|
*/
|
||||||
private void initialiseBoatPositions() {
|
private void initialiseBoatPositions() {
|
||||||
// CompoundMark cm = GameState.getMarkOrder().getMarkOrder().get(0);
|
|
||||||
// GeoPoint startMark1 = cm.getSubMark(1);
|
|
||||||
// GeoPoint startMark2 = cm.getSubMark(2);
|
|
||||||
//
|
|
||||||
// // Calculating midpoint
|
|
||||||
// Double perpendicularAngle = GeoUtility.getBearing(startMark1, startMark2);
|
|
||||||
// Double length = GeoUtility.getDistance(startMark1, startMark2);
|
|
||||||
// GeoPoint midpoint = GeoUtility.getGeoCoordinate(startMark1, perpendicularAngle, length / 2);
|
|
||||||
//
|
|
||||||
// // Setting each boats position side by side
|
|
||||||
// final double SEPARATION = 50.0; // distance apart in meters
|
|
||||||
//
|
|
||||||
// int boatIndex = 0;
|
|
||||||
// for (ServerYacht yacht : GameState.getYachts().values()) {
|
|
||||||
// int distanceApart = boatIndex / 2;
|
|
||||||
//
|
|
||||||
// if (boatIndex % 2 == 1 && boatIndex != 0) {
|
|
||||||
// distanceApart++;
|
|
||||||
// distanceApart *= -1;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// GeoPoint spawnMark = GeoUtility
|
|
||||||
// .getGeoCoordinate(midpoint, perpendicularAngle, distanceApart * SEPARATION);
|
|
||||||
//
|
|
||||||
// if (yacht.getHeading() < perpendicularAngle) {
|
|
||||||
// spawnMark = GeoUtility
|
|
||||||
// .getGeoCoordinate(spawnMark, perpendicularAngle + 90, SEPARATION);
|
|
||||||
// } else {
|
|
||||||
// spawnMark = GeoUtility
|
|
||||||
// .getGeoCoordinate(spawnMark, perpendicularAngle + 270, SEPARATION);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// yacht.setLocation(spawnMark);
|
|
||||||
// boatIndex++;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// final double SEPARATION = 50.0; // distance apart in meters
|
|
||||||
//
|
|
||||||
// //Reverse of the angle from start to first mark
|
|
||||||
// double angleToFirstMark = 360 - GeoUtility.getBearing(
|
|
||||||
// GameState.getMarkOrder().getMarkOrder().get(0).getMidPoint(),
|
|
||||||
// GameState.getMarkOrder().getMarkOrder().get(1).getMidPoint()
|
|
||||||
// );
|
|
||||||
//
|
|
||||||
// //Length of start line
|
|
||||||
// double startLineLength = GeoUtility.getDistance(
|
|
||||||
// GameState.getMarkOrder().getMarkOrder().get(0).getSubMark(1),
|
|
||||||
// GameState.getMarkOrder().getMarkOrder().get(0).getSubMark(2)
|
|
||||||
// );
|
|
||||||
//
|
|
||||||
// //Angle of start line
|
|
||||||
// double startMarkToMarkAngle = GeoUtility.getBearing(
|
|
||||||
// GameState.getMarkOrder().getMarkOrder().get(0).getSubMark(1),
|
|
||||||
// GameState.getMarkOrder().getMarkOrder().get(0).getSubMark(2)
|
|
||||||
// );
|
|
||||||
//
|
|
||||||
// //How many yachts can fit along the start line
|
|
||||||
// int spacesAlongLine = (int) Math.round(startLineLength / SEPARATION);
|
|
||||||
// //The free space left by the boats.
|
|
||||||
// double buffer = (startLineLength % SEPARATION) / 2;
|
|
||||||
//
|
|
||||||
// //Randomize starting order.
|
|
||||||
// List<ServerYacht> serverYachtList = new ArrayList<>(GameState.getYachts().values());
|
|
||||||
// Collections.shuffle(serverYachtList);
|
|
||||||
//
|
|
||||||
// //set the starting point away from start line.
|
|
||||||
// GeoPoint startingPoint = GeoUtility.getGeoCoordinate(
|
|
||||||
// GameState.getMarkOrder().getMarkOrder().get(0).getSubMark(1),
|
|
||||||
// angleToFirstMark, SEPARATION
|
|
||||||
// );
|
|
||||||
//
|
|
||||||
// //Move it along the start line
|
|
||||||
// startingPoint = GeoUtility.getGeoCoordinate(
|
|
||||||
// startingPoint, startMarkToMarkAngle, buffer
|
|
||||||
// );
|
|
||||||
//
|
|
||||||
// int yachtCount = 0;
|
|
||||||
// int repeats = 0;
|
|
||||||
//
|
|
||||||
// GeoPoint yachtLocation;
|
|
||||||
//
|
|
||||||
// for (ServerYacht serverYacht : serverYachtList) {
|
|
||||||
//
|
|
||||||
// //Move away from start line
|
|
||||||
// yachtLocation = GeoUtility.getGeoCoordinate(
|
|
||||||
// startingPoint, angleToFirstMark,repeats * SEPARATION
|
|
||||||
// );
|
|
||||||
// //Move along start line
|
|
||||||
// yachtLocation = GeoUtility.getGeoCoordinate(
|
|
||||||
// yachtLocation, startMarkToMarkAngle, yachtCount * SEPARATION
|
|
||||||
// );
|
|
||||||
// serverYacht.setLocation(yachtLocation);
|
|
||||||
// serverYacht.setHeading(GeoUtility.getBearing(
|
|
||||||
// yachtLocation, GameState.getMarkOrder().getMarkOrder().get(1).getMidPoint()
|
|
||||||
// ));
|
|
||||||
// //Set location for next yacht
|
|
||||||
// yachtCount++;
|
|
||||||
// if (yachtCount > spacesAlongLine) {
|
|
||||||
// yachtCount = 0;
|
|
||||||
// repeats++;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
final double DISTANCE_TO_START = 75d;
|
final double DISTANCE_TO_START = 75d;
|
||||||
final double YACHT_SEPARATION = 20d;
|
final double YACHT_SEPARATION = 20d;
|
||||||
@@ -438,7 +321,9 @@ public class MainServerThread implements Runnable, ClientConnectionDelegate {
|
|||||||
Collections.shuffle(randomisedYachts);
|
Collections.shuffle(randomisedYachts);
|
||||||
while (randomisedYachts.size() > 0) {
|
while (randomisedYachts.size() > 0) {
|
||||||
|
|
||||||
int numYachtsInLine = spacesAlongLine > randomisedYachts.size() ? randomisedYachts.size() : spacesAlongLine;
|
int numYachtsInLine =
|
||||||
|
spacesAlongLine > randomisedYachts.size() ? randomisedYachts.size()
|
||||||
|
: spacesAlongLine;
|
||||||
double yachtSpace = numYachtsInLine * YACHT_SEPARATION / 2;
|
double yachtSpace = numYachtsInLine * YACHT_SEPARATION / 2;
|
||||||
|
|
||||||
GeoPoint firstYachtPoint = GeoUtility.getGeoCoordinate(
|
GeoPoint firstYachtPoint = GeoUtility.getGeoCoordinate(
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
package seng302.gameServer;
|
package seng302.gameServer;
|
||||||
|
|
||||||
import seng302.gameServer.messages.*;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import seng302.gameServer.messages.BoatLocationMessage;
|
import seng302.gameServer.messages.BoatLocationMessage;
|
||||||
@@ -25,9 +24,6 @@ import seng302.model.token.Token;
|
|||||||
import seng302.model.token.TokenType;
|
import seng302.model.token.TokenType;
|
||||||
import seng302.utilities.XMLGenerator;
|
import seng302.utilities.XMLGenerator;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A Class for interfacing between the data we have in the GameState to the messages we need to send
|
* A Class for interfacing between the data we have in the GameState to the messages we need to send
|
||||||
* through the MainServerThread.
|
* through the MainServerThread.
|
||||||
@@ -77,9 +73,6 @@ public class MessageFactory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static void updateBoats(List<ServerYacht> yachts) {
|
public static void updateBoats(List<ServerYacht> yachts) {
|
||||||
// for (ServerYacht serverYacht : yachts) {
|
|
||||||
// System.out.println(serverYacht);
|
|
||||||
// }
|
|
||||||
xmlGenerator.getRace().setBoats(yachts);
|
xmlGenerator.getRace().setBoats(yachts);
|
||||||
String xmlStr = xmlGenerator.getBoatsAsXml();
|
String xmlStr = xmlGenerator.getBoatsAsXml();
|
||||||
MessageFactory.boats = new XMLMessage(xmlStr, XMLMessageSubType.BOAT, xmlStr.length());
|
MessageFactory.boats = new XMLMessage(xmlStr, XMLMessageSubType.BOAT, xmlStr.length());
|
||||||
|
|||||||
@@ -1,14 +1,5 @@
|
|||||||
package seng302.visualiser;
|
package seng302.visualiser;
|
||||||
|
|
||||||
import javafx.application.Platform;
|
|
||||||
import javafx.util.Pair;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
import seng302.gameServer.messages.*;
|
|
||||||
import seng302.model.stream.packets.PacketType;
|
|
||||||
import seng302.model.stream.packets.StreamPacket;
|
|
||||||
import seng302.utilities.XMLParser;
|
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
@@ -43,7 +34,7 @@ import seng302.model.stream.xml.generator.RaceXMLTemplate;
|
|||||||
import seng302.model.stream.xml.generator.RegattaXMLTemplate;
|
import seng302.model.stream.xml.generator.RegattaXMLTemplate;
|
||||||
import seng302.utilities.XMLGenerator;
|
import seng302.utilities.XMLGenerator;
|
||||||
import seng302.utilities.XMLParser;
|
import seng302.utilities.XMLParser;
|
||||||
import seng302.visualiser.controllers.ViewManager;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A class describing a single connection to a Server for the purposes of sending and receiving on
|
* A class describing a single connection to a Server for the purposes of sending and receiving on
|
||||||
|
|||||||
@@ -5,9 +5,7 @@ import java.text.SimpleDateFormat;
|
|||||||
import java.time.ZoneId;
|
import java.time.ZoneId;
|
||||||
import java.time.ZoneOffset;
|
import java.time.ZoneOffset;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.TimeZone;
|
import java.util.TimeZone;
|
||||||
import java.util.Timer;
|
import java.util.Timer;
|
||||||
@@ -17,7 +15,6 @@ import javafx.collections.FXCollections;
|
|||||||
import javafx.collections.ObservableList;
|
import javafx.collections.ObservableList;
|
||||||
import javafx.scene.input.KeyCode;
|
import javafx.scene.input.KeyCode;
|
||||||
import javafx.scene.input.KeyEvent;
|
import javafx.scene.input.KeyEvent;
|
||||||
import javafx.scene.layout.Pane;
|
|
||||||
import javafx.scene.paint.Color;
|
import javafx.scene.paint.Color;
|
||||||
import javafx.util.Pair;
|
import javafx.util.Pair;
|
||||||
import seng302.gameServer.GameStages;
|
import seng302.gameServer.GameStages;
|
||||||
@@ -49,19 +46,12 @@ import seng302.visualiser.controllers.RaceViewController;
|
|||||||
import seng302.visualiser.controllers.ViewManager;
|
import seng302.visualiser.controllers.ViewManager;
|
||||||
import seng302.visualiser.controllers.dialogs.PopupDialogController;
|
import seng302.visualiser.controllers.dialogs.PopupDialogController;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.text.SimpleDateFormat;
|
|
||||||
import java.time.ZoneId;
|
|
||||||
import java.time.ZoneOffset;
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class is a client side instance of a yacht racing game in JavaFX. The game is instantiated
|
* This class is a client side instance of a yacht racing game in JavaFX. The game is instantiated
|
||||||
* with a JavaFX Pane to insert itself into.
|
* with a JavaFX Pane to insert itself into.
|
||||||
*/
|
*/
|
||||||
public class GameClient {
|
public class GameClient {
|
||||||
|
|
||||||
private Pane holderPane;
|
|
||||||
private ClientToServerThread socketThread;
|
private ClientToServerThread socketThread;
|
||||||
private MainServerThread server;
|
private MainServerThread server;
|
||||||
|
|
||||||
@@ -83,10 +73,8 @@ public class GameClient {
|
|||||||
/**
|
/**
|
||||||
* Create an instance of the game client. Does not do anything until run with runAsClient()
|
* Create an instance of the game client. Does not do anything until run with runAsClient()
|
||||||
* runAsHost().
|
* runAsHost().
|
||||||
* @param holder The JavaFX Pane that the visual elements for the race will be inserted into.
|
|
||||||
*/
|
*/
|
||||||
public GameClient(Pane holder) {
|
public GameClient() {
|
||||||
this.holderPane = holder;
|
|
||||||
this.gameKeyBind = GameKeyBind.getInstance();
|
this.gameKeyBind = GameKeyBind.getInstance();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -124,10 +112,7 @@ public class GameClient {
|
|||||||
ViewManager.getInstance().setProperty("serverName", regattaData.getRegattaName());
|
ViewManager.getInstance().setProperty("serverName", regattaData.getRegattaName());
|
||||||
ViewManager.getInstance().setProperty("mapName", regattaData.getCourseName());
|
ViewManager.getInstance().setProperty("mapName", regattaData.getCourseName());
|
||||||
|
|
||||||
getServerThread().setConnectionErrorListener((eMessage) -> {
|
getServerThread().setConnectionErrorListener((eMessage) -> ViewManager.getInstance().showErrorSnackBar(eMessage));
|
||||||
ViewManager.getInstance().showErrorSnackBar(eMessage);
|
|
||||||
//destroyClientToServerThread();
|
|
||||||
});
|
|
||||||
|
|
||||||
this.lobbyController = ViewManager.getInstance().goToLobby(true);
|
this.lobbyController = ViewManager.getInstance().goToLobby(true);
|
||||||
|
|
||||||
@@ -138,18 +123,11 @@ public class GameClient {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void destroyClientToServerThread() {
|
|
||||||
socketThread.closeSocket();
|
|
||||||
socketThread = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Connect to a game as the host at the given address and starts the visualiser.
|
* Connect to a game as the host at the given address and starts the visualiser.
|
||||||
* @param ipAddress IP to connect to.
|
|
||||||
* @param portNumber Port to connect to.
|
|
||||||
*/
|
*/
|
||||||
public ServerDescription runAsHost(
|
public ServerDescription runAsHost(
|
||||||
String ipAddress, Integer portNumber, String serverName, Integer maxPlayers, String race,
|
String serverName, Integer maxPlayers, String race,
|
||||||
Integer numLegs, Boolean tokensEnabled
|
Integer numLegs, Boolean tokensEnabled
|
||||||
) {
|
) {
|
||||||
XMLGenerator.setDefaultRaceName(serverName);
|
XMLGenerator.setDefaultRaceName(serverName);
|
||||||
@@ -165,7 +143,7 @@ public class GameClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
startClientToServerThread(ipAddress, server.getPortNumber());
|
startClientToServerThread("localhost", server.getPortNumber());
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
showConnectionError("Cannot connect to server as host");
|
showConnectionError("Cannot connect to server as host");
|
||||||
}
|
}
|
||||||
@@ -202,7 +180,8 @@ public class GameClient {
|
|||||||
lobbyController.setPortNumber(""+server.getPortNumber());
|
lobbyController.setPortNumber(""+server.getPortNumber());
|
||||||
|
|
||||||
ViewManager.getInstance().setPlayerList(clientLobbyList);
|
ViewManager.getInstance().setPlayerList(clientLobbyList);
|
||||||
return new ServerDescription(serverName, regattaData.getCourseName(), GameState.getNumberOfPlayers(), GameState.getCapacity(), ipAddress, server.getPortNumber());
|
return new ServerDescription(serverName, regattaData.getCourseName(), GameState.getNumberOfPlayers(), GameState.getCapacity(),
|
||||||
|
"localhost", server.getPortNumber());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void tearDownConnection() {
|
private void tearDownConnection() {
|
||||||
@@ -305,6 +284,7 @@ public class GameClient {
|
|||||||
case CHATTER_TEXT:
|
case CHATTER_TEXT:
|
||||||
Pair<Integer, String> playerIdMessagePair = StreamParser
|
Pair<Integer, String> playerIdMessagePair = StreamParser
|
||||||
.extractChatterText(packet);
|
.extractChatterText(packet);
|
||||||
|
if (playerIdMessagePair != null) {
|
||||||
raceView.updateChatHistory(
|
raceView.updateChatHistory(
|
||||||
allBoatsMap.get(playerIdMessagePair.getKey()).getColour(),
|
allBoatsMap.get(playerIdMessagePair.getKey()).getColour(),
|
||||||
playerIdMessagePair.getValue()
|
playerIdMessagePair.getValue()
|
||||||
@@ -312,6 +292,7 @@ public class GameClient {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void startRaceIfAllDataReceived() {
|
private void startRaceIfAllDataReceived() {
|
||||||
if (allXMLReceived() && raceView == null) {
|
if (allXMLReceived() && raceView == null) {
|
||||||
@@ -325,6 +306,7 @@ public class GameClient {
|
|||||||
formatAndSendChatMessage(raceView.readChatInput());
|
formatAndSendChatMessage(raceView.readChatInput());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
gameKeyBind.toggleTurningMode();
|
||||||
sendToggleTurningModePacket(); // notify the server about player's steering mode
|
sendToggleTurningModePacket(); // notify the server about player's steering mode
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -344,8 +326,6 @@ public class GameClient {
|
|||||||
positionData.getLon(), positionData.getHeading(),
|
positionData.getLon(), positionData.getHeading(),
|
||||||
positionData.getGroundSpeed());
|
positionData.getGroundSpeed());
|
||||||
}
|
}
|
||||||
} else if (positionData.getType() == DeviceType.MARK_TYPE) {
|
|
||||||
//CompoundMark mark = courseData.getCompoundMarks().get(positionData.getDeviceId());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -383,21 +363,17 @@ public class GameClient {
|
|||||||
ClientYacht clientYacht = allBoatsMap.get((int) boatData[0]);
|
ClientYacht clientYacht = allBoatsMap.get((int) boatData[0]);
|
||||||
clientYacht.setEstimateTimeTillNextMark(raceState.getRaceTime() - boatData[1]);
|
clientYacht.setEstimateTimeTillNextMark(raceState.getRaceTime() - boatData[1]);
|
||||||
clientYacht.setEstimateTimeAtFinish(boatData[2]);
|
clientYacht.setEstimateTimeAtFinish(boatData[2]);
|
||||||
// int legNumber = (int) boatData[3];
|
|
||||||
clientYacht.setBoatStatus((int) boatData[4]);
|
clientYacht.setBoatStatus((int) boatData[4]);
|
||||||
// if (legNumber != clientYacht.getLegNumber()) {
|
|
||||||
// clientYacht.setLegNumber(legNumber);
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (raceFinished) {
|
if (raceFinished && !raceState.getRaceFinished()) {
|
||||||
raceViewController.showFinishDialog(finishedBoats);
|
raceState.setRaceFinished();
|
||||||
Sounds.playFinishSound();
|
Sounds.playFinishSound();
|
||||||
close();
|
raceViewController.showFinishDialog(finishedBoats);
|
||||||
ViewManager.getInstance().getGameClient().stopGame();
|
// close();
|
||||||
|
// ViewManager.getInstance().getGameClient().stopGame();
|
||||||
//loadFinishScreenView();
|
//loadFinishScreenView();
|
||||||
}
|
}
|
||||||
raceState.setRaceFinished();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -408,10 +384,6 @@ public class GameClient {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void close() {
|
|
||||||
socketThread.setSocketToClose();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle the key-pressed event from the text field.
|
* Handle the key-pressed event from the text field.
|
||||||
* @param e The key event triggering this call
|
* @param e The key event triggering this call
|
||||||
@@ -538,10 +510,6 @@ public class GameClient {
|
|||||||
return socketThread;
|
return socketThread;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<String> getPlayerNames(){
|
|
||||||
return Collections.unmodifiableList(clientLobbyList.sorted());
|
|
||||||
}
|
|
||||||
|
|
||||||
public void stopGame() {
|
public void stopGame() {
|
||||||
GameState.setCurrentStage(GameStages.CANCELLED);
|
GameState.setCurrentStage(GameStages.CANCELLED);
|
||||||
if (server != null) server.terminate();
|
if (server != null) server.terminate();
|
||||||
|
|||||||
@@ -350,7 +350,7 @@ public class GameView3D extends GameView{
|
|||||||
for (ObservableValue o : Arrays
|
for (ObservableValue o : Arrays
|
||||||
.asList(playerBoat.layoutXProperty(), playerBoat.layoutXProperty())) {
|
.asList(playerBoat.layoutXProperty(), playerBoat.layoutXProperty())) {
|
||||||
o.addListener((obs, oldVal, newVal) -> {
|
o.addListener((obs, oldVal, newVal) -> {
|
||||||
|
if (playerYacht.getLegNumber() < course.size()) {
|
||||||
List<Mark> marks = course.get(playerYacht.getLegNumber()).getMarks();
|
List<Mark> marks = course.get(playerYacht.getLegNumber()).getMarks();
|
||||||
Point2D midPoint = new Point2D(0, 0);
|
Point2D midPoint = new Point2D(0, 0);
|
||||||
if (marks.size() == 1) {
|
if (marks.size() == 1) {
|
||||||
@@ -363,6 +363,7 @@ public class GameView3D extends GameView{
|
|||||||
if (midPoint != null) {
|
if (midPoint != null) {
|
||||||
playerBoat.updateMarkIndicator(midPoint);
|
playerBoat.updateMarkIndicator(midPoint);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ public class MapMaker {
|
|||||||
private XMLGenerator xmlGenerator = new XMLGenerator();
|
private XMLGenerator xmlGenerator = new XMLGenerator();
|
||||||
|
|
||||||
private List<String> maps = new ArrayList<>(
|
private List<String> maps = new ArrayList<>(
|
||||||
Arrays.asList("default.xml", "horseshoe.xml", "madagascar.xml", "loop.xml"));
|
Arrays.asList("default.xml", "horseshoe.xml", "loop.xml", "madagascar.xml"));
|
||||||
|
|
||||||
public static MapMaker getInstance() {
|
public static MapMaker getInstance() {
|
||||||
if (instance == null) {
|
if (instance == null) {
|
||||||
@@ -108,10 +108,6 @@ public class MapMaker {
|
|||||||
return mapPreviews.get(index).getAssets();
|
return mapPreviews.get(index).getAssets();
|
||||||
}
|
}
|
||||||
|
|
||||||
public RaceXMLData getCurrentRace() {
|
|
||||||
return races.get(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
public RegattaXMLData getCurrentRegatta() {
|
public RegattaXMLData getCurrentRegatta() {
|
||||||
return regattas.get(index);
|
return regattas.get(index);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ import seng302.visualiser.fxObjects.assets_2D.Marker2D;
|
|||||||
public class MapPreview extends GameView {
|
public class MapPreview extends GameView {
|
||||||
|
|
||||||
private Polygon raceBorder = new CourseBoundary();
|
private Polygon raceBorder = new CourseBoundary();
|
||||||
private Map<Mark, Marker2D> markerObjects;
|
protected Map<Mark, Marker2D> markerObjects;
|
||||||
|
|
||||||
public MapPreview(List<CompoundMark> marks, List<Corner> course, List<Limit> border) {
|
public MapPreview(List<CompoundMark> marks, List<Corner> course, List<Limit> border) {
|
||||||
this.compoundMarks = marks;
|
this.compoundMarks = marks;
|
||||||
|
|||||||
@@ -0,0 +1,86 @@
|
|||||||
|
package seng302.visualiser;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import javafx.application.Platform;
|
||||||
|
import javafx.geometry.Point2D;
|
||||||
|
import javafx.scene.paint.Color;
|
||||||
|
import javafx.scene.shape.Polygon;
|
||||||
|
import javafx.scene.transform.Rotate;
|
||||||
|
import seng302.model.ClientYacht;
|
||||||
|
import seng302.model.Limit;
|
||||||
|
import seng302.model.mark.CompoundMark;
|
||||||
|
import seng302.model.mark.Corner;
|
||||||
|
import seng302.model.mark.Mark;
|
||||||
|
import seng302.utilities.Sounds;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class converts a map preview to a minimap by adding boats.
|
||||||
|
*/
|
||||||
|
public class MiniMap extends MapPreview {
|
||||||
|
|
||||||
|
private HashMap<ClientYacht, Polygon> boatIcons = new HashMap<>();
|
||||||
|
private Polygon playerBoat;
|
||||||
|
private double playerRotation;
|
||||||
|
private List<ClientYacht> boats;
|
||||||
|
private ClientYacht player;
|
||||||
|
|
||||||
|
public MiniMap (List<CompoundMark> marks, List<Corner> course, List<Limit> border, List<ClientYacht> boats, ClientYacht player) {
|
||||||
|
super(marks, course, border);
|
||||||
|
this.boats = boats;
|
||||||
|
this.player = player;
|
||||||
|
setBoats(boats);
|
||||||
|
player.addMarkRoundingListener(this::updateMarkArrows);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBoats(List<ClientYacht> yachts) {
|
||||||
|
for (ClientYacht yacht : yachts) {
|
||||||
|
Polygon boatIcon = new Polygon(0, -3.5, 3.5, 3.5, -3.5, 3.5);
|
||||||
|
boatIcon.setStroke(Color.BLACK);
|
||||||
|
boatIcon.setFill(Color.GRAY);
|
||||||
|
boatIcon.setFill(yacht.getColour());
|
||||||
|
boatIcon.setFill(yacht.getColour());
|
||||||
|
boatIcons.put(yacht, boatIcon);
|
||||||
|
boatIcon.getTransforms().add(new Rotate(0));
|
||||||
|
yacht.addLocationListener((boat, lat, lon, heading, sailIn, velocity) -> {
|
||||||
|
Platform.runLater(() -> {
|
||||||
|
Polygon bi = boatIcons.get(boat);
|
||||||
|
Point2D p2d = scaledPoint.findScaledXY(lat, lon);
|
||||||
|
bi.setLayoutX(p2d.getX());
|
||||||
|
bi.setLayoutY(p2d.getY());
|
||||||
|
((Rotate) bi.getTransforms().get(0)).setAngle(heading);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
Platform.runLater(() -> {
|
||||||
|
gameObjects.getChildren().addAll(boatIcons.values());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateMarkArrows (ClientYacht yacht, int legNumber) {
|
||||||
|
CompoundMark compoundMark;
|
||||||
|
if (legNumber - 1 >= 0) {
|
||||||
|
Sounds.playMarkRoundingSound();
|
||||||
|
compoundMark = course.get(legNumber-1);
|
||||||
|
for (Mark mark : compoundMark.getMarks()) {
|
||||||
|
markerObjects.get(mark).showNextExitArrow();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CompoundMark nextMark = null;
|
||||||
|
if (legNumber < course.size() - 1) {
|
||||||
|
Sounds.playMarkRoundingSound();
|
||||||
|
nextMark = course.get(legNumber);
|
||||||
|
for (Mark mark : nextMark.getMarks()) {
|
||||||
|
markerObjects.get(mark).showNextEnterArrow();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (legNumber - 2 >= 0) {
|
||||||
|
CompoundMark lastMark = course.get(Math.max(0, legNumber - 2));
|
||||||
|
if (lastMark != nextMark) {
|
||||||
|
for (Mark mark : lastMark.getMarks()) {
|
||||||
|
markerObjects.get(mark).hideAllArrows();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,17 +1,17 @@
|
|||||||
package seng302.visualiser;
|
package seng302.visualiser;
|
||||||
|
|
||||||
import seng302.gameServer.ServerAdvertiser;
|
import static seng302.gameServer.ServerAdvertiser.getLocalHostIp;
|
||||||
import seng302.gameServer.ServerDescription;
|
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.InetAddress;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
import javax.jmdns.JmDNS;
|
import javax.jmdns.JmDNS;
|
||||||
import javax.jmdns.ServiceEvent;
|
import javax.jmdns.ServiceEvent;
|
||||||
import javax.jmdns.ServiceListener;
|
import javax.jmdns.ServiceListener;
|
||||||
import javax.jmdns.impl.JmDNSImpl;
|
import seng302.gameServer.ServerAdvertiser;
|
||||||
import java.io.IOException;
|
import seng302.gameServer.ServerDescription;
|
||||||
import java.net.InetAddress;
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
import static seng302.gameServer.ServerAdvertiser.getLocalHostIp;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Listens for servers on the local network
|
* Listens for servers on the local network
|
||||||
@@ -58,7 +58,7 @@ public class ServerListener{
|
|||||||
servers.remove(toRemove);
|
servers.remove(toRemove);
|
||||||
}
|
}
|
||||||
|
|
||||||
delegate.serverRemoved(new ArrayList<ServerDescription>(servers));
|
delegate.serverRemoved(new ArrayList<>(servers));
|
||||||
|
|
||||||
// Get all other servers with the same name to respond if they are up
|
// Get all other servers with the same name to respond if they are up
|
||||||
jmdns.requestServiceInfo(ServerAdvertiser.SERVICE_TYPE, serverName);
|
jmdns.requestServiceInfo(ServerAdvertiser.SERVICE_TYPE, serverName);
|
||||||
@@ -94,13 +94,6 @@ public class ServerListener{
|
|||||||
|
|
||||||
listener = new GameServeMonitor();
|
listener = new GameServeMonitor();
|
||||||
jmdns.addServiceListener(ServerAdvertiser.SERVICE_TYPE, listener);
|
jmdns.addServiceListener(ServerAdvertiser.SERVICE_TYPE, listener);
|
||||||
|
|
||||||
/*new Timer().schedule(new TimerTask() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
refresh();
|
|
||||||
}
|
|
||||||
}, 50, SERVICE_REFRESH_INTERVAL);*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ServerListener getInstance() throws IOException {
|
public static ServerListener getInstance() throws IOException {
|
||||||
@@ -134,7 +127,7 @@ public class ServerListener{
|
|||||||
for (ServerDescription server : servers){
|
for (ServerDescription server : servers){
|
||||||
if (server.serverShouldBeRemoved()){
|
if (server.serverShouldBeRemoved()){
|
||||||
listener.servers.remove(server);
|
listener.servers.remove(server);
|
||||||
delegate.serverRemoved(new ArrayList<ServerDescription>(listener.servers));
|
delegate.serverRemoved(new ArrayList<>(listener.servers));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,97 +0,0 @@
|
|||||||
package seng302.visualiser.controllers;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.net.URL;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Comparator;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.ResourceBundle;
|
|
||||||
import javafx.collections.FXCollections;
|
|
||||||
import javafx.collections.ObservableList;
|
|
||||||
import javafx.fxml.FXML;
|
|
||||||
import javafx.fxml.FXMLLoader;
|
|
||||||
import javafx.fxml.Initializable;
|
|
||||||
import javafx.scene.control.TableColumn;
|
|
||||||
import javafx.scene.control.TableView;
|
|
||||||
import javafx.scene.control.cell.PropertyValueFactory;
|
|
||||||
import javafx.scene.input.MouseEvent;
|
|
||||||
import javafx.scene.layout.AnchorPane;
|
|
||||||
import javafx.scene.layout.GridPane;
|
|
||||||
import javafx.scene.layout.Pane;
|
|
||||||
import seng302.model.ClientYacht;
|
|
||||||
import seng302.utilities.Sounds;
|
|
||||||
|
|
||||||
public class FinishScreenViewController implements Initializable {
|
|
||||||
|
|
||||||
@FXML
|
|
||||||
private GridPane finishScreenGridPane;
|
|
||||||
@FXML
|
|
||||||
private TableView<ClientYacht> finishOrderTable;
|
|
||||||
@FXML
|
|
||||||
private TableColumn<ClientYacht, String> posCol;
|
|
||||||
@FXML
|
|
||||||
private TableColumn<ClientYacht, String> boatNameCol;
|
|
||||||
@FXML
|
|
||||||
private TableColumn<ClientYacht, String> shortNameCol;
|
|
||||||
@FXML
|
|
||||||
private TableColumn<ClientYacht, String> countryCol;
|
|
||||||
|
|
||||||
ObservableList<ClientYacht> data = FXCollections.observableArrayList();
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void initialize(URL location, ResourceBundle resources) {
|
|
||||||
finishScreenGridPane.getStylesheets()
|
|
||||||
.add(getClass().getResource("/css/Master.css").toString());
|
|
||||||
finishOrderTable.getStylesheets().add(getClass().getResource("/css/Master.css").toString());
|
|
||||||
|
|
||||||
// set up data for table
|
|
||||||
finishOrderTable.setItems(data);
|
|
||||||
|
|
||||||
// setting table col data
|
|
||||||
posCol.setCellValueFactory(
|
|
||||||
new PropertyValueFactory<>("position")
|
|
||||||
);
|
|
||||||
boatNameCol.setCellValueFactory(
|
|
||||||
new PropertyValueFactory<>("boatName")
|
|
||||||
);
|
|
||||||
shortNameCol.setCellValueFactory(
|
|
||||||
new PropertyValueFactory<>("shortName")
|
|
||||||
);
|
|
||||||
countryCol.setCellValueFactory(
|
|
||||||
new PropertyValueFactory<>("country")
|
|
||||||
);
|
|
||||||
finishOrderTable.refresh();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setFinishers(Collection<ClientYacht> participants) {
|
|
||||||
List<ClientYacht> sorted = new ArrayList<>(participants);
|
|
||||||
sorted.sort(Comparator.comparingInt(ClientYacht::getPlacing));
|
|
||||||
finishOrderTable.getItems().setAll(sorted);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setContentPane(String jfxUrl) {
|
|
||||||
try {
|
|
||||||
// get the main controller anchor pane (FinishView -> MainView)
|
|
||||||
AnchorPane contentPane = (AnchorPane) finishScreenGridPane.getParent();
|
|
||||||
contentPane.getChildren().removeAll();
|
|
||||||
contentPane.getChildren().clear();
|
|
||||||
contentPane.getStylesheets().add(getClass().getResource("/css/master.css").toString());
|
|
||||||
contentPane.getChildren()
|
|
||||||
.addAll((Pane) FXMLLoader.load(getClass().getResource(jfxUrl)));
|
|
||||||
} catch (javafx.fxml.LoadException e) {
|
|
||||||
System.out.println("[Controller] FXML load exception");
|
|
||||||
} catch (IOException e) {
|
|
||||||
System.out.println("[Controller] IO exception");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void switchToStartScreenView() {
|
|
||||||
Sounds.playButtonClick();
|
|
||||||
setContentPane("/views/StartScreenView.fxml");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void playButtonHoverSound(MouseEvent mouseEvent) {
|
|
||||||
Sounds.playHoverSound();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -4,67 +4,38 @@ import com.jfoenix.controls.JFXButton;
|
|||||||
import com.jfoenix.controls.JFXDialog;
|
import com.jfoenix.controls.JFXDialog;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Timer;
|
import java.util.Timer;
|
||||||
import java.util.TimerTask;
|
import java.util.TimerTask;
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
import javafx.animation.RotateTransition;
|
import javafx.animation.RotateTransition;
|
||||||
import javafx.animation.Timeline;
|
|
||||||
import javafx.application.Platform;
|
import javafx.application.Platform;
|
||||||
import javafx.beans.property.ReadOnlyBooleanProperty;
|
import javafx.beans.property.ReadOnlyBooleanProperty;
|
||||||
import javafx.collections.FXCollections;
|
|
||||||
import javafx.collections.ListChangeListener;
|
|
||||||
import javafx.collections.ObservableList;
|
|
||||||
import javafx.fxml.FXML;
|
import javafx.fxml.FXML;
|
||||||
import javafx.fxml.FXMLLoader;
|
import javafx.fxml.FXMLLoader;
|
||||||
import javafx.geometry.Point2D;
|
|
||||||
import javafx.scene.Scene;
|
|
||||||
import javafx.scene.SubScene;
|
import javafx.scene.SubScene;
|
||||||
import javafx.scene.chart.LineChart;
|
|
||||||
import javafx.scene.chart.NumberAxis;
|
|
||||||
import javafx.scene.chart.XYChart.Series;
|
|
||||||
import javafx.scene.control.Button;
|
|
||||||
import javafx.scene.control.CheckBox;
|
|
||||||
import javafx.scene.control.ComboBox;
|
|
||||||
import javafx.scene.control.Label;
|
import javafx.scene.control.Label;
|
||||||
import javafx.scene.control.Slider;
|
|
||||||
import javafx.scene.control.TextField;
|
import javafx.scene.control.TextField;
|
||||||
import javafx.scene.image.Image;
|
import javafx.scene.image.Image;
|
||||||
import javafx.scene.image.ImageView;
|
import javafx.scene.image.ImageView;
|
||||||
import javafx.scene.layout.AnchorPane;
|
import javafx.scene.layout.AnchorPane;
|
||||||
import javafx.scene.layout.GridPane;
|
|
||||||
import javafx.scene.layout.Pane;
|
import javafx.scene.layout.Pane;
|
||||||
import javafx.scene.layout.StackPane;
|
import javafx.scene.layout.StackPane;
|
||||||
import javafx.scene.layout.VBox;
|
|
||||||
import javafx.scene.paint.Color;
|
|
||||||
import javafx.scene.paint.Paint;
|
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;
|
|
||||||
import javafx.util.Duration;
|
import javafx.util.Duration;
|
||||||
import seng302.model.ClientYacht;
|
import seng302.model.ClientYacht;
|
||||||
import seng302.model.RaceState;
|
import seng302.model.RaceState;
|
||||||
import seng302.model.mark.CompoundMark;
|
|
||||||
import seng302.model.mark.Mark;
|
|
||||||
import seng302.model.stream.xml.parser.RaceXMLData;
|
import seng302.model.stream.xml.parser.RaceXMLData;
|
||||||
import seng302.model.token.TokenType;
|
import seng302.model.token.TokenType;
|
||||||
import seng302.utilities.Sounds;
|
import seng302.utilities.Sounds;
|
||||||
import seng302.visualiser.GameView3D;
|
import seng302.visualiser.GameView3D;
|
||||||
import seng302.visualiser.controllers.annotations.ImportantAnnotationController;
|
import seng302.visualiser.MiniMap;
|
||||||
import seng302.visualiser.controllers.annotations.ImportantAnnotationDelegate;
|
|
||||||
import seng302.visualiser.controllers.annotations.ImportantAnnotationsState;
|
|
||||||
import seng302.visualiser.controllers.dialogs.FinishDialogController;
|
import seng302.visualiser.controllers.dialogs.FinishDialogController;
|
||||||
import seng302.visualiser.fxObjects.ChatHistory;
|
import seng302.visualiser.fxObjects.ChatHistory;
|
||||||
import seng302.visualiser.fxObjects.assets_2D.WindArrow;
|
|
||||||
import seng302.visualiser.fxObjects.assets_3D.BoatObject;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Controller class that manages the display of a race
|
* Controller class that manages the display of a race
|
||||||
*/
|
*/
|
||||||
public class RaceViewController extends Thread implements ImportantAnnotationDelegate {
|
public class RaceViewController extends Thread {
|
||||||
|
|
||||||
private final int CHAT_LIMIT = 128;
|
private final int CHAT_LIMIT = 128;
|
||||||
private static final Double ICON_BLINK_TIMEOUT_RATIO = 0.6;
|
private static final Double ICON_BLINK_TIMEOUT_RATIO = 0.6;
|
||||||
@@ -75,39 +46,17 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
|||||||
@FXML
|
@FXML
|
||||||
private ImageView loadingScreen;
|
private ImageView loadingScreen;
|
||||||
@FXML
|
@FXML
|
||||||
private Pane basePane;
|
|
||||||
@FXML
|
|
||||||
private JFXButton chatSend;
|
private JFXButton chatSend;
|
||||||
@FXML
|
@FXML
|
||||||
private Pane chatHistoryHolder;
|
private Pane chatHistoryHolder;
|
||||||
@FXML
|
@FXML
|
||||||
private TextField chatInput;
|
private TextField chatInput;
|
||||||
@FXML
|
@FXML
|
||||||
private LineChart<String, Double> raceSparkLine;
|
|
||||||
@FXML
|
|
||||||
private NumberAxis sparklineYAxis;
|
|
||||||
@FXML
|
|
||||||
private VBox positionVbox;
|
|
||||||
@FXML
|
|
||||||
private CheckBox toggleFps;
|
|
||||||
@FXML
|
|
||||||
private Label timerLabel;
|
private Label timerLabel;
|
||||||
@FXML
|
@FXML
|
||||||
private StackPane contentStackPane;
|
private StackPane contentStackPane;
|
||||||
|
|
||||||
private GridPane contentGridPane;
|
|
||||||
@FXML
|
@FXML
|
||||||
private AnchorPane rvAnchorPane;
|
private Pane miniMapPane;
|
||||||
@FXML
|
|
||||||
private AnchorPane windArrowHolder;
|
|
||||||
@FXML
|
|
||||||
private Slider annotationSlider;
|
|
||||||
@FXML
|
|
||||||
private Button selectAnnotationBtn;
|
|
||||||
@FXML
|
|
||||||
private ComboBox<ClientYacht> yachtSelectionComboBox;
|
|
||||||
@FXML
|
|
||||||
private Text fpsDisplay;
|
|
||||||
@FXML
|
@FXML
|
||||||
private ImageView windImageView;
|
private ImageView windImageView;
|
||||||
@FXML
|
@FXML
|
||||||
@@ -118,33 +67,24 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
|||||||
private Label positionLabel, boatSpeedLabel, boatHeadingLabel;
|
private Label positionLabel, boatSpeedLabel, boatHeadingLabel;
|
||||||
@FXML
|
@FXML
|
||||||
private ImageView velocityIcon, handlingIcon, windWalkerIcon, bumperIcon, badRandomIcon;
|
private ImageView velocityIcon, handlingIcon, windWalkerIcon, bumperIcon, badRandomIcon;
|
||||||
|
@FXML
|
||||||
|
private JFXButton miniMapButton;
|
||||||
|
|
||||||
//Race Data
|
|
||||||
private Map<Integer, ClientYacht> participants;
|
|
||||||
private Map<Integer, CompoundMark> markers;
|
|
||||||
private RaceXMLData courseData;
|
|
||||||
private GameView3D gameView;
|
private GameView3D gameView;
|
||||||
private RaceState raceState;
|
private RaceState raceState;
|
||||||
|
|
||||||
private ChatHistory chatHistory;
|
private ChatHistory chatHistory;
|
||||||
|
|
||||||
private Timeline timerTimeline;
|
|
||||||
private Timer timer = new Timer();
|
private Timer timer = new Timer();
|
||||||
private List<Series<String, Double>> sparkLineData = new ArrayList<>();
|
|
||||||
private ImportantAnnotationsState importantAnnotations;
|
|
||||||
private Polyline windArrow = new WindArrow(Color.LIGHTGRAY);
|
|
||||||
private ObservableList<ClientYacht> selectionComboBoxList = FXCollections.observableArrayList();
|
|
||||||
private ClientYacht player;
|
private ClientYacht player;
|
||||||
private JFXDialog finishScreenDialog;
|
private JFXDialog finishScreenDialog;
|
||||||
private FinishDialogController finishDialogController;
|
private FinishDialogController finishDialogController;
|
||||||
|
|
||||||
//Icon stuff
|
|
||||||
private Timer blinkingTimer = new Timer();
|
private Timer blinkingTimer = new Timer();
|
||||||
private ImageView iconToDisplay;
|
private ImageView iconToDisplay;
|
||||||
|
|
||||||
private Double lastWindDirection;
|
private Double lastWindDirection;
|
||||||
|
private MiniMap miniMap;
|
||||||
|
|
||||||
public void initialize() {
|
public void initialize() {
|
||||||
|
miniMapPane.setVisible(false);
|
||||||
|
miniMapButton.setVisible(false);
|
||||||
contentStackPane.setVisible(false);
|
contentStackPane.setVisible(false);
|
||||||
Image loadingImage = new Image("PP.png");
|
Image loadingImage = new Image("PP.png");
|
||||||
loadingScreen.setImage(loadingImage);
|
loadingScreen.setImage(loadingImage);
|
||||||
@@ -204,13 +144,9 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
|||||||
public void showView(){
|
public void showView(){
|
||||||
loadingScreenPane.setVisible(false);
|
loadingScreenPane.setVisible(false);
|
||||||
contentStackPane.setVisible(true);
|
contentStackPane.setVisible(true);
|
||||||
|
miniMapPane.setVisible(true);
|
||||||
Platform.runLater(new Runnable() {
|
miniMapButton.setVisible(true);
|
||||||
@Override
|
Platform.runLater(() -> contentStackPane.requestFocus());
|
||||||
public void run() {
|
|
||||||
contentStackPane.requestFocus();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -238,31 +174,36 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
|||||||
Map<Integer, ClientYacht> participants, RaceXMLData raceData, RaceState raceState,
|
Map<Integer, ClientYacht> participants, RaceXMLData raceData, RaceState raceState,
|
||||||
ClientYacht player) {
|
ClientYacht player) {
|
||||||
|
|
||||||
this.participants = participants;
|
|
||||||
this.courseData = raceData;
|
|
||||||
this.markers = raceData.getCompoundMarks();
|
|
||||||
this.raceState = raceState;
|
this.raceState = raceState;
|
||||||
this.player = player;
|
this.player = player;
|
||||||
|
|
||||||
raceState.getPlayerPositions().addListener((ListChangeListener<ClientYacht>) c -> {
|
|
||||||
while (c.next()) {
|
|
||||||
if (c.wasPermutated()) {
|
|
||||||
updateOrder(raceState.getPlayerPositions());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
player.addPowerUpListener(this::displayPowerUpIcon);
|
player.addPowerUpListener(this::displayPowerUpIcon);
|
||||||
player.addPowerDownListener(this::removeIcon);
|
player.addPowerDownListener(this::removeIcon);
|
||||||
|
|
||||||
updateOrder(raceState.getPlayerPositions());
|
|
||||||
gameView = new GameView3D();
|
gameView = new GameView3D();
|
||||||
|
miniMap = new MiniMap(
|
||||||
|
new ArrayList<>(raceData.getCompoundMarks().values()),
|
||||||
|
raceData.getMarkSequence(), raceData.getCourseLimit(),
|
||||||
|
new ArrayList<>(participants.values()), player
|
||||||
|
);
|
||||||
|
|
||||||
|
miniMapButton.setOnMouseClicked((event) -> {
|
||||||
|
if (miniMapPane.visibleProperty().get()) {
|
||||||
|
miniMapPane.setVisible(false);
|
||||||
|
miniMapButton.setText("✓");
|
||||||
|
} else {
|
||||||
|
miniMapPane.setVisible(true);
|
||||||
|
miniMapButton.setText("✕");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
Platform.runLater(() -> {
|
Platform.runLater(() -> {
|
||||||
contentStackPane.getChildren().add(0, gameView.getAssets());
|
contentStackPane.getChildren().add(0, gameView.getAssets());
|
||||||
((SubScene) gameView.getAssets()).widthProperty()
|
((SubScene) gameView.getAssets()).widthProperty()
|
||||||
.bind(ViewManager.getInstance().getStage().widthProperty());
|
.bind(ViewManager.getInstance().getStage().widthProperty());
|
||||||
((SubScene) gameView.getAssets()).heightProperty()
|
((SubScene) gameView.getAssets()).heightProperty()
|
||||||
.bind(ViewManager.getInstance().getStage().heightProperty());
|
.bind(ViewManager.getInstance().getStage().heightProperty());
|
||||||
|
miniMapPane.getChildren().add(miniMap.getAssets());
|
||||||
});
|
});
|
||||||
gameView.setBoats(new ArrayList<>(participants.values()));
|
gameView.setBoats(new ArrayList<>(participants.values()));
|
||||||
gameView.updateBorder(raceData.getCourseLimit());
|
gameView.updateBorder(raceData.getCourseLimit());
|
||||||
@@ -342,7 +283,7 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void removeIcon(ClientYacht yacht) {
|
private void removeIcon(ClientYacht yacht) {
|
||||||
if (yacht == player) {
|
if (yacht == player) {
|
||||||
blinkingTimer.cancel();
|
blinkingTimer.cancel();
|
||||||
iconToDisplay.setVisible(false);
|
iconToDisplay.setVisible(false);
|
||||||
@@ -350,45 +291,6 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The important annotations have been changed, update this view
|
|
||||||
*
|
|
||||||
* @param importantAnnotationsState The current state of the selected annotations
|
|
||||||
*/
|
|
||||||
public void importantAnnotationsChanged(ImportantAnnotationsState importantAnnotationsState) {
|
|
||||||
this.importantAnnotations = importantAnnotationsState;
|
|
||||||
setAnnotations((int) annotationSlider.getValue()); // Refresh the displayed annotations
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Loads the "select annotations" view in a new window
|
|
||||||
*/
|
|
||||||
private void loadSelectAnnotationView() {
|
|
||||||
try {
|
|
||||||
FXMLLoader fxmlLoader = new FXMLLoader();
|
|
||||||
Stage stage = new Stage();
|
|
||||||
// Set controller
|
|
||||||
ImportantAnnotationController controller = new ImportantAnnotationController(
|
|
||||||
this, stage
|
|
||||||
);
|
|
||||||
fxmlLoader.setController(controller);
|
|
||||||
// Load FXML and set CSS
|
|
||||||
fxmlLoader.setLocation(
|
|
||||||
getClass().getResource("/views/importantAnnotationSelectView.fxml")
|
|
||||||
);
|
|
||||||
Scene scene = new Scene(fxmlLoader.load(), 469, 298);
|
|
||||||
scene.getStylesheets().add(getClass().getResource("/css/master.css").toString());
|
|
||||||
stage.initStyle(StageStyle.UNDECORATED);
|
|
||||||
stage.setScene(scene);
|
|
||||||
stage.show();
|
|
||||||
controller.loadState(importantAnnotations);
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialises a timer which updates elements of the RaceView such as wind direction, yacht
|
* Initialises a timer which updates elements of the RaceView such as wind direction, yacht
|
||||||
* orderings etc.. which are dependent on the info from the stream parser constantly.
|
* orderings etc.. which are dependent on the info from the stream parser constantly.
|
||||||
@@ -406,35 +308,6 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
|||||||
}, 0, 1000);
|
}, 0, 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Iterates over all corners until ones SeqID matches with the yachts current leg number.
|
|
||||||
* Then it gets the compoundMarkID of that corner and uses it to fetch the appropriate mark
|
|
||||||
* Returns null if no next mark found.
|
|
||||||
* @param bg The BoatGroup to find the next mark of
|
|
||||||
* @return The next Mark or null if none found
|
|
||||||
*/
|
|
||||||
private Mark getNextMark(BoatObject bg) {
|
|
||||||
// TODO: 1/08/17 Move to GameView
|
|
||||||
//
|
|
||||||
// Integer legNumber = bg.getClientYacht().getLegNumber();
|
|
||||||
// List<Corner> markSequence = courseData.getMarkSequence();
|
|
||||||
//
|
|
||||||
// if (legNumber == 0) {
|
|
||||||
// return null;
|
|
||||||
// } else if (legNumber == markSequence.size() - 1) {
|
|
||||||
// return null;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// for (Corner corner : markSequence) {
|
|
||||||
// if (legNumber + 2 == corner.getSeqID()) {
|
|
||||||
// return courseData.getCompoundMarks().get(corner.getCompoundMarkID());
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// return null;
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates the wind direction arrow and text as from info from the StreamParser
|
* Updates the wind direction arrow and text as from info from the StreamParser
|
||||||
* @param direction the from north angle of the wind.
|
* @param direction the from north angle of the wind.
|
||||||
@@ -516,226 +389,6 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
|||||||
boatHeadingLabel.setText(String.format("Boat Heading:\n%.1f°", player.getHeading()));
|
boatHeadingLabel.setText(String.format("Boat Heading:\n%.1f°", player.getHeading()));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Updates the order of the yachts as from the StreamParser and sets them in the yacht order
|
|
||||||
* section
|
|
||||||
*/
|
|
||||||
private void updateOrder(ObservableList<ClientYacht> yachts) {
|
|
||||||
// List<Text> vboxEntries = new ArrayList<>();
|
|
||||||
//
|
|
||||||
// for (int i = 0; i < yachts.size(); i++) {
|
|
||||||
//// System.out.println("yacht == null " + String.valueOf(yacht == null));
|
|
||||||
// if (yachts.get(i).getBoatStatus() == BoatStatus.FINISHED
|
|
||||||
// .getCode()) { // 3 is finish status
|
|
||||||
// Text textToAdd = new Text(i + 1 + ". " +
|
|
||||||
// yachts.get(i).getShortName() + " (Finished)");
|
|
||||||
// textToAdd.setFill(Paint.valueOf("#d3d3d3"));
|
|
||||||
// vboxEntries.add(textToAdd);
|
|
||||||
//
|
|
||||||
// } else {
|
|
||||||
// Text textToAdd = new Text(i + 1 + ". " +
|
|
||||||
// yachts.get(i).getShortName() + " ");
|
|
||||||
// textToAdd.setFill(Paint.valueOf("#d3d3d3"));
|
|
||||||
// textToAdd.setStyle("");
|
|
||||||
// vboxEntries.add(textToAdd);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// Platform.runLater(() ->
|
|
||||||
// positionVbox.getChildren().setAll(vboxEntries)
|
|
||||||
// );
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private void updateLaylines(BoatObject bg) {
|
|
||||||
// TODO: 1/08/17 move to GameView
|
|
||||||
//
|
|
||||||
// Mark nextMark = getNextMark(bg);
|
|
||||||
// Boolean isUpwind = null;
|
|
||||||
// // Can only calc leg direction if there is a next mark and it is a gate mark
|
|
||||||
// if (nextMark != null) {
|
|
||||||
// if (nextMark instanceof GateMark) {
|
|
||||||
// if (bg.isUpwindLeg(gameViewController, nextMark)) {
|
|
||||||
// isUpwind = true;
|
|
||||||
// } else {
|
|
||||||
// isUpwind = false;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// for(MarkObject mg : gameViewController.getMarkGroups()) {
|
|
||||||
//
|
|
||||||
// mg.removeLaylines();
|
|
||||||
//
|
|
||||||
// if (mg.getMainMark().getId() == nextMark.getId()) {
|
|
||||||
//
|
|
||||||
// SingleMark singleMark1 = ((GateMark) nextMark).getSingleMark1();
|
|
||||||
// SingleMark singleMark2 = ((GateMark) nextMark).getSingleMark2();
|
|
||||||
// Point2D markPoint1 = gameViewController
|
|
||||||
// .findScaledXY(singleMark1.getLatitude(), singleMark1.getLongitude());
|
|
||||||
// Point2D markPoint2 = gameViewController
|
|
||||||
// .findScaledXY(singleMark2.getLatitude(), singleMark2.getLongitude());
|
|
||||||
// HashMap<Double, Double> angleAndSpeed;
|
|
||||||
// if (isUpwind) {
|
|
||||||
// angleAndSpeed = PolarTable.getOptimalUpwindVMG(StreamParser.getWindSpeed());
|
|
||||||
// } else {
|
|
||||||
// angleAndSpeed = PolarTable.getOptimalDownwindVMG(StreamParser.getWindSpeed());
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// Double resultingAngle = angleAndSpeed.keySet().iterator().next();
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// Point2D yachtCurrentPos = new Point2D(bg.getBoatLayoutX(), bg.getBoatLayoutY());
|
|
||||||
// Point2D gateMidPoint = markPoint1.midpoint(markPoint2);
|
|
||||||
// Integer lineFuncResult = GeoUtility.lineFunction(yachtCurrentPos, gateMidPoint, markPoint2);
|
|
||||||
// Line rightLayline = new Line();
|
|
||||||
// Line leftLayline = new Line();
|
|
||||||
// if (lineFuncResult == 1) {
|
|
||||||
// rightLayline = makeRightLayline(markPoint2, 180 - resultingAngle, StreamParser.getWindDirection());
|
|
||||||
// leftLayline = makeLeftLayline(markPoint1, 180 - resultingAngle, StreamParser.getWindDirection());
|
|
||||||
// } else if (lineFuncResult == -1) {
|
|
||||||
// rightLayline = makeRightLayline(markPoint1, 180 - resultingAngle, StreamParser.getWindDirection());
|
|
||||||
// leftLayline = makeLeftLayline(markPoint2, 180 - resultingAngle, StreamParser.getWindDirection());
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// leftLayline.setStrokeWidth(0.5);
|
|
||||||
// leftLayline.setStroke(bg.getBoat().getColour());
|
|
||||||
//
|
|
||||||
// rightLayline.setStrokeWidth(0.5);
|
|
||||||
// rightLayline.setStroke(bg.getBoat().getColour());
|
|
||||||
//
|
|
||||||
// bg.setLaylines(leftLayline, rightLayline);
|
|
||||||
// mg.addLaylines(leftLayline, rightLayline);
|
|
||||||
//
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private Point2D getPointRotation(Point2D ref, Double distance, Double angle) {
|
|
||||||
Double newX = ref.getX() + (ref.getX() + distance - ref.getX()) * Math.cos(angle)
|
|
||||||
- (ref.getY() + distance - ref.getY()) * Math.sin(angle);
|
|
||||||
Double newY = ref.getY() + (ref.getX() + distance - ref.getX()) * Math.sin(angle)
|
|
||||||
+ (ref.getY() + distance - ref.getY()) * Math.cos(angle);
|
|
||||||
|
|
||||||
return new Point2D(newX, newY);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public Line makeLeftLayline(Point2D startPoint, Double layLineAngle, Double baseAngle) {
|
|
||||||
Point2D ep = getPointRotation(startPoint, 50.0, baseAngle + layLineAngle);
|
|
||||||
Line line = new Line(startPoint.getX(), startPoint.getY(), ep.getX(), ep.getY());
|
|
||||||
return line;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public Line makeRightLayline(Point2D startPoint, Double layLineAngle, Double baseAngle) {
|
|
||||||
|
|
||||||
Point2D ep = getPointRotation(startPoint, 50.0, baseAngle - layLineAngle);
|
|
||||||
Line line = new Line(startPoint.getX(), startPoint.getY(), ep.getX(), ep.getY());
|
|
||||||
return line;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialised the combo box with any yachts currently in the race and adds the required listener
|
|
||||||
* for the combobox to take action upon selection
|
|
||||||
*/
|
|
||||||
private void initialiseBoatSelectionComboBox() {
|
|
||||||
// yachtSelectionComboBox.setItems(
|
|
||||||
// FXCollections.observableArrayList(participants.values())
|
|
||||||
// );
|
|
||||||
// //Null check is if the listener is fired but nothing selected
|
|
||||||
// yachtSelectionComboBox.valueProperty().addListener((obs, lastSelection, selectedBoat) -> {
|
|
||||||
// if (selectedBoat != null) {
|
|
||||||
// gameView.selectBoat(selectedBoat);
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
|
|
||||||
//TODO uncomment out
|
|
||||||
// selectionComboBoxList.setAll(participants.values());
|
|
||||||
// yachtSelectionComboBox.setItems(selectionComboBoxList);
|
|
||||||
// yachtSelectionComboBox.valueProperty().addListener((obs, lastSelection, selectedBoat) -> {
|
|
||||||
// if (selectedBoat != null) {
|
|
||||||
// gameView.selectBoat(selectedBoat);
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Display the list of yachts in the order they finished the race
|
|
||||||
*/
|
|
||||||
private void loadRaceResultView() {
|
|
||||||
FXMLLoader loader = new FXMLLoader(getClass().getResource("/views/FinishView.fxml"));
|
|
||||||
|
|
||||||
try {
|
|
||||||
contentGridPane.getChildren().removeAll();
|
|
||||||
contentGridPane.getChildren().clear();
|
|
||||||
contentGridPane.getChildren().addAll((Pane) loader.load());
|
|
||||||
|
|
||||||
} catch (javafx.fxml.LoadException e) {
|
|
||||||
System.err.println(e.getCause().toString());
|
|
||||||
} catch (IOException e) {
|
|
||||||
System.err.println(e.toString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getMillisToFormattedTime(long milliseconds) {
|
|
||||||
return String.format("%02d:%02d:%02d",
|
|
||||||
TimeUnit.MILLISECONDS.toHours(milliseconds),
|
|
||||||
TimeUnit.MILLISECONDS.toMinutes(milliseconds) % 60, //Modulus 60 minutes per hour
|
|
||||||
TimeUnit.MILLISECONDS.toSeconds(milliseconds) % 60 //Modulus 60 seconds per minute
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets all the annotations of the selected yacht to be visible and all others to be hidden
|
|
||||||
*
|
|
||||||
* @param yacht The yacht for which we want to view all annotations
|
|
||||||
*/
|
|
||||||
private void setSelectedBoat(ClientYacht yacht) {
|
|
||||||
// for (BoatObject bg : gameViewController.getBoatGroups()) {
|
|
||||||
// //We need to iterate over all race groups to get the matching yacht group belonging to this yacht if we
|
|
||||||
// //are to toggle its annotations, there is no other backwards knowledge of a yacht to its yachtgroup.
|
|
||||||
// if (bg.getBoat().getHullID().equals(yacht.getHullID())) {
|
|
||||||
//// updateLaylines(bg);
|
|
||||||
// bg.setIsSelected(true);
|
|
||||||
//// selectedBoat = yacht;
|
|
||||||
// } else {
|
|
||||||
// bg.setIsSelected(false);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
|
|
||||||
public void updateTokens(RaceXMLData raceData) {
|
public void updateTokens(RaceXMLData raceData) {
|
||||||
gameView.updateTokens(raceData.getTokens());
|
gameView.updateTokens(raceData.getTokens());
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import javafx.scene.layout.StackPane;
|
|||||||
import javafx.stage.Stage;
|
import javafx.stage.Stage;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* The pre loading screen before launch the start view
|
||||||
* Created by Kusal on 26-Sep-17.
|
* Created by Kusal on 26-Sep-17.
|
||||||
*/
|
*/
|
||||||
public class SplashScreenController implements Initializable{
|
public class SplashScreenController implements Initializable{
|
||||||
@@ -26,9 +27,7 @@ public class SplashScreenController implements Initializable{
|
|||||||
public void run(){
|
public void run(){
|
||||||
try {
|
try {
|
||||||
Thread.sleep(3000);
|
Thread.sleep(3000);
|
||||||
Platform.runLater(new Runnable() {
|
Platform.runLater(() -> {
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
try {
|
try {
|
||||||
Stage stage = new Stage();
|
Stage stage = new Stage();
|
||||||
ViewManager.getInstance().initialStartView(stage);
|
ViewManager.getInstance().initialStartView(stage);
|
||||||
@@ -36,7 +35,6 @@ public class SplashScreenController implements Initializable{
|
|||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
rootPane.getScene().getWindow().hide();
|
rootPane.getScene().getWindow().hide();
|
||||||
}
|
|
||||||
});
|
});
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
|
|||||||
@@ -79,7 +79,7 @@ public class ViewManager {
|
|||||||
decorator.applyCss();
|
decorator.applyCss();
|
||||||
decorator.getStylesheets()
|
decorator.getStylesheets()
|
||||||
.add(getClass().getResource("/css/Master.css").toExternalForm());
|
.add(getClass().getResource("/css/Master.css").toExternalForm());
|
||||||
gameClient = new GameClient(decorator);
|
gameClient = new GameClient();
|
||||||
setDecorator(decorator);
|
setDecorator(decorator);
|
||||||
|
|
||||||
stage.getIcons().add(new Image(getClass().getResourceAsStream("/PP.png")));
|
stage.getIcons().add(new Image(getClass().getResourceAsStream("/PP.png")));
|
||||||
@@ -404,7 +404,9 @@ public class ViewManager {
|
|||||||
.add(getClass().getResource("/css/dialogs/Snackbar.css").toExternalForm());
|
.add(getClass().getResource("/css/dialogs/Snackbar.css").toExternalForm());
|
||||||
|
|
||||||
JFXSnackbar bar = new JFXSnackbar(decorator);
|
JFXSnackbar bar = new JFXSnackbar(decorator);
|
||||||
|
Platform.runLater(() -> {
|
||||||
bar.enqueue(new JFXSnackbar.SnackbarEvent(msg));
|
bar.enqueue(new JFXSnackbar.SnackbarEvent(msg));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public Stage getStage() {
|
public Stage getStage() {
|
||||||
|
|||||||
@@ -116,6 +116,7 @@ public class ServerCreationController implements Initializable {
|
|||||||
private void createServer() {
|
private void createServer() {
|
||||||
ServerDescription serverDescription = ViewManager.getInstance().getGameClient()
|
ServerDescription serverDescription = ViewManager.getInstance().getGameClient()
|
||||||
.runAsHost("localhost", 0, serverName.getText(), (int) maxPlayersSlider
|
.runAsHost("localhost", 0, serverName.getText(), (int) maxPlayersSlider
|
||||||
|
.runAsHost(serverName.getText(), (int) maxPlayersSlider
|
||||||
.getValue(), mapMaker.getCurrentRacePath(), (int) legsSlider.getValue(), pickupsCheckBox.isSelected());
|
.getValue(), mapMaker.getCurrentRacePath(), (int) legsSlider.getValue(), pickupsCheckBox.isSelected());
|
||||||
|
|
||||||
if (serverDescription == null){
|
if (serverDescription == null){
|
||||||
|
|||||||
@@ -29,11 +29,11 @@ public class MarkArrowFactory {
|
|||||||
STARBOARD,
|
STARBOARD,
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final double MARK_ARROW_SEPARATION = 15;
|
public static final double MARK_ARROW_SEPARATION = 8;
|
||||||
public static final double ARROW_LENGTH = 75;
|
public static final double ARROW_LENGTH = 20;
|
||||||
public static final double ARROW_HEAD_DEPTH = 10;
|
public static final double ARROW_HEAD_DEPTH = 5;
|
||||||
public static final double ARROW_HEAD_WIDTH = 6;
|
public static final double ARROW_HEAD_WIDTH = 3;
|
||||||
public static final double STROKE_WIDTH = 3;
|
public static final double STROKE_WIDTH = 1;
|
||||||
|
|
||||||
public static Model constructEntryArrow3D (
|
public static Model constructEntryArrow3D (
|
||||||
RoundingSide roundingSide, double angle, ModelType type) {
|
RoundingSide roundingSide, double angle, ModelType type) {
|
||||||
@@ -106,7 +106,7 @@ public class MarkArrowFactory {
|
|||||||
Arc roundSection = new Arc(
|
Arc roundSection = new Arc(
|
||||||
0, 0, MARK_ARROW_SEPARATION, MARK_ARROW_SEPARATION,
|
0, 0, MARK_ARROW_SEPARATION, MARK_ARROW_SEPARATION,
|
||||||
//Where to start drawing arc from
|
//Where to start drawing arc from
|
||||||
(roundingSide == RoundingSide.PORT ? 0 : angleOfEntry),
|
(roundingSide == RoundingSide.PORT ? 180 + angleOfEntry : angleOfEntry),
|
||||||
//Which way to go around the mark. (clockwise vs anticlockwise)
|
//Which way to go around the mark. (clockwise vs anticlockwise)
|
||||||
roundingSide == RoundingSide.PORT ? Math.abs(angleOfExit - angleOfEntry) : -Math.abs(angleOfEntry - angleOfExit)
|
roundingSide == RoundingSide.PORT ? Math.abs(angleOfExit - angleOfEntry) : -Math.abs(angleOfEntry - angleOfExit)
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,230 +0,0 @@
|
|||||||
package seng302.visualiser.fxObjects.assets_2D;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
import javafx.application.Platform;
|
|
||||||
import javafx.beans.value.ObservableValue;
|
|
||||||
import javafx.scene.CacheHint;
|
|
||||||
import javafx.scene.Group;
|
|
||||||
import javafx.scene.paint.Color;
|
|
||||||
import javafx.scene.paint.Paint;
|
|
||||||
import javafx.scene.shape.Rectangle;
|
|
||||||
import javafx.scene.text.Text;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Grouping of string objects over a semi transparent background.
|
|
||||||
*/
|
|
||||||
public class AnnotationBox extends Group {
|
|
||||||
|
|
||||||
@FunctionalInterface
|
|
||||||
public interface AnnotationFormatter<T> {
|
|
||||||
String transformString (T input);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Class stores a text object and relationship for updating the text object if needed
|
|
||||||
*
|
|
||||||
* @param <T> The type of observable value passed to the annotation, if there is one.
|
|
||||||
*/
|
|
||||||
public class Annotation<T> {
|
|
||||||
private Text text;
|
|
||||||
private ObservableValue<T> source;
|
|
||||||
private AnnotationFormatter<T> format;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor for observing annotation
|
|
||||||
* @param textObject the javaFX text object the annotation is displayed in
|
|
||||||
* @param source observable value that the annotation is taken from
|
|
||||||
* @param formatter interface describing how to format the source data if needed
|
|
||||||
*/
|
|
||||||
public Annotation (Text textObject, ObservableValue<T> source, AnnotationFormatter<T> formatter) {
|
|
||||||
this.text = textObject;
|
|
||||||
this.source = source;
|
|
||||||
this.format = formatter;
|
|
||||||
source.addListener((obs, oldVal, newVal) ->
|
|
||||||
Platform.runLater(() -> text.setText(format.transformString(newVal)))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor for a static annotation
|
|
||||||
* @param textObject the javaFX text object the annotation is displayed in
|
|
||||||
* @param annotationText the static value of the test object
|
|
||||||
*/
|
|
||||||
public Annotation (Text textObject, String annotationText) {
|
|
||||||
textObject.setText(annotationText);
|
|
||||||
text = textObject;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Text getText () {
|
|
||||||
return text;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//Text offset constants
|
|
||||||
private static final double X_OFFSET_TEXT = 20d;
|
|
||||||
private static final double Y_OFFSET_TEXT_INIT = -35d;
|
|
||||||
private static final double Y_OFFSET_PER_TEXT = 12d;
|
|
||||||
//Background constants
|
|
||||||
private static final double TEXT_BUFFER = 3;
|
|
||||||
private static final double BACKGROUND_X = X_OFFSET_TEXT - TEXT_BUFFER;
|
|
||||||
private static final double BACKGROUND_Y = Y_OFFSET_TEXT_INIT - TEXT_BUFFER;
|
|
||||||
private static final double BACKGROUND_H_PER_TEXT = 9.5d;
|
|
||||||
private static final double BACKGROUND_ARC_SIZE = 10;
|
|
||||||
|
|
||||||
private int visibleAnnotations = 0;
|
|
||||||
private double backgroundWidth = 145d;
|
|
||||||
|
|
||||||
private Rectangle background = new Rectangle();
|
|
||||||
private Paint theme = Color.BLACK;
|
|
||||||
|
|
||||||
private Map<String, Annotation> annotationsByName = new HashMap<>();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates an empty annotation box. The box is offset from (0,0) by (17, -38).
|
|
||||||
*/
|
|
||||||
public AnnotationBox() {
|
|
||||||
this.setCache(true);
|
|
||||||
background.setX(BACKGROUND_X);
|
|
||||||
background.setY(BACKGROUND_Y);
|
|
||||||
background.setWidth(backgroundWidth);
|
|
||||||
background.setHeight(Math.abs(BACKGROUND_X) + TEXT_BUFFER + BACKGROUND_H_PER_TEXT * 4);
|
|
||||||
background.setArcHeight(BACKGROUND_ARC_SIZE);
|
|
||||||
background.setArcWidth(BACKGROUND_ARC_SIZE);
|
|
||||||
background.setFill(new Color(1, 1, 1, 0.75));
|
|
||||||
background.setStroke(theme);
|
|
||||||
background.setStrokeWidth(2);
|
|
||||||
background.setCache(true);
|
|
||||||
background.setCacheHint(CacheHint.SCALE);
|
|
||||||
this.getChildren().add(background);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds an annotation to the box. Use the name to reference the annotation for removal or\
|
|
||||||
* changing visibility.
|
|
||||||
* @param annotationName the name of the annotation.
|
|
||||||
* @param annotation the annotation.
|
|
||||||
*/
|
|
||||||
public void addAnnotation (String annotationName, Annotation annotation) {
|
|
||||||
annotationsByName.put(annotationName, annotation);
|
|
||||||
Platform.runLater(() -> {
|
|
||||||
this.getChildren().add(annotation.getText());
|
|
||||||
visibleAnnotations++;
|
|
||||||
update();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds an annotation with a constant text.
|
|
||||||
* @param annotationName The name of the annotation. Will be used to reference it later.
|
|
||||||
* @param annotationText The desired text.
|
|
||||||
*/
|
|
||||||
public void addAnnotation (String annotationName, String annotationText) {
|
|
||||||
Text text = getTextObject();
|
|
||||||
addAnnotation(annotationName, new Annotation(text, annotationText));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds an annotation with the given name. The annotation will contain the value of the given
|
|
||||||
* ObservableValue. The formatter should return a String and takes an object of the same type as
|
|
||||||
* the ObservableValue as a parameter. The String is how you want the annotation to look.
|
|
||||||
* @param annotationName The annotation name.
|
|
||||||
* @param observable The observable value the annotation will display.
|
|
||||||
* @param formatter A formatting function for the observable value.
|
|
||||||
* @param <E> The type of ObservableValue.
|
|
||||||
*/
|
|
||||||
public <E> void addAnnotation (String annotationName, ObservableValue<E> observable,
|
|
||||||
AnnotationFormatter<E> formatter) {
|
|
||||||
Text newText = getTextObject();
|
|
||||||
addAnnotation(annotationName, new Annotation<>(newText, observable, formatter));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the visibility of the annotation with the given name if it exists.
|
|
||||||
* @param annotationName The name of the annotation
|
|
||||||
* @param visibility the desired visibility
|
|
||||||
*/
|
|
||||||
public void setAnnotationVisibility (String annotationName, boolean visibility) {
|
|
||||||
if (annotationsByName.containsKey(annotationName)) {
|
|
||||||
Text textField = annotationsByName.get(annotationName).text;
|
|
||||||
boolean currentState = textField.visibleProperty().get();
|
|
||||||
if (visibility != currentState) {
|
|
||||||
if (visibility)
|
|
||||||
visibleAnnotations++;
|
|
||||||
else
|
|
||||||
visibleAnnotations--;
|
|
||||||
}
|
|
||||||
textField.setVisible(visibility);
|
|
||||||
update();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes the annotation with the given name if it exits.
|
|
||||||
* @param annotationName The name given when the annotation was created.
|
|
||||||
*/
|
|
||||||
public void removeAnnotation (String annotationName) {
|
|
||||||
if (annotationName.contains(annotationName)) {
|
|
||||||
Platform.runLater(() -> {
|
|
||||||
this.getChildren().remove(annotationsByName.remove(annotationName).getText());
|
|
||||||
visibleAnnotations--;
|
|
||||||
update();
|
|
||||||
});
|
|
||||||
annotationsByName.remove(annotationName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Moves the annotation.
|
|
||||||
* @param x x location
|
|
||||||
* @param y y location
|
|
||||||
*/
|
|
||||||
public void setLocation (double x, double y) {
|
|
||||||
Platform.runLater(()-> this.relocate(x + BACKGROUND_X, y + BACKGROUND_Y));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Changes the width of the annotation box. Default is 145.
|
|
||||||
* @param width new width.
|
|
||||||
*/
|
|
||||||
public void setWidth (double width) {
|
|
||||||
backgroundWidth = width;
|
|
||||||
Platform.runLater(() -> background.setWidth(backgroundWidth));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void update () {
|
|
||||||
background.setVisible(visibleAnnotations != 0);
|
|
||||||
background.setHeight(Math.abs(BACKGROUND_X) + TEXT_BUFFER + BACKGROUND_H_PER_TEXT * visibleAnnotations);
|
|
||||||
for (int i = 1; i <= visibleAnnotations; i++) {
|
|
||||||
Text text = (Text) this.getChildren().get(i);
|
|
||||||
if (text.visibleProperty().get()) {
|
|
||||||
text.setX(X_OFFSET_TEXT);
|
|
||||||
text.setY(Y_OFFSET_TEXT_INIT + Y_OFFSET_PER_TEXT * i);
|
|
||||||
// });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a text object for an annotation.
|
|
||||||
* @return The text object
|
|
||||||
*/
|
|
||||||
private Text getTextObject() {
|
|
||||||
Text text = new Text();
|
|
||||||
text.setFill(theme);
|
|
||||||
text.setStrokeWidth(2);
|
|
||||||
// text.setCacheHint(CacheHint.QUALITY);
|
|
||||||
text.setCache(true);
|
|
||||||
return text;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the colour of the annotation box's border and text colour.
|
|
||||||
* @param value desired colour.
|
|
||||||
*/
|
|
||||||
public void setFill (Paint value) {
|
|
||||||
theme = value;
|
|
||||||
background.setStroke(theme);
|
|
||||||
annotationsByName.forEach((name, annotation) -> annotation.getText().setFill(theme));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -28,8 +28,7 @@ public class Marker2D extends Group {
|
|||||||
mark.setRadius(5);
|
mark.setRadius(5);
|
||||||
mark.setCenterX(0);
|
mark.setCenterX(0);
|
||||||
mark.setCenterY(0);
|
mark.setCenterY(0);
|
||||||
Platform.runLater(() -> this.getChildren()
|
Platform.runLater(() -> this.getChildren().add(mark));
|
||||||
.addAll(mark, new Group())); //Empty group placeholder or arrows.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -82,13 +81,9 @@ public class Marker2D extends Group {
|
|||||||
|
|
||||||
private void showArrow(List<Group> arrowList, int arrowListIndex) {
|
private void showArrow(List<Group> arrowList, int arrowListIndex) {
|
||||||
if (arrowListIndex < arrowList.size()) {
|
if (arrowListIndex < arrowList.size()) {
|
||||||
if (arrowListIndex == 1) {
|
Platform.runLater(() ->
|
||||||
;
|
this.getChildren().setAll(mark, arrowList.get(arrowListIndex))
|
||||||
}
|
);
|
||||||
Platform.runLater(() -> {
|
|
||||||
this.getChildren().remove(1);
|
|
||||||
this.getChildren().add(arrowList.get(arrowListIndex));
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,10 +16,6 @@ public class Wake extends Group {
|
|||||||
|
|
||||||
//The number of wakes
|
//The number of wakes
|
||||||
private int numWakes = 8;
|
private int numWakes = 8;
|
||||||
//The total possible difference between the first wake and the last. Increasing/Decreasing this will make wakes fan out more/less.
|
|
||||||
private final double MAX_DIFF = 75;
|
|
||||||
//Increasing/decreasing this will alter the speed that wakes converge when the heading stop changing. Anything over about 1500 may cause oscillation.
|
|
||||||
private final int UNIFICATION_SPEED = 45;
|
|
||||||
|
|
||||||
|
|
||||||
private Arc[] arcs = new Arc[numWakes];
|
private Arc[] arcs = new Arc[numWakes];
|
||||||
@@ -69,34 +65,6 @@ public class Wake extends Group {
|
|||||||
rad += (14 / numWakes) + (velocity / 2.5);
|
rad += (14 / numWakes) + (velocity / 2.5);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
// } else {
|
|
||||||
// rotations[0] = rotation;
|
|
||||||
// ((Rotate) arcs[0].getTransforms().get(0)).setAngle(rotation);
|
|
||||||
// for (int i = 1; i < numWakes; i++) {
|
|
||||||
// double wakeSeparationRad = Math.toRadians(rotations[i - 1] - rotations[i]);
|
|
||||||
// double shortestDistance = Math.atan2(
|
|
||||||
// Math.sin(wakeSeparationRad),
|
|
||||||
// Math.cos(wakeSeparationRad)
|
|
||||||
// );
|
|
||||||
// double distDeg = Math.toDegrees(shortestDistance);
|
|
||||||
// if (rotationalVelocities[i - 1] < 0.01 && rotationalVelocities[i - 1] > -0.01) {
|
|
||||||
// rotationalVelocities[i] = distDeg / UNIFICATION_SPEED * 2 * Math.log(Math.abs(distDeg) + 1) / Math.log(MAX_DIFF / numWakes);
|
|
||||||
//
|
|
||||||
// } else {
|
|
||||||
// if (distDeg < (MAX_DIFF / numWakes)) {
|
|
||||||
// rotationalVelocities[i] = distDeg / UNIFICATION_SPEED * Math.log(Math.abs(distDeg) + 1) / Math.log(MAX_DIFF / numWakes);
|
|
||||||
// } else
|
|
||||||
// rotationalVelocities[i] = rotationalVelocities[i - 1];
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// double rad = (14 / numWakes) + velocity;
|
|
||||||
// for (Arc arc : arcs) {
|
|
||||||
// arc.setRadiusX(rad);
|
|
||||||
// arc.setRadiusY(rad);
|
|
||||||
// rad += (14 / numWakes) + (velocity / 2.5);
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,25 +0,0 @@
|
|||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -60,8 +60,10 @@ public class BoatModel extends Model {
|
|||||||
*/
|
*/
|
||||||
public void changeColour(Color newColour) {
|
public void changeColour(Color newColour) {
|
||||||
changeColourChild(HULL_INDEX, newColour);
|
changeColourChild(HULL_INDEX, newColour);
|
||||||
|
if (meshType != BoatMeshType.PARROT) {
|
||||||
changeColourChild(MAST_INDEX, newColour);
|
changeColourChild(MAST_INDEX, newColour);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void changeColourChild(int index, Color newColour) {
|
private void changeColourChild(int index, Color newColour) {
|
||||||
MeshView meshView = getMeshViewChild(index);
|
MeshView meshView = getMeshViewChild(index);
|
||||||
|
|||||||
@@ -1,44 +0,0 @@
|
|||||||
package seng302.visualiser.map;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The Boundary class represents a rectangle territorial boundary on a map. It
|
|
||||||
* contains four extremity double values(N, E, S, W). N and S are represented as
|
|
||||||
* latitudes in radians. E and W are represented as longitudes in radians.
|
|
||||||
*
|
|
||||||
* Created by Haoming on 10/5/17
|
|
||||||
*/
|
|
||||||
public class Boundary {
|
|
||||||
|
|
||||||
private double northLat, eastLng, southLat, westLng;
|
|
||||||
|
|
||||||
public Boundary(double northLat, double eastLng, double southLat, double westLng) {
|
|
||||||
this.northLat = northLat;
|
|
||||||
this.eastLng = eastLng;
|
|
||||||
this.southLat = southLat;
|
|
||||||
this.westLng = westLng;
|
|
||||||
}
|
|
||||||
|
|
||||||
double getCentreLat() {
|
|
||||||
return (northLat + southLat) / 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
double getCentreLng() {
|
|
||||||
return (eastLng + westLng) / 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
double getNorthLat() {
|
|
||||||
return northLat;
|
|
||||||
}
|
|
||||||
|
|
||||||
double getEastLng() {
|
|
||||||
return eastLng;
|
|
||||||
}
|
|
||||||
|
|
||||||
double getSouthLat() {
|
|
||||||
return southLat;
|
|
||||||
}
|
|
||||||
|
|
||||||
double getWestLng() {
|
|
||||||
return westLng;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,103 +0,0 @@
|
|||||||
package seng302.visualiser.map;
|
|
||||||
|
|
||||||
import java.net.URL;
|
|
||||||
import javafx.geometry.Point2D;
|
|
||||||
import javafx.scene.image.Image;
|
|
||||||
import javax.net.ssl.HttpsURLConnection;
|
|
||||||
import seng302.model.GeoPoint;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* CanvasMap retrieves a map image with given geo boundary from Google Map server.
|
|
||||||
* By passing a rectangle like geo boundary, it returns a map image with the
|
|
||||||
* highest resolution. However, due to free quote account usage limit, the maximum
|
|
||||||
* resolution is only 1280 * 1280.
|
|
||||||
*
|
|
||||||
* Created by Haoming on 15/5/2017
|
|
||||||
*/
|
|
||||||
public class CanvasMap {
|
|
||||||
|
|
||||||
private Boundary boundary;
|
|
||||||
private long width, height; // desired image size
|
|
||||||
private int zoom;
|
|
||||||
|
|
||||||
private String KEY = "AIzaSyC-5oOShMCY5Oy_9L7guYMPUPFHDMr37wE";
|
|
||||||
|
|
||||||
public CanvasMap(Boundary boundary) {
|
|
||||||
this.boundary = boundary;
|
|
||||||
calculateOptimalMapSize();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Image getMapImage() {
|
|
||||||
try {
|
|
||||||
URL url = new URL(getRequest());
|
|
||||||
HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
|
|
||||||
|
|
||||||
return new Image(connection.getInputStream());
|
|
||||||
} catch (Exception e) {
|
|
||||||
System.out.println("[CanvasMap] Exception");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getRequest() {
|
|
||||||
StringBuilder sb = new StringBuilder();
|
|
||||||
sb.append("https://maps.googleapis.com/maps/api/staticmap?");
|
|
||||||
sb.append(String.format("center=%f,%f", boundary.getCentreLat(), boundary.getCentreLng()));
|
|
||||||
sb.append(String.format("&zoom=%d", zoom));
|
|
||||||
sb.append(String.format("&size=%dx%d&scale=2", width, height));
|
|
||||||
sb.append("&style=feature:all|element:labels|visibility:off"); // hide all labels on map
|
|
||||||
// sb.append(String.format("&markers=%f,%f", boundary.getSouthLat(), boundary.getWestLng()));
|
|
||||||
// sb.append(String.format("&key=%s", KEY));
|
|
||||||
return sb.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void calculateOptimalMapSize() {
|
|
||||||
for (int z = 20; z > 0; z--) {
|
|
||||||
MapSize mapSize = getMapSize(z, boundary);
|
|
||||||
zoom = z;
|
|
||||||
width = mapSize.width;
|
|
||||||
height = mapSize.height;
|
|
||||||
// if map size is valid, exit the loop as we have the highest resolution
|
|
||||||
if (mapSize.isValid()) break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private MapSize getMapSize(int zoom, Boundary boundary) {
|
|
||||||
double scale = Math.pow(2, zoom);
|
|
||||||
GeoPoint geoSW = new GeoPoint(boundary.getSouthLat(), boundary.getWestLng());
|
|
||||||
GeoPoint geoNE = new GeoPoint(boundary.getNorthLat(), boundary.getEastLng());
|
|
||||||
Point2D pointSW = MercatorProjection.toMapPoint(geoSW);
|
|
||||||
Point2D pointNE = MercatorProjection.toMapPoint(geoNE);
|
|
||||||
return new MapSize(Math.abs(pointNE.getX() - pointSW.getX()) * scale,
|
|
||||||
Math.abs(pointNE.getY() - pointSW.getY()) * scale);
|
|
||||||
}
|
|
||||||
|
|
||||||
class MapSize {
|
|
||||||
long width, height;
|
|
||||||
|
|
||||||
MapSize(double width, double height) {
|
|
||||||
this.width = Math.round(width);
|
|
||||||
this.height = Math.round(height);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Map size is valid when width and height are both less than 640 pixels
|
|
||||||
* @return true if both dimensions are less than 640px
|
|
||||||
*/
|
|
||||||
boolean isValid() {
|
|
||||||
return Math.max(width, height) <= 640;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getWidth() {
|
|
||||||
return width;
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getHeight() {
|
|
||||||
return height;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getZoom() {
|
|
||||||
return zoom;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,55 +0,0 @@
|
|||||||
package seng302.visualiser.map;
|
|
||||||
|
|
||||||
import javafx.geometry.Point2D;
|
|
||||||
import seng302.model.GeoPoint;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An utility class useful to convert between Geo locations and Mercator projection
|
|
||||||
* planar coordinates.
|
|
||||||
* Created by Haoming on 15/5/2017
|
|
||||||
*/
|
|
||||||
public class MercatorProjection {
|
|
||||||
|
|
||||||
private static final double MERCATOR_RANGE = 256;
|
|
||||||
private static final double pixelsPerLngDegree = MERCATOR_RANGE / 360.0;
|
|
||||||
private static final double pixelsPerLngRadian = MERCATOR_RANGE / (2 * Math.PI);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A help function keeps the value in bound between -0.9999 and 0.9999.
|
|
||||||
* @param value in bound value
|
|
||||||
* @return the value in bound
|
|
||||||
*/
|
|
||||||
private static double bound(double value) {
|
|
||||||
return Math.min(Math.max(value, -0.9999), 0.9999);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Projects a Geo Location (lat, lng) on a planar
|
|
||||||
* @param geo GeoPoint (lat, lng) location to be projected
|
|
||||||
* @return the projection Point2D (x, y) on planar
|
|
||||||
*/
|
|
||||||
public static Point2D toMapPoint(GeoPoint geo) {
|
|
||||||
double x, y;
|
|
||||||
Point2D origin = new Point2D(MERCATOR_RANGE / 2.0, MERCATOR_RANGE / 2.0);
|
|
||||||
x = (origin.getX() + geo.getLng() * pixelsPerLngDegree);
|
|
||||||
|
|
||||||
// NOTE(appleton): Truncating to 0.9999 effectively limits latitude to
|
|
||||||
// 89.189. This is about a third of a tile past the edge of the world tile.
|
|
||||||
double sinY = bound(Math.sin(Math.toRadians(geo.getLat())));
|
|
||||||
y = origin.getY() + 0.5 * Math.log((1 + sinY) / (1 - sinY)) * (-pixelsPerLngRadian);
|
|
||||||
return new Point2D(x, y);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts the planar projection (x, y) back to Geo Location (lat, lng)
|
|
||||||
* @param point Point2D (x, y) to be converted back
|
|
||||||
* @return the original Geo location converted from the given projection point
|
|
||||||
*/
|
|
||||||
public static GeoPoint toMapGeo(Point2D point) {
|
|
||||||
Point2D origin = new Point2D(MERCATOR_RANGE / 2.0, MERCATOR_RANGE / 2.0);
|
|
||||||
double lng = (point.getX() - origin.getX()) / pixelsPerLngDegree;
|
|
||||||
double latRadians = (point.getY() - origin.getY()) / (-pixelsPerLngRadian);
|
|
||||||
double lat = Math.toDegrees(2 * Math.atan(Math.exp(latRadians)) - Math.PI / 2.0);
|
|
||||||
return new GeoPoint(lat, lng);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
package seng302.visualiser.map;
|
|
||||||
|
|
||||||
import java.net.URL;
|
|
||||||
import java.util.ResourceBundle;
|
|
||||||
import javafx.fxml.FXML;
|
|
||||||
import javafx.fxml.Initializable;
|
|
||||||
import javafx.scene.canvas.Canvas;
|
|
||||||
import javafx.scene.canvas.GraphicsContext;
|
|
||||||
|
|
||||||
public class TestMapController implements Initializable{
|
|
||||||
|
|
||||||
@FXML
|
|
||||||
private Canvas mapCanvas;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void initialize(URL location, ResourceBundle resources) {
|
|
||||||
GraphicsContext gc = mapCanvas.getGraphicsContext2D();
|
|
||||||
Boundary bound = new Boundary(57.662943, 11.848501, 57.673945, 11.824966);
|
|
||||||
CanvasMap canvasMap = new CanvasMap(bound);
|
|
||||||
gc.drawImage(canvasMap.getMapImage(), 0, 0, canvasMap.getWidth(), canvasMap.getHeight());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -15,7 +15,6 @@
|
|||||||
</CompoundMark>
|
</CompoundMark>
|
||||||
<CompoundMark CompoundMarkID="2">
|
<CompoundMark CompoundMarkID="2">
|
||||||
<Mark Lat="57.670914" Lng="11.835263"/>
|
<Mark Lat="57.670914" Lng="11.835263"/>
|
||||||
<Mark Lat="57.6699024" Lng="11.8353195"/>
|
|
||||||
</CompoundMark>
|
</CompoundMark>
|
||||||
<CompoundMark CompoundMarkID="3">
|
<CompoundMark CompoundMarkID="3">
|
||||||
<Mark Lat="57.6674596" Lng="11.8417500"/>
|
<Mark Lat="57.6674596" Lng="11.8417500"/>
|
||||||
@@ -29,21 +28,27 @@
|
|||||||
<Mark Lat="57.667311" Lng="11.828857"/>
|
<Mark Lat="57.667311" Lng="11.828857"/>
|
||||||
<Mark Lat="57.667334" Lng="11.825853"/>
|
<Mark Lat="57.667334" Lng="11.825853"/>
|
||||||
</CompoundMark>
|
</CompoundMark>
|
||||||
|
<CompoundMark CompoundMarkID="6">
|
||||||
|
<Mark Lat="57.6675700" Lng="11.8359880"/>
|
||||||
|
<Mark Lat="57.667610" Lng="11.833473"/>
|
||||||
|
</CompoundMark>
|
||||||
</Marks>
|
</Marks>
|
||||||
|
|
||||||
<Course>
|
<Course>
|
||||||
<OpeningSegment>
|
<OpeningSegment>
|
||||||
<Corner CompoundMarkID="1" Rounding="PS"/>
|
<Corner CompoundMarkID="1" Rounding="PS"/>
|
||||||
<Corner CompoundMarkID="2" Rounding="P"/>
|
<Corner CompoundMarkID="2" Rounding="S"/>
|
||||||
</OpeningSegment>
|
</OpeningSegment>
|
||||||
|
|
||||||
<RepeatingSegment>
|
<RepeatingSegment>
|
||||||
<Corner CompoundMarkID="3" Rounding="SP"/>
|
<Corner CompoundMarkID="3" Rounding="SP"/>
|
||||||
<Corner CompoundMarkID="4" Rounding="PS"/>
|
<Corner CompoundMarkID="4" Rounding="PS"/>
|
||||||
|
<Corner CompoundMarkID="5" Rounding="PS"/>
|
||||||
|
<Corner CompoundMarkID="2" Rounding="S"/>
|
||||||
</RepeatingSegment>
|
</RepeatingSegment>
|
||||||
|
|
||||||
<ClosingSegment>
|
<ClosingSegment>
|
||||||
<Corner CompoundMarkID="5" Rounding="PS"/>
|
<Corner CompoundMarkID="6" Rounding="PS"/>
|
||||||
</ClosingSegment>
|
</ClosingSegment>
|
||||||
</Course>
|
</Course>
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,53 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
|
|
||||||
<?import java.lang.*?>
|
|
||||||
<?import javafx.geometry.*?>
|
|
||||||
<?import javafx.scene.control.*?>
|
|
||||||
<?import javafx.scene.layout.*?>
|
|
||||||
<?import javafx.scene.text.*?>
|
|
||||||
<?import javafx.geometry.Insets?>
|
|
||||||
<?import javafx.scene.control.Button?>
|
|
||||||
<?import javafx.scene.control.Label?>
|
|
||||||
<?import javafx.scene.control.TableColumn?>
|
|
||||||
<?import javafx.scene.control.TableView?>
|
|
||||||
<?import javafx.scene.layout.AnchorPane?>
|
|
||||||
<?import javafx.scene.layout.ColumnConstraints?>
|
|
||||||
<?import javafx.scene.layout.GridPane?>
|
|
||||||
<?import javafx.scene.layout.RowConstraints?>
|
|
||||||
<?import javafx.scene.text.Font?>
|
|
||||||
|
|
||||||
<GridPane fx:id="finishScreenGridPane" maxHeight="837.0" maxWidth="837.0" minHeight="837.0" minWidth="837.0" nodeOrientation="LEFT_TO_RIGHT" prefHeight="837.0" prefWidth="837.0" style="-fx-background-color: #2C2c36;" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="seng302.visualiser.controllers.FinishScreenViewController">
|
|
||||||
<columnConstraints>
|
|
||||||
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
|
|
||||||
</columnConstraints>
|
|
||||||
<rowConstraints>
|
|
||||||
<RowConstraints maxHeight="259.0" minHeight="259.0" prefHeight="259.0" vgrow="SOMETIMES" />
|
|
||||||
<RowConstraints maxHeight="64.0" minHeight="64.0" prefHeight="64.0" vgrow="SOMETIMES" />
|
|
||||||
<RowConstraints maxHeight="257.0" minHeight="257.0" prefHeight="257.0" vgrow="SOMETIMES" />
|
|
||||||
<RowConstraints maxHeight="257.0" minHeight="257.0" prefHeight="257.0" vgrow="SOMETIMES" />
|
|
||||||
</rowConstraints>
|
|
||||||
<children>
|
|
||||||
<Label alignment="CENTER" text="Race Finished!" textFill="WHITE" GridPane.halignment="CENTER" GridPane.valignment="CENTER">
|
|
||||||
<font>
|
|
||||||
<Font size="40.0" />
|
|
||||||
</font>
|
|
||||||
</Label>
|
|
||||||
<Label alignment="CENTER" text="Race Result:" textFill="WHITE" GridPane.halignment="CENTER" GridPane.rowIndex="1" GridPane.valignment="CENTER">
|
|
||||||
<font>
|
|
||||||
<Font size="28.0" />
|
|
||||||
</font>
|
|
||||||
</Label>
|
|
||||||
<TableView fx:id="finishOrderTable" maxWidth="661.0" prefHeight="324.0" prefWidth="629.0" styleClass="ui-table" GridPane.halignment="CENTER" GridPane.rowIndex="2">
|
|
||||||
<columns>
|
|
||||||
<TableColumn fx:id="posCol" editable="false" maxWidth="74.0" minWidth="74.0" prefWidth="74.0" resizable="false" sortable="false" text="Position" />
|
|
||||||
<TableColumn fx:id="boatNameCol" editable="false" maxWidth="171.0" minWidth="171.0" prefWidth="171.0" resizable="false" sortable="false" text="Boat Name" />
|
|
||||||
<TableColumn fx:id="shortNameCol" editable="false" maxWidth="155.18472290039062" minWidth="107.0" prefWidth="155.18472290039062" resizable="false" sortable="false" text="Short Name" />
|
|
||||||
<TableColumn fx:id="countryCol" editable="false" maxWidth="258.9999694824219" minWidth="147.0" prefWidth="258.9999694824219" resizable="false" sortable="false" text="Country" />
|
|
||||||
</columns>
|
|
||||||
<GridPane.margin>
|
|
||||||
<Insets bottom="50.0" />
|
|
||||||
</GridPane.margin>
|
|
||||||
</TableView>
|
|
||||||
<Button mnemonicParsing="false" onAction="#switchToStartScreenView" onMouseEntered="#playButtonHoverSound" styleClass="blue-ui-btn" text="Return to Start Screen" GridPane.halignment="CENTER" GridPane.rowIndex="3" GridPane.valignment="TOP" />
|
|
||||||
</children>
|
|
||||||
</GridPane>
|
|
||||||
@@ -1,7 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
<?import javafx.scene.*?>
|
|
||||||
<?import javafx.scene.shape.*?>
|
|
||||||
<?import com.jfoenix.controls.*?>
|
<?import com.jfoenix.controls.*?>
|
||||||
<?import java.lang.*?>
|
<?import java.lang.*?>
|
||||||
<?import javafx.geometry.*?>
|
<?import javafx.geometry.*?>
|
||||||
@@ -294,6 +292,19 @@
|
|||||||
</GridPane>
|
</GridPane>
|
||||||
</children>
|
</children>
|
||||||
</StackPane>
|
</StackPane>
|
||||||
|
<Pane fx:id="miniMapPane" maxHeight="200.0" maxWidth="200.0" minHeight="200.0" minWidth="200.0" prefHeight="200.0" prefWidth="200.0" style="-fx-background-color: white; -fx-opacity: 0.45; -fx-background-radius: 10;" StackPane.alignment="TOP_RIGHT">
|
||||||
|
<StackPane.margin>
|
||||||
|
<Insets right="15.0" top="15.0" />
|
||||||
|
</StackPane.margin>
|
||||||
|
</Pane>
|
||||||
|
<JFXButton fx:id="miniMapButton" style="-fx-background-color: white; -fx-opacity: 0.45; -fx-background-radius: 10;" text="✕" StackPane.alignment="TOP_RIGHT">
|
||||||
|
<font>
|
||||||
|
<Font size="15.0" />
|
||||||
|
</font>
|
||||||
|
<StackPane.margin>
|
||||||
|
<Insets right="15.0" top="15.0" />
|
||||||
|
</StackPane.margin>
|
||||||
|
</JFXButton>
|
||||||
<AnchorPane fx:id="loadingScreenPane">
|
<AnchorPane fx:id="loadingScreenPane">
|
||||||
<ImageView fx:id="loadingScreen" fitHeight="672.0" fitWidth="1200.0" pickOnBounds="true" preserveRatio="true" />
|
<ImageView fx:id="loadingScreen" fitHeight="672.0" fitWidth="1200.0" pickOnBounds="true" preserveRatio="true" />
|
||||||
<JFXSpinner layoutX="566.0" layoutY="692.0" radius="30.0" />
|
<JFXSpinner layoutX="566.0" layoutY="692.0" radius="30.0" />
|
||||||
|
|||||||
@@ -0,0 +1,78 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
|
<?import javafx.scene.text.*?>
|
||||||
|
<?import com.jfoenix.controls.*?>
|
||||||
|
<?import java.lang.*?>
|
||||||
|
<?import java.net.*?>
|
||||||
|
<?import javafx.geometry.*?>
|
||||||
|
<?import javafx.scene.control.*?>
|
||||||
|
<?import javafx.scene.layout.*?>
|
||||||
|
<?import com.jfoenix.controls.JFXButton?>
|
||||||
|
<?import com.jfoenix.controls.JFXDialogLayout?>
|
||||||
|
<?import java.net.URL?>
|
||||||
|
<?import javafx.geometry.Insets?>
|
||||||
|
<?import javafx.scene.control.Label?>
|
||||||
|
<?import javafx.scene.layout.ColumnConstraints?>
|
||||||
|
<?import javafx.scene.layout.GridPane?>
|
||||||
|
<?import javafx.scene.layout.RowConstraints?>
|
||||||
|
|
||||||
|
<JFXDialogLayout maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity"
|
||||||
|
minWidth="-Infinity" prefHeight="273.0" prefWidth="436.0" xmlns="http://javafx.com/javafx/8"
|
||||||
|
xmlns:fx="http://javafx.com/fxml/1"
|
||||||
|
fx:controller="seng302.visualiser.controllers.dialogs.TokenInfoDialogController">
|
||||||
|
<children>
|
||||||
|
<GridPane>
|
||||||
|
<columnConstraints>
|
||||||
|
<ColumnConstraints hgrow="SOMETIMES" maxWidth="1.7976931348623157E308"/>
|
||||||
|
</columnConstraints>
|
||||||
|
<rowConstraints>
|
||||||
|
<RowConstraints maxHeight="40.0" minHeight="30.0" prefHeight="40.0"
|
||||||
|
vgrow="SOMETIMES"/>
|
||||||
|
<RowConstraints maxHeight="1.7976931348623157E308" minHeight="80.0"
|
||||||
|
prefHeight="115.0" vgrow="SOMETIMES"/>
|
||||||
|
<RowConstraints maxHeight="141.0" minHeight="34.0" prefHeight="73.0"
|
||||||
|
vgrow="SOMETIMES"/>
|
||||||
|
</rowConstraints>
|
||||||
|
<children>
|
||||||
|
<JFXButton fx:id="optionButton" buttonType="RAISED" prefHeight="55.0"
|
||||||
|
prefWidth="150.0" text="Ok" GridPane.halignment="CENTER" GridPane.rowIndex="2"
|
||||||
|
GridPane.valignment="CENTER">
|
||||||
|
<GridPane.margin>
|
||||||
|
<Insets/>
|
||||||
|
</GridPane.margin>
|
||||||
|
</JFXButton>
|
||||||
|
<Label fx:id="headerLabel" text="Popup header" GridPane.halignment="CENTER">
|
||||||
|
<font>
|
||||||
|
<Font size="15.0"/>
|
||||||
|
</font>
|
||||||
|
</Label>
|
||||||
|
<GridPane GridPane.rowIndex="1">
|
||||||
|
<columnConstraints>
|
||||||
|
<ColumnConstraints hgrow="SOMETIMES" maxWidth="270.0" minWidth="10.0"
|
||||||
|
prefWidth="270.0"/>
|
||||||
|
<ColumnConstraints hgrow="SOMETIMES" maxWidth="225.0" minWidth="-Infinity"
|
||||||
|
prefWidth="138.0"/>
|
||||||
|
</columnConstraints>
|
||||||
|
<rowConstraints>
|
||||||
|
<RowConstraints minHeight="10.0" prefHeight="100.0" vgrow="SOMETIMES"/>
|
||||||
|
</rowConstraints>
|
||||||
|
<children>
|
||||||
|
<Pane fx:id="tokenPane" prefHeight="200.0" prefWidth="200.0"
|
||||||
|
GridPane.columnIndex="1"/>
|
||||||
|
<TextArea fx:id="contentText" nodeOrientation="RIGHT_TO_LEFT"
|
||||||
|
prefHeight="200.0" prefWidth="200.0" promptText="This is some text"
|
||||||
|
stylesheets="@../../css/TokenInfoDialog.css" wrapText="true">
|
||||||
|
<font>
|
||||||
|
<Font size="16.0"/>
|
||||||
|
</font>
|
||||||
|
</TextArea>
|
||||||
|
</children>
|
||||||
|
</GridPane>
|
||||||
|
</children>
|
||||||
|
</GridPane>
|
||||||
|
</children>
|
||||||
|
<stylesheets>
|
||||||
|
<URL value="@../../css/dialogs/Popup.css"/>
|
||||||
|
<URL value="@../../css/Master.css"/>
|
||||||
|
</stylesheets>
|
||||||
|
</JFXDialogLayout>
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
|
|
||||||
<?import java.lang.String?>
|
|
||||||
<?import javafx.scene.control.Button?>
|
|
||||||
<?import javafx.scene.control.CheckBox?>
|
|
||||||
<?import javafx.scene.layout.AnchorPane?>
|
|
||||||
<?import javafx.scene.text.Font?>
|
|
||||||
<?import javafx.scene.text.Text?>
|
|
||||||
<AnchorPane fx:id="annotationSelectWindow" maxHeight="270.0" maxWidth="469.0" minHeight="270.0" minWidth="469.0" prefHeight="270.0" prefWidth="469.0" styleClass="background-blue" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
|
|
||||||
<children>
|
|
||||||
<Text fill="WHITE" layoutX="26.0" layoutY="52.0" strokeType="OUTSIDE" strokeWidth="0.0" text="Select important annotations">
|
|
||||||
<font>
|
|
||||||
<Font size="24.0" />
|
|
||||||
</font>
|
|
||||||
</Text>
|
|
||||||
<CheckBox fx:id="boatWakeSelect" layoutX="26.0" layoutY="80.0" mnemonicParsing="false" style="-fx-border-width: 0; -fx-background-insets: 0;" text="Boat Wakes" textFill="#e7e7e7" />
|
|
||||||
<CheckBox fx:id="boatSpeedSelect" layoutX="26.0" layoutY="111.0" mnemonicParsing="false" text="Boat Speed" textFill="#e7e7e7" />
|
|
||||||
<CheckBox fx:id="boatTrackSelect" layoutX="26.0" layoutY="142.0" mnemonicParsing="false" text="Boat Tracks" textFill="#e7e7e7" />
|
|
||||||
<CheckBox fx:id="boatNameSelect" layoutX="26.0" layoutY="173.0" mnemonicParsing="false" text="Boat Name" textFill="#e7e7e7" />
|
|
||||||
<CheckBox fx:id="boatEstTimeToNextMarkSelect" layoutX="26.0" layoutY="204.0" mnemonicParsing="false" text="Boat Estimated Time To Next Mark" textFill="#e7e7e7" />
|
|
||||||
<Button fx:id="closeButton" layoutX="424.0" layoutY="-1.0" mnemonicParsing="false" prefHeight="11.0" prefWidth="49.0" style=": 0;" text="X" textFill="#ffffff4e">
|
|
||||||
<font>
|
|
||||||
<Font size="24.0" />
|
|
||||||
</font>
|
|
||||||
<styleClass>
|
|
||||||
<String fx:value="background-blue" />
|
|
||||||
<String fx:value="clearExitButton" />
|
|
||||||
</styleClass>
|
|
||||||
</Button>
|
|
||||||
<CheckBox fx:id="boatElapsedTimeSelect" layoutX="26.0" layoutY="235.0" mnemonicParsing="false" text="Boat Elapsed Time Since Last Mark" textFill="#e7e7e7" />
|
|
||||||
</children>
|
|
||||||
</AnchorPane>
|
|
||||||
@@ -48,9 +48,10 @@ public class ServerTableTest {
|
|||||||
|
|
||||||
serverTable.addServer(listing);
|
serverTable.addServer(listing);
|
||||||
|
|
||||||
|
listing.decrementTtl();
|
||||||
listing.decrementTtl();
|
listing.decrementTtl();
|
||||||
|
|
||||||
Thread.sleep(1000);
|
Thread.sleep(1500);
|
||||||
|
|
||||||
assertTrue(!serverTable.getAllServers().contains(listing));
|
assertTrue(!serverTable.getAllServers().contains(listing));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,43 +0,0 @@
|
|||||||
package seng302.visualiser.map;
|
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
|
||||||
|
|
||||||
import org.junit.Test;
|
|
||||||
import seng302.model.GeoPoint;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Unit test for Mercator Project class.
|
|
||||||
* Created by hyi25 on 15/05/17.
|
|
||||||
*/
|
|
||||||
public class MercatorProjectionTest {
|
|
||||||
@Test
|
|
||||||
public void toMapPoint() throws Exception {
|
|
||||||
GeoPoint geo1 = new GeoPoint(12.485394, 19.38947);
|
|
||||||
javafx.geometry.Point2D actualPoint1 = MercatorProjection.toMapPoint(geo1);
|
|
||||||
javafx.geometry.Point2D expectedPoint1 = new javafx.geometry.Point2D(141.78806755555556, 119.0503853635612);
|
|
||||||
assertEquals(expectedPoint1.getX(), actualPoint1.getX(), 0.0001);
|
|
||||||
assertEquals(expectedPoint1.getY(), actualPoint1.getY(), 0.0001);
|
|
||||||
|
|
||||||
GeoPoint geo2 = new GeoPoint(77.456432, -23.456462);
|
|
||||||
javafx.geometry.Point2D actualPoint2 = MercatorProjection.toMapPoint(geo2);
|
|
||||||
javafx.geometry.Point2D expectedPoint2 = new javafx.geometry.Point2D(111.31984924444444, 38.03143323746788);
|
|
||||||
assertEquals(expectedPoint2.getX(), actualPoint2.getX(), 0.0001);
|
|
||||||
assertEquals(expectedPoint2.getY(), actualPoint2.getY(), 0.0001);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void toMapGeo() throws Exception {
|
|
||||||
javafx.geometry.Point2D point1 = new javafx.geometry.Point2D(123.1234, 25.4565);
|
|
||||||
GeoPoint actualGeo1 = MercatorProjection.toMapGeo(point1);
|
|
||||||
GeoPoint expectedGeo1 = new GeoPoint(80.77043127275441, -6.857718749999995);
|
|
||||||
assertEquals(expectedGeo1.getLat(), actualGeo1.getLat(), 0.0001);
|
|
||||||
assertEquals(expectedGeo1.getLng(), actualGeo1.getLng(), 0.0001);
|
|
||||||
|
|
||||||
javafx.geometry.Point2D point2 = new javafx.geometry.Point2D(1.235, 255.4565);
|
|
||||||
GeoPoint actualGeo2 = MercatorProjection.toMapGeo(point2);
|
|
||||||
GeoPoint expectedGeo2 = new GeoPoint(-84.98475532898011, -178.26328125);
|
|
||||||
assertEquals(expectedGeo2.getLat(), actualGeo2.getLat(), 0.0001);
|
|
||||||
assertEquals(expectedGeo2.getLng(), actualGeo2.getLng(), 0.0001);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -3,6 +3,9 @@ package steps;
|
|||||||
import cucumber.api.java.en.Given;
|
import cucumber.api.java.en.Given;
|
||||||
import cucumber.api.java.en.Then;
|
import cucumber.api.java.en.Then;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.lang.reflect.Array;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Comparator;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import seng302.visualiser.MapMaker;
|
import seng302.visualiser.MapMaker;
|
||||||
|
|
||||||
@@ -29,11 +32,11 @@ public class CustomMapsSteps {
|
|||||||
@Then("^all of them can be seen$")
|
@Then("^all of them can be seen$")
|
||||||
public void all_of_them_can_be_seen() throws Throwable {
|
public void all_of_them_can_be_seen() throws Throwable {
|
||||||
File[] files = new File(this.getClass().getResource("/maps/").getPath()).listFiles();
|
File[] files = new File(this.getClass().getResource("/maps/").getPath()).listFiles();
|
||||||
|
Arrays.sort(files);
|
||||||
for (File file : files) {
|
for (File file : files) {
|
||||||
if (file.isFile()) {
|
if (file.isFile()) {
|
||||||
Assert.assertTrue(file.getAbsolutePath().equals(mapMaker.getCurrentRacePath()));
|
Assert.assertTrue(file.getAbsolutePath().endsWith(mapMaker.getCurrentRacePath()));
|
||||||
mapMaker.next();
|
mapMaker.next();
|
||||||
System.out.println(file.getAbsolutePath());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user