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/model/ClientYacht.java # src/main/java/seng302/visualiser/GameView.java # src/test/java/seng302/visualiser/map/BoatSailAnimationToggleTest.java # src/test/java/steps/ToggleSailSteps.java
This commit is contained in:
@@ -180,3 +180,7 @@ local.properties
|
||||
.recommenders/
|
||||
|
||||
Makefile
|
||||
|
||||
infer-out/
|
||||
infer.txt
|
||||
log.log
|
||||
@@ -1,9 +1,11 @@
|
||||
package seng302.gameServer;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import seng302.gameServer.server.messages.BoatAction;
|
||||
@@ -12,6 +14,7 @@ import seng302.gameServer.server.messages.MarkRoundingMessage;
|
||||
import seng302.gameServer.server.messages.MarkType;
|
||||
import seng302.gameServer.server.messages.Message;
|
||||
import seng302.gameServer.server.messages.RoundingBoatStatus;
|
||||
import seng302.gameServer.server.messages.YachtEventCodeMessage;
|
||||
import seng302.model.GeoPoint;
|
||||
import seng302.model.Player;
|
||||
import seng302.model.PolarTable;
|
||||
@@ -29,8 +32,8 @@ import seng302.utilities.GeoUtility;
|
||||
public class GameState implements Runnable {
|
||||
|
||||
@FunctionalInterface
|
||||
interface MarkPassingListener {
|
||||
void markPassing(Message message);
|
||||
interface NewMessageListener {
|
||||
void notify(Message message);
|
||||
}
|
||||
|
||||
private Logger logger = LoggerFactory.getLogger(GameState.class);
|
||||
@@ -38,6 +41,11 @@ public class GameState implements Runnable {
|
||||
private static final Integer STATE_UPDATES_PER_SECOND = 60;
|
||||
public static Integer MAX_PLAYERS = 8;
|
||||
public static Double ROUNDING_DISTANCE = 50d; // TODO: 14/08/17 wmu16 - Look into this value further
|
||||
public static final Double MARK_COLLISION_DISTANCE = 15d;
|
||||
public static final Double YACHT_COLLISION_DISTANCE = 25.0;
|
||||
public static final Double BOUNCE_DISTANCE_MARK = 20.0;
|
||||
public static final Double BOUNCE_DISTANCE_YACHT = 30.0;
|
||||
public static final Double COLLISION_VELOCITY_PENALTY = 0.3;
|
||||
|
||||
private static Long previousUpdateTime;
|
||||
public static Double windDirection;
|
||||
@@ -50,8 +58,9 @@ public class GameState implements Runnable {
|
||||
private static GameStages currentStage;
|
||||
private static MarkOrder markOrder;
|
||||
private static long startTime;
|
||||
private static Set<Mark> marks;
|
||||
|
||||
private static List<MarkPassingListener> markListeners;
|
||||
private static List<NewMessageListener> markListeners;
|
||||
|
||||
private static Map<Player, String> playerStringMap = new HashMap<>();
|
||||
/*
|
||||
@@ -81,12 +90,18 @@ public class GameState implements Runnable {
|
||||
markListeners = new ArrayList<>();
|
||||
|
||||
new Thread(this).start(); //Run the auto updates on the game state
|
||||
|
||||
marks = new MarkOrder().getAllMarks();
|
||||
}
|
||||
|
||||
public static String getHostIpAddress() {
|
||||
return hostIpAddress;
|
||||
}
|
||||
|
||||
public static Set<Mark> getMarks(){
|
||||
return Collections.unmodifiableSet(marks);
|
||||
}
|
||||
|
||||
public static List<Player> getPlayers() {
|
||||
return players;
|
||||
}
|
||||
@@ -120,7 +135,7 @@ public class GameState implements Runnable {
|
||||
}
|
||||
|
||||
public static void setCurrentStage(GameStages currentStage) {
|
||||
if (currentStage == GameStages.RACING){
|
||||
if (currentStage == GameStages.RACING) {
|
||||
startTime = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
@@ -221,12 +236,49 @@ public class GameState implements Runnable {
|
||||
yacht.runAutoPilot();
|
||||
yacht.updateLocation(timeInterval);
|
||||
if (!yacht.getFinishedRace()) {
|
||||
checkForCollision(yacht);
|
||||
checkForLegProgression(yacht);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static void checkForCollision(ServerYacht serverYacht) {
|
||||
ServerYacht collidedYacht = checkCollision(serverYacht);
|
||||
if (collidedYacht != null) {
|
||||
GeoPoint originalLocation = serverYacht.getLocation();
|
||||
serverYacht.setLocation(
|
||||
calculateBounceBack(serverYacht, originalLocation, BOUNCE_DISTANCE_YACHT)
|
||||
);
|
||||
serverYacht.setCurrentVelocity(
|
||||
serverYacht.getCurrentVelocity() * COLLISION_VELOCITY_PENALTY
|
||||
);
|
||||
collidedYacht.setLocation(
|
||||
calculateBounceBack(collidedYacht, originalLocation, BOUNCE_DISTANCE_YACHT)
|
||||
);
|
||||
collidedYacht.setCurrentVelocity(
|
||||
collidedYacht.getCurrentVelocity() * COLLISION_VELOCITY_PENALTY
|
||||
);
|
||||
notifyMessageListeners(
|
||||
new YachtEventCodeMessage(serverYacht.getSourceId())
|
||||
);
|
||||
} else {
|
||||
Mark collidedMark = markCollidedWith(serverYacht);
|
||||
if (collidedMark != null) {
|
||||
serverYacht.setLocation(
|
||||
calculateBounceBack(serverYacht, collidedMark, BOUNCE_DISTANCE_MARK)
|
||||
);
|
||||
serverYacht.setCurrentVelocity(
|
||||
serverYacht.getCurrentVelocity() * COLLISION_VELOCITY_PENALTY
|
||||
);
|
||||
notifyMessageListeners(
|
||||
new YachtEventCodeMessage(serverYacht.getSourceId())
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void updateVelocity(ServerYacht yacht) {
|
||||
Double velocity = yacht.getCurrentVelocity();
|
||||
Double trueWindAngle = Math.abs(windDirection - yacht.getHeading());
|
||||
@@ -235,7 +287,7 @@ public class GameState implements Runnable {
|
||||
// TODO: 15/08/17 remove magic numbers from these equations.
|
||||
if (yacht.getSailIn()) {
|
||||
if (velocity < maxBoatSpeed - 500) {
|
||||
yacht.changeVelocity(maxBoatSpeed / 150);
|
||||
yacht.changeVelocity(maxBoatSpeed / 100);
|
||||
} else if (velocity > maxBoatSpeed + 500) {
|
||||
yacht.changeVelocity(-maxBoatSpeed / 100);
|
||||
} else {
|
||||
@@ -317,6 +369,7 @@ public class GameState implements Runnable {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* If we pass the start line gate in the correct direction, progress
|
||||
*
|
||||
@@ -449,6 +502,50 @@ public class GameState implements Runnable {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
private static Mark markCollidedWith(ServerYacht yacht) {
|
||||
Set<Mark> marksInRace = GameState.getMarks();
|
||||
for (Mark mark : marksInRace) {
|
||||
if (GeoUtility.getDistance(yacht.getLocation(), mark)
|
||||
<= MARK_COLLISION_DISTANCE) {
|
||||
return mark;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the new position of the boat after it has had a collision
|
||||
*
|
||||
* @return The boats new position
|
||||
*/
|
||||
private static GeoPoint calculateBounceBack(ServerYacht yacht, GeoPoint collidedWith, Double bounceDistance) {
|
||||
Double heading = GeoUtility.getBearing(yacht.getLocation(), collidedWith);
|
||||
// Invert heading
|
||||
heading -= 180;
|
||||
Integer newHeading = Math.floorMod(heading.intValue(), 360);
|
||||
return GeoUtility.getGeoCoordinate(yacht.getLocation(), newHeading.doubleValue(), bounceDistance);
|
||||
}
|
||||
|
||||
/**
|
||||
* Collision detection which iterates through all the yachts and check if any yacht collided
|
||||
* with this yacht. Return collided yacht or null if no collision.
|
||||
*
|
||||
* @return yacht to compare to all other yachts.
|
||||
*/
|
||||
private static ServerYacht checkCollision(ServerYacht yacht) {
|
||||
|
||||
for (ServerYacht otherYacht : GameState.getYachts().values()) {
|
||||
if (otherYacht != yacht) {
|
||||
Double distance = GeoUtility.getDistance(otherYacht.getLocation(), yacht.getLocation());
|
||||
if (distance < YACHT_COLLISION_DISTANCE) {
|
||||
return otherYacht;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void sendMarkRoundingMessage(ServerYacht yacht) {
|
||||
Integer sourceID = yacht.getSourceId();
|
||||
Integer currentMarkSeqID = yacht.getCurrentMarkSeqID();
|
||||
@@ -461,11 +558,14 @@ public class GameState implements Runnable {
|
||||
sourceID, RoundingBoatStatus.RACING, roundingMark.getRoundingSide(), markType,
|
||||
roundingMark.getSourceID());
|
||||
|
||||
for (MarkPassingListener mpl : markListeners) {
|
||||
mpl.markPassing(markRoundingMessage);
|
||||
}
|
||||
notifyMessageListeners(markRoundingMessage);
|
||||
}
|
||||
|
||||
private static void notifyMessageListeners(Message message) {
|
||||
for (NewMessageListener mpl : markListeners) {
|
||||
mpl.notify(message);
|
||||
}
|
||||
}
|
||||
|
||||
private void logMarkRounding(ServerYacht yacht) {
|
||||
Mark roundingMark = yacht.getClosestCurrentMark();
|
||||
@@ -475,7 +575,7 @@ public class GameState implements Runnable {
|
||||
}
|
||||
|
||||
|
||||
public static void addMarkPassListener(MarkPassingListener listener) {
|
||||
public static void addMarkPassListener(NewMessageListener listener) {
|
||||
markListeners.add(listener);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,18 +4,22 @@ import java.io.IOException;
|
||||
import java.net.ServerSocket;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Observable;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
import seng302.gameServer.server.messages.Message;
|
||||
import seng302.model.GeoPoint;
|
||||
import seng302.model.Player;
|
||||
import seng302.model.PolarTable;
|
||||
import seng302.model.ServerYacht;
|
||||
import seng302.model.mark.CompoundMark;
|
||||
import seng302.utilities.GeoUtility;
|
||||
import seng302.visualiser.GameClient;
|
||||
|
||||
/**
|
||||
* A class describing the overall server, which creates and collects server threads for each client
|
||||
* Created by wmu16 on 13/07/17.
|
||||
*/
|
||||
public class MainServerThread extends Observable implements Runnable, ClientConnectionDelegate{
|
||||
public class MainServerThread implements Runnable, ClientConnectionDelegate {
|
||||
|
||||
private static final int PORT = 4942;
|
||||
private static final Integer CLIENT_UPDATES_PER_SECOND = 10;
|
||||
@@ -27,6 +31,8 @@ public class MainServerThread extends Observable implements Runnable, ClientConn
|
||||
private ServerSocket serverSocket = null;
|
||||
private ArrayList<ServerToClientThread> serverToClientThreads = new ArrayList<>();
|
||||
|
||||
private GameClient gameClient;
|
||||
|
||||
public MainServerThread() {
|
||||
new GameState("localhost");
|
||||
try {
|
||||
@@ -47,7 +53,6 @@ public class MainServerThread extends Observable implements Runnable, ClientConn
|
||||
HeartbeatThread heartbeatThread;
|
||||
|
||||
serverListenThread = new ServerListenThread(serverSocket, this);
|
||||
|
||||
heartbeatThread = new HeartbeatThread(this);
|
||||
|
||||
heartbeatThread.start();
|
||||
@@ -98,14 +103,16 @@ public class MainServerThread extends Observable implements Runnable, ClientConn
|
||||
}
|
||||
|
||||
|
||||
static void serverLog(String message, int logLevel){
|
||||
if(logLevel <= LOG_LEVEL){
|
||||
System.out.println("[SERVER " + LocalDateTime.now().toLocalTime().toString() + "] " + message);
|
||||
static void serverLog(String message, int logLevel) {
|
||||
if (logLevel <= LOG_LEVEL) {
|
||||
System.out.println(
|
||||
"[SERVER " + LocalDateTime.now().toLocalTime().toString() + "] " + message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A client has tried to connect to the server
|
||||
*
|
||||
* @param serverToClientThread The player that connected
|
||||
*/
|
||||
@Override
|
||||
@@ -121,6 +128,7 @@ public class MainServerThread extends Observable implements Runnable, ClientConn
|
||||
|
||||
/**
|
||||
* A player has left the game, remove the player from the GameState
|
||||
*
|
||||
* @param player The player that left
|
||||
*/
|
||||
@Override
|
||||
@@ -142,11 +150,10 @@ public class MainServerThread extends Observable implements Runnable, ClientConn
|
||||
}
|
||||
}
|
||||
serverToClientThreads.remove(closedConnection);
|
||||
setChanged();
|
||||
notifyObservers();
|
||||
}
|
||||
|
||||
public void startGame() {
|
||||
initialiseBoatPositions();
|
||||
Timer t = new Timer();
|
||||
|
||||
t.schedule(new TimerTask() {
|
||||
@@ -163,4 +170,56 @@ public class MainServerThread extends Observable implements Runnable, ClientConn
|
||||
public void terminate() {
|
||||
terminated = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pass GameClient to main server thread so it can access the properties inside.
|
||||
*
|
||||
* @param gameClient gameClient
|
||||
*/
|
||||
public void setGameClient(GameClient gameClient) {
|
||||
this.gameClient = gameClient;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialise boats to specific spaced out geopoints behind starting line.
|
||||
*/
|
||||
private void initialiseBoatPositions() {
|
||||
// Getting the start line compound marks
|
||||
CompoundMark cm = gameClient.getCourseData().getCompoundMarks().get(1);
|
||||
GeoPoint startMark1 = new GeoPoint(cm.getMarks().get(0).getLat(),
|
||||
cm.getMarks().get(0).getLng());
|
||||
GeoPoint startMark2 = new GeoPoint(cm.getMarks().get(1).getLat(),
|
||||
cm.getMarks().get(1).getLng());
|
||||
|
||||
// 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
|
||||
double DISTANCE_FACTOR = 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 * DISTANCE_FACTOR);
|
||||
|
||||
if (yacht.getHeading() < perpendicularAngle) {
|
||||
spawnMark = GeoUtility
|
||||
.getGeoCoordinate(spawnMark, perpendicularAngle + 90, DISTANCE_FACTOR);
|
||||
} else {
|
||||
spawnMark = GeoUtility
|
||||
.getGeoCoordinate(spawnMark, perpendicularAngle + 270, DISTANCE_FACTOR);
|
||||
}
|
||||
|
||||
yacht.setLocation(spawnMark);
|
||||
boatIndex++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,9 +19,15 @@ import java.util.zip.CRC32;
|
||||
import java.util.zip.Checksum;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import seng302.gameServer.server.messages.YachtEventCodeMessage;
|
||||
import seng302.model.Player;
|
||||
import seng302.model.stream.packets.PacketType;
|
||||
import seng302.model.stream.packets.StreamPacket;
|
||||
import seng302.model.stream.xml.generator.Race;
|
||||
import seng302.model.stream.xml.generator.Regatta;
|
||||
import seng302.utilities.XMLGenerator;
|
||||
import seng302.gameServer.server.messages.BoatAction;
|
||||
import seng302.gameServer.server.messages.BoatLocationMessage;
|
||||
import seng302.gameServer.server.messages.BoatStatus;
|
||||
import seng302.gameServer.server.messages.BoatSubMessage;
|
||||
import seng302.gameServer.server.messages.ClientType;
|
||||
import seng302.gameServer.server.messages.Message;
|
||||
@@ -32,13 +38,7 @@ import seng302.gameServer.server.messages.RegistrationResponseMessage;
|
||||
import seng302.gameServer.server.messages.RegistrationResponseStatus;
|
||||
import seng302.gameServer.server.messages.XMLMessage;
|
||||
import seng302.gameServer.server.messages.XMLMessageSubType;
|
||||
import seng302.model.Player;
|
||||
import seng302.model.ServerYacht;
|
||||
import seng302.model.stream.packets.PacketType;
|
||||
import seng302.model.stream.packets.StreamPacket;
|
||||
import seng302.model.stream.xml.generator.Race;
|
||||
import seng302.model.stream.xml.generator.Regatta;
|
||||
import seng302.utilities.XMLGenerator;
|
||||
|
||||
/**
|
||||
* A class describing a single connection to a Client for the purposes of sending and receiving on
|
||||
@@ -75,6 +75,8 @@ public class ServerToClientThread implements Runnable, Observer {
|
||||
|
||||
private List<ConnectionListener> connectionListeners = new ArrayList<>();
|
||||
|
||||
private ServerYacht yacht;
|
||||
|
||||
public ServerToClientThread(Socket socket) {
|
||||
this.socket = socket;
|
||||
seqNo = 0;
|
||||
@@ -167,7 +169,6 @@ public class ServerToClientThread implements Runnable, Observer {
|
||||
int sync2;
|
||||
// TODO: 14/07/17 wmu16 - Work out how to fix this while loop
|
||||
|
||||
|
||||
while (socket.isConnected()) {
|
||||
|
||||
try {
|
||||
@@ -346,6 +347,14 @@ public class ServerToClientThread implements Runnable, Observer {
|
||||
return socket;
|
||||
}
|
||||
|
||||
public ServerYacht getYacht() {
|
||||
return yacht;
|
||||
}
|
||||
|
||||
public void sendCollisionMessage(Integer yachtId) {
|
||||
sendMessage(new YachtEventCodeMessage(yachtId));
|
||||
}
|
||||
|
||||
public void addConnectionListener(ConnectionListener listener) {
|
||||
connectionListeners.add(listener);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
package seng302.gameServer.server.messages;
|
||||
|
||||
/**
|
||||
* Created by zyt10 on 10/08/17.
|
||||
*/
|
||||
public class YachtEventCodeMessage extends Message {
|
||||
|
||||
private final MessageType MESSAGE_TYPE = MessageType.YACHT_EVENT_CODE;
|
||||
private final int MESSAGE_VERSION = 1; //Always set to 1
|
||||
private final int MESSAGE_SIZE = 22;
|
||||
|
||||
// Message fields
|
||||
private long timeStamp;
|
||||
private long ack = 0x00; //Unused
|
||||
private int raceId;
|
||||
private int destSourceId;
|
||||
private int incidentId;
|
||||
private int eventId;
|
||||
|
||||
|
||||
public YachtEventCodeMessage(Integer subjectId) {
|
||||
timeStamp = System.currentTimeMillis() / 1000L;
|
||||
ack = 0;
|
||||
raceId = 1;
|
||||
destSourceId = subjectId; // collision boat source id
|
||||
incidentId = 0;
|
||||
eventId = 33;
|
||||
|
||||
setHeader(new Header(MESSAGE_TYPE, 0x01, (short) getSize()));
|
||||
allocateBuffer();
|
||||
writeHeaderToBuffer();
|
||||
|
||||
// Write message fields
|
||||
putUnsignedByte((byte) MESSAGE_VERSION);
|
||||
putInt((int) timeStamp, 6);
|
||||
putInt((int) ack, 2);
|
||||
putInt((int) raceId, 4);
|
||||
putInt((int) destSourceId, 4);
|
||||
putInt((int) incidentId, 4);
|
||||
putInt((int) eventId, 1);
|
||||
|
||||
writeCRC();
|
||||
rewind();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The length of this message
|
||||
*/
|
||||
public int getSize() {
|
||||
return MESSAGE_SIZE;
|
||||
}
|
||||
}
|
||||
@@ -3,8 +3,9 @@ package seng302.model;
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Observable;
|
||||
import java.util.Observer;
|
||||
import javafx.beans.property.ReadOnlyDoubleProperty;
|
||||
import javafx.beans.property.ReadOnlyDoubleWrapper;
|
||||
import javafx.beans.property.ReadOnlyLongProperty;
|
||||
@@ -12,31 +13,23 @@ import javafx.beans.property.ReadOnlyLongWrapper;
|
||||
import javafx.scene.paint.Color;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import seng302.gameServer.GameState;
|
||||
import seng302.model.mark.CompoundMark;
|
||||
import seng302.model.mark.Mark;
|
||||
import seng302.utilities.GeoUtility;
|
||||
|
||||
/**
|
||||
* Yacht class for the racing boat.
|
||||
*
|
||||
* Class created to store more variables (eg. boat statuses) compared to the XMLParser boat class,
|
||||
* also done outside Boat class because some old variables are not used anymore.
|
||||
* Yacht class for the racing boat. <p> Class created to store more variables (eg. boat statuses)
|
||||
* compared to the XMLParser boat class, also done outside Boat class because some old variables are
|
||||
* not used anymore.
|
||||
*/
|
||||
public class ClientYacht {
|
||||
|
||||
public class ClientYacht extends Observable {
|
||||
|
||||
@FunctionalInterface
|
||||
public interface YachtLocationListener {
|
||||
|
||||
void notifyLocation(ClientYacht yacht, double lat, double lon, double heading,
|
||||
double velocity, boolean sailIn);
|
||||
void notifyLocation(ClientYacht clientYacht, double lat, double lon, double heading,
|
||||
Boolean sailsIn, double velocity);
|
||||
}
|
||||
|
||||
private Logger logger = LoggerFactory.getLogger(ClientYacht.class);
|
||||
|
||||
private static final Double ROUNDING_DISTANCE = 50d; // TODO: 3/08/17 wmu16 - Look into this value further
|
||||
|
||||
|
||||
//BOTH AFAIK
|
||||
private String boatType;
|
||||
@@ -47,29 +40,15 @@ public class ClientYacht {
|
||||
private String country;
|
||||
|
||||
private Long estimateTimeAtFinish;
|
||||
private Boolean sailIn = false;
|
||||
private Integer currentMarkSeqID = 0;
|
||||
private Long markRoundTime;
|
||||
private Double distanceToCurrentMark;
|
||||
private Long timeTillNext;
|
||||
private Double heading;
|
||||
private Integer legNumber = 0;
|
||||
|
||||
//SERVER SIDE
|
||||
public static final Double TURN_STEP = 5.0; //This should be in some utils class somewhere 2bh. Public for tests sake.
|
||||
private Double lastHeading;
|
||||
private Boolean sailIn = false;
|
||||
private GeoPoint location;
|
||||
private Integer boatStatus;
|
||||
private Double velocity;
|
||||
private Boolean isAuto;
|
||||
private Double autoHeading;
|
||||
|
||||
//MARK ROUNDING INFO
|
||||
private GeoPoint lastLocation; //For purposes of mark rounding calculations
|
||||
private Boolean hasEnteredRoundingZone; //The distance that the boat must be from the mark to round
|
||||
private Boolean hasPassedLine;
|
||||
private Boolean hasPassedThroughGate;
|
||||
private Boolean finishedRace;
|
||||
private Double currentVelocity;
|
||||
|
||||
//CLIENT SIDE
|
||||
private List<YachtLocationListener> locationListeners = new ArrayList<>();
|
||||
@@ -79,7 +58,6 @@ public class ClientYacht {
|
||||
private CompoundMark lastMarkRounded;
|
||||
private Integer positionInt = 0;
|
||||
private Color colour;
|
||||
private Boolean clientSailsIn = true;
|
||||
|
||||
public ClientYacht(String boatType, Integer sourceId, String hullID, String shortName,
|
||||
String boatName, String country) {
|
||||
@@ -89,389 +67,19 @@ public class ClientYacht {
|
||||
this.shortName = shortName;
|
||||
this.boatName = boatName;
|
||||
this.country = country;
|
||||
this.sailIn = false;
|
||||
this.isAuto = false;
|
||||
this.location = new GeoPoint(57.670341, 11.826856);
|
||||
this.lastLocation = location;
|
||||
this.heading = 120.0; //In degrees
|
||||
this.velocity = 0d; //in mms-1
|
||||
|
||||
this.hasEnteredRoundingZone = false;
|
||||
this.hasPassedLine = false;
|
||||
this.hasPassedThroughGate = false;
|
||||
this.finishedRace = false;
|
||||
this.currentVelocity = 0d;
|
||||
this.boatStatus = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param timeInterval since last update in milliseconds
|
||||
* Add ServerToClientThread as the observer, this observer pattern mainly server for the boat
|
||||
* rounding package.
|
||||
*/
|
||||
public void update(Long timeInterval) {
|
||||
|
||||
Double secondsElapsed = timeInterval / 1000000.0;
|
||||
Double windSpeedKnots = GameState.getWindSpeedKnots();
|
||||
Double trueWindAngle = Math.abs(GameState.getWindDirection() - heading);
|
||||
Double boatSpeedInKnots = PolarTable.getBoatSpeed(windSpeedKnots, trueWindAngle);
|
||||
Double maxBoatSpeed = boatSpeedInKnots / 1.943844492 * 1000;
|
||||
if (sailIn && velocity <= maxBoatSpeed && maxBoatSpeed != 0d) {
|
||||
|
||||
if (velocity < maxBoatSpeed) {
|
||||
velocity += maxBoatSpeed / 15; // Acceleration
|
||||
}
|
||||
if (velocity > maxBoatSpeed) {
|
||||
velocity = maxBoatSpeed; // Prevent the boats from exceeding top speed
|
||||
}
|
||||
|
||||
} else { // Deceleration
|
||||
|
||||
if (velocity > 0d) {
|
||||
if (maxBoatSpeed != 0d) {
|
||||
velocity -= maxBoatSpeed / 600;
|
||||
} else {
|
||||
velocity -= velocity / 100;
|
||||
}
|
||||
if (velocity < 0) {
|
||||
velocity = 0d;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
runAutoPilot();
|
||||
|
||||
//UPDATE BOAT LOCATION
|
||||
lastLocation = location;
|
||||
location = GeoUtility.getGeoCoordinate(location, heading, velocity * secondsElapsed);
|
||||
|
||||
//CHECK FOR MARK ROUNDING
|
||||
if (!finishedRace) {
|
||||
checkForLegProgression();
|
||||
}
|
||||
|
||||
// TODO: 3/08/17 wmu16 - Implement line cross check here
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Calculates the distance to the next mark (closest of the two if a gate mark). For purposes
|
||||
* of mark rounding
|
||||
*
|
||||
* @return A distance in metres. Returns -1 if there is no next mark
|
||||
* @throws IndexOutOfBoundsException If the next mark is null (ie the last mark in the race)
|
||||
* Check first using {@link seng302.model.mark.MarkOrder#isLastMark(Integer)}
|
||||
*/
|
||||
public Double calcDistanceToCurrentMark() throws IndexOutOfBoundsException {
|
||||
CompoundMark nextMark = GameState.getMarkOrder().getCurrentMark(currentMarkSeqID);
|
||||
|
||||
if (nextMark.isGate()) {
|
||||
Mark sub1 = nextMark.getSubMark(1);
|
||||
Mark sub2 = nextMark.getSubMark(2);
|
||||
Double distance1 = GeoUtility.getDistance(location, sub1);
|
||||
Double distance2 = GeoUtility.getDistance(location, sub2);
|
||||
return (distance1 < distance2) ? distance1 : distance2;
|
||||
} else {
|
||||
return GeoUtility.getDistance(location, nextMark.getSubMark(1));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 4 Different cases of progression in the race
|
||||
* 1 - Passing the start line
|
||||
* 2 - Passing any in-race Gate
|
||||
* 3 - Passing any in-race Mark
|
||||
* 4 - Passing the finish line
|
||||
*/
|
||||
private void checkForLegProgression() {
|
||||
CompoundMark currentMark = GameState.getMarkOrder().getCurrentMark(currentMarkSeqID);
|
||||
if (currentMarkSeqID == 0) {
|
||||
checkStartLineCrossing(currentMark);
|
||||
} else if (GameState.getMarkOrder().isLastMark(currentMarkSeqID)) {
|
||||
checkFinishLineCrossing(currentMark);
|
||||
} else if (currentMark.isGate()) {
|
||||
checkGateRounding(currentMark);
|
||||
} else {
|
||||
checkMarkRounding(currentMark);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If we pass the start line gate in the correct direction, progress
|
||||
*
|
||||
* @param currentMark The current gate
|
||||
*/
|
||||
private void checkStartLineCrossing(CompoundMark currentMark) {
|
||||
Mark mark1 = currentMark.getSubMark(1);
|
||||
Mark mark2 = currentMark.getSubMark(2);
|
||||
CompoundMark nextMark = GameState.getMarkOrder().getNextMark(currentMarkSeqID);
|
||||
|
||||
Integer crossedLine = GeoUtility.checkCrossedLine(mark1, mark2, lastLocation, location);
|
||||
if (crossedLine > 0) {
|
||||
Boolean isClockwiseCross = GeoUtility.isClockwise(mark1, mark2, nextMark.getMidPoint());
|
||||
if (crossedLine == 2 && isClockwiseCross || crossedLine == 1 && !isClockwiseCross) {
|
||||
currentMarkSeqID++;
|
||||
logMarkRounding(currentMark);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This algorithm checks for mark rounding. And increments the currentMarSeqID number attribute
|
||||
* of the yacht if so.
|
||||
* A visual representation of this algorithm can be seen on the Wiki under
|
||||
* 'mark passing algorithm'
|
||||
*/
|
||||
private void checkMarkRounding(CompoundMark currentMark) {
|
||||
distanceToCurrentMark = calcDistanceToCurrentMark();
|
||||
GeoPoint nextPoint = GameState.getMarkOrder().getNextMark(currentMarkSeqID).getMidPoint();
|
||||
GeoPoint prevPoint = GameState.getMarkOrder().getPreviousMark(currentMarkSeqID)
|
||||
.getMidPoint();
|
||||
GeoPoint midPoint = GeoUtility.getDirtyMidPoint(nextPoint, prevPoint);
|
||||
|
||||
//1 TEST FOR ENTERING THE ROUNDING DISTANCE
|
||||
if (distanceToCurrentMark < ROUNDING_DISTANCE) {
|
||||
hasEnteredRoundingZone = true;
|
||||
}
|
||||
|
||||
//In case current mark is a gate, loop through all marks just in case
|
||||
for (Mark thisCurrentMark : currentMark.getMarks()) {
|
||||
if (GeoUtility.isPointInTriangle(lastLocation, location, midPoint, thisCurrentMark)) {
|
||||
hasPassedLine = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (hasPassedLine && hasEnteredRoundingZone) {
|
||||
currentMarkSeqID++;
|
||||
hasPassedLine = false;
|
||||
hasEnteredRoundingZone = false;
|
||||
hasPassedThroughGate = false;
|
||||
logMarkRounding(currentMark);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Checks if a gate line has been crossed and in the correct direction
|
||||
*
|
||||
* @param currentMark The current gate
|
||||
*/
|
||||
private void checkGateRounding(CompoundMark currentMark) {
|
||||
Mark mark1 = currentMark.getSubMark(1);
|
||||
Mark mark2 = currentMark.getSubMark(2);
|
||||
CompoundMark prevMark = GameState.getMarkOrder().getPreviousMark(currentMarkSeqID);
|
||||
CompoundMark nextMark = GameState.getMarkOrder().getNextMark(currentMarkSeqID);
|
||||
|
||||
Integer crossedLine = GeoUtility.checkCrossedLine(mark1, mark2, lastLocation, location);
|
||||
|
||||
//We have crossed the line
|
||||
if (crossedLine > 0) {
|
||||
Boolean isClockwiseCross = GeoUtility.isClockwise(mark1, mark2, prevMark.getMidPoint());
|
||||
|
||||
//Check we cross the line in the correct direction
|
||||
if (crossedLine == 1 && isClockwiseCross || crossedLine == 2 && !isClockwiseCross) {
|
||||
hasPassedThroughGate = true;
|
||||
}
|
||||
}
|
||||
|
||||
Boolean prevMarkSide = GeoUtility.isClockwise(mark1, mark2, prevMark.getMidPoint());
|
||||
Boolean nextMarkSide = GeoUtility.isClockwise(mark1, mark2, nextMark.getMidPoint());
|
||||
|
||||
if (hasPassedThroughGate) {
|
||||
//Check if we need to round this gate after passing through
|
||||
if (prevMarkSide == nextMarkSide) {
|
||||
checkMarkRounding(currentMark);
|
||||
} else {
|
||||
currentMarkSeqID++;
|
||||
logMarkRounding(currentMark);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If we pass the finish gate in the correct direction
|
||||
*
|
||||
* @param currentMark The current gate
|
||||
*/
|
||||
private void checkFinishLineCrossing(CompoundMark currentMark) {
|
||||
Mark mark1 = currentMark.getSubMark(1);
|
||||
Mark mark2 = currentMark.getSubMark(2);
|
||||
CompoundMark prevMark = GameState.getMarkOrder().getPreviousMark(currentMarkSeqID);
|
||||
|
||||
Integer crossedLine = GeoUtility.checkCrossedLine(mark1, mark2, lastLocation, location);
|
||||
if (crossedLine > 0) {
|
||||
Boolean isClockwiseCross = GeoUtility.isClockwise(mark1, mark2, prevMark.getMidPoint());
|
||||
if (crossedLine == 1 && isClockwiseCross || crossedLine == 2 && !isClockwiseCross) {
|
||||
currentMarkSeqID++;
|
||||
finishedRace = true;
|
||||
logMarkRounding(currentMark);
|
||||
logger.debug(sourceId + " finished");
|
||||
// TODO: 8/08/17 wmu16 - Do something!
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Adjusts the heading of the boat by a given amount, while recording the boats
|
||||
* last heading.
|
||||
*
|
||||
* @param amount the amount by which to adjust the boat heading.
|
||||
*/
|
||||
public void adjustHeading(Double amount) {
|
||||
Double newVal = heading + amount;
|
||||
lastHeading = heading;
|
||||
heading = (double) Math.floorMod(newVal.longValue(), 360L);
|
||||
}
|
||||
|
||||
/**
|
||||
* Swaps the boats direction from one side of the wind to the other.
|
||||
*/
|
||||
public void tackGybe(Double windDirection) {
|
||||
if (isAuto) {
|
||||
disableAutoPilot();
|
||||
} else {
|
||||
Double normalizedHeading = normalizeHeading();
|
||||
Double newVal = (-2 * normalizedHeading) + heading;
|
||||
Double newHeading = (double) Math.floorMod(newVal.longValue(), 360L);
|
||||
setAutoPilot(newHeading);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables the boats auto pilot feature, which will move the boat towards a given heading.
|
||||
*
|
||||
* @param thisHeading The heading to move the boat towards.
|
||||
*/
|
||||
private void setAutoPilot(Double thisHeading) {
|
||||
isAuto = true;
|
||||
autoHeading = thisHeading;
|
||||
}
|
||||
|
||||
/**
|
||||
* Disables the auto pilot function.
|
||||
*/
|
||||
public void disableAutoPilot() {
|
||||
isAuto = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves the boat towards the given heading when the auto pilot was set. Disables the auto pilot
|
||||
* in the event that the boat is within the range of 1 turn step of its goal.
|
||||
*/
|
||||
public void runAutoPilot() {
|
||||
if (isAuto) {
|
||||
turnTowardsHeading(autoHeading);
|
||||
if (Math.abs(heading - autoHeading)
|
||||
<= TURN_STEP) { //Cancel when within 1 turn step of target.
|
||||
isAuto = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void toggleSailIn() {
|
||||
sailIn = !sailIn;
|
||||
}
|
||||
|
||||
public void turnUpwind() {
|
||||
disableAutoPilot();
|
||||
Double normalizedHeading = normalizeHeading();
|
||||
if (normalizedHeading == 0) {
|
||||
if (lastHeading < 180) {
|
||||
adjustHeading(-TURN_STEP);
|
||||
} else {
|
||||
adjustHeading(TURN_STEP);
|
||||
}
|
||||
} else if (normalizedHeading == 180) {
|
||||
if (lastHeading < 180) {
|
||||
adjustHeading(TURN_STEP);
|
||||
} else {
|
||||
adjustHeading(-TURN_STEP);
|
||||
}
|
||||
} else if (normalizedHeading < 180) {
|
||||
adjustHeading(-TURN_STEP);
|
||||
} else {
|
||||
adjustHeading(TURN_STEP);
|
||||
}
|
||||
}
|
||||
|
||||
public void turnDownwind() {
|
||||
disableAutoPilot();
|
||||
Double normalizedHeading = normalizeHeading();
|
||||
if (normalizedHeading == 0) {
|
||||
if (lastHeading < 180) {
|
||||
adjustHeading(TURN_STEP);
|
||||
} else {
|
||||
adjustHeading(-TURN_STEP);
|
||||
}
|
||||
} else if (normalizedHeading == 180) {
|
||||
if (lastHeading < 180) {
|
||||
adjustHeading(-TURN_STEP);
|
||||
} else {
|
||||
adjustHeading(TURN_STEP);
|
||||
}
|
||||
} else if (normalizedHeading < 180) {
|
||||
adjustHeading(TURN_STEP);
|
||||
} else {
|
||||
adjustHeading(-TURN_STEP);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes the VMG from the polartable for upwind or downwind depending on the boats direction,
|
||||
* and uses this to calculate a heading to move the yacht towards.
|
||||
*/
|
||||
public void turnToVMG() {
|
||||
if (isAuto) {
|
||||
disableAutoPilot();
|
||||
} else {
|
||||
Double normalizedHeading = normalizeHeading();
|
||||
Double optimalHeading;
|
||||
HashMap<Double, Double> optimalPolarMap;
|
||||
|
||||
if (normalizedHeading >= 90 && normalizedHeading <= 270) { // Downwind
|
||||
optimalPolarMap = PolarTable.getOptimalDownwindVMG(GameState.getWindSpeedKnots());
|
||||
} else {
|
||||
optimalPolarMap = PolarTable.getOptimalUpwindVMG(GameState.getWindSpeedKnots());
|
||||
}
|
||||
optimalHeading = optimalPolarMap.keySet().iterator().next();
|
||||
|
||||
if (normalizedHeading > 180) {
|
||||
optimalHeading = 360 - optimalHeading;
|
||||
}
|
||||
|
||||
// Take optimal heading and turn into a boat heading rather than a wind heading.
|
||||
optimalHeading =
|
||||
optimalHeading + GameState.getWindDirection();
|
||||
|
||||
setAutoPilot(optimalHeading);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes a given heading and rotates the boat towards that heading.
|
||||
* This does not care about being upwind or downwind, just which direction will reach a given
|
||||
* heading faster.
|
||||
*
|
||||
* @param newHeading The heading to turn the yacht towards.
|
||||
*/
|
||||
private void turnTowardsHeading(Double newHeading) {
|
||||
Double newVal = heading - newHeading;
|
||||
if (Math.floorMod(newVal.longValue(), 360L) > 180) {
|
||||
adjustHeading(TURN_STEP / 5);
|
||||
} else {
|
||||
adjustHeading(-TURN_STEP / 5);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a heading normalized for the wind direction. Heading direction into the wind is 0,
|
||||
* directly away is 180.
|
||||
*
|
||||
* @return The normalized heading accounting for wind direction.
|
||||
*/
|
||||
private Double normalizeHeading() {
|
||||
Double normalizedHeading = heading - GameState.windDirection;
|
||||
normalizedHeading = (double) Math.floorMod(normalizedHeading.longValue(), 360L);
|
||||
return normalizedHeading;
|
||||
@Override
|
||||
public void addObserver(Observer o) {
|
||||
super.addObserver(o);
|
||||
}
|
||||
|
||||
public String getBoatType() {
|
||||
@@ -521,9 +129,6 @@ public class ClientYacht {
|
||||
}
|
||||
|
||||
public void setLegNumber(Integer legNumber) {
|
||||
// if (colour != null && position != "-" && legNumber != this.legNumber) {
|
||||
// RaceViewController.updateYachtPositionSparkline(this, legNumber);
|
||||
// }
|
||||
this.legNumber = legNumber;
|
||||
}
|
||||
|
||||
@@ -560,18 +165,10 @@ public class ClientYacht {
|
||||
return velocityProperty.getReadOnlyProperty();
|
||||
}
|
||||
|
||||
public double getVelocityMMS() {
|
||||
return velocity;
|
||||
}
|
||||
|
||||
public ReadOnlyLongProperty timeTillNextProperty() {
|
||||
return timeTillNextProperty.getReadOnlyProperty();
|
||||
}
|
||||
|
||||
public Double getVelocityKnots() {
|
||||
return velocity / 1000 * 1.943844492; // TODO: 26/07/17 cir27 - remove magic number
|
||||
}
|
||||
|
||||
public Long getTimeTillNext() {
|
||||
return timeTillNext;
|
||||
}
|
||||
@@ -592,6 +189,11 @@ public class ClientYacht {
|
||||
return location;
|
||||
}
|
||||
|
||||
public void toggleSail() {
|
||||
sailIn = !sailIn;
|
||||
}
|
||||
//// TODO: 15/08/17 asd
|
||||
|
||||
/**
|
||||
* Sets the current location of the boat in lat and long whilst preserving the last location
|
||||
*
|
||||
@@ -599,8 +201,6 @@ public class ClientYacht {
|
||||
* @param lng Longitude
|
||||
*/
|
||||
public void setLocation(Double lat, Double lng) {
|
||||
lastLocation.setLat(location.getLat());
|
||||
lastLocation.setLng(location.getLng());
|
||||
location.setLat(lat);
|
||||
location.setLng(lng);
|
||||
}
|
||||
@@ -613,10 +213,6 @@ public class ClientYacht {
|
||||
this.heading = heading;
|
||||
}
|
||||
|
||||
public Boolean getSailIn() {
|
||||
return sailIn;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return boatName;
|
||||
@@ -626,7 +222,7 @@ public class ClientYacht {
|
||||
this.timeSinceLastMarkProperty.set(timeSinceLastMark);
|
||||
}
|
||||
|
||||
public ReadOnlyLongProperty timeSinceLastMarkProperty () {
|
||||
public ReadOnlyLongProperty timeSinceLastMarkProperty() {
|
||||
return timeSinceLastMarkProperty.getReadOnlyProperty();
|
||||
}
|
||||
|
||||
@@ -643,51 +239,30 @@ public class ClientYacht {
|
||||
this.colour = colour;
|
||||
}
|
||||
|
||||
public void toggleClientSail() {
|
||||
clientSailsIn = !clientSailsIn;
|
||||
}
|
||||
// public Double getCurrentVelocity() {
|
||||
// return currentVelocity;
|
||||
// }
|
||||
//
|
||||
// public void setCurrentVelocity(Double currentVelocity) {
|
||||
// this.currentVelocity = currentVelocity;
|
||||
// }
|
||||
|
||||
public Double getVelocity() {
|
||||
return velocity;
|
||||
}
|
||||
|
||||
public void setVelocity(Double velocity) {
|
||||
this.velocity = velocity;
|
||||
}
|
||||
|
||||
public Double getDistanceToCurrentMark() {
|
||||
return distanceToCurrentMark;
|
||||
}
|
||||
|
||||
public Boolean getClientSailsIn() {
|
||||
return clientSailsIn;
|
||||
}
|
||||
|
||||
public void updateLocation(double lat, double lng, double heading, double velocity) {
|
||||
setLocation(lat, lng);
|
||||
this.heading = heading;
|
||||
this.velocity = velocity;
|
||||
// this.currentVelocity = velocity;
|
||||
updateVelocityProperty(velocity);
|
||||
for (YachtLocationListener yll : locationListeners) {
|
||||
yll.notifyLocation(this, lat, lng, heading, velocity, clientSailsIn);
|
||||
yll.notifyLocation(this, lat, lng, heading, sailIn, velocity);
|
||||
}
|
||||
}
|
||||
|
||||
private void logMarkRounding(CompoundMark currentMark) {
|
||||
String typeString = "mark";
|
||||
if (currentMark.isGate()) {
|
||||
typeString = "gate";
|
||||
}
|
||||
logger.debug(
|
||||
String.format("BoatID %d passed %s %s with id %d. Now on leg %d",
|
||||
sourceId,
|
||||
typeString,
|
||||
currentMark.getMarks().get(0).getName(),
|
||||
currentMark.getId(),
|
||||
currentMarkSeqID));
|
||||
}
|
||||
|
||||
public void addLocationListener(YachtLocationListener listener) {
|
||||
locationListeners.add(listener);
|
||||
}
|
||||
|
||||
public boolean getSailIn () {
|
||||
return sailIn;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,12 +6,12 @@ import javafx.scene.paint.Color;
|
||||
* Enum for generating colours.
|
||||
*/
|
||||
public enum Colors {
|
||||
RED, PERU, SEAGREEN, GREEN, BLUE, PURPLE;
|
||||
RED, PERU, GOLD, GREEN, BLUE, PURPLE, DEEPPINK, GRAY;
|
||||
|
||||
static Integer index = 0;
|
||||
|
||||
public static Color getColor() {
|
||||
if (index == 6) {
|
||||
if (index == 8) {
|
||||
index = 0;
|
||||
}
|
||||
return Color.valueOf(values()[index++].toString());
|
||||
|
||||
@@ -28,4 +28,9 @@ public class GeoPoint {
|
||||
public void setLng(double lng) {
|
||||
this.lng = lng;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "lat: " + lat + " lng: " + lng;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,6 +92,10 @@ public class ServerYacht extends Observable {
|
||||
location = GeoUtility.getGeoCoordinate(location, heading, currentVelocity * secondsElapsed);
|
||||
}
|
||||
|
||||
public void setLocation(GeoPoint geoPoint) {
|
||||
location = geoPoint;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add ServerToClientThread as the observer, this observer pattern mainly server for the boat
|
||||
* rounding package.
|
||||
@@ -386,4 +390,6 @@ public class ServerYacht extends Observable {
|
||||
public Boolean hasPassedLine() {
|
||||
return hasPassedLine;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -2,10 +2,6 @@ package seng302.model.mark;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.StringReader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
@@ -19,14 +15,15 @@ import seng302.model.stream.xml.generator.Race;
|
||||
import seng302.model.stream.xml.parser.RaceXMLData;
|
||||
import seng302.utilities.XMLGenerator;
|
||||
import seng302.utilities.XMLParser;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Class to hold the order of the marks in the race.
|
||||
*/
|
||||
public class MarkOrder {
|
||||
|
||||
private List<CompoundMark> raceMarkOrder;
|
||||
private Logger logger = LoggerFactory.getLogger(MarkOrder.class);
|
||||
private Set<Mark> allMarks;
|
||||
|
||||
public MarkOrder(){
|
||||
loadRaceProperties();
|
||||
@@ -76,6 +73,10 @@ public class MarkOrder {
|
||||
return raceMarkOrder.get(currentSeqID + 1);
|
||||
}
|
||||
|
||||
public Set<Mark> getAllMarks(){
|
||||
return Collections.unmodifiableSet(allMarks);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the race order from an XML string
|
||||
* @param xml An AC35 RaceXML
|
||||
@@ -86,6 +87,7 @@ public class MarkOrder {
|
||||
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
|
||||
DocumentBuilder db;
|
||||
Document doc;
|
||||
allMarks = new HashSet<>();
|
||||
|
||||
try {
|
||||
db = dbf.newDocumentBuilder();
|
||||
@@ -107,6 +109,7 @@ public class MarkOrder {
|
||||
CompoundMark compoundMark = marks.get(corner.getCompoundMarkID());
|
||||
compoundMark.setRoundingSide(RoundingSide.getRoundingSide(corner.getRounding()));
|
||||
course.add(compoundMark);
|
||||
allMarks.addAll(compoundMark.getMarks());
|
||||
}
|
||||
|
||||
return course;
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
package seng302.model.stream.parser;
|
||||
|
||||
/**
|
||||
* Stores parsed data from yacht event code packet
|
||||
*/
|
||||
public class YachtEventData {
|
||||
private Long subjectId;
|
||||
private Long incidentId;
|
||||
private Integer eventId;
|
||||
private Long timeStamp;
|
||||
|
||||
public YachtEventData(Long subjectId, Long incidentId, Integer eventId, Long timeStamp) {
|
||||
this.subjectId = subjectId;
|
||||
this.incidentId = incidentId;
|
||||
this.eventId = eventId;
|
||||
this.timeStamp = timeStamp;
|
||||
}
|
||||
|
||||
public Long getSubjectId() {
|
||||
return subjectId;
|
||||
}
|
||||
|
||||
public Long getIncidentId() {
|
||||
return incidentId;
|
||||
}
|
||||
|
||||
public Integer getEventId() {
|
||||
return eventId;
|
||||
}
|
||||
|
||||
public Long getTimeStamp() {
|
||||
return timeStamp;
|
||||
}
|
||||
}
|
||||
@@ -13,15 +13,12 @@ import org.xml.sax.InputSource;
|
||||
import org.xml.sax.SAXException;
|
||||
import seng302.model.stream.packets.PacketType;
|
||||
import seng302.model.stream.packets.StreamPacket;
|
||||
import seng302.model.stream.parser.MarkRoundingData;
|
||||
import seng302.model.stream.parser.PositionUpdateData;
|
||||
import seng302.model.stream.parser.*;
|
||||
import seng302.model.stream.parser.PositionUpdateData.DeviceType;
|
||||
import seng302.model.stream.parser.RaceStartData;
|
||||
import seng302.model.stream.parser.RaceStatusData;
|
||||
|
||||
/**
|
||||
* StreamParser is a utilities class for taking byte data, formatted according to the AC35
|
||||
* streaming protocol, and parsing it into basic data types or collections.
|
||||
* StreamParser is a utilities class for taking byte data, formatted according to the AC35 streaming
|
||||
* protocol, and parsing it into basic data types or collections.
|
||||
*
|
||||
* Created by kre39 on 23/04/17.
|
||||
*/
|
||||
@@ -34,8 +31,9 @@ public class StreamParser {
|
||||
* @return the packet sequence number if the packet is of type HEARTBEAT, null otherwise.
|
||||
*/
|
||||
public static Long extractHeartBeat(StreamPacket packet) {
|
||||
if (packet.getType() != PacketType.HEARTBEAT)
|
||||
if (packet.getType() != PacketType.HEARTBEAT) {
|
||||
return null;
|
||||
}
|
||||
long heartbeat = bytesToLong(packet.getPayload());
|
||||
System.out.println("heartbeat = " + heartbeat);
|
||||
return heartbeat;
|
||||
@@ -52,16 +50,17 @@ public class StreamParser {
|
||||
* containing the parsed packet data.
|
||||
*/
|
||||
public static RaceStatusData extractRaceStatus(StreamPacket packet) {
|
||||
if (packet.getType() != PacketType.RACE_STATUS)
|
||||
if (packet.getType() != PacketType.RACE_STATUS) {
|
||||
return null;
|
||||
}
|
||||
byte[] payload = packet.getPayload();
|
||||
int messageVersionNo = payload[0];
|
||||
long currentTime = bytesToLong(Arrays.copyOfRange(payload, 1, 7));
|
||||
long raceId = bytesToLong(Arrays.copyOfRange(payload, 7, 11));
|
||||
int raceStatus = payload[11];
|
||||
long expectedStartTime = bytesToLong(Arrays.copyOfRange(payload,12,18));
|
||||
long windDir = bytesToLong(Arrays.copyOfRange(payload,18,20));
|
||||
long rawWindSpeed = bytesToLong(Arrays.copyOfRange(payload,20,22));
|
||||
long expectedStartTime = bytesToLong(Arrays.copyOfRange(payload, 12, 18));
|
||||
long windDir = bytesToLong(Arrays.copyOfRange(payload, 18, 20));
|
||||
long rawWindSpeed = bytesToLong(Arrays.copyOfRange(payload, 20, 22));
|
||||
|
||||
// DateFormat format = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");
|
||||
// currentTime = format.format((new Date(currentTime)))
|
||||
@@ -70,7 +69,6 @@ public class StreamParser {
|
||||
windDir, rawWindSpeed, raceStatus, currentTime, expectedStartTime
|
||||
);
|
||||
|
||||
|
||||
// long timeTillStart =
|
||||
// ((new Date(expectedStartTime)).getTime() - (new Date(currentTime)).getTime()) / 1000;
|
||||
//
|
||||
@@ -110,7 +108,7 @@ public class StreamParser {
|
||||
// boat.setEstimateTimeAtFinish(estTimeAtFinish);
|
||||
data.addBoatData(boatID, estTimeAtNextMark, estTimeAtFinish, leg, boatStatus);
|
||||
}
|
||||
return data;
|
||||
return data;
|
||||
}
|
||||
|
||||
// private static void setBoatLegPosition(Yacht updatingBoat, Integer leg){
|
||||
@@ -139,8 +137,9 @@ public class StreamParser {
|
||||
* DISPLAY_TEXT_MESSAGE.
|
||||
*/
|
||||
public static List<String> extractDisplayMessage(StreamPacket packet) {
|
||||
if (packet.getType() != PacketType.DISPLAY_TEXT_MESSAGE)
|
||||
if (packet.getType() != PacketType.DISPLAY_TEXT_MESSAGE) {
|
||||
return null;
|
||||
}
|
||||
List<String> message = new ArrayList<>();
|
||||
byte[] payload = packet.getPayload();
|
||||
int messageVersionNo = payload[0];
|
||||
@@ -166,10 +165,11 @@ public class StreamParser {
|
||||
* XML_MESSAGE.
|
||||
*/
|
||||
public static Document extractXmlMessage(StreamPacket packet) {
|
||||
if ( packet.getType() != PacketType.RACE_XML &&
|
||||
packet.getType() != PacketType.REGATTA_XML &&
|
||||
packet.getType() != PacketType.BOAT_XML )
|
||||
if (packet.getType() != PacketType.RACE_XML &&
|
||||
packet.getType() != PacketType.REGATTA_XML &&
|
||||
packet.getType() != PacketType.BOAT_XML) {
|
||||
return null;
|
||||
}
|
||||
|
||||
byte[] payload = packet.getPayload();
|
||||
int messageType = payload[9];
|
||||
@@ -194,8 +194,8 @@ public class StreamParser {
|
||||
* Extracts the race start status from the packet and returns it as a long array.
|
||||
*
|
||||
* @param packet Packet parsed in to use the payload
|
||||
* @return An array of form [raceID, raceStartTime, notificationType, timeStamp] or null if
|
||||
* the packet type is not of RACE_START_STATUS.
|
||||
* @return An array of form [raceID, raceStartTime, notificationType, timeStamp] or null if the
|
||||
* packet type is not of RACE_START_STATUS.
|
||||
*/
|
||||
public static RaceStartData extractRaceStartStatus(StreamPacket packet) {
|
||||
if (packet.getType() != PacketType.RACE_START_STATUS) {
|
||||
@@ -212,23 +212,25 @@ public class StreamParser {
|
||||
|
||||
/**
|
||||
* Parses the the byte array in a StreamPacket for yacht events to retrieve the necessary info
|
||||
* and returns it a an array of longs.
|
||||
* and returns it as YachtEventData.
|
||||
*
|
||||
* @param packet Packet parsed in to use the payload
|
||||
* @return the event data in the form [boatID, incidentID, eventID, timeStamp]. Returns null if
|
||||
* the packet is not of type YACHT_EVENT_CODE.
|
||||
* @return the event data in the form of YachtEventData. Returns null if the packet is not of
|
||||
* type YACHT_EVENT_CODE.
|
||||
*/
|
||||
public static long[] extractYachtEventCode(StreamPacket packet) {
|
||||
if (packet.getType() != PacketType.YACHT_EVENT_CODE)
|
||||
public static YachtEventData extractYachtEventCode(StreamPacket packet) {
|
||||
if (packet.getType() != PacketType.YACHT_EVENT_CODE) {
|
||||
return null;
|
||||
}
|
||||
byte[] payload = packet.getPayload();
|
||||
int messageVersionNo = payload[0];
|
||||
long timeStamp = bytesToLong(Arrays.copyOfRange(payload, 1, 7));
|
||||
long ackNumber = bytesToLong(Arrays.copyOfRange(payload, 7, 9));
|
||||
long raceId = bytesToLong(Arrays.copyOfRange(payload, 9, 13));
|
||||
long subjectId = bytesToLong(Arrays.copyOfRange(payload, 13, 17));
|
||||
long incidentId = bytesToLong(Arrays.copyOfRange(payload, 17, 21));
|
||||
int eventId = payload[21];
|
||||
return new long[] {subjectId, incidentId, eventId, timeStamp};
|
||||
return new YachtEventData(subjectId, incidentId, eventId, timeStamp);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -239,15 +241,16 @@ public class StreamParser {
|
||||
* Returns null if the packet is not of type YACHT_ACTION_CODE.
|
||||
*/
|
||||
public static long[] extractYachtActionCode(StreamPacket packet) {
|
||||
if (packet.getType() != PacketType.YACHT_ACTION_CODE)
|
||||
if (packet.getType() != PacketType.YACHT_ACTION_CODE) {
|
||||
return null;
|
||||
}
|
||||
byte[] payload = packet.getPayload();
|
||||
int messageVersionNo = payload[0];
|
||||
long timeStamp = bytesToLong(Arrays.copyOfRange(payload, 1, 7));
|
||||
long subjectId = bytesToLong(Arrays.copyOfRange(payload, 9, 13));
|
||||
long incidentId = bytesToLong(Arrays.copyOfRange(payload, 13, 17));
|
||||
int eventId = payload[17];
|
||||
return new long[] {subjectId, incidentId, eventId, timeStamp};
|
||||
return new long[]{subjectId, incidentId, eventId, timeStamp};
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -258,8 +261,9 @@ public class StreamParser {
|
||||
* CHATTER_TEXT.
|
||||
*/
|
||||
public static String extractChatterText(StreamPacket packet) {
|
||||
if (packet.getType() != PacketType.CHATTER_TEXT)
|
||||
if (packet.getType() != PacketType.CHATTER_TEXT) {
|
||||
return null;
|
||||
}
|
||||
byte[] payload = packet.getPayload();
|
||||
int messageVersionNo = payload[0];
|
||||
int messageType = payload[1];
|
||||
@@ -276,8 +280,9 @@ public class StreamParser {
|
||||
* is not of type BOAT_LOCATION.
|
||||
*/
|
||||
public static PositionUpdateData extractBoatLocation(StreamPacket packet) {
|
||||
if (packet.getType() != PacketType.BOAT_LOCATION)
|
||||
if (packet.getType() != PacketType.BOAT_LOCATION) {
|
||||
return null;
|
||||
}
|
||||
byte[] payload = packet.getPayload();
|
||||
int deviceType = (int) payload[15];
|
||||
long timeValid = bytesToLong(Arrays.copyOfRange(payload, 1, 7));
|
||||
@@ -293,10 +298,11 @@ public class StreamParser {
|
||||
double groundSpeed = bytesToLong(Arrays.copyOfRange(payload, 38, 40)) / 1000.0;
|
||||
|
||||
DeviceType type;
|
||||
if (deviceType == 1)
|
||||
if (deviceType == 1) {
|
||||
type = DeviceType.YACHT_TYPE;
|
||||
else
|
||||
} else {
|
||||
type = DeviceType.MARK_TYPE;
|
||||
}
|
||||
|
||||
return new PositionUpdateData((int) boatId, type, lat, lon, heading, groundSpeed);
|
||||
}
|
||||
@@ -309,8 +315,9 @@ public class StreamParser {
|
||||
* if packet is not of type MARK_ROUNDING.
|
||||
*/
|
||||
public static MarkRoundingData extractMarkRounding(StreamPacket packet) {
|
||||
if (packet.getType() != PacketType.MARK_ROUNDING)
|
||||
if (packet.getType() != PacketType.MARK_ROUNDING) {
|
||||
return null;
|
||||
}
|
||||
byte[] payload = packet.getPayload();
|
||||
int messageVersionNo = payload[0];
|
||||
long timeStamp = bytesToLong(Arrays.copyOfRange(payload, 1, 7));
|
||||
@@ -325,16 +332,17 @@ public class StreamParser {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list containing the string value of data within the given stream packet for
|
||||
* course wind.
|
||||
* Returns a list containing the string value of data within the given stream packet for course
|
||||
* wind.
|
||||
*
|
||||
* @param packet The packet containing the payload
|
||||
* @return the string values of the wind packet. Returns null if the packet is not of type
|
||||
* COURSE_WIND.
|
||||
*/
|
||||
public static List<String> extractCourseWind(StreamPacket packet) {
|
||||
if (packet.getType() != PacketType.COURSE_WIND)
|
||||
if (packet.getType() != PacketType.COURSE_WIND) {
|
||||
return null;
|
||||
}
|
||||
byte[] payload = packet.getPayload();
|
||||
int messageVersionNo = payload[0];
|
||||
int selectedWindId = payload[1];
|
||||
@@ -366,13 +374,13 @@ public class StreamParser {
|
||||
* Returns the parsed data from a StreamPacket for average wind data.
|
||||
*
|
||||
* @param packet The packet containing the payload
|
||||
* @return The wind data in the form
|
||||
* [rawPeriod, rawSamplePeriod, period2, speed2, period3, speed3, period4, speed4, timestamp]
|
||||
* or null if the packet is not of type AVG_WIND.
|
||||
* @return The wind data in the form [rawPeriod, rawSamplePeriod, period2, speed2, period3,
|
||||
* speed3, period4, speed4, timestamp] or null if the packet is not of type AVG_WIND.
|
||||
*/
|
||||
public static long[] extractAvgWind(StreamPacket packet) {
|
||||
if (packet.getType() != PacketType.AVG_WIND)
|
||||
if (packet.getType() != PacketType.AVG_WIND) {
|
||||
return null;
|
||||
}
|
||||
byte[] payload = packet.getPayload();
|
||||
int messageVersionNo = payload[0];
|
||||
long timeStamp = bytesToLong(Arrays.copyOfRange(payload, 1, 7));
|
||||
@@ -384,7 +392,7 @@ public class StreamParser {
|
||||
long speed3 = bytesToLong(Arrays.copyOfRange(payload, 17, 19));
|
||||
long period4 = bytesToLong(Arrays.copyOfRange(payload, 19, 21));
|
||||
long speed4 = bytesToLong(Arrays.copyOfRange(payload, 21, 23));
|
||||
return new long[] {
|
||||
return new long[]{
|
||||
rawPeriod, rawSamplePeriod, period2, speed2, period3, speed3, period4, speed4, timeStamp
|
||||
};
|
||||
}
|
||||
@@ -410,8 +418,7 @@ public class StreamParser {
|
||||
}
|
||||
|
||||
/**
|
||||
* takes an array of up to 7 bytes and returns a positive
|
||||
* long constructed from the input bytes
|
||||
* takes an array of up to 7 bytes and returns a positive long constructed from the input bytes
|
||||
*
|
||||
* @param bytes the byte array to conver to Long
|
||||
* @return a positive long if there is less than 7 bytes -1 otherwise
|
||||
|
||||
@@ -21,6 +21,7 @@ import seng302.model.stream.parser.MarkRoundingData;
|
||||
import seng302.model.stream.parser.PositionUpdateData;
|
||||
import seng302.model.stream.parser.PositionUpdateData.DeviceType;
|
||||
import seng302.model.stream.parser.RaceStatusData;
|
||||
import seng302.model.stream.parser.YachtEventData;
|
||||
import seng302.model.stream.xml.parser.RaceXMLData;
|
||||
import seng302.model.stream.xml.parser.RegattaXMLData;
|
||||
import seng302.utilities.StreamParser;
|
||||
@@ -102,6 +103,8 @@ public class GameClient {
|
||||
loadStartScreen();
|
||||
}
|
||||
});
|
||||
|
||||
server.setGameClient(this);
|
||||
}
|
||||
|
||||
private void loadStartScreen() {
|
||||
@@ -126,7 +129,8 @@ public class GameClient {
|
||||
* @return the lobby controller.
|
||||
*/
|
||||
private LobbyController loadLobby() {
|
||||
FXMLLoader fxmlLoader = new FXMLLoader(GameClient.class.getResource("/views/LobbyView.fxml"));
|
||||
FXMLLoader fxmlLoader = new FXMLLoader(
|
||||
GameClient.class.getResource("/views/LobbyView.fxml"));
|
||||
try {
|
||||
holderPane.getChildren().clear();
|
||||
holderPane.getChildren().add(fxmlLoader.load());
|
||||
@@ -155,6 +159,20 @@ public class GameClient {
|
||||
raceView.loadRace(allBoatsMap, courseData, raceState, player);
|
||||
}
|
||||
|
||||
private void loadFinishScreenView() {
|
||||
FXMLLoader fxmlLoader = new FXMLLoader(
|
||||
getClass().getResource("/views/FinishScreenView.fxml"));
|
||||
try {
|
||||
final Node finishScreenFX = fxmlLoader.load();
|
||||
Platform.runLater(() -> {
|
||||
holderPane.getChildren().clear();
|
||||
holderPane.getChildren().add(finishScreenFX);
|
||||
});
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private void parsePackets() {
|
||||
while (socketThread.getPacketQueue().peek() != null) {
|
||||
StreamPacket packet = socketThread.getPacketQueue().poll();
|
||||
@@ -205,13 +223,18 @@ public class GameClient {
|
||||
case MARK_ROUNDING:
|
||||
updateMarkRounding(StreamParser.extractMarkRounding(packet));
|
||||
break;
|
||||
|
||||
case YACHT_EVENT_CODE:
|
||||
showCollisionAlert(StreamParser.extractYachtEventCode(packet));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void startRaceIfAllDataReceived() {
|
||||
if (allXMLReceived() && raceView == null)
|
||||
if (allXMLReceived() && raceView == null) {
|
||||
loadRaceView();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean allXMLReceived() {
|
||||
@@ -257,8 +280,19 @@ public class GameClient {
|
||||
private void processRaceStatusUpdate(RaceStatusData data) {
|
||||
if (allXMLReceived()) {
|
||||
raceState.updateState(data);
|
||||
if (raceView != null)
|
||||
raceView.getGameView().setWindDir(raceState.getWindDirection());
|
||||
if (raceView != null) {
|
||||
raceView.getGameView().setWindDir(raceState.getWindDirection());
|
||||
}
|
||||
boolean raceFinished = true;
|
||||
for (ClientYacht yacht : allBoatsMap.values()) {
|
||||
if (yacht.getBoatStatus() != 3) {
|
||||
raceFinished = false;
|
||||
}
|
||||
}
|
||||
if (raceFinished == true) {
|
||||
loadFinishScreenView();
|
||||
}
|
||||
|
||||
for (long[] boatData : data.getBoatData()) {
|
||||
ClientYacht clientYacht = allBoatsMap.get((int) boatData[0]);
|
||||
clientYacht.setEstimateTimeTillNextMark(raceState.getRaceTime() - boatData[1]);
|
||||
@@ -313,11 +347,25 @@ public class GameClient {
|
||||
//TODO 12/07/17 Determine the sail state and send the appropriate packet (eg. if sails are in, send a sail out packet)
|
||||
case SHIFT: // sails in/sails out
|
||||
socketThread.sendBoatAction(BoatAction.SAILS_IN);
|
||||
raceView.getGameView().getPlayerYacht().toggleClientSail();
|
||||
raceView.getGameView().getPlayerYacht().toggleSail();
|
||||
break;
|
||||
case PAGE_UP:
|
||||
case PAGE_DOWN:
|
||||
socketThread.sendBoatAction(BoatAction.MAINTAIN_HEADING); break;
|
||||
}
|
||||
}
|
||||
|
||||
public RaceXMLData getCourseData() {
|
||||
return courseData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells race view to show a collision animation.
|
||||
*/
|
||||
private void showCollisionAlert(YachtEventData yachtEventData) {
|
||||
// 33 is the agreed code to show collision
|
||||
if (yachtEventData.getEventId() == 33) {
|
||||
raceView.showCollision(yachtEventData.getSubjectId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,23 +7,24 @@ import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import javafx.animation.AnimationTimer;
|
||||
import javafx.animation.KeyFrame;
|
||||
import javafx.animation.KeyValue;
|
||||
import javafx.animation.Timeline;
|
||||
import javafx.application.Platform;
|
||||
import javafx.collections.ObservableList;
|
||||
import javafx.event.EventHandler;
|
||||
import javafx.geometry.Point2D;
|
||||
import javafx.scene.Group;
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.image.ImageView;
|
||||
import javafx.scene.input.KeyCode;
|
||||
import javafx.scene.input.KeyEvent;
|
||||
import javafx.scene.input.ScrollEvent;
|
||||
import javafx.scene.layout.AnchorPane;
|
||||
import javafx.scene.layout.Pane;
|
||||
import javafx.scene.paint.Color;
|
||||
import javafx.scene.paint.Paint;
|
||||
import javafx.scene.shape.Circle;
|
||||
import javafx.scene.shape.Polygon;
|
||||
import javafx.scene.text.Text;
|
||||
import seng302.model.ClientYacht;
|
||||
import javafx.util.Duration;
|
||||
import seng302.model.Colors;
|
||||
import seng302.model.GeoPoint;
|
||||
import seng302.model.Limit;
|
||||
@@ -44,10 +45,10 @@ import seng302.visualiser.map.CanvasMap;
|
||||
*/
|
||||
public class GameView extends Pane {
|
||||
|
||||
private double bufferSize = 50;
|
||||
private double panelWidth = 1260; // it should be 1280 but, minors 40 to cancel the bias.
|
||||
private double panelHeight = 960;
|
||||
private double canvasWidth = 1100;
|
||||
private double bufferSize = 50;
|
||||
private double panelWidth = 1260; // it should be 1280 but, minors 40 to cancel the bias.
|
||||
private double panelHeight = 960;
|
||||
private double canvasWidth = 1100;
|
||||
private double canvasHeight = 920;
|
||||
private boolean horizontalInversion = false;
|
||||
|
||||
@@ -112,7 +113,7 @@ public class GameView extends Pane {
|
||||
VERTICAL
|
||||
}
|
||||
|
||||
public GameView () {
|
||||
public GameView() {
|
||||
gameObjects = this.getChildren();
|
||||
// create image view for map, bind panel size to image
|
||||
gameObjects.add(mapImage);
|
||||
@@ -122,49 +123,10 @@ public class GameView extends Pane {
|
||||
gameObjects.add(fpsDisplay);
|
||||
gameObjects.add(raceBorder);
|
||||
gameObjects.add(markers);
|
||||
//
|
||||
// this.setOnKeyPressed(new EventHandler<KeyEvent>() {
|
||||
// @Override public void handle(KeyEvent event) {
|
||||
// event.consume();
|
||||
// switch (event.getCode()) {
|
||||
// case Z:
|
||||
// scaleFactor = scaleFactor * 1.2;
|
||||
// break;
|
||||
// case X:
|
||||
// scaleFactor = scaleFactor * 0.8;
|
||||
// break;
|
||||
// }
|
||||
// if (event.getCode() == KeyCode.Z || event.getCode() == KeyCode.X) {
|
||||
// for (Node child : getChildren()) {
|
||||
// child.setScaleX(child.getScaleX() * scaleFactor);
|
||||
// child.setScaleY(child.getScaleY() * scaleFactor);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
//
|
||||
// this.setOnScroll(new EventHandler<ScrollEvent>() {
|
||||
// @Override public void handle(ScrollEvent event) {
|
||||
// event.consume();
|
||||
// if (event.getDeltaY() == 0) {
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// double scaleFactor =
|
||||
// (event.getDeltaY() > 0)
|
||||
// ? SCALE_DELTA
|
||||
// : 1/SCALE_DELTA;
|
||||
// for (Node child : getChildren()) {
|
||||
// child.setScaleX(child.getScaleX() * scaleFactor);
|
||||
// child.setScaleY(child.getScaleY() * scaleFactor);
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
|
||||
initializeTimer();
|
||||
}
|
||||
|
||||
private void initializeTimer () {
|
||||
private void initializeTimer() {
|
||||
Arrays.fill(frameTimes, 1_000_000_000 / 60);
|
||||
timer = new AnimationTimer() {
|
||||
private long lastTime = 0;
|
||||
@@ -207,8 +169,8 @@ public class GameView extends Pane {
|
||||
}
|
||||
|
||||
/**
|
||||
* First find the top right and bottom left points' geo locations, then retrieve
|
||||
* map from google to display on image view. - Haoming 22/5/2017
|
||||
* First find the top right and bottom left points' geo locations, then retrieve map from google
|
||||
* to display on image view. - Haoming 22/5/2017
|
||||
*/
|
||||
private void drawGoogleMap() {
|
||||
findMetersPerPixel();
|
||||
@@ -266,13 +228,23 @@ public class GameView extends Pane {
|
||||
for (Mark mark : cMark.getMarks()) {
|
||||
makeAndBindMarker(mark, colour);
|
||||
}
|
||||
|
||||
//UNCOMMENT THIS TO HIGHLIGHT SUBMARKS 1 and 2 RED AND GREEN RESPECTIVELY FOR DEBUG
|
||||
//(instead of above for loop)
|
||||
// for (Mark mark : cMark.getMarks()) {
|
||||
// if (mark.getSeqID() == 1) {
|
||||
// makeAndBindMarker(mark, Color.RED);
|
||||
// } else {
|
||||
// makeAndBindMarker(mark, Color.GREEN);
|
||||
// }
|
||||
// }
|
||||
//Create gate line
|
||||
if (cMark.isGate()) {
|
||||
for (int i = 1; i < cMark.getMarks().size(); i++) {
|
||||
gates.add(
|
||||
makeAndBindGate(
|
||||
markerObjects.get(cMark.getSubMark(i)),
|
||||
markerObjects.get(cMark.getSubMark(i+1)),
|
||||
markerObjects.get(cMark.getSubMark(i + 1)),
|
||||
colour
|
||||
)
|
||||
);
|
||||
@@ -335,7 +307,7 @@ public class GameView extends Pane {
|
||||
gate.endYProperty().bind(
|
||||
m2.centerYProperty()
|
||||
);
|
||||
return gate;
|
||||
return gate;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -389,7 +361,7 @@ public class GameView extends Pane {
|
||||
boatObjectGroup.getChildren().add(newBoat);
|
||||
trails.getChildren().add(newBoat.getTrail());
|
||||
// TODO: 1/08/17 Make this less vile to look at.
|
||||
clientYacht.addLocationListener((boat, lat, lon, heading, velocity, sailIn) -> {
|
||||
clientYacht.addLocationListener((boat, lat, lon, heading, sailIn, velocity) -> {
|
||||
BoatObject bo = boatObjects.get(boat);
|
||||
Point2D p2d = findScaledXY(lat, lon);
|
||||
bo.moveTo(p2d.getX(), p2d.getY(), heading, velocity, sailIn, windDir);
|
||||
@@ -443,25 +415,25 @@ public class GameView extends Pane {
|
||||
annotations.put(clientYacht, newAnnotation);
|
||||
}
|
||||
|
||||
private void drawFps(Double fps){
|
||||
private void drawFps(Double fps) {
|
||||
Platform.runLater(() -> fpsDisplay.setText(String.format("%d FPS", Math.round(fps))));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the class variables minLatPoint, maxLatPoint, minLonPoint, maxLonPoint to the point
|
||||
* with the leftmost point, rightmost point, southern most point and northern most point
|
||||
* Sets the class variables minLatPoint, maxLatPoint, minLonPoint, maxLonPoint to the point with
|
||||
* the leftmost point, rightmost point, southern most point and northern most point
|
||||
* respectively.
|
||||
*/
|
||||
private void findMinMaxPoint(List<GeoPoint> points) {
|
||||
List<GeoPoint> sortedPoints = new ArrayList<>(points);
|
||||
sortedPoints.sort(Comparator.comparingDouble(GeoPoint::getLat));
|
||||
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());
|
||||
|
||||
sortedPoints.sort(Comparator.comparingDouble(GeoPoint::getLng));
|
||||
minLonPoint = new GeoPoint(sortedPoints.get(0).getLat(), sortedPoints.get(0).getLng());
|
||||
GeoPoint maxLon = sortedPoints.get(sortedPoints.size()-1);
|
||||
GeoPoint maxLon = sortedPoints.get(sortedPoints.size() - 1);
|
||||
maxLonPoint = new GeoPoint(maxLon.getLat(), maxLon.getLng());
|
||||
if (maxLonPoint.getLng() - minLonPoint.getLng() > 180) {
|
||||
horizontalInversion = true;
|
||||
@@ -481,15 +453,19 @@ public class GameView extends Pane {
|
||||
|
||||
if (scaleDirection == ScaleDirection.HORIZONTAL) {
|
||||
referenceAngle = Math.abs(
|
||||
GeoUtility.getBearingRad(referencePoint, minLonPoint)
|
||||
GeoUtility.getBearingRad(referencePoint, minLonPoint)
|
||||
);
|
||||
referencePointX = bufferSize + distanceScaleFactor * Math.sin(referenceAngle) * GeoUtility.getDistance(referencePoint, minLonPoint);
|
||||
referencePointX =
|
||||
bufferSize + distanceScaleFactor * Math.sin(referenceAngle) * GeoUtility
|
||||
.getDistance(referencePoint, minLonPoint);
|
||||
referenceAngle = Math.abs(GeoUtility.getDistance(referencePoint, maxLatPoint));
|
||||
referencePointY = canvasHeight - (bufferSize + bufferSize);
|
||||
referencePointY -= distanceScaleFactor * Math.cos(referenceAngle) * GeoUtility.getDistance(referencePoint, maxLatPoint);
|
||||
referencePointY = referencePointY / 2;
|
||||
referencePointY = canvasHeight - (bufferSize + bufferSize);
|
||||
referencePointY -= distanceScaleFactor * Math.cos(referenceAngle) * GeoUtility
|
||||
.getDistance(referencePoint, maxLatPoint);
|
||||
referencePointY = referencePointY / 2;
|
||||
referencePointY += bufferSize;
|
||||
referencePointY += distanceScaleFactor * Math.cos(referenceAngle) * GeoUtility.getDistance(referencePoint, maxLatPoint);
|
||||
referencePointY += distanceScaleFactor * Math.cos(referenceAngle) * GeoUtility
|
||||
.getDistance(referencePoint, maxLatPoint);
|
||||
} else {
|
||||
referencePointY = canvasHeight - bufferSize;
|
||||
referenceAngle = Math.abs(
|
||||
@@ -497,11 +473,14 @@ public class GameView extends Pane {
|
||||
GeoUtility.getDistance(referencePoint, minLonPoint)
|
||||
)
|
||||
);
|
||||
referencePointX = bufferSize;
|
||||
referencePointX += distanceScaleFactor * Math.sin(referenceAngle) * GeoUtility.getDistance(referencePoint, minLonPoint);
|
||||
referencePointX += ((canvasWidth - (bufferSize + bufferSize)) - (minLonToMaxLon * distanceScaleFactor)) / 2;
|
||||
referencePointX = bufferSize;
|
||||
referencePointX += distanceScaleFactor * Math.sin(referenceAngle) * GeoUtility
|
||||
.getDistance(referencePoint, minLonPoint);
|
||||
referencePointX +=
|
||||
((canvasWidth - (bufferSize + bufferSize)) - (minLonToMaxLon * distanceScaleFactor))
|
||||
/ 2;
|
||||
}
|
||||
if(horizontalInversion) {
|
||||
if (horizontalInversion) {
|
||||
referencePointX = canvasWidth - bufferSize - (referencePointX - bufferSize);
|
||||
}
|
||||
}
|
||||
@@ -514,12 +493,12 @@ public class GameView extends Pane {
|
||||
private double scaleRaceExtremities() {
|
||||
|
||||
double vertAngle = Math.abs(
|
||||
GeoUtility.getBearingRad(minLatPoint, maxLatPoint)
|
||||
GeoUtility.getBearingRad(minLatPoint, maxLatPoint)
|
||||
);
|
||||
double vertDistance =
|
||||
Math.cos(vertAngle) * GeoUtility.getDistance(minLatPoint, maxLatPoint);
|
||||
double horiAngle = Math.abs(
|
||||
GeoUtility.getBearingRad(minLonPoint, maxLonPoint)
|
||||
GeoUtility.getBearingRad(minLonPoint, maxLonPoint)
|
||||
);
|
||||
if (horiAngle <= (Math.PI / 2)) {
|
||||
horiAngle = (Math.PI / 2) - horiAngle;
|
||||
@@ -545,35 +524,43 @@ public class GameView extends Pane {
|
||||
return findScaledXY(unscaled.getLat(), unscaled.getLng());
|
||||
}
|
||||
|
||||
private Point2D findScaledXY (double unscaledLat, double unscaledLon) {
|
||||
private Point2D findScaledXY(double unscaledLat, double unscaledLon) {
|
||||
double distanceFromReference;
|
||||
double angleFromReference;
|
||||
double xAxisLocation = referencePointX;
|
||||
double yAxisLocation = referencePointY;
|
||||
|
||||
angleFromReference = GeoUtility.getBearingRad(
|
||||
minLatPoint, new GeoPoint(unscaledLat, unscaledLon)
|
||||
minLatPoint, new GeoPoint(unscaledLat, unscaledLon)
|
||||
);
|
||||
distanceFromReference = GeoUtility.getDistance(
|
||||
minLatPoint, new GeoPoint(unscaledLat, unscaledLon)
|
||||
);
|
||||
if (angleFromReference >= 0 && angleFromReference <= Math.PI / 2) {
|
||||
xAxisLocation += Math.round(distanceScaleFactor * Math.sin(angleFromReference) * distanceFromReference);
|
||||
yAxisLocation -= Math.round(distanceScaleFactor * Math.cos(angleFromReference) * distanceFromReference);
|
||||
xAxisLocation += Math
|
||||
.round(distanceScaleFactor * Math.sin(angleFromReference) * distanceFromReference);
|
||||
yAxisLocation -= Math
|
||||
.round(distanceScaleFactor * Math.cos(angleFromReference) * distanceFromReference);
|
||||
} else if (angleFromReference >= 0) {
|
||||
angleFromReference = angleFromReference - Math.PI / 2;
|
||||
xAxisLocation += Math.round(distanceScaleFactor * Math.cos(angleFromReference) * distanceFromReference);
|
||||
yAxisLocation += Math.round(distanceScaleFactor * Math.sin(angleFromReference) * distanceFromReference);
|
||||
xAxisLocation += Math
|
||||
.round(distanceScaleFactor * Math.cos(angleFromReference) * distanceFromReference);
|
||||
yAxisLocation += Math
|
||||
.round(distanceScaleFactor * Math.sin(angleFromReference) * distanceFromReference);
|
||||
} else if (angleFromReference < 0 && angleFromReference >= -Math.PI / 2) {
|
||||
angleFromReference = Math.abs(angleFromReference);
|
||||
xAxisLocation -= Math.round(distanceScaleFactor * Math.sin(angleFromReference) * distanceFromReference);
|
||||
yAxisLocation -= Math.round(distanceScaleFactor * Math.cos(angleFromReference) * distanceFromReference);
|
||||
xAxisLocation -= Math
|
||||
.round(distanceScaleFactor * Math.sin(angleFromReference) * distanceFromReference);
|
||||
yAxisLocation -= Math
|
||||
.round(distanceScaleFactor * Math.cos(angleFromReference) * distanceFromReference);
|
||||
} else {
|
||||
angleFromReference = Math.abs(angleFromReference) - Math.PI / 2;
|
||||
xAxisLocation -= Math.round(distanceScaleFactor * Math.cos(angleFromReference) * distanceFromReference);
|
||||
yAxisLocation += Math.round(distanceScaleFactor * Math.sin(angleFromReference) * distanceFromReference);
|
||||
xAxisLocation -= Math
|
||||
.round(distanceScaleFactor * Math.cos(angleFromReference) * distanceFromReference);
|
||||
yAxisLocation += Math
|
||||
.round(distanceScaleFactor * Math.sin(angleFromReference) * distanceFromReference);
|
||||
}
|
||||
if(horizontalInversion) {
|
||||
if (horizontalInversion) {
|
||||
xAxisLocation = canvasWidth - bufferSize - (xAxisLocation - bufferSize);
|
||||
}
|
||||
return new Point2D(xAxisLocation, yAxisLocation);
|
||||
@@ -600,7 +587,7 @@ public class GameView extends Pane {
|
||||
metersPerPixelY = dVertical / dy;
|
||||
}
|
||||
|
||||
public void setAnnotationVisibilities (boolean teamName, boolean velocity, boolean estTime,
|
||||
public void setAnnotationVisibilities(boolean teamName, boolean velocity, boolean estTime,
|
||||
boolean legTime, boolean trail, boolean wake) {
|
||||
for (BoatObject boatObject : boatObjects.values()) {
|
||||
boatObject.setVisibility(teamName, velocity, estTime, legTime, trail, wake);
|
||||
@@ -613,7 +600,7 @@ public class GameView extends Pane {
|
||||
}
|
||||
}
|
||||
|
||||
public void setFPSVisibility (boolean visibility) {
|
||||
public void setFPSVisibility(boolean visibility) {
|
||||
fpsDisplay.setVisible(visibility);
|
||||
}
|
||||
|
||||
@@ -623,7 +610,7 @@ public class GameView extends Pane {
|
||||
);
|
||||
}
|
||||
|
||||
public void pauseRace () {
|
||||
public void pauseRace() {
|
||||
timer.stop();
|
||||
}
|
||||
|
||||
@@ -632,8 +619,7 @@ public class GameView extends Pane {
|
||||
this.windDir = windDir;
|
||||
}
|
||||
|
||||
|
||||
public void startRace () {
|
||||
public void startRace() {
|
||||
timer.start();
|
||||
}
|
||||
|
||||
@@ -641,9 +627,10 @@ public class GameView extends Pane {
|
||||
return playerYacht;
|
||||
}
|
||||
|
||||
|
||||
public void setBoatAsPlayer (ClientYacht playerYacht) {
|
||||
this.playerYacht = playerYacht;
|
||||
this.playerYacht.toggleClientSail();
|
||||
this.playerYacht.toggleSail();
|
||||
boatObjects.get(playerYacht).setAsPlayer();
|
||||
annotations.get(playerYacht).addAnnotation(
|
||||
"velocity",
|
||||
@@ -657,4 +644,40 @@ public class GameView extends Pane {
|
||||
gameObjects.add(annotations.get(playerYacht));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Given yacht geopoint by race view controller, drawCollision will calculate canvas X and Y and
|
||||
* display a flashing red circle on collision point.
|
||||
*
|
||||
* @param collisionPoint yacht collision point
|
||||
*/
|
||||
public void drawCollision(GeoPoint collisionPoint) {
|
||||
Platform.runLater(() -> {
|
||||
Point2D point = findScaledXY(collisionPoint);
|
||||
double circleRadius = 0.0;
|
||||
Circle circle = new Circle(point.getX(), point.getY(), circleRadius, Color.RED);
|
||||
gameObjects.add(circle);
|
||||
|
||||
circle.setFill(Color.TRANSPARENT);
|
||||
circle.setStroke(Color.RED);
|
||||
circle.setStrokeWidth(3);
|
||||
|
||||
Timeline timeline = new Timeline();
|
||||
timeline.setCycleCount(1);
|
||||
|
||||
KeyFrame keyframe1 = new KeyFrame(Duration.ZERO,
|
||||
new KeyValue(circle.radiusProperty(), 0),
|
||||
new KeyValue(circle.strokeProperty(), Color.TRANSPARENT));
|
||||
KeyFrame keyFrame2 = new KeyFrame(new Duration(1000),
|
||||
new KeyValue(circle.radiusProperty(), 50),
|
||||
new KeyValue(circle.strokeProperty(), Color.RED));
|
||||
KeyFrame keyFrame3 = new KeyFrame(new Duration(1500),
|
||||
new KeyValue(circle.strokeProperty(), Color.TRANSPARENT));
|
||||
|
||||
timeline.getKeyFrames().addAll(keyframe1, keyFrame2, keyFrame3);
|
||||
timeline.play();
|
||||
|
||||
timeline.setOnFinished(event -> gameObjects.remove(circle));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,7 +79,6 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
||||
private GameView gameView;
|
||||
private RaceState raceState;
|
||||
|
||||
private Timeline timerTimeline;
|
||||
private Timer timer = new Timer();
|
||||
private List<Series<String, Double>> sparkLineData = new ArrayList<>();
|
||||
private ImportantAnnotationsState importantAnnotations;
|
||||
@@ -209,9 +208,10 @@ 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
|
||||
sparkLineData.clear();
|
||||
@@ -229,14 +229,14 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
||||
1.0 + participants.size() - yacht.getPositionInteger()
|
||||
)
|
||||
);
|
||||
sparkLineData.add(yachtData);
|
||||
sparkLineData.add(yachtData);
|
||||
});
|
||||
|
||||
// Lambda function to sort the series in order of leg (later legs shown more to the right)
|
||||
sparkLineData.sort((o1, o2) -> {
|
||||
Integer leg1 = Integer.parseInt(o1.getData().get(o1.getData().size()-1).getXValue());
|
||||
Integer leg2 = Integer.parseInt(o2.getData().get(o2.getData().size()-1).getXValue());
|
||||
if (leg2 < leg1){
|
||||
Integer leg1 = Integer.parseInt(o1.getData().get(o1.getData().size() - 1).getXValue());
|
||||
Integer leg2 = Integer.parseInt(o2.getData().get(o2.getData().size() - 1).getXValue());
|
||||
if (leg2 < leg1) {
|
||||
return 1;
|
||||
} else {
|
||||
return -1;
|
||||
@@ -249,7 +249,8 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
||||
.filter(spark -> !raceSparkLine.getData().contains(spark))
|
||||
.forEach(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()));
|
||||
})
|
||||
);
|
||||
}
|
||||
@@ -285,26 +286,27 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
||||
|
||||
/**
|
||||
* gets the rgb string of the yachts colour to use for the chart via css
|
||||
*
|
||||
* @param yachtId id of yacht passed in to get the yachts colour
|
||||
* @return the colour as an rgb string
|
||||
*/
|
||||
private String getBoatColorAsRGB(String yachtId){
|
||||
private String getBoatColorAsRGB(String yachtId) {
|
||||
Color color = participants.get(Integer.valueOf(yachtId)).getColour();
|
||||
if (color == null){
|
||||
return String.format("#%02X%02X%02X",255,255,255);
|
||||
if (color == null) {
|
||||
return String.format("#%02X%02X%02X", 255, 255, 255);
|
||||
}
|
||||
return String.format( "#%02X%02X%02X",
|
||||
(int)( color.getRed() * 255 ),
|
||||
(int)( color.getGreen() * 255 ),
|
||||
(int)( color.getBlue() * 255 )
|
||||
return String.format("#%02X%02X%02X",
|
||||
(int) (color.getRed() * 255),
|
||||
(int) (color.getGreen() * 255),
|
||||
(int) (color.getBlue() * 255)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* Updates of each of these attributes are called ONCE EACH SECOND
|
||||
* orderings etc.. which are dependent on the info from the stream parser constantly. Updates of
|
||||
* each of these attributes are called ONCE EACH SECOND
|
||||
*/
|
||||
private void initializeUpdateTimer() {
|
||||
timer.scheduleAtFixedRate(new TimerTask() {
|
||||
@@ -319,9 +321,10 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* 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
|
||||
*/
|
||||
@@ -396,7 +399,6 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
||||
textToAdd.setStyle("");
|
||||
vboxEntries.add(textToAdd);
|
||||
}
|
||||
// System.out.println("finished a loop :))))))))))))");
|
||||
}
|
||||
Platform.runLater(() ->
|
||||
positionVbox.getChildren().setAll(vboxEntries)
|
||||
@@ -476,15 +478,17 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
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) {
|
||||
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());
|
||||
@@ -503,8 +507,8 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
||||
|
||||
|
||||
/**
|
||||
* Initialised the combo box with any yachts currently in the race and adds the required listener
|
||||
* for the combobox to take action upon selection
|
||||
* 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(
|
||||
@@ -541,7 +545,7 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
||||
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) {
|
||||
@@ -592,11 +596,22 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
||||
// }
|
||||
}
|
||||
|
||||
public void updateRaceData (RaceXMLData raceData) {
|
||||
public void updateRaceData(RaceXMLData raceData) {
|
||||
this.courseData = raceData;
|
||||
gameView.updateBorder(raceData.getCourseLimit());
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by game client after receiving yacht event packet. Parameter subject id is the
|
||||
* offending yacht. This function in turn will pass the yacht location to game view to display a
|
||||
* collision alert.
|
||||
*
|
||||
* @param subjectId source id of offending yacht
|
||||
*/
|
||||
public void showCollision(Long subjectId) {
|
||||
gameView.drawCollision(participants.get((int) (long) subjectId).getLocation());
|
||||
}
|
||||
|
||||
public GameView getGameView() {
|
||||
return gameView;
|
||||
}
|
||||
|
||||
@@ -1,171 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<BoatConfig>
|
||||
<Modified>2015-08-28T17:32:59+0100</Modified>
|
||||
<Version>12</Version>
|
||||
<Snapshot>219</Snapshot>
|
||||
<Settings>
|
||||
<RaceBoatType Type="AC45"/>
|
||||
<BoatDimension BoatLength="14.019" HullLength="13.449"/>
|
||||
<ZoneSize MarkZoneSize="40.347" CourseZoneSize="53.796"/>
|
||||
<ZoneLimits Limit1="200" Limit2="100" Limit3="53.796" Limit4="0" Limit5="-100"/>
|
||||
</Settings>
|
||||
<BoatShapes>
|
||||
<BoatShape ShapeID="0">
|
||||
<Vertices>
|
||||
<Vtx Seq="3" Y="25" X="0"/>
|
||||
</Vertices>
|
||||
</BoatShape>
|
||||
<BoatShape ShapeID="14">
|
||||
<Vertices>
|
||||
<Vtx Seq="1" Y="0" X="-1"/>
|
||||
<Vtx Seq="2" Y="0.75" X="-1"/>
|
||||
<Vtx Seq="3" Y="0.75" X="-0.25"/>
|
||||
<Vtx Seq="4" Y="3.5" X="-0.25"/>
|
||||
<Vtx Seq="5" Y="4.5" X="-1"/>
|
||||
<Vtx Seq="6" Y="6.5" X="-1"/>
|
||||
<Vtx Seq="7" Y="7" X="-0.5"/>
|
||||
<Vtx Seq="8" Y="7" X="0.5"/>
|
||||
<Vtx Seq="9" Y="6.5" X="1"/>
|
||||
<Vtx Seq="10" Y="4.5" X="1"/>
|
||||
<Vtx Seq="11" Y="3.5" X="0.25"/>
|
||||
<Vtx Seq="12" Y="0.75" X="0.25"/>
|
||||
<Vtx Seq="13" Y="0.75" X="1"/>
|
||||
<Vtx Seq="14" Y="0" X="1"/>
|
||||
</Vertices>
|
||||
</BoatShape>
|
||||
<BoatShape ShapeID="15">
|
||||
<Vertices>
|
||||
<Vtx Seq="1" Y="0" X="-3.46"/>
|
||||
<Vtx Seq="2" Y="13.449" X="-3.46"/>
|
||||
<Vtx Seq="3" Y="14.019" X="0"/>
|
||||
<Vtx Seq="4" Y="13.449" X="3.46"/>
|
||||
<Vtx Seq="5" Y="0" X="3.46"/>
|
||||
</Vertices>
|
||||
<Catamaran>
|
||||
<Vtx Seq="1" Y="1.769" X="-2.752"/>
|
||||
<Vtx Seq="2" Y="0" X="-2.813"/>
|
||||
<Vtx Seq="3" Y="0" X="-3.34"/>
|
||||
<Vtx Seq="4" Y="5.351" X="-3.46"/>
|
||||
<Vtx Seq="5" Y="10.544" X="-3.387"/>
|
||||
<Vtx Seq="6" Y="13.449" X="-3.075"/>
|
||||
<Vtx Seq="7" Y="10.851" X="-2.793"/>
|
||||
<Vtx Seq="8" Y="6.669" X="-2.699"/>
|
||||
<Vtx Seq="9" Y="6.669" X="2.699"/>
|
||||
<Vtx Seq="10" Y="10.851" X="2.793"/>
|
||||
<Vtx Seq="11" Y="13.449" X="3.075"/>
|
||||
<Vtx Seq="12" Y="10.544" X="3.387"/>
|
||||
<Vtx Seq="13" Y="5.351" X="3.46"/>
|
||||
<Vtx Seq="14" Y="0" X="3.34"/>
|
||||
<Vtx Seq="15" Y="0" X="2.813"/>
|
||||
<Vtx Seq="16" Y="1.769" X="2.752"/>
|
||||
</Catamaran>
|
||||
<Bowsprit>
|
||||
<Vtx Seq="1" Y="6.669" X="-0.2"/>
|
||||
<Vtx Seq="2" Y="11.377" X="-0.2"/>
|
||||
<Vtx Seq="3" Y="14.019" X="0"/>
|
||||
<Vtx Seq="4" Y="11.377" X="0.2"/>
|
||||
<Vtx Seq="5" Y="6.669" X="0.2"/>
|
||||
</Bowsprit>
|
||||
<Trampoline>
|
||||
<Vtx Seq="1" Y="2" X="-2.699"/>
|
||||
<Vtx Seq="2" Y="6.438" X="-2.699"/>
|
||||
<Vtx Seq="3" Y="6.438" X="2.699"/>
|
||||
<Vtx Seq="4" Y="2" X="2.699"/>
|
||||
</Trampoline>
|
||||
</BoatShape>
|
||||
<BoatShape ShapeID="18">
|
||||
<Vertices>
|
||||
<Vtx Seq="1" Y="0" X="-1.04"/>
|
||||
<Vtx Seq="2" Y="0.11" X="-1.18"/>
|
||||
<Vtx Seq="3" Y="0.42" X="-1.28"/>
|
||||
<Vtx Seq="4" Y="3.74" X="-1.29"/>
|
||||
<Vtx Seq="5" Y="5.36" X="-1.21"/>
|
||||
<Vtx Seq="6" Y="6.29" X="-1.08"/>
|
||||
<Vtx Seq="7" Y="7.15" X="-0.84"/>
|
||||
<Vtx Seq="8" Y="7.63" X="-0.62"/>
|
||||
<Vtx Seq="9" Y="7.94" X="-0.34"/>
|
||||
<Vtx Seq="10" Y="8.06" X="0"/>
|
||||
<Vtx Seq="11" Y="7.94" X="0.34"/>
|
||||
<Vtx Seq="12" Y="7.63" X="0.62"/>
|
||||
<Vtx Seq="13" Y="7.15" X="0.84"/>
|
||||
<Vtx Seq="14" Y="6.29" X="1.08"/>
|
||||
<Vtx Seq="15" Y="5.36" X="1.21"/>
|
||||
<Vtx Seq="16" Y="3.74" X="1.29"/>
|
||||
<Vtx Seq="17" Y="0.42" X="1.28"/>
|
||||
<Vtx Seq="18" Y="0.11" X="1.18"/>
|
||||
<Vtx Seq="19" Y="0" X="1.04"/>
|
||||
</Vertices>
|
||||
</BoatShape>
|
||||
<BoatShape ShapeID="24">
|
||||
<Vertices>
|
||||
<Vtx Seq="1" Y="0" X="-2.5"/>
|
||||
<Vtx Seq="2" Y="7" X="-2.5"/>
|
||||
<Vtx Seq="3" Y="12.6" X="-2.2"/>
|
||||
<Vtx Seq="4" Y="12.6" X="2.2"/>
|
||||
<Vtx Seq="5" Y="7" X="2.5"/>
|
||||
<Vtx Seq="6" Y="0" X="2.5"/>
|
||||
</Vertices>
|
||||
</BoatShape>
|
||||
<BoatShape ShapeID="34">
|
||||
<Vertices>
|
||||
<Vtx Seq="1" Y="0" X="-1.16"/>
|
||||
<Vtx Seq="2" Y="5.51" X="-1.16"/>
|
||||
<Vtx Seq="3" Y="5.846" X="-0.84"/>
|
||||
<Vtx Seq="4" Y="5.846" X="0.84"/>
|
||||
<Vtx Seq="5" Y="5.51" X="1.16"/>
|
||||
<Vtx Seq="6" Y="0" X="1.16"/>
|
||||
</Vertices>
|
||||
</BoatShape>
|
||||
<BoatShape ShapeID="35">
|
||||
<Vertices>
|
||||
<Vtx Seq="1" Y="0" X="-1.461"/>
|
||||
<Vtx Seq="2" Y="6" X="-1.461"/>
|
||||
<Vtx Seq="3" Y="7" X="-1.44"/>
|
||||
<Vtx Seq="4" Y="8" X="-1.38"/>
|
||||
<Vtx Seq="5" Y="9" X="-1.17"/>
|
||||
<Vtx Seq="6" Y="10" X="-0.76"/>
|
||||
<Vtx Seq="7" Y="10.6" X="-0.34"/>
|
||||
<Vtx Seq="8" Y="10.61" X="0"/>
|
||||
<Vtx Seq="9" Y="10.6" X="0.34"/>
|
||||
<Vtx Seq="10" Y="10" X="0.76"/>
|
||||
<Vtx Seq="11" Y="9" X="1.17"/>
|
||||
<Vtx Seq="12" Y="8" X="1.38"/>
|
||||
<Vtx Seq="13" Y="7" X="1.44"/>
|
||||
<Vtx Seq="14" Y="6" X="1.461"/>
|
||||
<Vtx Seq="15" Y="0" X="1.461"/>
|
||||
</Vertices>
|
||||
</BoatShape>
|
||||
</BoatShapes>
|
||||
<Boats>
|
||||
<Boat Type="Yacht" SourceID="201" ShapeID="15" StoweName="USA" ShortName="ORACLE" ShorterName="USA" BoatName="ORACLE TEAM USA" HullNum="AC4515" Skipper="SPITHILL" Helmsman="SPITHILL" Country="USA" PeliID="101" RadioIP="172.20.2.101">
|
||||
<GPSposition Z="1.78" Y="-0.331" X="-0.006"/>
|
||||
<MastTop Z="21.496" Y="3.7" X="0"/>
|
||||
<FlagPosition Z="0" Y="6.2" X="0"/>
|
||||
</Boat>
|
||||
<Boat Type="Yacht" SourceID="301" ShapeID="15" StoweName="SWE" ShortName="ARTEMIS" ShorterName="SWE" BoatName="ARTEMIS RACING" HullNum="AC4517" Skipper="OUTTERIDGE" Helmsman="OUTTERIDGE" Country="SWE" PeliID="102" RadioIP="172.20.2.102">
|
||||
<GPSposition Z="1.727" Y="-0.359" X="-0.0121"/>
|
||||
<MastTop Z="21.496" Y="3.7" X="0"/>
|
||||
<FlagPosition Z="0" Y="6.2" X="0"/>
|
||||
</Boat>
|
||||
<Boat Type="Yacht" SourceID="401" ShapeID="15" StoweName="NZL" ShortName="ETNZ" ShorterName="NZL" BoatName="EMIRATES TEAM NZ" HullNum="AC4503" Skipper="ASHBY" Helmsman="BURLING" Country="NZL" PeliID="103" RadioIP="172.20.2.103">
|
||||
<GPSposition Z="1.881" Y="-0.291" X="-0.003"/>
|
||||
<MastTop Z="21.496" Y="3.7" X="0"/>
|
||||
<FlagPosition Z="0" Y="6.2" X="0"/>
|
||||
</Boat>
|
||||
<Boat Type="Yacht" SourceID="501" ShapeID="15" StoweName="JPN" ShortName="JAPAN" ShorterName="JPN" BoatName="SOFTBANK TEAM JAPAN" HullNum="AC4504" Skipper="BARKER" Helmsman="BARKER" Country="JPN" PeliID="104" RadioIP="172.20.2.104">
|
||||
<GPSposition Z="1.805" Y="-0.322" X="-0.003"/>
|
||||
<MastTop Z="21.496" Y="3.7" X="0"/>
|
||||
<FlagPosition Z="0" Y="6.2" X="0"/>
|
||||
</Boat>
|
||||
<Boat Type="Yacht" SourceID="601" ShapeID="15" StoweName="FRA" ShortName="FRANCE" ShorterName="FRA" BoatName="GROUPAMA TEAM FRANCE" HullNum="AC4505" Skipper="CAMMAS" Helmsman="CAMMAS" Country="FRA" PeliID="105" RadioIP="172.20.2.105">
|
||||
<GPSposition Z="1.863" Y="-0.3" X="-0.003"/>
|
||||
<MastTop Z="21.496" Y="3.7" X="0"/>
|
||||
<FlagPosition Z="0" Y="6.2" X="0"/>
|
||||
</Boat>
|
||||
<Boat Type="Yacht" SourceID="701" ShapeID="15" StoweName="GBR" ShortName="GBR" ShorterName="GBR" BoatName="LAND ROVER BAR" HullNum="AC4516" Skipper="ANSLIE" Helmsman="ANSLIE" Country="GBR" PeliID="106" RadioIP="172.20.2.106">
|
||||
<GPSposition Z="1.734" Y="-0.352" X="0"/>
|
||||
<MastTop Z="21.496" Y="3.7" X="0"/>
|
||||
<FlagPosition Z="0" Y="6.2" X="0"/>
|
||||
</Boat>
|
||||
</Boats>
|
||||
</BoatConfig>
|
||||
@@ -1,161 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<BoatConfig>
|
||||
<Modified>2015-08-28T17:32:59+0100</Modified>
|
||||
<Version>12</Version>
|
||||
<Snapshot>219</Snapshot>
|
||||
<Settings>
|
||||
<RaceBoatType Type="AC45"/>
|
||||
<BoatDimension BoatLength="14.019" HullLength="13.449"/>
|
||||
<ZoneSize MarkZoneSize="40.347" CourseZoneSize="53.796"/>
|
||||
<ZoneLimits Limit1="200" Limit2="100" Limit3="53.796" Limit4="0" Limit5="-100"/>
|
||||
</Settings>
|
||||
<BoatShapes>
|
||||
<BoatShape ShapeID="0">
|
||||
<Vertices>
|
||||
<Vtx Seq="3" Y="25" X="0"/>
|
||||
</Vertices>
|
||||
</BoatShape>
|
||||
<BoatShape ShapeID="14">
|
||||
<Vertices>
|
||||
<Vtx Seq="1" Y="0" X="-1"/>
|
||||
<Vtx Seq="2" Y="0.75" X="-1"/>
|
||||
<Vtx Seq="3" Y="0.75" X="-0.25"/>
|
||||
<Vtx Seq="4" Y="3.5" X="-0.25"/>
|
||||
<Vtx Seq="5" Y="4.5" X="-1"/>
|
||||
<Vtx Seq="6" Y="6.5" X="-1"/>
|
||||
<Vtx Seq="7" Y="7" X="-0.5"/>
|
||||
<Vtx Seq="8" Y="7" X="0.5"/>
|
||||
<Vtx Seq="9" Y="6.5" X="1"/>
|
||||
<Vtx Seq="10" Y="4.5" X="1"/>
|
||||
<Vtx Seq="11" Y="3.5" X="0.25"/>
|
||||
<Vtx Seq="12" Y="0.75" X="0.25"/>
|
||||
<Vtx Seq="13" Y="0.75" X="1"/>
|
||||
<Vtx Seq="14" Y="0" X="1"/>
|
||||
</Vertices>
|
||||
</BoatShape>
|
||||
<BoatShape ShapeID="15">
|
||||
<Vertices>
|
||||
<Vtx Seq="1" Y="0" X="-3.46"/>
|
||||
<Vtx Seq="2" Y="13.449" X="-3.46"/>
|
||||
<Vtx Seq="3" Y="14.019" X="0"/>
|
||||
<Vtx Seq="4" Y="13.449" X="3.46"/>
|
||||
<Vtx Seq="5" Y="0" X="3.46"/>
|
||||
</Vertices>
|
||||
<Catamaran>
|
||||
<Vtx Seq="1" Y="1.769" X="-2.752"/>
|
||||
<Vtx Seq="2" Y="0" X="-2.813"/>
|
||||
<Vtx Seq="3" Y="0" X="-3.34"/>
|
||||
<Vtx Seq="4" Y="5.351" X="-3.46"/>
|
||||
<Vtx Seq="5" Y="10.544" X="-3.387"/>
|
||||
<Vtx Seq="6" Y="13.449" X="-3.075"/>
|
||||
<Vtx Seq="7" Y="10.851" X="-2.793"/>
|
||||
<Vtx Seq="8" Y="6.669" X="-2.699"/>
|
||||
<Vtx Seq="9" Y="6.669" X="2.699"/>
|
||||
<Vtx Seq="10" Y="10.851" X="2.793"/>
|
||||
<Vtx Seq="11" Y="13.449" X="3.075"/>
|
||||
<Vtx Seq="12" Y="10.544" X="3.387"/>
|
||||
<Vtx Seq="13" Y="5.351" X="3.46"/>
|
||||
<Vtx Seq="14" Y="0" X="3.34"/>
|
||||
<Vtx Seq="15" Y="0" X="2.813"/>
|
||||
<Vtx Seq="16" Y="1.769" X="2.752"/>
|
||||
</Catamaran>
|
||||
<Bowsprit>
|
||||
<Vtx Seq="1" Y="6.669" X="-0.2"/>
|
||||
<Vtx Seq="2" Y="11.377" X="-0.2"/>
|
||||
<Vtx Seq="3" Y="14.019" X="0"/>
|
||||
<Vtx Seq="4" Y="11.377" X="0.2"/>
|
||||
<Vtx Seq="5" Y="6.669" X="0.2"/>
|
||||
</Bowsprit>
|
||||
<Trampoline>
|
||||
<Vtx Seq="1" Y="2" X="-2.699"/>
|
||||
<Vtx Seq="2" Y="6.438" X="-2.699"/>
|
||||
<Vtx Seq="3" Y="6.438" X="2.699"/>
|
||||
<Vtx Seq="4" Y="2" X="2.699"/>
|
||||
</Trampoline>
|
||||
</BoatShape>
|
||||
<BoatShape ShapeID="18">
|
||||
<Vertices>
|
||||
<Vtx Seq="1" Y="0" X="-1.04"/>
|
||||
<Vtx Seq="2" Y="0.11" X="-1.18"/>
|
||||
<Vtx Seq="3" Y="0.42" X="-1.28"/>
|
||||
<Vtx Seq="4" Y="3.74" X="-1.29"/>
|
||||
<Vtx Seq="5" Y="5.36" X="-1.21"/>
|
||||
<Vtx Seq="6" Y="6.29" X="-1.08"/>
|
||||
<Vtx Seq="7" Y="7.15" X="-0.84"/>
|
||||
<Vtx Seq="8" Y="7.63" X="-0.62"/>
|
||||
<Vtx Seq="9" Y="7.94" X="-0.34"/>
|
||||
<Vtx Seq="10" Y="8.06" X="0"/>
|
||||
<Vtx Seq="11" Y="7.94" X="0.34"/>
|
||||
<Vtx Seq="12" Y="7.63" X="0.62"/>
|
||||
<Vtx Seq="13" Y="7.15" X="0.84"/>
|
||||
<Vtx Seq="14" Y="6.29" X="1.08"/>
|
||||
<Vtx Seq="15" Y="5.36" X="1.21"/>
|
||||
<Vtx Seq="16" Y="3.74" X="1.29"/>
|
||||
<Vtx Seq="17" Y="0.42" X="1.28"/>
|
||||
<Vtx Seq="18" Y="0.11" X="1.18"/>
|
||||
<Vtx Seq="19" Y="0" X="1.04"/>
|
||||
</Vertices>
|
||||
</BoatShape>
|
||||
<BoatShape ShapeID="24">
|
||||
<Vertices>
|
||||
<Vtx Seq="1" Y="0" X="-2.5"/>
|
||||
<Vtx Seq="2" Y="7" X="-2.5"/>
|
||||
<Vtx Seq="3" Y="12.6" X="-2.2"/>
|
||||
<Vtx Seq="4" Y="12.6" X="2.2"/>
|
||||
<Vtx Seq="5" Y="7" X="2.5"/>
|
||||
<Vtx Seq="6" Y="0" X="2.5"/>
|
||||
</Vertices>
|
||||
</BoatShape>
|
||||
<BoatShape ShapeID="34">
|
||||
<Vertices>
|
||||
<Vtx Seq="1" Y="0" X="-1.16"/>
|
||||
<Vtx Seq="2" Y="5.51" X="-1.16"/>
|
||||
<Vtx Seq="3" Y="5.846" X="-0.84"/>
|
||||
<Vtx Seq="4" Y="5.846" X="0.84"/>
|
||||
<Vtx Seq="5" Y="5.51" X="1.16"/>
|
||||
<Vtx Seq="6" Y="0" X="1.16"/>
|
||||
</Vertices>
|
||||
</BoatShape>
|
||||
<BoatShape ShapeID="35">
|
||||
<Vertices>
|
||||
<Vtx Seq="1" Y="0" X="-1.461"/>
|
||||
<Vtx Seq="2" Y="6" X="-1.461"/>
|
||||
<Vtx Seq="3" Y="7" X="-1.44"/>
|
||||
<Vtx Seq="4" Y="8" X="-1.38"/>
|
||||
<Vtx Seq="5" Y="9" X="-1.17"/>
|
||||
<Vtx Seq="6" Y="10" X="-0.76"/>
|
||||
<Vtx Seq="7" Y="10.6" X="-0.34"/>
|
||||
<Vtx Seq="8" Y="10.61" X="0"/>
|
||||
<Vtx Seq="9" Y="10.6" X="0.34"/>
|
||||
<Vtx Seq="10" Y="10" X="0.76"/>
|
||||
<Vtx Seq="11" Y="9" X="1.17"/>
|
||||
<Vtx Seq="12" Y="8" X="1.38"/>
|
||||
<Vtx Seq="13" Y="7" X="1.44"/>
|
||||
<Vtx Seq="14" Y="6" X="1.461"/>
|
||||
<Vtx Seq="15" Y="0" X="1.461"/>
|
||||
</Vertices>
|
||||
</BoatShape>
|
||||
</BoatShapes>
|
||||
<Boats>
|
||||
<Boat Type="Yacht" SourceID="201" ShapeID="15" StoweName="USA" ShortName="ORACLE" ShorterName="USA" BoatName="ORACLE TEAM USA" HullNum="AC4515" Skipper="SPITHILL" Helmsman="SPITHILL" Country="USA" PeliID="101" RadioIP="172.20.2.101">
|
||||
<GPSposition Z="1.78" Y="-0.331" X="-0.006"/>
|
||||
<MastTop Z="21.496" Y="3.7" X="0"/>
|
||||
<FlagPosition Z="0" Y="6.2" X="0"/>
|
||||
</Boat>
|
||||
<Boat Type="Yacht" SourceID="401" ShapeID="15" StoweName="NZL" ShortName="ETNZ" ShorterName="NZL" BoatName="EMIRATES TEAM NZ" HullNum="AC4503" Skipper="ASHBY" Helmsman="BURLING" Country="NZL" PeliID="103" RadioIP="172.20.2.103">
|
||||
<GPSposition Z="1.881" Y="-0.291" X="-0.003"/>
|
||||
<MastTop Z="21.496" Y="3.7" X="0"/>
|
||||
<FlagPosition Z="0" Y="6.2" X="0"/>
|
||||
</Boat>
|
||||
<Boat Type="Yacht" SourceID="501" ShapeID="15" StoweName="JPN" ShortName="JAPAN" ShorterName="JPN" BoatName="SOFTBANK TEAM JAPAN" HullNum="AC4504" Skipper="BARKER" Helmsman="BARKER" Country="JPN" PeliID="104" RadioIP="172.20.2.104">
|
||||
<GPSposition Z="1.805" Y="-0.322" X="-0.003"/>
|
||||
<MastTop Z="21.496" Y="3.7" X="0"/>
|
||||
<FlagPosition Z="0" Y="6.2" X="0"/>
|
||||
</Boat>
|
||||
<Boat Type="Yacht" SourceID="701" ShapeID="15" StoweName="GBR" ShortName="GBR" ShorterName="GBR" BoatName="LAND ROVER BAR" HullNum="AC4516" Skipper="ANSLIE" Helmsman="ANSLIE" Country="GBR" PeliID="106" RadioIP="172.20.2.106">
|
||||
<GPSposition Z="1.734" Y="-0.352" X="0"/>
|
||||
<MastTop Z="21.496" Y="3.7" X="0"/>
|
||||
<FlagPosition Z="0" Y="6.2" X="0"/>
|
||||
</Boat>
|
||||
</Boats>
|
||||
</BoatConfig>
|
||||
@@ -1,171 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<BoatConfig>
|
||||
<Modified>2015-08-28T17:32:59+0100</Modified>
|
||||
<Version>12</Version>
|
||||
<Snapshot>219</Snapshot>
|
||||
<Settings>
|
||||
<RaceBoatType Type="AC45"/>
|
||||
<BoatDimension BoatLength="14.019" HullLength="13.449"/>
|
||||
<ZoneSize MarkZoneSize="40.347" CourseZoneSize="53.796"/>
|
||||
<ZoneLimits Limit1="200" Limit2="100" Limit3="53.796" Limit4="0" Limit5="-100"/>
|
||||
</Settings>
|
||||
<BoatShapes>
|
||||
<BoatShape ShapeID="0">
|
||||
<Vertices>
|
||||
<Vtx Seq="3" Y="25" X="0"/>
|
||||
</Vertices>
|
||||
</BoatShape>
|
||||
<BoatShape ShapeID="14">
|
||||
<Vertices>
|
||||
<Vtx Seq="1" Y="0" X="-1"/>
|
||||
<Vtx Seq="2" Y="0.75" X="-1"/>
|
||||
<Vtx Seq="3" Y="0.75" X="-0.25"/>
|
||||
<Vtx Seq="4" Y="3.5" X="-0.25"/>
|
||||
<Vtx Seq="5" Y="4.5" X="-1"/>
|
||||
<Vtx Seq="6" Y="6.5" X="-1"/>
|
||||
<Vtx Seq="7" Y="7" X="-0.5"/>
|
||||
<Vtx Seq="8" Y="7" X="0.5"/>
|
||||
<Vtx Seq="9" Y="6.5" X="1"/>
|
||||
<Vtx Seq="10" Y="4.5" X="1"/>
|
||||
<Vtx Seq="11" Y="3.5" X="0.25"/>
|
||||
<Vtx Seq="12" Y="0.75" X="0.25"/>
|
||||
<Vtx Seq="13" Y="0.75" X="1"/>
|
||||
<Vtx Seq="14" Y="0" X="1"/>
|
||||
</Vertices>
|
||||
</BoatShape>
|
||||
<BoatShape ShapeID="15">
|
||||
<Vertices>
|
||||
<Vtx Seq="1" Y="0" X="-3.46"/>
|
||||
<Vtx Seq="2" Y="13.449" X="-3.46"/>
|
||||
<Vtx Seq="3" Y="14.019" X="0"/>
|
||||
<Vtx Seq="4" Y="13.449" X="3.46"/>
|
||||
<Vtx Seq="5" Y="0" X="3.46"/>
|
||||
</Vertices>
|
||||
<Catamaran>
|
||||
<Vtx Seq="1" Y="1.769" X="-2.752"/>
|
||||
<Vtx Seq="2" Y="0" X="-2.813"/>
|
||||
<Vtx Seq="3" Y="0" X="-3.34"/>
|
||||
<Vtx Seq="4" Y="5.351" X="-3.46"/>
|
||||
<Vtx Seq="5" Y="10.544" X="-3.387"/>
|
||||
<Vtx Seq="6" Y="13.449" X="-3.075"/>
|
||||
<Vtx Seq="7" Y="10.851" X="-2.793"/>
|
||||
<Vtx Seq="8" Y="6.669" X="-2.699"/>
|
||||
<Vtx Seq="9" Y="6.669" X="2.699"/>
|
||||
<Vtx Seq="10" Y="10.851" X="2.793"/>
|
||||
<Vtx Seq="11" Y="13.449" X="3.075"/>
|
||||
<Vtx Seq="12" Y="10.544" X="3.387"/>
|
||||
<Vtx Seq="13" Y="5.351" X="3.46"/>
|
||||
<Vtx Seq="14" Y="0" X="3.34"/>
|
||||
<Vtx Seq="15" Y="0" X="2.813"/>
|
||||
<Vtx Seq="16" Y="1.769" X="2.752"/>
|
||||
</Catamaran>
|
||||
<Bowsprit>
|
||||
<Vtx Seq="1" Y="6.669" X="-0.2"/>
|
||||
<Vtx Seq="2" Y="11.377" X="-0.2"/>
|
||||
<Vtx Seq="3" Y="14.019" X="0"/>
|
||||
<Vtx Seq="4" Y="11.377" X="0.2"/>
|
||||
<Vtx Seq="5" Y="6.669" X="0.2"/>
|
||||
</Bowsprit>
|
||||
<Trampoline>
|
||||
<Vtx Seq="1" Y="2" X="-2.699"/>
|
||||
<Vtx Seq="2" Y="6.438" X="-2.699"/>
|
||||
<Vtx Seq="3" Y="6.438" X="2.699"/>
|
||||
<Vtx Seq="4" Y="2" X="2.699"/>
|
||||
</Trampoline>
|
||||
</BoatShape>
|
||||
<BoatShape ShapeID="18">
|
||||
<Vertices>
|
||||
<Vtx Seq="1" Y="0" X="-1.04"/>
|
||||
<Vtx Seq="2" Y="0.11" X="-1.18"/>
|
||||
<Vtx Seq="3" Y="0.42" X="-1.28"/>
|
||||
<Vtx Seq="4" Y="3.74" X="-1.29"/>
|
||||
<Vtx Seq="5" Y="5.36" X="-1.21"/>
|
||||
<Vtx Seq="6" Y="6.29" X="-1.08"/>
|
||||
<Vtx Seq="7" Y="7.15" X="-0.84"/>
|
||||
<Vtx Seq="8" Y="7.63" X="-0.62"/>
|
||||
<Vtx Seq="9" Y="7.94" X="-0.34"/>
|
||||
<Vtx Seq="10" Y="8.06" X="0"/>
|
||||
<Vtx Seq="11" Y="7.94" X="0.34"/>
|
||||
<Vtx Seq="12" Y="7.63" X="0.62"/>
|
||||
<Vtx Seq="13" Y="7.15" X="0.84"/>
|
||||
<Vtx Seq="14" Y="6.29" X="1.08"/>
|
||||
<Vtx Seq="15" Y="5.36" X="1.21"/>
|
||||
<Vtx Seq="16" Y="3.74" X="1.29"/>
|
||||
<Vtx Seq="17" Y="0.42" X="1.28"/>
|
||||
<Vtx Seq="18" Y="0.11" X="1.18"/>
|
||||
<Vtx Seq="19" Y="0" X="1.04"/>
|
||||
</Vertices>
|
||||
</BoatShape>
|
||||
<BoatShape ShapeID="24">
|
||||
<Vertices>
|
||||
<Vtx Seq="1" Y="0" X="-2.5"/>
|
||||
<Vtx Seq="2" Y="7" X="-2.5"/>
|
||||
<Vtx Seq="3" Y="12.6" X="-2.2"/>
|
||||
<Vtx Seq="4" Y="12.6" X="2.2"/>
|
||||
<Vtx Seq="5" Y="7" X="2.5"/>
|
||||
<Vtx Seq="6" Y="0" X="2.5"/>
|
||||
</Vertices>
|
||||
</BoatShape>
|
||||
<BoatShape ShapeID="34">
|
||||
<Vertices>
|
||||
<Vtx Seq="1" Y="0" X="-1.16"/>
|
||||
<Vtx Seq="2" Y="5.51" X="-1.16"/>
|
||||
<Vtx Seq="3" Y="5.846" X="-0.84"/>
|
||||
<Vtx Seq="4" Y="5.846" X="0.84"/>
|
||||
<Vtx Seq="5" Y="5.51" X="1.16"/>
|
||||
<Vtx Seq="6" Y="0" X="1.16"/>
|
||||
</Vertices>
|
||||
</BoatShape>
|
||||
<BoatShape ShapeID="35">
|
||||
<Vertices>
|
||||
<Vtx Seq="1" Y="0" X="-1.461"/>
|
||||
<Vtx Seq="2" Y="6" X="-1.461"/>
|
||||
<Vtx Seq="3" Y="7" X="-1.44"/>
|
||||
<Vtx Seq="4" Y="8" X="-1.38"/>
|
||||
<Vtx Seq="5" Y="9" X="-1.17"/>
|
||||
<Vtx Seq="6" Y="10" X="-0.76"/>
|
||||
<Vtx Seq="7" Y="10.6" X="-0.34"/>
|
||||
<Vtx Seq="8" Y="10.61" X="0"/>
|
||||
<Vtx Seq="9" Y="10.6" X="0.34"/>
|
||||
<Vtx Seq="10" Y="10" X="0.76"/>
|
||||
<Vtx Seq="11" Y="9" X="1.17"/>
|
||||
<Vtx Seq="12" Y="8" X="1.38"/>
|
||||
<Vtx Seq="13" Y="7" X="1.44"/>
|
||||
<Vtx Seq="14" Y="6" X="1.461"/>
|
||||
<Vtx Seq="15" Y="0" X="1.461"/>
|
||||
</Vertices>
|
||||
</BoatShape>
|
||||
</BoatShapes>
|
||||
<Boats>
|
||||
<Boat Type="Yacht" SourceID="201" ShapeID="15" StoweName="USA" ShortName="ORACLE" ShorterName="USA" BoatName="ORACLE TEAM USA" HullNum="AC4515" Skipper="SPITHILL" Helmsman="SPITHILL" Country="USA" PeliID="101" RadioIP="172.20.2.101">
|
||||
<GPSposition Z="1.78" Y="-0.331" X="-0.006"/>
|
||||
<MastTop Z="21.496" Y="3.7" X="0"/>
|
||||
<FlagPosition Z="0" Y="6.2" X="0"/>
|
||||
</Boat>
|
||||
<Boat Type="Yacht" SourceID="301" ShapeID="15" StoweName="SWE" ShortName="ARTEMIS" ShorterName="SWE" BoatName="ARTEMIS RACING" HullNum="AC4517" Skipper="OUTTERIDGE" Helmsman="OUTTERIDGE" Country="SWE" PeliID="102" RadioIP="172.20.2.102">
|
||||
<GPSposition Z="1.727" Y="-0.359" X="-0.0121"/>
|
||||
<MastTop Z="21.496" Y="3.7" X="0"/>
|
||||
<FlagPosition Z="0" Y="6.2" X="0"/>
|
||||
</Boat>
|
||||
<Boat Type="Yacht" SourceID="401" ShapeID="15" StoweName="NZL" ShortName="ETNZ" ShorterName="NZL" BoatName="EMIRATES TEAM NZ" HullNum="AC4503" Skipper="ASHBY" Helmsman="BURLING" Country="NZL" PeliID="103" RadioIP="172.20.2.103">
|
||||
<GPSposition Z="1.881" Y="-0.291" X="-0.003"/>
|
||||
<MastTop Z="21.496" Y="3.7" X="0"/>
|
||||
<FlagPosition Z="0" Y="6.2" X="0"/>
|
||||
</Boat>
|
||||
<Boat Type="Yacht" SourceID="501" ShapeID="15" StoweName="JPN" ShortName="JAPAN" ShorterName="JPN" BoatName="SOFTBANK TEAM JAPAN" HullNum="AC4504" Skipper="BARKER" Helmsman="BARKER" Country="JPN" PeliID="104" RadioIP="172.20.2.104">
|
||||
<GPSposition Z="1.805" Y="-0.322" X="-0.003"/>
|
||||
<MastTop Z="21.496" Y="3.7" X="0"/>
|
||||
<FlagPosition Z="0" Y="6.2" X="0"/>
|
||||
</Boat>
|
||||
<Boat Type="Yacht" SourceID="601" ShapeID="15" StoweName="FRA" ShortName="FRANCE" ShorterName="FRA" BoatName="GROUPAMA TEAM FRANCE" HullNum="AC4505" Skipper="CAMMAS" Helmsman="CAMMAS" Country="FRA" PeliID="105" RadioIP="172.20.2.105">
|
||||
<GPSposition Z="1.863" Y="-0.3" X="-0.003"/>
|
||||
<MastTop Z="21.496" Y="3.7" X="0"/>
|
||||
<FlagPosition Z="0" Y="6.2" X="0"/>
|
||||
</Boat>
|
||||
<Boat Type="Yacht" SourceID="701" ShapeID="15" StoweName="GBR" ShortName="GBR" ShorterName="GBR" BoatName="LAND ROVER BAR" HullNum="AC4516" Skipper="ANSLIE" Helmsman="ANSLIE" Country="GBR" PeliID="106" RadioIP="172.20.2.106">
|
||||
<GPSposition Z="1.734" Y="-0.352" X="0"/>
|
||||
<MastTop Z="21.496" Y="3.7" X="0"/>
|
||||
<FlagPosition Z="0" Y="6.2" X="0"/>
|
||||
</Boat>
|
||||
</Boats>
|
||||
</BoatConfig>
|
||||
@@ -1,5 +1,10 @@
|
||||
<?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?>
|
||||
@@ -10,6 +15,7 @@
|
||||
<?import javafx.scene.layout.RowConstraints?>
|
||||
<?import javafx.scene.text.Font?>
|
||||
<?import javafx.scene.text.Text?>
|
||||
|
||||
<AnchorPane fx:id="holder" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="960.0" prefWidth="1530.0" style="-fx-background-color: #2C2c36;" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="seng302.visualiser.controllers.StartScreenController">
|
||||
<children>
|
||||
<GridPane fx:id="startScreen2" layoutX="365.0" layoutY="285.0" nodeOrientation="LEFT_TO_RIGHT" prefWidth="800.0" style="-fx-background-color: #2C2c36;">
|
||||
@@ -25,7 +31,7 @@
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</GridPane.margin>
|
||||
</Button>
|
||||
<TextField fx:id="ipTextField" alignment="CENTER" maxWidth="-Infinity" prefHeight="25.0" prefWidth="148.0" promptText="Host IP" text="132.181.14." GridPane.halignment="RIGHT" GridPane.rowIndex="4">
|
||||
<TextField fx:id="ipTextField" alignment="CENTER" maxWidth="-Infinity" prefHeight="25.0" prefWidth="148.0" promptText="Host IP" text="localhost" GridPane.halignment="RIGHT" GridPane.rowIndex="4">
|
||||
<GridPane.margin>
|
||||
<Insets bottom="10.0" left="5.0" right="85.0" top="10.0" />
|
||||
</GridPane.margin>
|
||||
|
||||
@@ -9,9 +9,9 @@ public class ColorsTest {
|
||||
|
||||
@Test
|
||||
public void testNextColor() {
|
||||
Color expectedColors[] = {Color.RED, Color.PERU, Color.SEAGREEN, Color.GREEN, Color.BLUE, Color.PURPLE};
|
||||
for (int i = 0; i<6; i++)
|
||||
{
|
||||
Color expectedColors[] = {Color.RED, Color.PERU, Color.GOLD, Color.GREEN, Color.BLUE,
|
||||
Color.PURPLE, Color.DEEPPINK, Color.GRAY};
|
||||
for (int i = 0; i < 8; i++) {
|
||||
Assert.assertEquals(expectedColors[i], Colors.getColor());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
package seng302.model;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import seng302.gameServer.GameState;
|
||||
import seng302.utilities.GeoUtility;
|
||||
|
||||
/**
|
||||
* Test update function in Yacht.java to make sure yacht will not be collide each other within 25.0
|
||||
* meters.
|
||||
*/
|
||||
public class UpdateYachtTest {
|
||||
|
||||
private ServerYacht yacht1 = new ServerYacht("Yacht", 1, "1", "Yacht" + 1, "Yacht" + 1, "Test1");
|
||||
private ServerYacht yacht2 = new ServerYacht("Yacht", 2, "2", "Yacht" + 2, "Yacht" + 2, "Test2");
|
||||
private GeoPoint geoPoint1 = new GeoPoint(50.0, 50.0);
|
||||
private GeoPoint geoPoint2 = GeoUtility.getGeoCoordinate(geoPoint1, 90.0, 50.0);
|
||||
|
||||
@Before
|
||||
public void setUpRace() {
|
||||
new GameState("");
|
||||
GameState.addYacht(1, yacht1);
|
||||
GameState.addYacht(2, yacht2);
|
||||
PolarTable.parsePolarFile(getClass().getResourceAsStream("/config/acc_polars.csv"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateYachtWithCollision() {
|
||||
// Yacht 1 heading towards 90 degrees heading
|
||||
yacht1.setLocation(geoPoint1);
|
||||
|
||||
// Yacht 2 heading towards 270 degrees heading
|
||||
yacht2.setLocation(geoPoint1);
|
||||
|
||||
// Start yacht 1 and rest yacht 2
|
||||
if (!yacht1.getSailIn()) {
|
||||
yacht1.toggleSailIn();
|
||||
}
|
||||
GameState.checkForCollision(yacht1);
|
||||
double moved = GeoUtility.getDistance(yacht1.getLocation(), geoPoint1);
|
||||
Assert.assertEquals(GameState.BOUNCE_DISTANCE_YACHT, moved, 0.1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateYachtWithoutCollision() {
|
||||
// Yacht 1 heading towards 90 degrees heading
|
||||
yacht1.setLocation(geoPoint1);
|
||||
|
||||
// Yacht 2 heading towards 270 degrees heading
|
||||
yacht2.setLocation(geoPoint2);
|
||||
|
||||
// Start yacht 1 and rest yacht 2
|
||||
if (!yacht1.getSailIn()) {
|
||||
yacht1.toggleSailIn();
|
||||
}
|
||||
GameState.checkForCollision(yacht1);
|
||||
Assert.assertTrue(
|
||||
GameState.YACHT_COLLISION_DISTANCE < GeoUtility.getDistance(geoPoint1, geoPoint2
|
||||
)
|
||||
); //Check that yachts are actually far enough apart for no collision.
|
||||
Assert.assertEquals(geoPoint1.getLat(), yacht1.getLocation().getLat(), 0.001);
|
||||
Assert.assertEquals(geoPoint1.getLng(), yacht1.getLocation().getLng(), 0.001);
|
||||
Assert.assertEquals(geoPoint2.getLat(), yacht1.getLocation().getLat(), 0.001);
|
||||
Assert.assertEquals(geoPoint2.getLng(), yacht1.getLocation().getLng(), 0.001);
|
||||
}
|
||||
}
|
||||
@@ -1,15 +1,9 @@
|
||||
package seng302.visualiser.ClientToServerTests;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import org.junit.After;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import seng302.gameServer.GameStages;
|
||||
import seng302.gameServer.GameState;
|
||||
import seng302.gameServer.MainServerThread;
|
||||
import seng302.gameServer.server.messages.BoatAction;
|
||||
import seng302.model.ServerYacht;
|
||||
import seng302.visualiser.ClientToServerThread;
|
||||
|
||||
/**
|
||||
@@ -22,32 +16,32 @@ public class RegularPacketsTest {
|
||||
|
||||
@Before
|
||||
public void setup() throws Exception {
|
||||
new GameState("localhost");
|
||||
serverThread = new MainServerThread();
|
||||
clientThread = new ClientToServerThread("localhost", 4942);
|
||||
GameState.setCurrentStage(GameStages.RACING);
|
||||
// new GameState("localhost");
|
||||
// serverThread = new MainServerThread();
|
||||
// clientThread = new ClientToServerThread("localhost", 4942);
|
||||
// GameState.setCurrentStage(GameStages.RACING);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void packetsSentAtRegularIntervals () throws Exception {
|
||||
final double TEST_DISTANCE = 10.0;
|
||||
serverThread.startGame();
|
||||
SleepThreadMaxDelay();
|
||||
ServerYacht yacht = new ArrayList<>(GameState.getYachts().values()).get(0);
|
||||
double startAngle = yacht.getHeading();
|
||||
long startTime = System.currentTimeMillis();
|
||||
clientThread.sendBoatAction(BoatAction.UPWIND);
|
||||
Thread.sleep(200);
|
||||
while (Math.abs(yacht.getHeading() - startAngle) < TEST_DISTANCE) {
|
||||
Thread.sleep(1);
|
||||
}
|
||||
clientThread.sendBoatAction(BoatAction.MAINTAIN_HEADING);
|
||||
long endTime = System.currentTimeMillis();
|
||||
SleepThreadMaxDelay();
|
||||
//Allowed to be two loops of delay due to loop delay and processing delay at client + server ends.
|
||||
Assert.assertEquals(
|
||||
TEST_DISTANCE / ServerYacht.TURN_STEP * ClientToServerThread.PACKET_SENDING_INTERVAL_MS,
|
||||
(endTime - startTime), 2 * ClientToServerThread.PACKET_SENDING_INTERVAL_MS);
|
||||
// final double TEST_DISTANCE = 10.0;
|
||||
// serverThread.startGame();
|
||||
// SleepThreadMaxDelay();
|
||||
// ServerYacht yacht = new ArrayList<>(GameState.getYachts().values()).get(0);
|
||||
// double startAngle = yacht.getHeading();
|
||||
// long startTime = System.currentTimeMillis();
|
||||
// clientThread.sendBoatAction(BoatAction.UPWIND);
|
||||
// Thread.sleep(200);
|
||||
// while (Math.abs(yacht.getHeading() - startAngle) < TEST_DISTANCE) {
|
||||
// Thread.sleep(1);
|
||||
// }
|
||||
// clientThread.sendBoatAction(BoatAction.MAINTAIN_HEADING);
|
||||
// long endTime = System.currentTimeMillis();
|
||||
// SleepThreadMaxDelay();
|
||||
// //Allowed to be two loops of delay due to loop delay and processing delay at client + server ends.
|
||||
// Assert.assertEquals(
|
||||
// TEST_DISTANCE / ServerYacht.TURN_STEP * ClientToServerThread.PACKET_SENDING_INTERVAL_MS,
|
||||
// (endTime - startTime), 2 * ClientToServerThread.PACKET_SENDING_INTERVAL_MS);
|
||||
}
|
||||
|
||||
// @Test
|
||||
@@ -72,10 +66,10 @@ public class RegularPacketsTest {
|
||||
|
||||
@After
|
||||
public void teardown () throws Exception {
|
||||
clientThread.setSocketToClose();
|
||||
serverThread.terminate();
|
||||
GameState.setCurrentStage(GameStages.LOBBYING);
|
||||
for (int i = 0; i<20; i++)
|
||||
SleepThreadMaxDelay(); //Make sure socket is closed and toolkit remade.
|
||||
// clientThread.setSocketToClose();
|
||||
// serverThread.terminate();
|
||||
// GameState.setCurrentStage(GameStages.LOBBYING);
|
||||
// for (int i = 0; i<20; i++)
|
||||
// SleepThreadMaxDelay(); //Make sure socket is closed and toolkit remade.
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package seng302.visualiser.map;
|
||||
|
||||
import static junit.framework.TestCase.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
@@ -21,8 +22,8 @@ public class BoatSailAnimationToggleTest {
|
||||
@Test
|
||||
public void sailToggleTest() throws Exception {
|
||||
assertFalse(yacht.getSailIn());
|
||||
yacht.toggleClientSail();
|
||||
assertFalse(yacht.getSailIn());
|
||||
yacht.toggleSail();
|
||||
assertTrue(yacht.getSailIn());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -17,14 +17,10 @@ import seng302.visualiser.ClientToServerThread;
|
||||
*/
|
||||
public class ToggleSailSteps {
|
||||
|
||||
|
||||
MainServerThread mst;
|
||||
ClientToServerThread client;
|
||||
boolean sailsIn = false;
|
||||
long startTime;
|
||||
|
||||
|
||||
|
||||
@Given("^The game is running$")
|
||||
public void the_game_is_running() throws Throwable {
|
||||
mst = new MainServerThread();
|
||||
|
||||
Reference in New Issue
Block a user