Fixed connecting to hosts. Fixed issue34 and 35 to the point where they can be developed off of.

#refactor #bug #issue[34, 35]
This commit is contained in:
Calum
2017-08-02 00:26:57 +12:00
parent 908c0749cf
commit 87ef37a689
48 changed files with 355 additions and 319 deletions
@@ -9,7 +9,7 @@ import javafx.collections.FXCollections;
import javafx.collections.ObservableList; import javafx.collections.ObservableList;
import seng302.model.Player; import seng302.model.Player;
import seng302.model.Yacht; import seng302.model.Yacht;
import seng302.server.messages.BoatActionType; import seng302.gameServer.server.messages.BoatActionType;
/** /**
* A Static class to hold information about the current state of the game (model) * A Static class to hold information about the current state of the game (model)
@@ -5,8 +5,8 @@ import java.util.Stack;
import java.util.Timer; import java.util.Timer;
import java.util.TimerTask; import java.util.TimerTask;
import seng302.model.Player; import seng302.model.Player;
import seng302.server.messages.Heartbeat; import seng302.gameServer.server.messages.Heartbeat;
import seng302.server.messages.Message; import seng302.gameServer.server.messages.Message;
/** /**
* Send Heartbeat messages to connected player at a specified interval * Send Heartbeat messages to connected player at a specified interval
@@ -2,7 +2,7 @@ package seng302.gameServer;
import java.util.Arrays; import java.util.Arrays;
import seng302.model.stream.packets.StreamPacket; import seng302.model.stream.packets.StreamPacket;
import seng302.server.messages.BoatActionType; import seng302.gameServer.server.messages.BoatActionType;
public class ServerPacketParser { public class ServerPacketParser {
@@ -25,16 +25,16 @@ import seng302.model.stream.packets.StreamPacket;
import seng302.model.stream.xml.generator.Race; import seng302.model.stream.xml.generator.Race;
import seng302.model.stream.xml.generator.Regatta; import seng302.model.stream.xml.generator.Regatta;
import seng302.utilities.XMLGenerator; import seng302.utilities.XMLGenerator;
import seng302.server.messages.BoatActionType; import seng302.gameServer.server.messages.BoatActionType;
import seng302.server.messages.BoatLocationMessage; import seng302.gameServer.server.messages.BoatLocationMessage;
import seng302.server.messages.BoatStatus; import seng302.gameServer.server.messages.BoatStatus;
import seng302.server.messages.BoatSubMessage; import seng302.gameServer.server.messages.BoatSubMessage;
import seng302.server.messages.Message; import seng302.gameServer.server.messages.Message;
import seng302.server.messages.RaceStatus; import seng302.gameServer.server.messages.RaceStatus;
import seng302.server.messages.RaceStatusMessage; import seng302.gameServer.server.messages.RaceStatusMessage;
import seng302.server.messages.RaceType; import seng302.gameServer.server.messages.RaceType;
import seng302.server.messages.XMLMessage; import seng302.gameServer.server.messages.XMLMessage;
import seng302.server.messages.XMLMessageSubType; import seng302.gameServer.server.messages.XMLMessageSubType;
/** /**
* A class describing a single connection to a Client for the purposes of sending and receiving on * A class describing a single connection to a Client for the purposes of sending and receiving on
@@ -1,4 +1,4 @@
package seng302.server.messages; package seng302.gameServer.server.messages;
/** /**
* Created by kre39 on 12/07/17. * Created by kre39 on 12/07/17.
@@ -1,4 +1,4 @@
package seng302.server.messages; package seng302.gameServer.server.messages;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
@@ -1,4 +1,4 @@
package seng302.server.messages; package seng302.gameServer.server.messages;
public class BoatLocationMessage extends Message { public class BoatLocationMessage extends Message {
private final int MESSAGE_SIZE = 56; private final int MESSAGE_SIZE = 56;
@@ -1,4 +1,4 @@
package seng302.server.messages; package seng302.gameServer.server.messages;
/** /**
* The current status of a boat * The current status of a boat
@@ -1,4 +1,4 @@
package seng302.server.messages; package seng302.gameServer.server.messages;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
@@ -1,4 +1,4 @@
package seng302.server.messages; package seng302.gameServer.server.messages;
/** /**
* Created by kre39 on 20/07/17. * Created by kre39 on 20/07/17.
@@ -1,4 +1,4 @@
package seng302.server.messages; package seng302.gameServer.server.messages;
public enum DeviceType { public enum DeviceType {
UNKNOWN(0), UNKNOWN(0),
@@ -1,4 +1,4 @@
package seng302.server.messages; package seng302.gameServer.server.messages;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
@@ -1,4 +1,4 @@
package seng302.server.messages; package seng302.gameServer.server.messages;
public class Heartbeat extends Message { public class Heartbeat extends Message {
private final int MESSAGE_SIZE = 4; private final int MESSAGE_SIZE = 4;
@@ -1,4 +1,4 @@
package seng302.server.messages; package seng302.gameServer.server.messages;
public class MarkRoundingMessage extends Message{ public class MarkRoundingMessage extends Message{
private final long MESSAGE_VERSION_NUMBER = 1; private final long MESSAGE_VERSION_NUMBER = 1;
@@ -1,4 +1,4 @@
package seng302.server.messages; package seng302.gameServer.server.messages;
/** /**
* Types of marks boats can round * Types of marks boats can round
@@ -1,4 +1,4 @@
package seng302.server.messages; package seng302.gameServer.server.messages;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.ByteOrder; import java.nio.ByteOrder;
@@ -1,4 +1,4 @@
package seng302.server.messages; package seng302.gameServer.server.messages;
/** /**
* Enum containing the types of messages * Enum containing the types of messages
@@ -1,4 +1,4 @@
package seng302.server.messages; package seng302.gameServer.server.messages;
/** /**
* The types of race start status messages * The types of race start status messages
@@ -1,4 +1,4 @@
package seng302.server.messages; package seng302.gameServer.server.messages;
public class RaceStartStatusMessage extends Message { public class RaceStartStatusMessage extends Message {
private final int MESSAGE_SIZE = 20; private final int MESSAGE_SIZE = 20;
@@ -1,4 +1,4 @@
package seng302.server.messages; package seng302.gameServer.server.messages;
/** /**
* The current status of the race * The current status of the race
@@ -1,4 +1,4 @@
package seng302.server.messages; package seng302.gameServer.server.messages;
import java.util.List; import java.util.List;
import java.util.zip.CRC32; import java.util.zip.CRC32;
@@ -1,4 +1,4 @@
package seng302.server.messages; package seng302.gameServer.server.messages;
/** /**
* Enum containing the types of races * Enum containing the types of races
@@ -1,4 +1,4 @@
package seng302.server.messages; package seng302.gameServer.server.messages;
/** /**
* The status of a boat rounding a mark * The status of a boat rounding a mark
@@ -1,4 +1,4 @@
package seng302.server.messages; package seng302.gameServer.server.messages;
/** /**
* The side the boat rounded the mark * The side the boat rounded the mark
@@ -1,4 +1,4 @@
package seng302.server.messages; package seng302.gameServer.server.messages;
public class XMLMessage extends Message{ public class XMLMessage extends Message{
private final MessageType MESSAGE_TYPE = MessageType.XML_MESSAGE; private final MessageType MESSAGE_TYPE = MessageType.XML_MESSAGE;
@@ -1,4 +1,4 @@
package seng302.server.messages; package seng302.gameServer.server.messages;
/** /**
* Enum containing the types of XML messages * Enum containing the types of XML messages
@@ -1,4 +1,4 @@
package seng302.server.simulator; package seng302.gameServer.server.simulator;
import seng302.model.GeoPoint; import seng302.model.GeoPoint;
import seng302.utilities.GeoUtility; import seng302.utilities.GeoUtility;
@@ -1,4 +1,4 @@
package seng302.server.simulator; package seng302.gameServer.server.simulator;
import seng302.model.mark.CompoundMark; import seng302.model.mark.CompoundMark;
@@ -1,4 +1,4 @@
package seng302.server.simulator; package seng302.gameServer.server.simulator;
public enum RoundingType { public enum RoundingType {
@@ -1,10 +1,10 @@
package seng302.server.simulator; package seng302.gameServer.server.simulator;
import java.util.List; import java.util.List;
import java.util.Observable; import java.util.Observable;
import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.ThreadLocalRandom;
import seng302.model.mark.Mark; import seng302.model.mark.Mark;
import seng302.server.simulator.parsers.RaceParser; import seng302.gameServer.server.simulator.parsers.RaceParser;
import seng302.model.GeoPoint; import seng302.model.GeoPoint;
import seng302.utilities.GeoUtility; import seng302.utilities.GeoUtility;
@@ -1,4 +1,4 @@
package seng302.server.simulator.parsers; package seng302.gameServer.server.simulator.parsers;
import org.w3c.dom.Document; import org.w3c.dom.Document;
@@ -1,4 +1,4 @@
package seng302.server.simulator.parsers; package seng302.gameServer.server.simulator.parsers;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
@@ -9,9 +9,9 @@ import org.w3c.dom.Element;
import org.w3c.dom.Node; import org.w3c.dom.Node;
import org.w3c.dom.NodeList; import org.w3c.dom.NodeList;
import seng302.model.mark.CompoundMark; import seng302.model.mark.CompoundMark;
import seng302.server.simulator.Corner; import seng302.gameServer.server.simulator.Corner;
import seng302.model.mark.Mark; import seng302.model.mark.Mark;
import seng302.server.simulator.RoundingType; import seng302.gameServer.server.simulator.RoundingType;
/** /**
* Parses the race xml file to get course details * Parses the race xml file to get course details
@@ -1,4 +1,4 @@
package seng302.server.simulator.parsers; package seng302.gameServer.server.simulator.parsers;
import java.io.InputStream; import java.io.InputStream;
import java.io.StringReader; import java.io.StringReader;
@@ -1,4 +1,4 @@
package seng302.server.simulator.parsers; package seng302.gameServer.server.simulator.parsers;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@@ -6,8 +6,8 @@ import org.w3c.dom.Document;
import org.w3c.dom.Element; import org.w3c.dom.Element;
import org.w3c.dom.Node; import org.w3c.dom.Node;
import org.w3c.dom.NodeList; import org.w3c.dom.NodeList;
import seng302.server.simulator.Boat; import seng302.gameServer.server.simulator.Boat;
import seng302.server.simulator.Corner; import seng302.gameServer.server.simulator.Corner;
/** /**
* Parses the race xml file to get course details * Parses the race xml file to get course details
@@ -9,7 +9,7 @@ import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import seng302.model.stream.xml.generator.Race; import seng302.model.stream.xml.generator.Race;
import seng302.model.stream.xml.generator.Regatta; import seng302.model.stream.xml.generator.Regatta;
import seng302.server.messages.XMLMessageSubType; import seng302.gameServer.server.messages.XMLMessageSubType;
/** /**
* An XML generator to generate the Race, Boat, and Regatta XML dynamically * An XML generator to generate the Race, Boat, and Regatta XML dynamically
@@ -16,8 +16,8 @@ import javafx.application.Platform;
import javafx.scene.control.Alert; import javafx.scene.control.Alert;
import javafx.scene.control.Alert.AlertType; import javafx.scene.control.Alert.AlertType;
import seng302.model.stream.packets.StreamPacket; import seng302.model.stream.packets.StreamPacket;
import seng302.server.messages.BoatActionMessage; import seng302.gameServer.server.messages.BoatActionMessage;
import seng302.server.messages.Message; import seng302.gameServer.server.messages.Message;
/** /**
* 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
@@ -130,7 +130,7 @@ public class ClientToServerThread implements Runnable {
} else { } else {
streamPackets.add(new StreamPacket(type, payloadLength, timeStamp, payload)); streamPackets.add(new StreamPacket(type, payloadLength, timeStamp, payload));
for (ClientSocketListener csl : listeners) for (ClientSocketListener csl : listeners)
Platform.runLater(csl::newPacket); csl.newPacket();
} }
} else { } else {
clientLog("Packet has been dropped", 1); clientLog("Packet has been dropped", 1);
@@ -147,6 +147,7 @@ public class ClientToServerThread implements Runnable {
clientLog(e.getMessage(), 1); clientLog(e.getMessage(), 1);
return; return;
} }
// System.out.println("streamPackets = " + streamPackets.size());
} }
closeSocket(); closeSocket();
clientLog("Closed connection to Server", 0); clientLog("Closed connection to Server", 0);
@@ -5,13 +5,13 @@ import java.time.ZoneId;
import java.time.ZoneOffset; import java.time.ZoneOffset;
import java.util.Map; import java.util.Map;
import java.util.TimeZone; import java.util.TimeZone;
import javafx.application.Platform;
import javafx.collections.FXCollections; import javafx.collections.FXCollections;
import javafx.collections.ObservableList; import javafx.collections.ObservableList;
import javafx.fxml.FXMLLoader; import javafx.fxml.FXMLLoader;
import javafx.scene.Node; import javafx.scene.Node;
import javafx.scene.input.KeyEvent; import javafx.scene.input.KeyEvent;
import javafx.scene.layout.Pane; import javafx.scene.layout.Pane;
import seng302.gameServer.GameState;
import seng302.gameServer.MainServerThread; import seng302.gameServer.MainServerThread;
import seng302.model.RaceState; import seng302.model.RaceState;
import seng302.model.Yacht; import seng302.model.Yacht;
@@ -22,8 +22,8 @@ import seng302.model.stream.parser.PositionUpdateData.DeviceType;
import seng302.model.stream.parser.RaceStatusData; import seng302.model.stream.parser.RaceStatusData;
import seng302.model.stream.xml.parser.RaceXMLData; import seng302.model.stream.xml.parser.RaceXMLData;
import seng302.model.stream.xml.parser.RegattaXMLData; import seng302.model.stream.xml.parser.RegattaXMLData;
import seng302.server.messages.BoatActionMessage; import seng302.gameServer.server.messages.BoatActionMessage;
import seng302.server.messages.BoatActionType; import seng302.gameServer.server.messages.BoatActionType;
import seng302.utilities.StreamParser; import seng302.utilities.StreamParser;
import seng302.utilities.XMLParser; import seng302.utilities.XMLParser;
import seng302.visualiser.controllers.LobbyController; import seng302.visualiser.controllers.LobbyController;
@@ -62,12 +62,12 @@ public class GameClient {
ioe.printStackTrace(); ioe.printStackTrace();
System.out.println("Unable to connect to host..."); System.out.println("Unable to connect to host...");
} }
LobbyController lobbyController = loadLobby("/views/LobbyView.fxml"); socketThread.addStreamObserver(this::parsePackets);
LobbyController lobbyController = loadLobby();
lobbyController.setPlayerListSource(clientLobbyList); lobbyController.setPlayerListSource(clientLobbyList);
lobbyController.disableReadyButton(); lobbyController.disableReadyButton();
lobbyController.setTitle("Connected to host - IP : " + ipAddress + " Port : " + portNumber); lobbyController.setTitle("Connected to host - IP : " + ipAddress + " Port : " + portNumber);
lobbyController.addCloseListener((exitCause) -> this.loadStartScreen()); lobbyController.addCloseListener((exitCause) -> this.loadStartScreen());
socketThread.addStreamObserver(this::parsePackets);
} }
public void runAsHost(String ipAddress, Integer portNumber) { public void runAsHost(String ipAddress, Integer portNumber) {
@@ -79,8 +79,8 @@ public class GameClient {
System.out.println("Unable to make local connection to host..."); System.out.println("Unable to make local connection to host...");
} }
socketThread.addStreamObserver(this::parsePackets); socketThread.addStreamObserver(this::parsePackets);
LobbyController lobbyController = loadLobby("/views/LobbyView.fxml"); LobbyController lobbyController = loadLobby();
lobbyController.setPlayerListSource(GameState.getObservablePlayers()); lobbyController.setPlayerListSource(clientLobbyList);
lobbyController.setTitle("Hosting Lobby - IP : " + ipAddress + " Port : " + portNumber); lobbyController.setTitle("Hosting Lobby - IP : " + ipAddress + " Port : " + portNumber);
lobbyController.addCloseListener(exitCause -> { lobbyController.addCloseListener(exitCause -> {
if (exitCause == CloseStatus.READY) { if (exitCause == CloseStatus.READY) {
@@ -112,11 +112,10 @@ public class GameClient {
/** /**
* Loads a view of the lobby into the clients pane * Loads a view of the lobby into the clients pane
* *
* @param lobbyView fxml file for the desired lobby
* @return the lobby controller. * @return the lobby controller.
*/ */
private LobbyController loadLobby(String lobbyView) { private LobbyController loadLobby() {
FXMLLoader fxmlLoader = new FXMLLoader(GameClient.class.getResource(lobbyView)); FXMLLoader fxmlLoader = new FXMLLoader(GameClient.class.getResource("/views/LobbyView.fxml"));
try { try {
holderPane.getChildren().clear(); holderPane.getChildren().clear();
holderPane.getChildren().add(fxmlLoader.load()); holderPane.getChildren().add(fxmlLoader.load());
@@ -130,9 +129,11 @@ public class GameClient {
FXMLLoader fxmlLoader = new FXMLLoader( FXMLLoader fxmlLoader = new FXMLLoader(
RaceViewController.class.getResource("/views/RaceView.fxml")); RaceViewController.class.getResource("/views/RaceView.fxml"));
try { try {
Node node = fxmlLoader.load(); final Node node = fxmlLoader.load();
Platform.runLater(() -> {
holderPane.getChildren().clear(); holderPane.getChildren().clear();
holderPane.getChildren().add(node); holderPane.getChildren().add(node);
});
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); e.printStackTrace();
} }
@@ -173,13 +174,14 @@ public class GameClient {
break; break;
case BOAT_XML: case BOAT_XML:
System.out.println("GOT SUM BOATS YAY :)");
allBoatsMap = XMLParser.parseBoats( allBoatsMap = XMLParser.parseBoats(
StreamParser.extractXmlMessage(packet) StreamParser.extractXmlMessage(packet)
); );
clientLobbyList.clear(); clientLobbyList.clear();
allBoatsMap.forEach((id, boat) -> { allBoatsMap.forEach((id, boat) -> {
clientLobbyList.add(id + " " + boat.getBoatName()); clientLobbyList.add(id + " " + boat.getBoatName());
System.out.println(id + " " + boat.getBoatName()); // System.out.println(id + " " + boat.getBoatName());
}); });
// startRaceIfAllDataReceived(); // startRaceIfAllDataReceived();
+42 -35
View File
@@ -1,11 +1,13 @@
package seng302.visualiser; package seng302.visualiser;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator; import java.util.Comparator;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import javafx.animation.AnimationTimer; import javafx.animation.AnimationTimer;
import javafx.application.Platform;
import javafx.collections.ObservableList; import javafx.collections.ObservableList;
import javafx.geometry.Point2D; import javafx.geometry.Point2D;
import javafx.scene.Group; import javafx.scene.Group;
@@ -70,12 +72,13 @@ public class GameView extends Pane {
private ImageView mapImage = new ImageView(); private ImageView mapImage = new ImageView();
//FRAME RATE //FRAME RATE
private Double frameRate = 60.0;
private final long[] frameTimes = new long[30];
private int frameTimeIndex = 0;
private boolean arrayFilled = false;
private AnimationTimer timer; private AnimationTimer timer;
private int NUM_SAMPLES = 10;
private final long[] frameTimes = new long[NUM_SAMPLES];
private Double frameRate = 60.0;
private int frameTimeIndex = 0;
private boolean arrayFilled = false;
private enum ScaleDirection { private enum ScaleDirection {
HORIZONTAL, HORIZONTAL,
@@ -98,9 +101,14 @@ public class GameView extends Pane {
} }
private void initializeTimer () { private void initializeTimer () {
Arrays.fill(frameTimes, 1_000_000_000 / 60);
timer = new AnimationTimer() { timer = new AnimationTimer() {
private long lastTime = 0; private long lastTime = 0;
private int FPSCount = 30; private int FPSCount = 30;
private Double frameRate = 60.0;
private int index = 0;
private boolean arrayFilled = false;
private long sum = 1_000_000_000 / 3;
@Override @Override
public void handle(long now) { public void handle(long now) {
@@ -121,13 +129,15 @@ public class GameView extends Pane {
frameRate = 1_000_000_000.0 / elapsedNanosPerFrame; frameRate = 1_000_000_000.0 / elapsedNanosPerFrame;
if (FPSCount-- == 0) { if (FPSCount-- == 0) {
FPSCount = 30; FPSCount = 30;
drawFps(frameRate.intValue()); drawFps(frameRate);
} }
} }
boatObjects.forEach((boat, boatObject) -> boatObject.updateLocation());
lastTime = now; lastTime = now;
} }
} }
// Platform.runLater(() ->
// boatObjects.forEach((boat, boatObject) -> boatObject.updateLocation())
// );
} }
}; };
} }
@@ -175,10 +185,9 @@ public class GameView extends Pane {
*/ */
public void updateCourse(List<CompoundMark> newCourse, List<Corner> sequence) { public void updateCourse(List<CompoundMark> newCourse, List<Corner> sequence) {
markerObjects = new HashMap<>(); markerObjects = new HashMap<>();
final List<Gate> gates = new ArrayList<>();
Paint colour = Color.BLACK; Paint colour = Color.BLACK;
markers.getChildren().clear();
//Creates new markers //Creates new markers
System.out.println(newCourse.size());
for (CompoundMark cMark : newCourse) { for (CompoundMark cMark : newCourse) {
//Set start and end colour //Set start and end colour
if (cMark.getId() == sequence.get(0).getCompoundMarkID()) { if (cMark.getId() == sequence.get(0).getCompoundMarkID()) {
@@ -189,26 +198,24 @@ public class GameView extends Pane {
//Create mark dots //Create mark dots
for (Mark mark : cMark.getMarks()) { for (Mark mark : cMark.getMarks()) {
makeAndBindMarker(mark, colour); makeAndBindMarker(mark, colour);
System.out.println("hi" + mark.getName());
} }
//Create gate line //Create gate line
if (cMark.isGate()) { if (cMark.isGate()) {
for (int i = 1; i < cMark.getMarks().size(); i++) { for (int i = 1; i < cMark.getMarks().size(); i++) {
gates.add(
makeAndBindGate( makeAndBindGate(
markerObjects.get(cMark.getSubMark(i)), markerObjects.get(cMark.getSubMark(i)),
markerObjects.get(cMark.getSubMark(i+1)), markerObjects.get(cMark.getSubMark(i+1)),
colour colour
)
); );
} }
} }
colour = Color.BLACK; colour = Color.BLACK;
System.out.println("cMark.toString() = " + cMark.toString());
} }
//Set X,Y co-ordinates //Scale race to markers if there is no border.
if (borderPoints == null) { if (borderPoints == null) {
rescaleRace(new ArrayList<>(markerObjects.keySet())); rescaleRace(new ArrayList<>(markerObjects.keySet()));
} else {
rescaleRace(new ArrayList<>(borderPoints));
} }
//Move the Markers to initial position. //Move the Markers to initial position.
markerObjects.forEach(((mark, marker) -> { markerObjects.forEach(((mark, marker) -> {
@@ -216,7 +223,11 @@ public class GameView extends Pane {
marker.setCenterX(p2d.getX()); marker.setCenterX(p2d.getX());
marker.setCenterY(p2d.getY()); marker.setCenterY(p2d.getY());
})); }));
Platform.runLater(() -> {
markers.getChildren().clear();
markers.getChildren().addAll(gates);
markers.getChildren().addAll(markerObjects.values()); markers.getChildren().addAll(markerObjects.values());
});
} }
/** /**
@@ -241,8 +252,9 @@ public class GameView extends Pane {
* @param m1 The first Mark of the gate. * @param m1 The first Mark of the gate.
* @param m2 The second Mark of the gate. * @param m2 The second Mark of the gate.
* @param colour The desired colour of the gate. * @param colour The desired colour of the gate.
* @return the new gate.
*/ */
private void makeAndBindGate(Marker m1, Marker m2, Paint colour) { private Gate makeAndBindGate(Marker m1, Marker m2, Paint colour) {
Gate gate = new Gate(colour); Gate gate = new Gate(colour);
gate.startXProperty().bind( gate.startXProperty().bind(
m1.centerXProperty() m1.centerXProperty()
@@ -256,7 +268,7 @@ public class GameView extends Pane {
gate.endYProperty().bind( gate.endYProperty().bind(
m2.centerYProperty() m2.centerYProperty()
); );
markers.getChildren().addAll(gate); return gate;
} }
/** /**
@@ -297,20 +309,22 @@ public class GameView extends Pane {
*/ */
public void setBoats(List<Yacht> yachts) { public void setBoats(List<Yacht> yachts) {
BoatObject newBoat; BoatObject newBoat;
final List<Group> wakes = new ArrayList<>();
for (Yacht yacht : yachts) { for (Yacht yacht : yachts) {
Paint colour = Colors.getColor(); Paint colour = Colors.getColor();
newBoat = new BoatObject(); newBoat = new BoatObject();
newBoat.setFill(colour); newBoat.setFill(colour);
boatObjects.put(yacht, newBoat); boatObjects.put(yacht, newBoat);
createAndBindAnnotationBox(yacht, colour); createAndBindAnnotationBox(yacht, colour);
wakesGroup.getChildren().add(newBoat.getWake()); // wakesGroup.getChildren().add(newBoat.getWake());
wakes.add(newBoat.getWake());
boatObjectGroup.getChildren().add(newBoat); boatObjectGroup.getChildren().add(newBoat);
trails.getChildren().add(newBoat.getTrail()); trails.getChildren().add(newBoat.getTrail());
// TODO: 1/08/17 Make this less vile to look at. // TODO: 1/08/17 Make this less vile to look at.
yacht.addLocationListener((boat, lat, lon, heading, velocity) ->{ yacht.addLocationListener((boat, lat, lon, heading, velocity) ->{
BoatObject bo = boatObjects.get(boat); BoatObject bo = boatObjects.get(boat);
Point2D p2d = findScaledXY(lat, lon); Point2D p2d = findScaledXY(lat, lon);
bo.moveTo(p2d.getX(), p2d.getY(), heading); bo.moveTo(p2d.getX(), p2d.getY(), heading, velocity);
// annotations.get(boat).setLayoutX(p2d.getX()); // annotations.get(boat).setLayoutX(p2d.getX());
// annotations.get(boat).setLayoutY(p2d.getY()); // annotations.get(boat).setLayoutY(p2d.getY());
// annotations.get(boat).setLocation(100d, 100d); // annotations.get(boat).setLocation(100d, 100d);
@@ -323,24 +337,14 @@ public class GameView extends Pane {
}); });
} }
annotationsGroup.getChildren().addAll(annotations.values()); annotationsGroup.getChildren().addAll(annotations.values());
Platform.runLater(() -> {
gameObjects.addAll(trails); gameObjects.addAll(trails);
gameObjects.add(wakesGroup); gameObjects.addAll(wakes);
gameObjects.addAll(annotationsGroup); gameObjects.addAll(annotationsGroup);
gameObjects.addAll(boatObjectGroup); gameObjects.addAll(boatObjectGroup);
});
} }
// private void updateBoatObject (Yacht correspondingYacht) {
// BoatObject bo = boatObjects.get(correspondingYacht);
// Point2D p2d = findScaledXY(lat, lon);
// bo.moveTo(p2d.getX(), p2d.getY(), heading);
// annotations.get(boat).moveTo(p2d.getX(), p2d.getY());
// bo.setTrajectory(
// heading,
// velocity,
// metersPerPixelX,
// metersPerPixelY);
// }
private void createAndBindAnnotationBox (Yacht yacht, Paint colour) { private void createAndBindAnnotationBox (Yacht yacht, Paint colour) {
AnnotationBox newAnnotation = new AnnotationBox(); AnnotationBox newAnnotation = new AnnotationBox();
newAnnotation.setFill(colour); newAnnotation.setFill(colour);
@@ -371,8 +375,8 @@ public class GameView extends Pane {
annotations.put(yacht, newAnnotation); annotations.put(yacht, newAnnotation);
} }
private void drawFps(int fps){ private void drawFps(Double fps){
fpsDisplay.setText(String.format("%d FPS", fps)); Platform.runLater(() -> fpsDisplay.setText(String.format("%d FPS", Math.round(fps))));
} }
/** /**
@@ -383,9 +387,6 @@ public class GameView extends Pane {
private void findMinMaxPoint(List<GeoPoint> points) { private void findMinMaxPoint(List<GeoPoint> points) {
List<GeoPoint> sortedPoints = new ArrayList<>(points); List<GeoPoint> sortedPoints = new ArrayList<>(points);
sortedPoints.sort(Comparator.comparingDouble(GeoPoint::getLat)); sortedPoints.sort(Comparator.comparingDouble(GeoPoint::getLat));
for (GeoPoint gp : sortedPoints) {
System.out.println(gp.getLat());
}
minLatPoint = new GeoPoint(sortedPoints.get(0).getLat(), sortedPoints.get(0).getLng()); minLatPoint = new GeoPoint(sortedPoints.get(0).getLat(), sortedPoints.get(0).getLng());
GeoPoint maxLat = sortedPoints.get(sortedPoints.size()-1); GeoPoint maxLat = sortedPoints.get(sortedPoints.size()-1);
maxLatPoint = new GeoPoint(maxLat.getLat(), maxLat.getLng()); maxLatPoint = new GeoPoint(maxLat.getLat(), maxLat.getLng());
@@ -572,5 +573,11 @@ public class GameView extends Pane {
playerYacht.getVelocityProperty(), playerYacht.getVelocityProperty(),
(velocity) -> String.format("Speed: %.2f ms", velocity.doubleValue()) (velocity) -> String.format("Speed: %.2f ms", velocity.doubleValue())
); );
Platform.runLater(() -> {
boatObjectGroup.getChildren().remove(boatObjects.get(playerYacht));
gameObjects.add(boatObjects.get(playerYacht));
annotationsGroup.getChildren().remove(annotations.get(playerYacht));
gameObjects.add(annotations.get(playerYacht));
});
} }
} }
@@ -3,6 +3,7 @@ package seng302.visualiser.controllers;
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 javafx.application.Platform;
import javafx.collections.FXCollections; import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener; import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList; import javafx.collections.ObservableList;
@@ -187,13 +188,12 @@ public class LobbyController {
lobbyListeners.add(listener); lobbyListeners.add(listener);
} }
// TODO: 1/08/17 could definitely do this in a cleaner way.
public void setPlayerListSource (ObservableList<String> players) { public void setPlayerListSource (ObservableList<String> players) {
this.players = players; this.players = players;
players.addListener((ListChangeListener<? super String>) (lcl) -> players.addListener((ListChangeListener<? super String>) (lcl) ->
initialiseListView() Platform.runLater(this::initialiseListView)
); );
initialiseListView(); Platform.runLater(this::initialiseListView);
} }
public void disableReadyButton () { public void disableReadyButton () {
@@ -3,14 +3,14 @@ package seng302.visualiser.controllers;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Comparator; import java.util.Comparator;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline; import javafx.animation.Timeline;
import javafx.application.Platform;
import javafx.collections.FXCollections; import javafx.collections.FXCollections;
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.geometry.Point2D;
@@ -33,7 +33,6 @@ import javafx.scene.shape.Line;
import javafx.scene.text.Text; import javafx.scene.text.Text;
import javafx.stage.Stage; import javafx.stage.Stage;
import javafx.stage.StageStyle; import javafx.stage.StageStyle;
import javafx.util.Duration;
import javafx.util.StringConverter; import javafx.util.StringConverter;
import seng302.model.RaceState; import seng302.model.RaceState;
import seng302.model.Yacht; import seng302.model.Yacht;
@@ -81,7 +80,8 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
private RaceState raceState; private RaceState raceState;
private Timeline timerTimeline; private Timeline timerTimeline;
private HashMap<Integer, Series<String, Double>> sparkLineData = new HashMap<>(); private Timer timer = new Timer();
private List<Series<String, Double>> sparkLineData = new ArrayList<>();
private ImportantAnnotationsState importantAnnotations; private ImportantAnnotationsState importantAnnotations;
public void initialize() { public void initialize() {
@@ -112,9 +112,10 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
initialiseFPSCheckBox(); initialiseFPSCheckBox();
initialiseAnnotationSlider(); initialiseAnnotationSlider();
initialiseBoatSelectionComboBox(); initialiseBoatSelectionComboBox();
initialiseSparkLine();
gameView = new GameView(); gameView = new GameView();
contentAnchorPane.getChildren().add(gameView); Platform.runLater(() -> contentAnchorPane.getChildren().add(gameView));
gameView.setBoats(new ArrayList<>(participants.values())); gameView.setBoats(new ArrayList<>(participants.values()));
gameView.updateBorder(raceData.getCourseLimit()); gameView.updateBorder(raceData.getCourseLimit());
gameView.updateCourse( gameView.updateCourse(
@@ -210,18 +211,15 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
* Used to add any new yachts into the race that may have started late or not have had data received yet * Used to add any new yachts into the race that may have started late or not have had data received yet
*/ */
private void updateSparkLine(){ private void updateSparkLine(){
// TODO: 2/08/17 there is about 0 chance of this working. Once we are keeping track of boat positions it can be fixed.
// Collect the racing yachts that aren't already in the chart // Collect the racing yachts that aren't already in the chart
List<Yacht> sparkLineCandidates = new ArrayList<>(); sparkLineData.clear();
// participants.forEach((id, yacht) ->{ List<Yacht> sparkLineCandidates = new ArrayList<>(participants.values());
// if (!sparkLineData.containsKey(id) && yacht.getPosition() != null && !yacht.getPosition().equals("-"))
// sparkLineCandidates.add(yacht);
// });
participants.forEach((id, yacht) -> sparkLineCandidates.add(yacht));
sparklineYAxis.setUpperBound(participants.size() + 1);
// Create a new data series for new yachts // Create a new data series for new yachts
sparkLineCandidates.stream().filter(yacht -> yacht.getPositionInteger() != null).forEach(yacht -> { sparkLineCandidates
.stream()
.filter(yacht -> yacht.getPositionInteger() != null)
.forEach(yacht -> {
Series<String, Double> yachtData = new Series<>(); Series<String, Double> yachtData = new Series<>();
yachtData.setName(yacht.getSourceId().toString()); yachtData.setName(yacht.getSourceId().toString());
yachtData.getData().add( yachtData.getData().add(
@@ -230,12 +228,11 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
1.0 + participants.size() - yacht.getPositionInteger() 1.0 + participants.size() - yacht.getPositionInteger()
) )
); );
sparkLineData.put(yacht.getSourceId(), yachtData); sparkLineData.add(yachtData);
}); });
// Lambda function to sort the series in order of leg (later legs shown more to the right) // Lambda function to sort the series in order of leg (later legs shown more to the right)
List<XYChart.Series<String, Double>> positions = new ArrayList<>(sparkLineData.values()); sparkLineData.sort((o1, o2) -> {
positions.sort((o1, o2) -> {
Integer leg1 = Integer.parseInt(o1.getData().get(o1.getData().size()-1).getXValue()); Integer leg1 = Integer.parseInt(o1.getData().get(o1.getData().size()-1).getXValue());
Integer leg2 = Integer.parseInt(o2.getData().get(o2.getData().size()-1).getXValue()); Integer leg2 = Integer.parseInt(o2.getData().get(o2.getData().size()-1).getXValue());
if (leg2 < leg1){ if (leg2 < leg1){
@@ -244,26 +241,30 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
return -1; return -1;
} }
}); });
// Adds the new data series to the sparkline (and set the colour of the series) // Adds the new data series to the sparkline (and set the colour of the series)
raceSparkLine.setCreateSymbols(false); Platform.runLater(() -> {
positions sparkLineData
.stream() .stream()
.filter(spark -> !raceSparkLine.getData().contains(spark)) .filter(spark -> !raceSparkLine.getData().contains(spark))
.forEach(spark -> { .forEach(spark -> {
raceSparkLine.getData().add(spark); raceSparkLine.getData().add(spark);
spark.getNode().lookup(".chart-series-line").setStyle("-fx-stroke:" + getBoatColorAsRGB(spark.getName())); spark.getNode().lookup(".chart-series-line").setStyle("-fx-stroke:" + getBoatColorAsRGB(spark.getName()));
}); });
});
} }
private void initialiseSparkLine() {
sparklineYAxis.setUpperBound(participants.size() + 1);
raceSparkLine.setCreateSymbols(false);
}
/** /**
* Updates the yachts sparkline of the desired yacht and using the new leg number * Updates the yachts sparkline of the desired yacht and using the new leg number
* @param yacht The yacht to be updated on the sparkline * @param yacht The yacht to be updated on the sparkline
* @param legNumber the leg number that the position will be assigned to * @param legNumber the leg number that the position will be assigned to
*/ */
public void updateYachtPositionSparkline(Yacht yacht, Integer legNumber){ void updateYachtPositionSparkline(Yacht yacht, Integer legNumber){
for (XYChart.Series<String, Double> positionData : sparkLineData.values()) { for (XYChart.Series<String, Double> positionData : sparkLineData) {
positionData.getData().add( positionData.getData().add(
new Data<>( new Data<>(
Integer.toString(legNumber), Integer.toString(legNumber),
@@ -305,23 +306,16 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
* Updates of each of these attributes are called ONCE EACH SECOND * Updates of each of these attributes are called ONCE EACH SECOND
*/ */
private void initializeUpdateTimer() { private void initializeUpdateTimer() {
timerTimeline = new Timeline(); timer.scheduleAtFixedRate(new TimerTask() {
timerTimeline.setCycleCount(Timeline.INDEFINITE); @Override
// Run timer update every second public void run() {
timerTimeline.getKeyFrames().add(
new KeyFrame(Duration.seconds(1),
event -> {
updateRaceTime(); updateRaceTime();
updateWindDirection(); updateWindDirection();
updateOrder(); updateOrder();
updateBoatSelectionComboBox();
updateSparkLine(); updateSparkLine();
})
);
// Start the timer
timerTimeline.playFromStart();
} }
}, 0, 1000);
}
/** /**
* Iterates over all corners until ones SeqID matches with the yachts current leg number. * Iterates over all corners until ones SeqID matches with the yachts current leg number.
@@ -331,6 +325,7 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
* @return The next Mark or null if none found * @return The next Mark or null if none found
*/ */
private Mark getNextMark(BoatObject bg) { private Mark getNextMark(BoatObject bg) {
// TODO: 1/08/17 Move to GameView
// //
// Integer legNumber = bg.getYacht().getLegNumber(); // Integer legNumber = bg.getYacht().getLegNumber();
// List<Corner> markSequence = courseData.getMarkSequence(); // List<Corner> markSequence = courseData.getMarkSequence();
@@ -346,6 +341,7 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
// return courseData.getCompoundMarks().get(corner.getCompoundMarkID()); // return courseData.getCompoundMarks().get(corner.getCompoundMarkID());
// } // }
// } // }
// return null;
return null; return null;
} }
@@ -376,13 +372,13 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
* section * section
*/ */
private void updateOrder() { private void updateOrder() {
positionVbox.getChildren().clear();
// positionVbox.getChildren().removeAll(); // positionVbox.getChildren().removeAll();
// positionVbox.getStylesheets().add(getClass().getResource("/css/master.css").toString()); // positionVbox.getStylesheets().add(getClass().getResource("/css/master.css").toString());
// list of racing yacht id // list of racing yacht id
List<Yacht> sorted = new ArrayList<>(participants.values()); List<Yacht> sorted = new ArrayList<>(participants.values());
sorted.sort(Comparator.comparingInt(Yacht::getPositionInteger)); sorted.sort(Comparator.comparingInt(Yacht::getPositionInteger));
List<Text> vboxEntries = new ArrayList<>();
for (Yacht yacht : sorted) { for (Yacht yacht : sorted) {
// System.out.println("yacht == null " + String.valueOf(yacht == null)); // System.out.println("yacht == null " + String.valueOf(yacht == null));
@@ -390,17 +386,20 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
Text textToAdd = new Text(yacht.getPositionInteger() + ". " + Text textToAdd = new Text(yacht.getPositionInteger() + ". " +
yacht.getShortName() + " (Finished)"); yacht.getShortName() + " (Finished)");
textToAdd.setFill(Paint.valueOf("#d3d3d3")); textToAdd.setFill(Paint.valueOf("#d3d3d3"));
positionVbox.getChildren().add(textToAdd); vboxEntries.add(textToAdd);
} else { } else {
Text textToAdd = new Text(yacht.getPositionInteger() + ". " + Text textToAdd = new Text(yacht.getPositionInteger() + ". " +
yacht.getShortName() + " "); yacht.getShortName() + " ");
textToAdd.setFill(Paint.valueOf("#d3d3d3")); textToAdd.setFill(Paint.valueOf("#d3d3d3"));
textToAdd.setStyle(""); textToAdd.setStyle("");
positionVbox.getChildren().add(textToAdd); vboxEntries.add(textToAdd);
} }
// System.out.println("finished a loop :))))))))))))"); // System.out.println("finished a loop :))))))))))))");
} }
Platform.runLater(() ->
positionVbox.getChildren().setAll(vboxEntries)
);
// participants.forEach((id, yacht) ->{ // participants.forEach((id, yacht) ->{
// Text textToAdd = new Text(yacht.getPosition() + ". " + // Text textToAdd = new Text(yacht.getPosition() + ". " +
// yacht.getShortName() + " "); // yacht.getShortName() + " ");
@@ -411,7 +410,8 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
} }
// private void updateLaylines(BoatObject bg) { private void updateLaylines(BoatObject bg) {
// TODO: 1/08/17 move to GameView
// //
// Mark nextMark = getNextMark(bg); // Mark nextMark = getNextMark(bg);
// Boolean isUpwind = null; // Boolean isUpwind = null;
@@ -472,7 +472,7 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
// } // }
// } // }
// } // }
// } }
private Point2D getPointRotation(Point2D ref, Double distance, Double angle){ private Point2D getPointRotation(Point2D ref, Double distance, Double angle){
@@ -517,17 +517,6 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
}); });
} }
/**
* Grabs the yachts currently in the race as from the StreamParser and sets them to be selectable
* in the yacht selection combo box
*/
private void updateBoatSelectionComboBox() {
ObservableList<Yacht> observableYachts = FXCollections.observableArrayList();
observableYachts.addAll(participants.values());
yachtSelectionComboBox.setItems(observableYachts);
}
/** /**
* Display the list of yachts in the order they finished the race * Display the list of yachts in the order they finished the race
*/ */
@@ -2,6 +2,7 @@ package seng302.visualiser.fxObjects;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import javafx.application.Platform;
import javafx.beans.value.ObservableValue; import javafx.beans.value.ObservableValue;
import javafx.scene.CacheHint; import javafx.scene.CacheHint;
import javafx.scene.Group; import javafx.scene.Group;
@@ -41,7 +42,7 @@ public class AnnotationBox extends Group{
this.source = source; this.source = source;
this.format = formatter; this.format = formatter;
source.addListener((obs, oldVal, newVal) -> source.addListener((obs, oldVal, newVal) ->
text.setText(format.transformString(newVal)) Platform.runLater(() -> text.setText(format.transformString(newVal)))
); );
} }
@@ -79,6 +80,9 @@ public class AnnotationBox extends Group{
private Map<String, Annotation> annotationsByName = new HashMap<>(); private Map<String, Annotation> annotationsByName = new HashMap<>();
/**
* Creates an empty annotation box. The box is offset from (0,0) by (17, -38).
*/
public AnnotationBox() { public AnnotationBox() {
this.setCache(true); this.setCache(true);
background.setX(BACKGROUND_X); background.setX(BACKGROUND_X);
@@ -95,34 +99,51 @@ public class AnnotationBox extends Group{
this.getChildren().add(background); 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) { public void addAnnotation (String annotationName, Annotation annotation) {
annotationsByName.put(annotationName, annotation); annotationsByName.put(annotationName, annotation);
Platform.runLater(() -> {
this.getChildren().add(annotation.getText()); this.getChildren().add(annotation.getText());
visibleAnnotations++; visibleAnnotations++;
update(); 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) { public void addAnnotation (String annotationName, String annotationText) {
Text text = getTextObject(); Text text = getTextObject();
annotationsByName.put(annotationName, new Annotation(text, annotationText)); addAnnotation(annotationName, new Annotation(text, annotationText));
this.getChildren().add(text);
visibleAnnotations++;
update();
}
public <E> void addAnnotation (String annotationName, ObservableValue<E> observable) {
addAnnotation(annotationName, observable, E::toString);
} }
/**
* 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, public <E> void addAnnotation (String annotationName, ObservableValue<E> observable,
AnnotationFormatter<E> formatter) { AnnotationFormatter<E> formatter) {
Text newText = getTextObject(); Text newText = getTextObject();
annotationsByName.put(annotationName, new Annotation<>(newText, observable, formatter)); addAnnotation(annotationName, new Annotation<>(newText, observable, formatter));
this.getChildren().add(newText);
visibleAnnotations++;
update();
} }
/**
* 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) { public void setAnnotationVisibility (String annotationName, boolean visibility) {
if (annotationsByName.containsKey(annotationName)) { if (annotationsByName.containsKey(annotationName)) {
Text textField = annotationsByName.get(annotationName).text; Text textField = annotationsByName.get(annotationName).text;
@@ -138,68 +159,54 @@ public class AnnotationBox extends Group{
} }
} }
/**
* 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) { public void removeAnnotation (String annotationName) {
if (annotationName.contains(annotationName)) {
Platform.runLater(() -> {
this.getChildren().remove(annotationsByName.remove(annotationName).getText()); this.getChildren().remove(annotationsByName.remove(annotationName).getText());
annotationsByName.remove(annotationName);
visibleAnnotations--; visibleAnnotations--;
update(); update();
});
annotationsByName.remove(annotationName);
}
} }
/**
* Moves the annotation.
* @param x x location
* @param y y location
*/
public void setLocation (double x, double y) { public void setLocation (double x, double y) {
// double dx = x - this.getLayoutX(); Platform.runLater(()-> this.relocate(x + BACKGROUND_X, y + BACKGROUND_Y));
// double dy = y - this.getLayoutY();
// this.relocate(x, y);
//// this.relocate(x, y);
// for (Node n : this.getChildren()) {
// n.relocate(
// n.getLayoutX() + dx,
// n.getLayoutY() + dy
// );
//// n.setLayoutX(n.getLayoutX() + dx);
//// n.setLayoutY(n.getLayoutY() + dy);
// }
// update();
this.relocate(x + BACKGROUND_X, y + BACKGROUND_Y);
// for (int i = 1; i <= visibleAnnotations; i++) {
// Text text = (Text) this.getChildren().get(i);
// if (text.visibleProperty().get()) {
// text.setLayoutX(x + X_OFFSET_TEXT);
// text.setLayoutY(y + Y_OFFSET_TEXT_INIT * Y_OFFSET_PER_TEXT * (i + 1));
// }
// }
// moveTexts(x, y);
// for (Node n : this.getChildren()) {
// n.relocate(x, y);
// }
} }
/**
* Changes the width of the annotation box. Default is 145.
* @param width new width.
*/
public void setWidth (double width) { public void setWidth (double width) {
backgroundWidth = width; backgroundWidth = width;
background.setWidth(backgroundWidth); Platform.runLater(() -> background.setWidth(backgroundWidth));
} }
private void update () { private void update () {
background.setVisible(visibleAnnotations != 0); background.setVisible(visibleAnnotations != 0);
background.setHeight(Math.abs(BACKGROUND_X) + TEXT_BUFFER + BACKGROUND_H_PER_TEXT * visibleAnnotations); background.setHeight(Math.abs(BACKGROUND_X) + TEXT_BUFFER + BACKGROUND_H_PER_TEXT * visibleAnnotations);
// System.out.println("visibleAnnotations = " + visibleAnnotations);
for (int i = 1; i <= visibleAnnotations; i++) { for (int i = 1; i <= visibleAnnotations; i++) {
Text text = (Text) this.getChildren().get(i); Text text = (Text) this.getChildren().get(i);
if (text.visibleProperty().get()) { if (text.visibleProperty().get()) {
// System.out.println("AYY LMAO");
// System.out.println("text.getText() = " + text.getText());
//// System.out
//// .println("text.visibleProperty().get() = " + text.visibleProperty().get());
// System.out.println(text.getLayoutX());
// System.out.println(background.getLayoutX());
text.setX(X_OFFSET_TEXT); text.setX(X_OFFSET_TEXT);
text.setY(Y_OFFSET_TEXT_INIT + Y_OFFSET_PER_TEXT * i); text.setY(Y_OFFSET_TEXT_INIT + Y_OFFSET_PER_TEXT * i);
// });
} }
} }
} }
/** /**
* Return a text object with caching and a color applied * Returns a text object for an annotation.
*
* @return The text object * @return The text object
*/ */
private Text getTextObject() { private Text getTextObject() {
@@ -211,6 +218,10 @@ public class AnnotationBox extends Group{
return text; return text;
} }
/**
* Set the colour of the annotation box's border and text colour.
* @param value desired colour.
*/
public void setFill (Paint value) { public void setFill (Paint value) {
theme = value; theme = value;
background.setStroke(theme); background.setStroke(theme);
@@ -1,13 +1,16 @@
package seng302.visualiser.fxObjects; package seng302.visualiser.fxObjects;
import java.util.ArrayList; import java.util.ArrayList;
import javafx.application.Platform;
import javafx.geometry.Point2D; import javafx.geometry.Point2D;
import javafx.scene.CacheHint; import javafx.scene.CacheHint;
import javafx.scene.Group; import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.paint.Color; import javafx.scene.paint.Color;
import javafx.scene.paint.Paint; import javafx.scene.paint.Paint;
import javafx.scene.shape.Line; import javafx.scene.shape.Line;
import javafx.scene.shape.Polygon; import javafx.scene.shape.Polygon;
import javafx.scene.shape.Polyline;
import javafx.scene.transform.Rotate; import javafx.scene.transform.Rotate;
/** /**
@@ -28,15 +31,16 @@ public class BoatObject extends Group {
private double yVelocity; private double yVelocity;
private double lastHeading; private double lastHeading;
//Graphical objects //Graphical objects
private Group lineGroup = new Group(); private Polyline trail = new Polyline();
private Polygon boatPoly; private Polygon boatPoly;
private Wake wake; private Wake wake;
private Line leftLayLine; private Line leftLayLine;
private Line rightLayline; private Line rightLayline;
private Double distanceTravelled = 0.0; private double distanceTravelled, lastRotation;
private Point2D lastPoint; private Point2D lastPoint;
private Paint colour = Color.BLACK; private Paint colour = Color.BLACK;
private Boolean isSelected = true; //All boats are initialised as selected private Boolean isSelected, destinationSet; //All boats are initialised as selected
private boolean isPlayer = false;
/** /**
* Creates a BoatGroup with the default triangular boat polygon. * Creates a BoatGroup with the default triangular boat polygon.
@@ -55,7 +59,6 @@ public class BoatObject extends Group {
* polygon. * polygon.
*/ */
public BoatObject(double... points) { public BoatObject(double... points) {
this.colour = colour;
initChildren(points); initChildren(points);
} }
@@ -66,7 +69,6 @@ public class BoatObject extends Group {
* polygon. * polygon.
*/ */
private void initChildren(double... points) { private void initChildren(double... points) {
// this.colour = color;
boatPoly = new Polygon(points); boatPoly = new Polygon(points);
boatPoly.setFill(colour); boatPoly.setFill(colour);
boatPoly.setFill(this.colour); boatPoly.setFill(this.colour);
@@ -88,44 +90,54 @@ public class BoatObject extends Group {
leftLayLine = new Line(); leftLayLine = new Line();
rightLayline = new Line(); rightLayline = new Line();
trail.getStrokeDashArray().setAll(5d, 10d);
trail.setCache(true);
wake = new Wake(0, -BOAT_HEIGHT); wake = new Wake(0, -BOAT_HEIGHT);
wake.setVisible(true);
super.getChildren().addAll(boatPoly);//, annotationBox); super.getChildren().addAll(boatPoly);//, annotationBox);
} }
public void setFill (Paint value) { public void setFill (Paint value) {
this.colour = value; this.colour = value;
boatPoly.setFill(colour); boatPoly.setFill(colour);
trail.setStroke(colour);
} }
/**
* Moves the boat and its children annotations from its current coordinates by specified
* amounts.
*
* @param dx The amount to move the X coordinate by
* @param dy The amount to move the Y coordinate by
*/
private void moveGroupBy(double dx, double dy) {
boatPoly.setLayoutX(boatPoly.getLayoutX() + dx);
boatPoly.setLayoutY(boatPoly.getLayoutY() + dy);
wake.setLayoutX(wake.getLayoutX() + dx);
wake.setLayoutY(wake.getLayoutY() + dy);
}
/** /**
* Moves the boat and its children annotations to coordinates specified * Moves the boat and its children annotations to coordinates specified
* *
* @param x The X coordinate to move the boat to * @param x The X coordinate to move the boat to
* @param y The Y coordinate to move the boat to * @param y The Y coordinate to move the boat to
*/ */
public void moveTo(double x, double y, double rotation) { public void moveTo(double x, double y, double rotation, double velocity) {
Double dx = Math.abs(boatPoly.getLayoutX() - x);
Double dy = Math.abs(boatPoly.getLayoutY() - y);
Platform.runLater(() -> {
rotateTo(rotation); rotateTo(rotation);
boatPoly.setLayoutX(x); boatPoly.setLayoutX(x);
boatPoly.setLayoutY(y); boatPoly.setLayoutY(y);
wake.setLayoutX(x); wake.setLayoutX(x);
wake.setLayoutY(y); wake.setLayoutY(y);
wake.rotate(rotation); });
wake.setRotation(rotation, velocity);
// rotateTo(rotation);
// boatPoly.setLayoutX(x);
// boatPoly.setLayoutY(y);
// wake.setLayoutX(x);
// wake.setLayoutY(y);
// wake.rotate(rotation);
// wake.setRotation(rotation, groundSpeed);
// isStopped = false;
// destinationSet = true;
lastRotation = rotation;
distanceTravelled += Math.sqrt((dx * dx) + (dy * dy));
if (distanceTravelled > 15 && isPlayer) {
distanceTravelled = 0d;
Platform.runLater(() -> trail.getPoints().addAll(x, y));
}
} }
private void rotateTo(double rotation) { private void rotateTo(double rotation) {
@@ -133,31 +145,31 @@ public class BoatObject extends Group {
} }
public void updateLocation() { public void updateLocation() {
double dx = xVelocity / 60; // double dx = xVelocity / 60;
double dy = yVelocity / 60; // double dy = yVelocity / 60;
//
distanceTravelled += Math.abs(dx) + Math.abs(dy); // distanceTravelled += Math.abs(dx) + Math.abs(dy);
moveGroupBy(dx, dy); // moveGroupBy(dx, dy);
//
if (distanceTravelled > 70) { // if (distanceTravelled > 70) {
distanceTravelled = 0d; // distanceTravelled = 0d;
//
if (lastPoint != null) { // if (lastPoint != null) {
Line l = new Line( // Line l = new Line(
lastPoint.getX(), // lastPoint.getX(),
lastPoint.getY(), // lastPoint.getY(),
boatPoly.getLayoutX(), // boatPoly.getLayoutX(),
boatPoly.getLayoutY() // boatPoly.getLayoutY()
); // );
l.getStrokeDashArray().setAll(3d, 7d); // l.getStrokeDashArray().setAll(3d, 7d);
l.setStroke(colour); // l.setStroke(colour);
l.setCache(true); // l.setCache(true);
l.setCacheHint(CacheHint.SPEED); // l.setCacheHint(CacheHint.SPEED);
lineGroup.getChildren().add(l); // lineGroup.getChildren().add(l);
} // }
lastPoint = new Point2D(boatPoly.getLayoutX(), boatPoly.getLayoutY()); // lastPoint = new Point2D(boatPoly.getLayoutX(), boatPoly.getLayoutY());
} // }
wake.updatePosition(); // wake.updatePosition();
} }
// /** // /**
@@ -203,16 +215,16 @@ public class BoatObject extends Group {
public void setVisibility (boolean teamName, boolean velocity, boolean estTime, boolean legTime, public void setVisibility (boolean teamName, boolean velocity, boolean estTime, boolean legTime,
boolean trail, boolean wake) { boolean trail, boolean wake) {
// boatAnnotations.setVisible(teamName, velocity, estTime, legTime); // boatAnnotations.setVisible(teamName, velocity, estTime, legTime);
this.wake.setVisible(wake); // this.wake.setVisible(wake);
this.lineGroup.setVisible(trail); this.trail.setVisible(trail);
} }
public void setLineGroupVisible(Boolean visible) { public void setLineGroupVisible(Boolean visible) {
lineGroup.setVisible(visible); trail.setVisible(visible);
} }
public void setWakeVisible(Boolean visible) { public void setWakeVisible(Boolean visible) {
wake.setVisible(visible); // wake.setVisible(visible);
} }
public void setLayLinesVisible(Boolean visible) { public void setLayLinesVisible(Boolean visible) {
@@ -236,8 +248,8 @@ public class BoatObject extends Group {
return wake; return wake;
} }
public Group getTrail() { public Node getTrail() {
return lineGroup; return trail;
} }
public Double getBoatLayoutX() { public Double getBoatLayoutX() {
@@ -260,6 +272,7 @@ public class BoatObject extends Group {
); );
boatPoly.setStroke(Color.BLACK); boatPoly.setStroke(Color.BLACK);
boatPoly.setStrokeWidth(3); boatPoly.setStrokeWidth(3);
isPlayer = true;
} }
public void setTrajectory(double heading, double velocity) { public void setTrajectory(double heading, double velocity) {
@@ -1,5 +1,6 @@
package seng302.visualiser.fxObjects; package seng302.visualiser.fxObjects;
import javafx.application.Platform;
import javafx.scene.CacheHint; import javafx.scene.CacheHint;
import javafx.scene.Group; import javafx.scene.Group;
import javafx.scene.paint.Color; import javafx.scene.paint.Color;
@@ -41,7 +42,11 @@ public class Wake extends Group {
arc.setCache(true); arc.setCache(true);
arc.setCacheHint(CacheHint.ROTATE); arc.setCacheHint(CacheHint.ROTATE);
arc.setType(ArcType.OPEN); arc.setType(ArcType.OPEN);
arc.setStroke(new Color(0.18, 0.7, 1.0, 1.0 + (-0.99 / numWakes * i))); arc.setStroke(
new Color(
0.18, 0.7, 1.0, 1.0 + (-0.99 / numWakes * i)
)
);
arc.setStrokeWidth(3.0); arc.setStrokeWidth(3.0);
arc.setStrokeLineCap(StrokeLineCap.ROUND); arc.setStrokeLineCap(StrokeLineCap.ROUND);
arc.setFill(new Color(0.0, 0.0, 0.0, 0.0)); arc.setFill(new Color(0.0, 0.0, 0.0, 0.0));
@@ -55,7 +60,15 @@ public class Wake extends Group {
void setRotation (double rotation, double velocity) { void setRotation (double rotation, double velocity) {
// if (Math.abs(rotations[0] - rotation) > 20) { // if (Math.abs(rotations[0] - rotation) > 20) {
Platform.runLater(() -> {
rotate(rotation); rotate(rotation);
double rad = (14 / numWakes) + velocity;
for (Arc arc : arcs) {
arc.setRadiusX(rad);
arc.setRadiusY(rad);
rad += (14 / numWakes) + (velocity / 2.5);
}
});
// } else { // } else {
// rotations[0] = rotation; // rotations[0] = rotation;
// ((Rotate) arcs[0].getTransforms().get(0)).setAngle(rotation); // ((Rotate) arcs[0].getTransforms().get(0)).setAngle(rotation);
@@ -78,12 +91,12 @@ public class Wake extends Group {
// } // }
// } // }
double rad = (14 / numWakes) + velocity; // double rad = (14 / numWakes) + velocity;
for (Arc arc : arcs) { // for (Arc arc : arcs) {
arc.setRadiusX(rad); // arc.setRadiusX(rad);
arc.setRadiusY(rad); // arc.setRadiusY(rad);
rad += (14 / numWakes) + (velocity / 2.5); // rad += (14 / numWakes) + (velocity / 2.5);
} // }
} }
/** /**
@@ -1,9 +1,9 @@
package seng302.server; package seng302.gameServer.server;
import static junit.framework.TestCase.assertEquals; import static junit.framework.TestCase.assertEquals;
import org.junit.Test; import org.junit.Test;
import seng302.server.messages.BoatLocationMessage; import seng302.gameServer.server.messages.BoatLocationMessage;
/** /**
* Test conversions used by the boat location messages * Test conversions used by the boat location messages
@@ -1,10 +1,10 @@
package seng302.server; package seng302.gameServer.server;
import static junit.framework.TestCase.assertTrue; import static junit.framework.TestCase.assertTrue;
import org.junit.Test; import org.junit.Test;
import seng302.server.messages.Header; import seng302.gameServer.server.messages.Header;
import seng302.server.messages.MessageType; import seng302.gameServer.server.messages.MessageType;
/** /**
* Tests message header * Tests message header
@@ -1,12 +1,12 @@
package seng302.server; package seng302.gameServer.server;
import static junit.framework.TestCase.assertEquals; import static junit.framework.TestCase.assertEquals;
import static junit.framework.TestCase.assertTrue; import static junit.framework.TestCase.assertTrue;
import org.junit.Test; import org.junit.Test;
import seng302.server.messages.Message; import seng302.gameServer.server.messages.Message;
import seng302.server.messages.XMLMessage; import seng302.gameServer.server.messages.XMLMessage;
import seng302.server.messages.XMLMessageSubType; import seng302.gameServer.server.messages.XMLMessageSubType;
public class TestMessage { public class TestMessage {
private static int XML_MESSAGE_LEN = 14; private static int XML_MESSAGE_LEN = 14;
@@ -1,4 +1,4 @@
package seng302.server.simulator; package seng302.gameServer.server.simulator;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;