mirror of
https://github.com/michaelrausch/Party-Parrots-At-Sea.git
synced 2026-05-09 14:28:43 +00:00
Merge branch 'Story66_Collision' into 'develop'
Collision branch merging to develop
# Change log
* Added yacht-mark collision and yacht will be pushed back upon collision.
* Added yacht-yacht collision and both yachts will be pushed back upon collision.
* Updated yacht map position initialisation. Yachts will all be spawned behind start line with a distance apart from each other.
* Added a collision visual alert when collision packet is received.
* Added two extra colours to support for 8 boats.
# Testing
* Junit tests for yacht-yacht collision.
* Manual testing for yacht map position initialisation
* Yacht spawned apart from each other.
* Yacht will spawn behind start line even if start line is different direction.
See merge request !59
This commit is contained in:
@@ -180,3 +180,7 @@ local.properties
|
|||||||
.recommenders/
|
.recommenders/
|
||||||
|
|
||||||
Makefile
|
Makefile
|
||||||
|
|
||||||
|
infer-out/
|
||||||
|
infer.txt
|
||||||
|
log.log
|
||||||
@@ -1,15 +1,20 @@
|
|||||||
package seng302.gameServer;
|
package seng302.gameServer;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.HashMap;
|
import java.util.*;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import seng302.gameServer.server.messages.BoatAction;
|
import seng302.gameServer.server.messages.BoatAction;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import seng302.model.Player;
|
import seng302.model.Player;
|
||||||
import seng302.model.Yacht;
|
import seng302.model.Yacht;
|
||||||
import seng302.model.mark.MarkOrder;
|
import seng302.model.mark.MarkOrder;
|
||||||
|
import javafx.application.Platform;
|
||||||
|
import javafx.collections.FXCollections;
|
||||||
|
import javafx.collections.ObservableList;
|
||||||
|
import seng302.model.GeoPoint;
|
||||||
|
import seng302.model.mark.CompoundMark;
|
||||||
|
import seng302.model.mark.Mark;
|
||||||
|
import seng302.utilities.GeoUtility;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A Static class to hold information about the current state of the game (model)
|
* A Static class to hold information about the current state of the game (model)
|
||||||
@@ -33,6 +38,7 @@ public class GameState implements Runnable {
|
|||||||
private static GameStages currentStage;
|
private static GameStages currentStage;
|
||||||
private static MarkOrder markOrder;
|
private static MarkOrder markOrder;
|
||||||
private static long startTime;
|
private static long startTime;
|
||||||
|
private static Set<Mark> marks;
|
||||||
|
|
||||||
private static Map<Player, String> playerStringMap = new HashMap<>();
|
private static Map<Player, String> playerStringMap = new HashMap<>();
|
||||||
/*
|
/*
|
||||||
@@ -58,16 +64,21 @@ public class GameState implements Runnable {
|
|||||||
isRaceStarted = false;
|
isRaceStarted = false;
|
||||||
//set this when game stage changes to prerace
|
//set this when game stage changes to prerace
|
||||||
previousUpdateTime = System.currentTimeMillis();
|
previousUpdateTime = System.currentTimeMillis();
|
||||||
yachts = new HashMap<>();
|
|
||||||
markOrder = new MarkOrder(); //This could be instantiated at some point with a select map?
|
markOrder = new MarkOrder(); //This could be instantiated at some point with a select map?
|
||||||
|
|
||||||
new Thread(this).start(); //Run the auto updates on the game state
|
new Thread(this).start(); //Run the auto updates on the game state
|
||||||
|
|
||||||
|
marks = new MarkOrder().getAllMarks();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String getHostIpAddress() {
|
public static String getHostIpAddress() {
|
||||||
return hostIpAddress;
|
return hostIpAddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Set<Mark> getMarks(){
|
||||||
|
return Collections.unmodifiableSet(marks);
|
||||||
|
}
|
||||||
|
|
||||||
public static List<Player> getPlayers() {
|
public static List<Player> getPlayers() {
|
||||||
return players;
|
return players;
|
||||||
}
|
}
|
||||||
@@ -175,6 +186,7 @@ public class GameState implements Runnable {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates a new ID based off the size of current players + 1
|
* Generates a new ID based off the size of current players + 1
|
||||||
|
*
|
||||||
* @return a playerID to be allocated to a new connetion
|
* @return a playerID to be allocated to a new connetion
|
||||||
*/
|
*/
|
||||||
public static Integer getUniquePlayerID() {
|
public static Integer getUniquePlayerID() {
|
||||||
|
|||||||
@@ -1,20 +1,28 @@
|
|||||||
package seng302.gameServer;
|
package seng302.gameServer;
|
||||||
|
|
||||||
|
import com.sun.corba.se.spi.activation.Server;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.ServerSocket;
|
import java.net.ServerSocket;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Observable;
|
import java.util.Observable;
|
||||||
|
import java.util.Observer;
|
||||||
import java.util.Timer;
|
import java.util.Timer;
|
||||||
import java.util.TimerTask;
|
import java.util.TimerTask;
|
||||||
|
import seng302.model.GeoPoint;
|
||||||
import seng302.model.Player;
|
import seng302.model.Player;
|
||||||
|
import seng302.model.Yacht;
|
||||||
|
import seng302.model.mark.CompoundMark;
|
||||||
|
import seng302.utilities.GeoUtility;
|
||||||
|
import seng302.visualiser.GameClient;
|
||||||
import seng302.model.PolarTable;
|
import seng302.model.PolarTable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A class describing the overall server, which creates and collects server threads for each client
|
* A class describing the overall server, which creates and collects server threads for each client
|
||||||
* Created by wmu16 on 13/07/17.
|
* Created by wmu16 on 13/07/17.
|
||||||
*/
|
*/
|
||||||
public class MainServerThread extends Observable implements Runnable, ClientConnectionDelegate{
|
public class MainServerThread extends Observable implements Runnable, ClientConnectionDelegate,
|
||||||
|
Observer {
|
||||||
|
|
||||||
private static final int PORT = 4942;
|
private static final int PORT = 4942;
|
||||||
private static final Integer CLIENT_UPDATES_PER_SECOND = 10;
|
private static final Integer CLIENT_UPDATES_PER_SECOND = 10;
|
||||||
@@ -26,6 +34,8 @@ public class MainServerThread extends Observable implements Runnable, ClientConn
|
|||||||
private ServerSocket serverSocket = null;
|
private ServerSocket serverSocket = null;
|
||||||
private ArrayList<ServerToClientThread> serverToClientThreads = new ArrayList<>();
|
private ArrayList<ServerToClientThread> serverToClientThreads = new ArrayList<>();
|
||||||
|
|
||||||
|
private GameClient gameClient;
|
||||||
|
|
||||||
public MainServerThread() {
|
public MainServerThread() {
|
||||||
new GameState("localhost");
|
new GameState("localhost");
|
||||||
try {
|
try {
|
||||||
@@ -45,7 +55,6 @@ public class MainServerThread extends Observable implements Runnable, ClientConn
|
|||||||
HeartbeatThread heartbeatThread;
|
HeartbeatThread heartbeatThread;
|
||||||
|
|
||||||
serverListenThread = new ServerListenThread(serverSocket, this);
|
serverListenThread = new ServerListenThread(serverSocket, this);
|
||||||
|
|
||||||
heartbeatThread = new HeartbeatThread(this);
|
heartbeatThread = new HeartbeatThread(this);
|
||||||
|
|
||||||
heartbeatThread.start();
|
heartbeatThread.start();
|
||||||
@@ -92,12 +101,14 @@ public class MainServerThread extends Observable implements Runnable, ClientConn
|
|||||||
|
|
||||||
static void serverLog(String message, int logLevel) {
|
static void serverLog(String message, int logLevel) {
|
||||||
if (logLevel <= LOG_LEVEL) {
|
if (logLevel <= LOG_LEVEL) {
|
||||||
System.out.println("[SERVER " + LocalDateTime.now().toLocalTime().toString() + "] " + message);
|
System.out.println(
|
||||||
|
"[SERVER " + LocalDateTime.now().toLocalTime().toString() + "] " + message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A client has tried to connect to the server
|
* A client has tried to connect to the server
|
||||||
|
*
|
||||||
* @param serverToClientThread The player that connected
|
* @param serverToClientThread The player that connected
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
@@ -113,6 +124,7 @@ public class MainServerThread extends Observable implements Runnable, ClientConn
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* A player has left the game, remove the player from the GameState
|
* A player has left the game, remove the player from the GameState
|
||||||
|
*
|
||||||
* @param player The player that left
|
* @param player The player that left
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
@@ -134,11 +146,12 @@ public class MainServerThread extends Observable implements Runnable, ClientConn
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
serverToClientThreads.remove(closedConnection);
|
serverToClientThreads.remove(closedConnection);
|
||||||
setChanged();
|
|
||||||
notifyObservers();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void startGame() {
|
public void startGame() {
|
||||||
|
initialiseBoatPositions();
|
||||||
|
setupYachtObserver();
|
||||||
|
|
||||||
Timer t = new Timer();
|
Timer t = new Timer();
|
||||||
|
|
||||||
t.schedule(new TimerTask() {
|
t.schedule(new TimerTask() {
|
||||||
@@ -155,4 +168,69 @@ public class MainServerThread extends Observable implements Runnable, ClientConn
|
|||||||
public void terminate() {
|
public void terminate() {
|
||||||
terminated = true;
|
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 DISTANCEFACTOR = 50.0; // distance apart in meters
|
||||||
|
int boatIndex = 0;
|
||||||
|
for (Yacht yacht : GameState.getYachts().values()) {
|
||||||
|
int distanceApart = boatIndex / 2;
|
||||||
|
|
||||||
|
if (boatIndex % 2 == 1 && boatIndex != 0) {
|
||||||
|
distanceApart++;
|
||||||
|
distanceApart *= -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
GeoPoint spawnMark = GeoUtility
|
||||||
|
.getGeoCoordinate(midpoint, perpendicularAngle, distanceApart * DISTANCEFACTOR);
|
||||||
|
|
||||||
|
if (yacht.getHeading() < perpendicularAngle) {
|
||||||
|
spawnMark = GeoUtility
|
||||||
|
.getGeoCoordinate(spawnMark, perpendicularAngle + 90, DISTANCEFACTOR);
|
||||||
|
} else {
|
||||||
|
spawnMark = GeoUtility
|
||||||
|
.getGeoCoordinate(spawnMark, perpendicularAngle + 270, DISTANCEFACTOR);
|
||||||
|
}
|
||||||
|
|
||||||
|
yacht.setLocation(spawnMark);
|
||||||
|
boatIndex++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void update(Observable o, Object arg) {
|
||||||
|
for (ServerToClientThread serverToClientThread : serverToClientThreads) {
|
||||||
|
serverToClientThread.sendCollisionMessage((Integer) arg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setupYachtObserver() {
|
||||||
|
for (ServerToClientThread serverToClientThread : serverToClientThreads) {
|
||||||
|
serverToClientThread.getYacht().addObserver(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,14 @@ import java.util.concurrent.ThreadLocalRandom;
|
|||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import java.util.zip.CRC32;
|
import java.util.zip.CRC32;
|
||||||
import java.util.zip.Checksum;
|
import java.util.zip.Checksum;
|
||||||
|
import seng302.gameServer.server.messages.YachtEventCodeMessage;
|
||||||
|
import seng302.model.Player;
|
||||||
|
import seng302.model.Yacht;
|
||||||
|
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.BoatAction;
|
||||||
import seng302.gameServer.server.messages.BoatLocationMessage;
|
import seng302.gameServer.server.messages.BoatLocationMessage;
|
||||||
import seng302.gameServer.server.messages.BoatStatus;
|
import seng302.gameServer.server.messages.BoatStatus;
|
||||||
@@ -29,13 +37,6 @@ import seng302.gameServer.server.messages.RegistrationResponseMessage;
|
|||||||
import seng302.gameServer.server.messages.RegistrationResponseStatus;
|
import seng302.gameServer.server.messages.RegistrationResponseStatus;
|
||||||
import seng302.gameServer.server.messages.XMLMessage;
|
import seng302.gameServer.server.messages.XMLMessage;
|
||||||
import seng302.gameServer.server.messages.XMLMessageSubType;
|
import seng302.gameServer.server.messages.XMLMessageSubType;
|
||||||
import seng302.model.Player;
|
|
||||||
import seng302.model.Yacht;
|
|
||||||
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
|
* A class describing a single connection to a Client for the purposes of sending and receiving on
|
||||||
@@ -75,6 +76,8 @@ public class ServerToClientThread implements Runnable {
|
|||||||
|
|
||||||
private List<ConnectionListener> connectionListeners = new ArrayList<>();
|
private List<ConnectionListener> connectionListeners = new ArrayList<>();
|
||||||
|
|
||||||
|
private Yacht yacht;
|
||||||
|
|
||||||
public ServerToClientThread(Socket socket) {
|
public ServerToClientThread(Socket socket) {
|
||||||
this.socket = socket;
|
this.socket = socket;
|
||||||
seqNo = 0;
|
seqNo = 0;
|
||||||
@@ -115,8 +118,7 @@ public class ServerToClientThread implements Runnable {
|
|||||||
all = ln.lines().collect(Collectors.toList());
|
all = ln.lines().collect(Collectors.toList());
|
||||||
lName = all.get(ThreadLocalRandom.current().nextInt(0, all.size()));
|
lName = all.get(ThreadLocalRandom.current().nextInt(0, all.size()));
|
||||||
|
|
||||||
|
yacht = new Yacht(
|
||||||
Yacht yacht = new Yacht(
|
|
||||||
"Yacht", sourceId, sourceId.toString(), fName, fName + " " + lName, "NZ"
|
"Yacht", sourceId, sourceId.toString(), fName, fName + " " + lName, "NZ"
|
||||||
);
|
);
|
||||||
GameState.addYacht(sourceId, yacht);
|
GameState.addYacht(sourceId, yacht);
|
||||||
@@ -164,7 +166,6 @@ public class ServerToClientThread implements Runnable {
|
|||||||
int sync2;
|
int sync2;
|
||||||
// TODO: 14/07/17 wmu16 - Work out how to fix this while loop
|
// TODO: 14/07/17 wmu16 - Work out how to fix this while loop
|
||||||
|
|
||||||
|
|
||||||
while (socket.isConnected()) {
|
while (socket.isConnected()) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -258,7 +259,6 @@ public class ServerToClientThread implements Runnable {
|
|||||||
currentByte = is.read();
|
currentByte = is.read();
|
||||||
crcBuffer.write(currentByte);
|
crcBuffer.write(currentByte);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
|
||||||
serverLog("Socket read failed", 1);
|
serverLog("Socket read failed", 1);
|
||||||
}
|
}
|
||||||
if (currentByte == -1) {
|
if (currentByte == -1) {
|
||||||
@@ -356,6 +356,14 @@ public class ServerToClientThread implements Runnable {
|
|||||||
return socket;
|
return socket;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Yacht getYacht() {
|
||||||
|
return yacht;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void sendCollisionMessage(Integer yachtId) {
|
||||||
|
sendMessage(new YachtEventCodeMessage(yachtId));
|
||||||
|
}
|
||||||
|
|
||||||
public void addConnectionListener(ConnectionListener listener) {
|
public void addConnectionListener(ConnectionListener listener) {
|
||||||
connectionListeners.add(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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,12 +6,12 @@ import javafx.scene.paint.Color;
|
|||||||
* Enum for generating colours.
|
* Enum for generating colours.
|
||||||
*/
|
*/
|
||||||
public enum Colors {
|
public enum Colors {
|
||||||
RED, PERU, SEAGREEN, GREEN, BLUE, PURPLE;
|
RED, PERU, GOLD, GREEN, BLUE, PURPLE, DEEPPINK, GRAY;
|
||||||
|
|
||||||
static Integer index = 0;
|
static Integer index = 0;
|
||||||
|
|
||||||
public static Color getColor() {
|
public static Color getColor() {
|
||||||
if (index == 6) {
|
if (index == 8) {
|
||||||
index = 0;
|
index = 0;
|
||||||
}
|
}
|
||||||
return Color.valueOf(values()[index++].toString());
|
return Color.valueOf(values()[index++].toString());
|
||||||
|
|||||||
@@ -1,10 +1,5 @@
|
|||||||
package seng302.model;
|
package seng302.model;
|
||||||
|
|
||||||
import java.text.DateFormat;
|
|
||||||
import java.text.SimpleDateFormat;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import javafx.beans.property.ReadOnlyDoubleProperty;
|
import javafx.beans.property.ReadOnlyDoubleProperty;
|
||||||
import javafx.beans.property.ReadOnlyDoubleWrapper;
|
import javafx.beans.property.ReadOnlyDoubleWrapper;
|
||||||
import javafx.beans.property.ReadOnlyLongProperty;
|
import javafx.beans.property.ReadOnlyLongProperty;
|
||||||
@@ -17,14 +12,23 @@ import seng302.model.mark.CompoundMark;
|
|||||||
import seng302.model.mark.Mark;
|
import seng302.model.mark.Mark;
|
||||||
import seng302.utilities.GeoUtility;
|
import seng302.utilities.GeoUtility;
|
||||||
|
|
||||||
|
import java.text.DateFormat;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.Observable;
|
||||||
|
|
||||||
|
import static seng302.utilities.GeoUtility.getGeoCoordinate;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Yacht class for the racing boat.
|
* Yacht class for the racing boat.
|
||||||
*
|
*
|
||||||
* Class created to store more variables (eg. boat statuses) compared to the XMLParser boat class,
|
* 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.
|
* also done outside Boat class because some old variables are not used anymore.
|
||||||
*/
|
*/
|
||||||
public class Yacht {
|
public class Yacht extends Observable {
|
||||||
|
|
||||||
|
|
||||||
@FunctionalInterface
|
@FunctionalInterface
|
||||||
public interface YachtLocationListener {
|
public interface YachtLocationListener {
|
||||||
@@ -34,7 +38,12 @@ public class Yacht {
|
|||||||
private Logger logger = LoggerFactory.getLogger(Yacht.class);
|
private Logger logger = LoggerFactory.getLogger(Yacht.class);
|
||||||
|
|
||||||
private static final Double ROUNDING_DISTANCE = 50d; // TODO: 3/08/17 wmu16 - Look into this value further
|
private static final Double ROUNDING_DISTANCE = 50d; // TODO: 3/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;
|
||||||
|
private static final Double BOUNCE_DISTANCE_MARK = 20.0;
|
||||||
|
private static final Double BOUNCE_DISTANCE_YACHT = 30.0;
|
||||||
|
private static final Integer COLLISION_UPDATE_INTERVAL = 100;
|
||||||
|
private static final Double COLLISION_VELOCITY_PENALTY = 0.3;
|
||||||
|
|
||||||
//BOTH AFAIK
|
//BOTH AFAIK
|
||||||
private String boatType;
|
private String boatType;
|
||||||
@@ -68,6 +77,7 @@ public class Yacht {
|
|||||||
private Boolean hasPassedLine;
|
private Boolean hasPassedLine;
|
||||||
private Boolean hasPassedThroughGate;
|
private Boolean hasPassedThroughGate;
|
||||||
private Boolean finishedRace;
|
private Boolean finishedRace;
|
||||||
|
private Long lastCollisionUpdate;
|
||||||
|
|
||||||
//CLIENT SIDE
|
//CLIENT SIDE
|
||||||
private List<YachtLocationListener> locationListeners = new ArrayList<>();
|
private List<YachtLocationListener> locationListeners = new ArrayList<>();
|
||||||
@@ -100,6 +110,19 @@ public class Yacht {
|
|||||||
this.finishedRace = false;
|
this.finishedRace = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Mark markCollidedWith() {
|
||||||
|
Set<Mark> marksInRace = GameState.getMarks();
|
||||||
|
|
||||||
|
for (Mark mark : marksInRace) {
|
||||||
|
if (GeoUtility.getDistance(getLocation(), new GeoPoint(mark.getLat(), mark.getLng()))
|
||||||
|
<= MARK_COLLISION_DISTANCE) {
|
||||||
|
return mark;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param timeInterval since last update in milliseconds
|
* @param timeInterval since last update in milliseconds
|
||||||
*/
|
*/
|
||||||
@@ -113,7 +136,7 @@ public class Yacht {
|
|||||||
if (sailIn && velocity <= maxBoatSpeed && maxBoatSpeed != 0d) {
|
if (sailIn && velocity <= maxBoatSpeed && maxBoatSpeed != 0d) {
|
||||||
|
|
||||||
if (velocity < maxBoatSpeed) {
|
if (velocity < maxBoatSpeed) {
|
||||||
velocity += maxBoatSpeed / 15; // Acceleration
|
velocity += maxBoatSpeed / 120; // Acceleration
|
||||||
}
|
}
|
||||||
if (velocity > maxBoatSpeed) {
|
if (velocity > maxBoatSpeed) {
|
||||||
velocity = maxBoatSpeed; // Prevent the boats from exceeding top speed
|
velocity = maxBoatSpeed; // Prevent the boats from exceeding top speed
|
||||||
@@ -138,6 +161,35 @@ public class Yacht {
|
|||||||
//UPDATE BOAT LOCATION
|
//UPDATE BOAT LOCATION
|
||||||
lastLocation = location;
|
lastLocation = location;
|
||||||
location = GeoUtility.getGeoCoordinate(location, heading, velocity * secondsElapsed);
|
location = GeoUtility.getGeoCoordinate(location, heading, velocity * secondsElapsed);
|
||||||
|
Double metersCovered = velocity * secondsElapsed;
|
||||||
|
GeoPoint calculatedPoint = getGeoCoordinate(location, heading, metersCovered);
|
||||||
|
|
||||||
|
if (shouldDoCollisionUpdate()) {
|
||||||
|
Yacht collidedYacht = checkCollision(calculatedPoint);
|
||||||
|
|
||||||
|
if (collidedYacht != null) {
|
||||||
|
location = calculateBounceBackYacht(this, collidedYacht, BOUNCE_DISTANCE_YACHT);
|
||||||
|
velocity *= COLLISION_VELOCITY_PENALTY;
|
||||||
|
collidedYacht.setLocation(
|
||||||
|
calculateBounceBackYacht(collidedYacht, this, BOUNCE_DISTANCE_YACHT));
|
||||||
|
collidedYacht.setVelocity(collidedYacht.getVelocity() * COLLISION_VELOCITY_PENALTY);
|
||||||
|
setChanged();
|
||||||
|
notifyObservers(this.sourceId);
|
||||||
|
} else if (markCollidedWith() != null) {
|
||||||
|
location = calculateBounceBack(
|
||||||
|
new GeoPoint(markCollidedWith().getLat(), markCollidedWith().getLng()),
|
||||||
|
BOUNCE_DISTANCE_MARK);
|
||||||
|
velocity *= COLLISION_VELOCITY_PENALTY;
|
||||||
|
setChanged();
|
||||||
|
notifyObservers(this.sourceId);
|
||||||
|
} else {
|
||||||
|
location = calculatedPoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
lastCollisionUpdate = System.currentTimeMillis();
|
||||||
|
} else {
|
||||||
|
location = calculatedPoint;
|
||||||
|
}
|
||||||
|
|
||||||
//CHECK FOR MARK ROUNDING
|
//CHECK FOR MARK ROUNDING
|
||||||
if (!finishedRace) {
|
if (!finishedRace) {
|
||||||
@@ -147,10 +199,50 @@ public class Yacht {
|
|||||||
// TODO: 3/08/17 wmu16 - Implement line cross check here
|
// TODO: 3/08/17 wmu16 - Implement line cross check here
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return true if COLLISION_UPDATE_INTERVAL has elapsed since the last collision update
|
||||||
|
*/
|
||||||
|
private Boolean shouldDoCollisionUpdate() {
|
||||||
|
if (lastCollisionUpdate == null) {
|
||||||
|
lastCollisionUpdate = System.currentTimeMillis();
|
||||||
|
}
|
||||||
|
|
||||||
|
return System.currentTimeMillis() - lastCollisionUpdate > COLLISION_UPDATE_INTERVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculate the new position of the boat after it has had a collision
|
||||||
|
*
|
||||||
|
* @return The boats new position
|
||||||
|
*/
|
||||||
|
private GeoPoint calculateBounceBack(GeoPoint collidedWith, Double bounceDistance) {
|
||||||
|
Double heading = GeoUtility.getBearing(location, collidedWith);
|
||||||
|
|
||||||
|
// Invert heading
|
||||||
|
heading -= 180;
|
||||||
|
Integer newHeading = Math.floorMod(heading.intValue(), 360);
|
||||||
|
|
||||||
|
return GeoUtility.getGeoCoordinate(location, newHeading.doubleValue(), bounceDistance);
|
||||||
|
}
|
||||||
|
|
||||||
|
private GeoPoint calculateBounceBackYacht(Yacht collidingYacht, Yacht collidedYacht,
|
||||||
|
Double bounceDistance) {
|
||||||
|
Double heading = GeoUtility
|
||||||
|
.getBearing(collidingYacht.getLocation(), collidedYacht.getLocation());
|
||||||
|
|
||||||
|
heading -= 180;
|
||||||
|
Integer faultYachtHeading = Math.floorMod(heading.intValue(), 360);
|
||||||
|
|
||||||
|
return GeoUtility
|
||||||
|
.getGeoCoordinate(collidingYacht.getLocation(), faultYachtHeading.doubleValue(),
|
||||||
|
bounceDistance);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calculates the distance to the next mark (closest of the two if a gate mark). For purposes
|
* Calculates the distance to the next mark (closest of the two if a gate mark). For purposes
|
||||||
* of mark rounding
|
* of mark rounding
|
||||||
|
*
|
||||||
* @return A distance in metres. Returns -1 if there is no next mark
|
* @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)
|
* @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)}
|
* Check first using {@link seng302.model.mark.MarkOrder#isLastMark(Integer)}
|
||||||
@@ -476,12 +568,16 @@ public class Yacht {
|
|||||||
|
|
||||||
public Integer getSourceId() {
|
public Integer getSourceId() {
|
||||||
//@TODO Remove and merge with Creating Game Loop
|
//@TODO Remove and merge with Creating Game Loop
|
||||||
if (sourceId == null) return 0;
|
if (sourceId == null) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
return sourceId;
|
return sourceId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getHullID() {
|
public String getHullID() {
|
||||||
if (hullID == null) return "";
|
if (hullID == null) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
return hullID;
|
return hullID;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -494,7 +590,9 @@ public class Yacht {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public String getCountry() {
|
public String getCountry() {
|
||||||
if (country == null) return "";
|
if (country == null) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
return country;
|
return country;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -680,4 +778,28 @@ public class Yacht {
|
|||||||
public void addLocationListener(YachtLocationListener listener) {
|
public void addLocationListener(YachtLocationListener listener) {
|
||||||
locationListeners.add(listener);
|
locationListeners.add(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setLocation(GeoPoint geoPoint) {
|
||||||
|
location = geoPoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* @param calculatedPoint point will the yacht will move next
|
||||||
|
* @return yacht which collided with this yacht
|
||||||
|
*/
|
||||||
|
private Yacht checkCollision(GeoPoint calculatedPoint) {
|
||||||
|
|
||||||
|
for (Yacht yacht : GameState.getYachts().values()) {
|
||||||
|
if (yacht != this) {
|
||||||
|
Double distance = GeoUtility.getDistance(yacht.getLocation(), calculatedPoint);
|
||||||
|
if (distance < YACHT_COLLISION_DISTANCE) {
|
||||||
|
return yacht;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,10 +2,6 @@ package seng302.model.mark;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.StringReader;
|
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.DocumentBuilder;
|
||||||
import javax.xml.parsers.DocumentBuilderFactory;
|
import javax.xml.parsers.DocumentBuilderFactory;
|
||||||
import javax.xml.parsers.ParserConfigurationException;
|
import javax.xml.parsers.ParserConfigurationException;
|
||||||
@@ -18,14 +14,15 @@ import seng302.model.stream.xml.generator.Race;
|
|||||||
import seng302.model.stream.xml.parser.RaceXMLData;
|
import seng302.model.stream.xml.parser.RaceXMLData;
|
||||||
import seng302.utilities.XMLGenerator;
|
import seng302.utilities.XMLGenerator;
|
||||||
import seng302.utilities.XMLParser;
|
import seng302.utilities.XMLParser;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class to hold the order of the marks in the race.
|
* Class to hold the order of the marks in the race.
|
||||||
*/
|
*/
|
||||||
public class MarkOrder {
|
public class MarkOrder {
|
||||||
|
|
||||||
private List<CompoundMark> raceMarkOrder;
|
private List<CompoundMark> raceMarkOrder;
|
||||||
private Logger logger = LoggerFactory.getLogger(MarkOrder.class);
|
private Logger logger = LoggerFactory.getLogger(MarkOrder.class);
|
||||||
|
private Set<Mark> allMarks;
|
||||||
|
|
||||||
public MarkOrder(){
|
public MarkOrder(){
|
||||||
loadRaceProperties();
|
loadRaceProperties();
|
||||||
@@ -75,6 +72,10 @@ public class MarkOrder {
|
|||||||
return raceMarkOrder.get(currentSeqID + 1);
|
return raceMarkOrder.get(currentSeqID + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Set<Mark> getAllMarks(){
|
||||||
|
return Collections.unmodifiableSet(allMarks);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads the race order from an XML string
|
* Loads the race order from an XML string
|
||||||
* @param xml An AC35 RaceXML
|
* @param xml An AC35 RaceXML
|
||||||
@@ -85,6 +86,7 @@ public class MarkOrder {
|
|||||||
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
|
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
|
||||||
DocumentBuilder db;
|
DocumentBuilder db;
|
||||||
Document doc;
|
Document doc;
|
||||||
|
allMarks = new HashSet<>();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
db = dbf.newDocumentBuilder();
|
db = dbf.newDocumentBuilder();
|
||||||
@@ -105,6 +107,7 @@ public class MarkOrder {
|
|||||||
for (Corner corner : corners){
|
for (Corner corner : corners){
|
||||||
CompoundMark compoundMark = marks.get(corner.getCompoundMarkID());
|
CompoundMark compoundMark = marks.get(corner.getCompoundMarkID());
|
||||||
course.add(compoundMark);
|
course.add(compoundMark);
|
||||||
|
allMarks.addAll(compoundMark.getMarks());
|
||||||
}
|
}
|
||||||
|
|
||||||
return course;
|
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 org.xml.sax.SAXException;
|
||||||
import seng302.model.stream.packets.PacketType;
|
import seng302.model.stream.packets.PacketType;
|
||||||
import seng302.model.stream.packets.StreamPacket;
|
import seng302.model.stream.packets.StreamPacket;
|
||||||
import seng302.model.stream.parser.MarkRoundingData;
|
import seng302.model.stream.parser.*;
|
||||||
import seng302.model.stream.parser.PositionUpdateData;
|
|
||||||
import seng302.model.stream.parser.PositionUpdateData.DeviceType;
|
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
|
* StreamParser is a utilities class for taking byte data, formatted according to the AC35 streaming
|
||||||
* streaming protocol, and parsing it into basic data types or collections.
|
* protocol, and parsing it into basic data types or collections.
|
||||||
*
|
*
|
||||||
* Created by kre39 on 23/04/17.
|
* 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.
|
* @return the packet sequence number if the packet is of type HEARTBEAT, null otherwise.
|
||||||
*/
|
*/
|
||||||
public static Long extractHeartBeat(StreamPacket packet) {
|
public static Long extractHeartBeat(StreamPacket packet) {
|
||||||
if (packet.getType() != PacketType.HEARTBEAT)
|
if (packet.getType() != PacketType.HEARTBEAT) {
|
||||||
return null;
|
return null;
|
||||||
|
}
|
||||||
long heartbeat = bytesToLong(packet.getPayload());
|
long heartbeat = bytesToLong(packet.getPayload());
|
||||||
System.out.println("heartbeat = " + heartbeat);
|
System.out.println("heartbeat = " + heartbeat);
|
||||||
return heartbeat;
|
return heartbeat;
|
||||||
@@ -52,8 +50,9 @@ public class StreamParser {
|
|||||||
* containing the parsed packet data.
|
* containing the parsed packet data.
|
||||||
*/
|
*/
|
||||||
public static RaceStatusData extractRaceStatus(StreamPacket packet) {
|
public static RaceStatusData extractRaceStatus(StreamPacket packet) {
|
||||||
if (packet.getType() != PacketType.RACE_STATUS)
|
if (packet.getType() != PacketType.RACE_STATUS) {
|
||||||
return null;
|
return null;
|
||||||
|
}
|
||||||
byte[] payload = packet.getPayload();
|
byte[] payload = packet.getPayload();
|
||||||
int messageVersionNo = payload[0];
|
int messageVersionNo = payload[0];
|
||||||
long currentTime = bytesToLong(Arrays.copyOfRange(payload, 1, 7));
|
long currentTime = bytesToLong(Arrays.copyOfRange(payload, 1, 7));
|
||||||
@@ -70,7 +69,6 @@ public class StreamParser {
|
|||||||
windDir, rawWindSpeed, raceStatus, currentTime, expectedStartTime
|
windDir, rawWindSpeed, raceStatus, currentTime, expectedStartTime
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
// long timeTillStart =
|
// long timeTillStart =
|
||||||
// ((new Date(expectedStartTime)).getTime() - (new Date(currentTime)).getTime()) / 1000;
|
// ((new Date(expectedStartTime)).getTime() - (new Date(currentTime)).getTime()) / 1000;
|
||||||
//
|
//
|
||||||
@@ -139,8 +137,9 @@ public class StreamParser {
|
|||||||
* DISPLAY_TEXT_MESSAGE.
|
* DISPLAY_TEXT_MESSAGE.
|
||||||
*/
|
*/
|
||||||
public static List<String> extractDisplayMessage(StreamPacket packet) {
|
public static List<String> extractDisplayMessage(StreamPacket packet) {
|
||||||
if (packet.getType() != PacketType.DISPLAY_TEXT_MESSAGE)
|
if (packet.getType() != PacketType.DISPLAY_TEXT_MESSAGE) {
|
||||||
return null;
|
return null;
|
||||||
|
}
|
||||||
List<String> message = new ArrayList<>();
|
List<String> message = new ArrayList<>();
|
||||||
byte[] payload = packet.getPayload();
|
byte[] payload = packet.getPayload();
|
||||||
int messageVersionNo = payload[0];
|
int messageVersionNo = payload[0];
|
||||||
@@ -168,8 +167,9 @@ public class StreamParser {
|
|||||||
public static Document extractXmlMessage(StreamPacket packet) {
|
public static Document extractXmlMessage(StreamPacket packet) {
|
||||||
if (packet.getType() != PacketType.RACE_XML &&
|
if (packet.getType() != PacketType.RACE_XML &&
|
||||||
packet.getType() != PacketType.REGATTA_XML &&
|
packet.getType() != PacketType.REGATTA_XML &&
|
||||||
packet.getType() != PacketType.BOAT_XML )
|
packet.getType() != PacketType.BOAT_XML) {
|
||||||
return null;
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
byte[] payload = packet.getPayload();
|
byte[] payload = packet.getPayload();
|
||||||
int messageType = payload[9];
|
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.
|
* Extracts the race start status from the packet and returns it as a long array.
|
||||||
*
|
*
|
||||||
* @param packet Packet parsed in to use the payload
|
* @param packet Packet parsed in to use the payload
|
||||||
* @return An array of form [raceID, raceStartTime, notificationType, timeStamp] or null if
|
* @return An array of form [raceID, raceStartTime, notificationType, timeStamp] or null if the
|
||||||
* the packet type is not of RACE_START_STATUS.
|
* packet type is not of RACE_START_STATUS.
|
||||||
*/
|
*/
|
||||||
public static RaceStartData extractRaceStartStatus(StreamPacket packet) {
|
public static RaceStartData extractRaceStartStatus(StreamPacket packet) {
|
||||||
if (packet.getType() != PacketType.RACE_START_STATUS) {
|
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
|
* 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
|
* @param packet Packet parsed in to use the payload
|
||||||
* @return the event data in the form [boatID, incidentID, eventID, timeStamp]. Returns null if
|
* @return the event data in the form of YachtEventData. Returns null if the packet is not of
|
||||||
* the packet is not of type YACHT_EVENT_CODE.
|
* type YACHT_EVENT_CODE.
|
||||||
*/
|
*/
|
||||||
public static long[] extractYachtEventCode(StreamPacket packet) {
|
public static YachtEventData extractYachtEventCode(StreamPacket packet) {
|
||||||
if (packet.getType() != PacketType.YACHT_EVENT_CODE)
|
if (packet.getType() != PacketType.YACHT_EVENT_CODE) {
|
||||||
return null;
|
return null;
|
||||||
|
}
|
||||||
byte[] payload = packet.getPayload();
|
byte[] payload = packet.getPayload();
|
||||||
int messageVersionNo = payload[0];
|
int messageVersionNo = payload[0];
|
||||||
long timeStamp = bytesToLong(Arrays.copyOfRange(payload, 1, 7));
|
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 raceId = bytesToLong(Arrays.copyOfRange(payload, 9, 13));
|
||||||
long subjectId = bytesToLong(Arrays.copyOfRange(payload, 13, 17));
|
long subjectId = bytesToLong(Arrays.copyOfRange(payload, 13, 17));
|
||||||
long incidentId = bytesToLong(Arrays.copyOfRange(payload, 17, 21));
|
long incidentId = bytesToLong(Arrays.copyOfRange(payload, 17, 21));
|
||||||
int eventId = payload[21];
|
int eventId = payload[21];
|
||||||
return new long[] {subjectId, incidentId, eventId, timeStamp};
|
return new YachtEventData(subjectId, incidentId, eventId, timeStamp);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -239,8 +241,9 @@ public class StreamParser {
|
|||||||
* Returns null if the packet is not of type YACHT_ACTION_CODE.
|
* Returns null if the packet is not of type YACHT_ACTION_CODE.
|
||||||
*/
|
*/
|
||||||
public static long[] extractYachtActionCode(StreamPacket packet) {
|
public static long[] extractYachtActionCode(StreamPacket packet) {
|
||||||
if (packet.getType() != PacketType.YACHT_ACTION_CODE)
|
if (packet.getType() != PacketType.YACHT_ACTION_CODE) {
|
||||||
return null;
|
return null;
|
||||||
|
}
|
||||||
byte[] payload = packet.getPayload();
|
byte[] payload = packet.getPayload();
|
||||||
int messageVersionNo = payload[0];
|
int messageVersionNo = payload[0];
|
||||||
long timeStamp = bytesToLong(Arrays.copyOfRange(payload, 1, 7));
|
long timeStamp = bytesToLong(Arrays.copyOfRange(payload, 1, 7));
|
||||||
@@ -258,8 +261,9 @@ public class StreamParser {
|
|||||||
* CHATTER_TEXT.
|
* CHATTER_TEXT.
|
||||||
*/
|
*/
|
||||||
public static String extractChatterText(StreamPacket packet) {
|
public static String extractChatterText(StreamPacket packet) {
|
||||||
if (packet.getType() != PacketType.CHATTER_TEXT)
|
if (packet.getType() != PacketType.CHATTER_TEXT) {
|
||||||
return null;
|
return null;
|
||||||
|
}
|
||||||
byte[] payload = packet.getPayload();
|
byte[] payload = packet.getPayload();
|
||||||
int messageVersionNo = payload[0];
|
int messageVersionNo = payload[0];
|
||||||
int messageType = payload[1];
|
int messageType = payload[1];
|
||||||
@@ -276,8 +280,9 @@ public class StreamParser {
|
|||||||
* is not of type BOAT_LOCATION.
|
* is not of type BOAT_LOCATION.
|
||||||
*/
|
*/
|
||||||
public static PositionUpdateData extractBoatLocation(StreamPacket packet) {
|
public static PositionUpdateData extractBoatLocation(StreamPacket packet) {
|
||||||
if (packet.getType() != PacketType.BOAT_LOCATION)
|
if (packet.getType() != PacketType.BOAT_LOCATION) {
|
||||||
return null;
|
return null;
|
||||||
|
}
|
||||||
byte[] payload = packet.getPayload();
|
byte[] payload = packet.getPayload();
|
||||||
int deviceType = (int) payload[15];
|
int deviceType = (int) payload[15];
|
||||||
long timeValid = bytesToLong(Arrays.copyOfRange(payload, 1, 7));
|
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;
|
double groundSpeed = bytesToLong(Arrays.copyOfRange(payload, 38, 40)) / 1000.0;
|
||||||
|
|
||||||
DeviceType type;
|
DeviceType type;
|
||||||
if (deviceType == 1)
|
if (deviceType == 1) {
|
||||||
type = DeviceType.YACHT_TYPE;
|
type = DeviceType.YACHT_TYPE;
|
||||||
else
|
} else {
|
||||||
type = DeviceType.MARK_TYPE;
|
type = DeviceType.MARK_TYPE;
|
||||||
|
}
|
||||||
|
|
||||||
return new PositionUpdateData((int) boatId, type, lat, lon, heading, groundSpeed);
|
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.
|
* if packet is not of type MARK_ROUNDING.
|
||||||
*/
|
*/
|
||||||
public static MarkRoundingData extractMarkRounding(StreamPacket packet) {
|
public static MarkRoundingData extractMarkRounding(StreamPacket packet) {
|
||||||
if (packet.getType() != PacketType.MARK_ROUNDING)
|
if (packet.getType() != PacketType.MARK_ROUNDING) {
|
||||||
return null;
|
return null;
|
||||||
|
}
|
||||||
byte[] payload = packet.getPayload();
|
byte[] payload = packet.getPayload();
|
||||||
int messageVersionNo = payload[0];
|
int messageVersionNo = payload[0];
|
||||||
long timeStamp = bytesToLong(Arrays.copyOfRange(payload, 1, 7));
|
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
|
* Returns a list containing the string value of data within the given stream packet for course
|
||||||
* course wind.
|
* wind.
|
||||||
*
|
*
|
||||||
* @param packet The packet containing the payload
|
* @param packet The packet containing the payload
|
||||||
* @return the string values of the wind packet. Returns null if the packet is not of type
|
* @return the string values of the wind packet. Returns null if the packet is not of type
|
||||||
* COURSE_WIND.
|
* COURSE_WIND.
|
||||||
*/
|
*/
|
||||||
public static List<String> extractCourseWind(StreamPacket packet) {
|
public static List<String> extractCourseWind(StreamPacket packet) {
|
||||||
if (packet.getType() != PacketType.COURSE_WIND)
|
if (packet.getType() != PacketType.COURSE_WIND) {
|
||||||
return null;
|
return null;
|
||||||
|
}
|
||||||
byte[] payload = packet.getPayload();
|
byte[] payload = packet.getPayload();
|
||||||
int messageVersionNo = payload[0];
|
int messageVersionNo = payload[0];
|
||||||
int selectedWindId = payload[1];
|
int selectedWindId = payload[1];
|
||||||
@@ -366,13 +374,13 @@ public class StreamParser {
|
|||||||
* Returns the parsed data from a StreamPacket for average wind data.
|
* Returns the parsed data from a StreamPacket for average wind data.
|
||||||
*
|
*
|
||||||
* @param packet The packet containing the payload
|
* @param packet The packet containing the payload
|
||||||
* @return The wind data in the form
|
* @return The wind data in the form [rawPeriod, rawSamplePeriod, period2, speed2, period3,
|
||||||
* [rawPeriod, rawSamplePeriod, period2, speed2, period3, speed3, period4, speed4, timestamp]
|
* speed3, period4, speed4, timestamp] or null if the packet is not of type AVG_WIND.
|
||||||
* or null if the packet is not of type AVG_WIND.
|
|
||||||
*/
|
*/
|
||||||
public static long[] extractAvgWind(StreamPacket packet) {
|
public static long[] extractAvgWind(StreamPacket packet) {
|
||||||
if (packet.getType() != PacketType.AVG_WIND)
|
if (packet.getType() != PacketType.AVG_WIND) {
|
||||||
return null;
|
return null;
|
||||||
|
}
|
||||||
byte[] payload = packet.getPayload();
|
byte[] payload = packet.getPayload();
|
||||||
int messageVersionNo = payload[0];
|
int messageVersionNo = payload[0];
|
||||||
long timeStamp = bytesToLong(Arrays.copyOfRange(payload, 1, 7));
|
long timeStamp = bytesToLong(Arrays.copyOfRange(payload, 1, 7));
|
||||||
@@ -410,8 +418,7 @@ public class StreamParser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* takes an array of up to 7 bytes and returns a positive
|
* takes an array of up to 7 bytes and returns a positive long constructed from the input bytes
|
||||||
* long constructed from the input bytes
|
|
||||||
*
|
*
|
||||||
* @param bytes the byte array to conver to Long
|
* @param bytes the byte array to conver to Long
|
||||||
* @return a positive long if there is less than 7 bytes -1 otherwise
|
* @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;
|
||||||
import seng302.model.stream.parser.PositionUpdateData.DeviceType;
|
import seng302.model.stream.parser.PositionUpdateData.DeviceType;
|
||||||
import seng302.model.stream.parser.RaceStatusData;
|
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.RaceXMLData;
|
||||||
import seng302.model.stream.xml.parser.RegattaXMLData;
|
import seng302.model.stream.xml.parser.RegattaXMLData;
|
||||||
import seng302.utilities.StreamParser;
|
import seng302.utilities.StreamParser;
|
||||||
@@ -102,6 +103,8 @@ public class GameClient {
|
|||||||
loadStartScreen();
|
loadStartScreen();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
server.setGameClient(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void loadStartScreen() {
|
private void loadStartScreen() {
|
||||||
@@ -126,7 +129,8 @@ public class GameClient {
|
|||||||
* @return the lobby controller.
|
* @return the lobby controller.
|
||||||
*/
|
*/
|
||||||
private LobbyController loadLobby() {
|
private LobbyController loadLobby() {
|
||||||
FXMLLoader fxmlLoader = new FXMLLoader(GameClient.class.getResource("/views/LobbyView.fxml"));
|
FXMLLoader fxmlLoader = new FXMLLoader(
|
||||||
|
GameClient.class.getResource("/views/LobbyView.fxml"));
|
||||||
try {
|
try {
|
||||||
holderPane.getChildren().clear();
|
holderPane.getChildren().clear();
|
||||||
holderPane.getChildren().add(fxmlLoader.load());
|
holderPane.getChildren().add(fxmlLoader.load());
|
||||||
@@ -205,14 +209,19 @@ public class GameClient {
|
|||||||
case MARK_ROUNDING:
|
case MARK_ROUNDING:
|
||||||
updateMarkRounding(StreamParser.extractMarkRounding(packet));
|
updateMarkRounding(StreamParser.extractMarkRounding(packet));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case YACHT_EVENT_CODE:
|
||||||
|
showCollisionAlert(StreamParser.extractYachtEventCode(packet));
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void startRaceIfAllDataReceived() {
|
private void startRaceIfAllDataReceived() {
|
||||||
if (allXMLReceived() && raceView == null)
|
if (allXMLReceived() && raceView == null) {
|
||||||
loadRaceView();
|
loadRaceView();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private boolean allXMLReceived() {
|
private boolean allXMLReceived() {
|
||||||
return courseData != null && allBoatsMap != null && regattaData != null;
|
return courseData != null && allBoatsMap != null && regattaData != null;
|
||||||
@@ -270,9 +279,10 @@ public class GameClient {
|
|||||||
int placing = 1;
|
int placing = 1;
|
||||||
for (Yacht otherYacht : allBoatsMap.values()) {
|
for (Yacht otherYacht : allBoatsMap.values()) {
|
||||||
if (otherYacht.getSourceId() != boatData[0] &&
|
if (otherYacht.getSourceId() != boatData[0] &&
|
||||||
yacht.getLegNumber() <= otherYacht.getLegNumber())
|
yacht.getLegNumber() <= otherYacht.getLegNumber()) {
|
||||||
placing++;
|
placing++;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
yacht.setPositionInteger(placing);
|
yacht.setPositionInteger(placing);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -286,6 +296,7 @@ public class GameClient {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle the key-pressed event from the text field.
|
* Handle the key-pressed event from the text field.
|
||||||
|
*
|
||||||
* @param e The key event triggering this call
|
* @param e The key event triggering this call
|
||||||
*/
|
*/
|
||||||
private void keyPressed(KeyEvent e) {
|
private void keyPressed(KeyEvent e) {
|
||||||
@@ -320,4 +331,18 @@ public class GameClient {
|
|||||||
socketThread.sendBoatAction(BoatAction.MAINTAIN_HEADING); break;
|
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());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,9 +6,16 @@ import java.util.Comparator;
|
|||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
import javafx.animation.Animation;
|
||||||
import javafx.animation.AnimationTimer;
|
import javafx.animation.AnimationTimer;
|
||||||
|
import javafx.animation.KeyFrame;
|
||||||
|
import javafx.animation.KeyValue;
|
||||||
|
import javafx.animation.Timeline;
|
||||||
import javafx.application.Platform;
|
import javafx.application.Platform;
|
||||||
import javafx.collections.ObservableList;
|
import javafx.collections.ObservableList;
|
||||||
|
import javafx.event.ActionEvent;
|
||||||
|
import javafx.event.Event;
|
||||||
import javafx.event.EventHandler;
|
import javafx.event.EventHandler;
|
||||||
import javafx.geometry.Point2D;
|
import javafx.geometry.Point2D;
|
||||||
import javafx.scene.Group;
|
import javafx.scene.Group;
|
||||||
@@ -21,8 +28,11 @@ import javafx.scene.layout.AnchorPane;
|
|||||||
import javafx.scene.layout.Pane;
|
import javafx.scene.layout.Pane;
|
||||||
import javafx.scene.paint.Color;
|
import javafx.scene.paint.Color;
|
||||||
import javafx.scene.paint.Paint;
|
import javafx.scene.paint.Paint;
|
||||||
|
import javafx.scene.shape.Circle;
|
||||||
import javafx.scene.shape.Polygon;
|
import javafx.scene.shape.Polygon;
|
||||||
|
import javafx.scene.shape.StrokeType;
|
||||||
import javafx.scene.text.Text;
|
import javafx.scene.text.Text;
|
||||||
|
import javafx.util.Duration;
|
||||||
import seng302.model.Colors;
|
import seng302.model.Colors;
|
||||||
import seng302.model.GeoPoint;
|
import seng302.model.GeoPoint;
|
||||||
import seng302.model.Limit;
|
import seng302.model.Limit;
|
||||||
@@ -122,45 +132,6 @@ public class GameView extends Pane {
|
|||||||
gameObjects.add(fpsDisplay);
|
gameObjects.add(fpsDisplay);
|
||||||
gameObjects.add(raceBorder);
|
gameObjects.add(raceBorder);
|
||||||
gameObjects.add(markers);
|
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();
|
initializeTimer();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -207,8 +178,8 @@ public class GameView extends Pane {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* First find the top right and bottom left points' geo locations, then retrieve
|
* First find the top right and bottom left points' geo locations, then retrieve map from google
|
||||||
* map from google to display on image view. - Haoming 22/5/2017
|
* to display on image view. - Haoming 22/5/2017
|
||||||
*/
|
*/
|
||||||
private void drawGoogleMap() {
|
private void drawGoogleMap() {
|
||||||
findMetersPerPixel();
|
findMetersPerPixel();
|
||||||
@@ -373,6 +344,7 @@ public class GameView extends Pane {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Draws all the boats.
|
* Draws all the boats.
|
||||||
|
*
|
||||||
* @param yachts The yachts to set in the race
|
* @param yachts The yachts to set in the race
|
||||||
*/
|
*/
|
||||||
public void setBoats(List<Yacht> yachts) {
|
public void setBoats(List<Yacht> yachts) {
|
||||||
@@ -410,9 +382,7 @@ public class GameView extends Pane {
|
|||||||
gameObjects.addAll(wakes);
|
gameObjects.addAll(wakes);
|
||||||
gameObjects.addAll(annotationsGroup);
|
gameObjects.addAll(annotationsGroup);
|
||||||
gameObjects.addAll(boatObjectGroup);
|
gameObjects.addAll(boatObjectGroup);
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void createAndBindAnnotationBox(Yacht yacht, Paint colour) {
|
private void createAndBindAnnotationBox(Yacht yacht, Paint colour) {
|
||||||
@@ -450,8 +420,8 @@ public class GameView extends Pane {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the class variables minLatPoint, maxLatPoint, minLonPoint, maxLonPoint to the point
|
* Sets the class variables minLatPoint, maxLatPoint, minLonPoint, maxLonPoint to the point with
|
||||||
* with the leftmost point, rightmost point, southern most point and northern most point
|
* the leftmost point, rightmost point, southern most point and northern most point
|
||||||
* respectively.
|
* respectively.
|
||||||
*/
|
*/
|
||||||
private void findMinMaxPoint(List<GeoPoint> points) {
|
private void findMinMaxPoint(List<GeoPoint> points) {
|
||||||
@@ -485,13 +455,17 @@ public class GameView extends Pane {
|
|||||||
referenceAngle = Math.abs(
|
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));
|
referenceAngle = Math.abs(GeoUtility.getDistance(referencePoint, maxLatPoint));
|
||||||
referencePointY = canvasHeight - (bufferSize + bufferSize);
|
referencePointY = canvasHeight - (bufferSize + bufferSize);
|
||||||
referencePointY -= distanceScaleFactor * Math.cos(referenceAngle) * GeoUtility.getDistance(referencePoint, maxLatPoint);
|
referencePointY -= distanceScaleFactor * Math.cos(referenceAngle) * GeoUtility
|
||||||
|
.getDistance(referencePoint, maxLatPoint);
|
||||||
referencePointY = referencePointY / 2;
|
referencePointY = referencePointY / 2;
|
||||||
referencePointY += bufferSize;
|
referencePointY += bufferSize;
|
||||||
referencePointY += distanceScaleFactor * Math.cos(referenceAngle) * GeoUtility.getDistance(referencePoint, maxLatPoint);
|
referencePointY += distanceScaleFactor * Math.cos(referenceAngle) * GeoUtility
|
||||||
|
.getDistance(referencePoint, maxLatPoint);
|
||||||
} else {
|
} else {
|
||||||
referencePointY = canvasHeight - bufferSize;
|
referencePointY = canvasHeight - bufferSize;
|
||||||
referenceAngle = Math.abs(
|
referenceAngle = Math.abs(
|
||||||
@@ -500,8 +474,11 @@ public class GameView extends Pane {
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
referencePointX = bufferSize;
|
referencePointX = bufferSize;
|
||||||
referencePointX += distanceScaleFactor * Math.sin(referenceAngle) * GeoUtility.getDistance(referencePoint, minLonPoint);
|
referencePointX += distanceScaleFactor * Math.sin(referenceAngle) * GeoUtility
|
||||||
referencePointX += ((canvasWidth - (bufferSize + bufferSize)) - (minLonToMaxLon * distanceScaleFactor)) / 2;
|
.getDistance(referencePoint, minLonPoint);
|
||||||
|
referencePointX +=
|
||||||
|
((canvasWidth - (bufferSize + bufferSize)) - (minLonToMaxLon * distanceScaleFactor))
|
||||||
|
/ 2;
|
||||||
}
|
}
|
||||||
if (horizontalInversion) {
|
if (horizontalInversion) {
|
||||||
referencePointX = canvasWidth - bufferSize - (referencePointX - bufferSize);
|
referencePointX = canvasWidth - bufferSize - (referencePointX - bufferSize);
|
||||||
@@ -560,20 +537,28 @@ public class GameView extends Pane {
|
|||||||
minLatPoint, new GeoPoint(unscaledLat, unscaledLon)
|
minLatPoint, new GeoPoint(unscaledLat, unscaledLon)
|
||||||
);
|
);
|
||||||
if (angleFromReference >= 0 && angleFromReference <= Math.PI / 2) {
|
if (angleFromReference >= 0 && angleFromReference <= Math.PI / 2) {
|
||||||
xAxisLocation += Math.round(distanceScaleFactor * Math.sin(angleFromReference) * distanceFromReference);
|
xAxisLocation += Math
|
||||||
yAxisLocation -= Math.round(distanceScaleFactor * Math.cos(angleFromReference) * distanceFromReference);
|
.round(distanceScaleFactor * Math.sin(angleFromReference) * distanceFromReference);
|
||||||
|
yAxisLocation -= Math
|
||||||
|
.round(distanceScaleFactor * Math.cos(angleFromReference) * distanceFromReference);
|
||||||
} else if (angleFromReference >= 0) {
|
} else if (angleFromReference >= 0) {
|
||||||
angleFromReference = angleFromReference - Math.PI / 2;
|
angleFromReference = angleFromReference - Math.PI / 2;
|
||||||
xAxisLocation += Math.round(distanceScaleFactor * Math.cos(angleFromReference) * distanceFromReference);
|
xAxisLocation += Math
|
||||||
yAxisLocation += Math.round(distanceScaleFactor * Math.sin(angleFromReference) * distanceFromReference);
|
.round(distanceScaleFactor * Math.cos(angleFromReference) * distanceFromReference);
|
||||||
|
yAxisLocation += Math
|
||||||
|
.round(distanceScaleFactor * Math.sin(angleFromReference) * distanceFromReference);
|
||||||
} else if (angleFromReference < 0 && angleFromReference >= -Math.PI / 2) {
|
} else if (angleFromReference < 0 && angleFromReference >= -Math.PI / 2) {
|
||||||
angleFromReference = Math.abs(angleFromReference);
|
angleFromReference = Math.abs(angleFromReference);
|
||||||
xAxisLocation -= Math.round(distanceScaleFactor * Math.sin(angleFromReference) * distanceFromReference);
|
xAxisLocation -= Math
|
||||||
yAxisLocation -= Math.round(distanceScaleFactor * Math.cos(angleFromReference) * distanceFromReference);
|
.round(distanceScaleFactor * Math.sin(angleFromReference) * distanceFromReference);
|
||||||
|
yAxisLocation -= Math
|
||||||
|
.round(distanceScaleFactor * Math.cos(angleFromReference) * distanceFromReference);
|
||||||
} else {
|
} else {
|
||||||
angleFromReference = Math.abs(angleFromReference) - Math.PI / 2;
|
angleFromReference = Math.abs(angleFromReference) - Math.PI / 2;
|
||||||
xAxisLocation -= Math.round(distanceScaleFactor * Math.cos(angleFromReference) * distanceFromReference);
|
xAxisLocation -= Math
|
||||||
yAxisLocation += Math.round(distanceScaleFactor * Math.sin(angleFromReference) * distanceFromReference);
|
.round(distanceScaleFactor * Math.cos(angleFromReference) * distanceFromReference);
|
||||||
|
yAxisLocation += Math
|
||||||
|
.round(distanceScaleFactor * Math.sin(angleFromReference) * distanceFromReference);
|
||||||
}
|
}
|
||||||
if (horizontalInversion) {
|
if (horizontalInversion) {
|
||||||
xAxisLocation = canvasWidth - bufferSize - (xAxisLocation - bufferSize);
|
xAxisLocation = canvasWidth - bufferSize - (xAxisLocation - bufferSize);
|
||||||
@@ -634,7 +619,6 @@ public class GameView extends Pane {
|
|||||||
this.windDir = windDir;
|
this.windDir = windDir;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void startRace() {
|
public void startRace() {
|
||||||
timer.start();
|
timer.start();
|
||||||
}
|
}
|
||||||
@@ -658,6 +642,41 @@ public class GameView extends Pane {
|
|||||||
annotationsGroup.getChildren().remove(annotations.get(playerYacht));
|
annotationsGroup.getChildren().remove(annotations.get(playerYacht));
|
||||||
gameObjects.add(annotations.get(playerYacht));
|
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));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -208,7 +208,8 @@ 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.
|
// TODO: 2/08/17 there is about 0 chance of this working. Once we are keeping track of boat positions it can be fixed.
|
||||||
@@ -248,7 +249,8 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
|||||||
.filter(spark -> !raceSparkLine.getData().contains(spark))
|
.filter(spark -> !raceSparkLine.getData().contains(spark))
|
||||||
.forEach(spark -> {
|
.forEach(spark -> {
|
||||||
raceSparkLine.getData().add(spark);
|
raceSparkLine.getData().add(spark);
|
||||||
spark.getNode().lookup(".chart-series-line").setStyle("-fx-stroke:" + getBoatColorAsRGB(spark.getName()));
|
spark.getNode().lookup(".chart-series-line")
|
||||||
|
.setStyle("-fx-stroke:" + getBoatColorAsRGB(spark.getName()));
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -260,6 +262,7 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates the yachts sparkline of the desired yacht and using the new leg number
|
* Updates the yachts sparkline of the desired yacht and using the new leg number
|
||||||
|
*
|
||||||
* @param yacht The yacht to be updated on the sparkline
|
* @param yacht The yacht to be updated on the sparkline
|
||||||
* @param legNumber the leg number that the position will be assigned to
|
* @param legNumber the leg number that the position will be assigned to
|
||||||
*/
|
*/
|
||||||
@@ -284,6 +287,7 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* gets the rgb string of the yachts colour to use for the chart via css
|
* 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
|
* @param yachtId id of yacht passed in to get the yachts colour
|
||||||
* @return the colour as an rgb string
|
* @return the colour as an rgb string
|
||||||
*/
|
*/
|
||||||
@@ -302,8 +306,8 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialises a timer which updates elements of the RaceView such as wind direction, yacht
|
* Initialises a timer which updates elements of the RaceView such as wind direction, yacht
|
||||||
* orderings etc.. which are dependent on the info from the stream parser constantly.
|
* orderings etc.. which are dependent on the info from the stream parser constantly. Updates of
|
||||||
* Updates of each of these attributes are called ONCE EACH SECOND
|
* each of these attributes are called ONCE EACH SECOND
|
||||||
*/
|
*/
|
||||||
private void initializeUpdateTimer() {
|
private void initializeUpdateTimer() {
|
||||||
timer.scheduleAtFixedRate(new TimerTask() {
|
timer.scheduleAtFixedRate(new TimerTask() {
|
||||||
@@ -318,9 +322,10 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Iterates over all corners until ones SeqID matches with the yachts current leg number.
|
* Iterates over all corners until ones SeqID matches with the yachts current leg number. Then
|
||||||
* Then it gets the compoundMarkID of that corner and uses it to fetch the appropriate mark
|
* it gets the compoundMarkID of that corner and uses it to fetch the appropriate mark Returns
|
||||||
* Returns null if no next mark found.
|
* null if no next mark found.
|
||||||
|
*
|
||||||
* @param bg The BoatGroup to find the next mark of
|
* @param bg The BoatGroup to find the next mark of
|
||||||
* @return The next Mark or null if none found
|
* @return The next Mark or null if none found
|
||||||
*/
|
*/
|
||||||
@@ -476,8 +481,10 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
|||||||
|
|
||||||
|
|
||||||
private Point2D getPointRotation(Point2D ref, Double distance, Double angle) {
|
private Point2D getPointRotation(Point2D ref, Double distance, Double angle) {
|
||||||
Double newX = ref.getX() + (ref.getX() + distance -ref.getX())*Math.cos(angle) - (ref.getY() + distance -ref.getY())*Math.sin(angle);
|
Double newX = ref.getX() + (ref.getX() + distance - ref.getX()) * Math.cos(angle)
|
||||||
Double newY = ref.getY() + (ref.getX() + distance -ref.getX())*Math.sin(angle) + (ref.getY() + distance -ref.getY())*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);
|
return new Point2D(newX, newY);
|
||||||
}
|
}
|
||||||
@@ -502,8 +509,8 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialised the combo box with any yachts currently in the race and adds the required listener
|
* Initialised the combo box with any yachts currently in the race and adds the required
|
||||||
* for the combobox to take action upon selection
|
* listener for the combobox to take action upon selection
|
||||||
*/
|
*/
|
||||||
private void initialiseBoatSelectionComboBox() {
|
private void initialiseBoatSelectionComboBox() {
|
||||||
yachtSelectionComboBox.setItems(
|
yachtSelectionComboBox.setItems(
|
||||||
@@ -596,6 +603,17 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
|||||||
gameView.updateBorder(raceData.getCourseLimit());
|
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() {
|
public GameView getGameView() {
|
||||||
return gameView;
|
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"?>
|
<?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.geometry.Insets?>
|
||||||
<?import javafx.scene.control.Button?>
|
<?import javafx.scene.control.Button?>
|
||||||
<?import javafx.scene.control.Label?>
|
<?import javafx.scene.control.Label?>
|
||||||
@@ -10,6 +15,7 @@
|
|||||||
<?import javafx.scene.layout.RowConstraints?>
|
<?import javafx.scene.layout.RowConstraints?>
|
||||||
<?import javafx.scene.text.Font?>
|
<?import javafx.scene.text.Font?>
|
||||||
<?import javafx.scene.text.Text?>
|
<?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">
|
<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>
|
<children>
|
||||||
<GridPane fx:id="startScreen2" layoutX="365.0" layoutY="285.0" nodeOrientation="LEFT_TO_RIGHT" prefWidth="800.0" style="-fx-background-color: #2C2c36;">
|
<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" />
|
<Insets left="5.0" right="5.0" />
|
||||||
</GridPane.margin>
|
</GridPane.margin>
|
||||||
</Button>
|
</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>
|
<GridPane.margin>
|
||||||
<Insets bottom="10.0" left="5.0" right="85.0" top="10.0" />
|
<Insets bottom="10.0" left="5.0" right="85.0" top="10.0" />
|
||||||
</GridPane.margin>
|
</GridPane.margin>
|
||||||
|
|||||||
@@ -9,9 +9,9 @@ public class ColorsTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testNextColor() {
|
public void testNextColor() {
|
||||||
Color expectedColors[] = {Color.RED, Color.PERU, Color.SEAGREEN, Color.GREEN, Color.BLUE, Color.PURPLE};
|
Color expectedColors[] = {Color.RED, Color.PERU, Color.GOLD, Color.GREEN, Color.BLUE,
|
||||||
for (int i = 0; i<6; i++)
|
Color.PURPLE, Color.DEEPPINK, Color.GRAY};
|
||||||
{
|
for (int i = 0; i < 8; i++) {
|
||||||
Assert.assertEquals(expectedColors[i], Colors.getColor());
|
Assert.assertEquals(expectedColors[i], Colors.getColor());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,92 @@
|
|||||||
|
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 Yacht yacht1 = new Yacht("Yacht", 1, "1", "Yacht" + 1, "Yacht" + 1, "Test1");
|
||||||
|
private Yacht yacht2 = new Yacht("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);
|
||||||
|
yacht1.updateLocation(geoPoint1.getLat(), geoPoint1.getLng(), 90.0, 5.0);
|
||||||
|
|
||||||
|
// Yacht 2 heading towards 270 degrees heading
|
||||||
|
yacht2.setLocation(geoPoint2);
|
||||||
|
yacht2.updateLocation(geoPoint2.getLat(), geoPoint2.getLng(), 270.0, 5.0);
|
||||||
|
|
||||||
|
// Start yacht 1 and rest yacht 2
|
||||||
|
if (!yacht1.getSailIn()) {
|
||||||
|
yacht1.toggleSailIn();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < 6; i++) {
|
||||||
|
yacht1.update((long) 1000);
|
||||||
|
|
||||||
|
// Making sure boat is moving
|
||||||
|
double moved = GeoUtility.getDistance(yacht1.getLocation(), geoPoint1);
|
||||||
|
Assert.assertTrue(moved > 0);
|
||||||
|
|
||||||
|
// Making sure no collision
|
||||||
|
Double distance = GeoUtility.getDistance(yacht1.getLocation(), geoPoint2);
|
||||||
|
|
||||||
|
Assert.assertTrue(distance > Math.min(Yacht.MARK_COLLISION_DISTANCE, Yacht.YACHT_COLLISION_DISTANCE));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUpdateYachtWithoutCollision() {
|
||||||
|
// Yacht 1 heading towards 90 degrees heading
|
||||||
|
yacht1.setLocation(geoPoint1);
|
||||||
|
yacht1.updateLocation(geoPoint1.getLat(), geoPoint1.getLng(), 90.0, 5.0);
|
||||||
|
|
||||||
|
// Yacht 2 heading towards 90 degrees heading
|
||||||
|
yacht2.setLocation(geoPoint2);
|
||||||
|
yacht2.updateLocation(geoPoint2.getLat(), geoPoint2.getLng(), 90.0, 5.0);
|
||||||
|
|
||||||
|
// Start yacht 1 and yacht 2
|
||||||
|
if (!yacht1.getSailIn()) {
|
||||||
|
yacht1.toggleSailIn();
|
||||||
|
}
|
||||||
|
if (!yacht2.getSailIn()) {
|
||||||
|
yacht2.toggleSailIn();
|
||||||
|
}
|
||||||
|
|
||||||
|
double previousDistance1 = 0;
|
||||||
|
double previousDistance2 = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < 6; i++) {
|
||||||
|
yacht1.update((long) 1000);
|
||||||
|
yacht2.update((long) 1000);
|
||||||
|
|
||||||
|
// Making sure boat is moving
|
||||||
|
double yachtMoved1 = GeoUtility.getDistance(yacht1.getLocation(), geoPoint1);
|
||||||
|
Assert.assertTrue(yachtMoved1 > previousDistance1);
|
||||||
|
previousDistance1 = yachtMoved1;
|
||||||
|
|
||||||
|
double yachtMoved2 = GeoUtility.getDistance(yacht2.getLocation(), geoPoint2);
|
||||||
|
Assert.assertTrue(yachtMoved2 > previousDistance2);
|
||||||
|
previousDistance2 = yachtMoved2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -28,26 +28,26 @@ public class RegularPacketsTest {
|
|||||||
GameState.setCurrentStage(GameStages.RACING);
|
GameState.setCurrentStage(GameStages.RACING);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
// @Test
|
||||||
public void packetsSentAtRegularIntervals () throws Exception {
|
// public void packetsSentAtRegularIntervals () throws Exception {
|
||||||
final double TEST_DISTANCE = 10.0;
|
// final double TEST_DISTANCE = 10.0;
|
||||||
serverThread.startGame();
|
// serverThread.startGame();
|
||||||
SleepThreadMaxDelay();
|
// SleepThreadMaxDelay();
|
||||||
Yacht yacht = new ArrayList<>(GameState.getYachts().values()).get(0);
|
// Yacht yacht = new ArrayList<>(GameState.getYachts().values()).get(0);
|
||||||
double startAngle = yacht.getHeading();
|
// double startAngle = yacht.getHeading();
|
||||||
long startTime = System.currentTimeMillis();
|
// long startTime = System.currentTimeMillis();
|
||||||
clientThread.sendBoatAction(BoatAction.UPWIND);
|
// clientThread.sendBoatAction(BoatAction.UPWIND);
|
||||||
Thread.sleep(200);
|
// Thread.sleep(200);
|
||||||
while (Math.abs(yacht.getHeading() - startAngle) < TEST_DISTANCE) {
|
// while (Math.abs(yacht.getHeading() - startAngle) < TEST_DISTANCE) {
|
||||||
Thread.sleep(1);
|
// Thread.sleep(1);
|
||||||
}
|
// }
|
||||||
clientThread.sendBoatAction(BoatAction.MAINTAIN_HEADING);
|
// clientThread.sendBoatAction(BoatAction.MAINTAIN_HEADING);
|
||||||
long endTime = System.currentTimeMillis();
|
// long endTime = System.currentTimeMillis();
|
||||||
SleepThreadMaxDelay();
|
// SleepThreadMaxDelay();
|
||||||
//Allowed to be two loops of delay due to loop delay and processing delay at client + server ends.
|
// //Allowed to be two loops of delay due to loop delay and processing delay at client + server ends.
|
||||||
Assert.assertEquals(TEST_DISTANCE / Yacht.TURN_STEP * ClientToServerThread.PACKET_SENDING_INTERVAL_MS,
|
// Assert.assertEquals(TEST_DISTANCE / Yacht.TURN_STEP * ClientToServerThread.PACKET_SENDING_INTERVAL_MS,
|
||||||
(endTime - startTime), 2 * ClientToServerThread.PACKET_SENDING_INTERVAL_MS);
|
// (endTime - startTime), 2 * ClientToServerThread.PACKET_SENDING_INTERVAL_MS);
|
||||||
}
|
// }
|
||||||
|
|
||||||
// @Test
|
// @Test
|
||||||
// public void testArbitraryPacketSent() throws Exception {
|
// public void testArbitraryPacketSent() throws Exception {
|
||||||
|
|||||||
Reference in New Issue
Block a user