Compare commits
86 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c0bd498f1b | |||
| b18d9e8573 | |||
| e9881bb24a | |||
| ab5ad58237 | |||
| df7264cc1f | |||
| 5248921576 | |||
| 2dcdd1c248 | |||
| 9b00f76907 | |||
| f11c457d28 | |||
| 9e4fa30787 | |||
| 99ce4fa11d | |||
| 69d1fa9488 | |||
| 66e6a8a2a4 | |||
| dd43097677 | |||
| 1a53579317 | |||
| 132a729758 | |||
| 2e7487fdfc | |||
| 1bd4db73cd | |||
| e990c68d40 | |||
| 83871a0336 | |||
| 6cba024d64 | |||
| 51747e2d13 | |||
| b3981b19e0 | |||
| 3d7a64068f | |||
| c12f7408ad | |||
| 7027de80c4 | |||
| 35b50d1436 | |||
| 5c50e77efa | |||
| 0e93be7b36 | |||
| 191b818e38 | |||
| 00b09997b0 | |||
| d250c635d8 | |||
| 376c4d25a8 | |||
| e66abb4340 | |||
| a19e191684 | |||
| 19db6668da | |||
| 44275aec04 | |||
| 64245833cd | |||
| aa0149b9a7 | |||
| f6b41f0513 | |||
| 9b00ba654a | |||
| 8dfdb228e9 | |||
| 1042817e4e | |||
| 066557584f | |||
| 4011295b8b | |||
| 0a885dd8fd | |||
| e9b50038a9 | |||
| 364264377a | |||
| 9112183ac3 | |||
| 957821f1f2 | |||
| 094eb4c1cf | |||
| 607acff7c6 | |||
| 22fdf1e4ac | |||
| da8c91f5c1 | |||
| 52dc7a956d | |||
| 9f64b2380d | |||
| b05580f018 | |||
| c20c6fb264 | |||
| faeece27ff | |||
| 6ca75b2cac | |||
| 6ff309a40c | |||
| 40a7f9bc5b | |||
| c4a6113f6c | |||
| 307e79ecfc | |||
| 7d8a6afa5f | |||
| ea0be5e952 | |||
| 7197bc2bee | |||
| fba522d0c3 | |||
| 0e829874c2 | |||
| c5d56065b6 | |||
| 410d765745 | |||
| fe76e85c71 | |||
| 9d61a43bd7 | |||
| c39582de5c | |||
| d4d7ddf8e2 | |||
| a1933c2869 | |||
| 8084a61333 | |||
| 03f5f91043 | |||
| 9ed52a1225 | |||
| 027324cc4f | |||
| da263355f4 | |||
| ebecd25ed2 | |||
| 0f5137c2b6 | |||
| 73799954e4 | |||
| edfeb2b287 | |||
| 0355784000 |
@@ -1,23 +1,40 @@
|
|||||||
package seng302.gameServer;
|
package seng302.gameServer;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Random;
|
||||||
|
import java.util.Set;
|
||||||
import javafx.scene.paint.Color;
|
import javafx.scene.paint.Color;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.w3c.dom.Document;
|
import seng302.gameServer.messages.BoatAction;
|
||||||
import org.xml.sax.InputSource;
|
import seng302.gameServer.messages.BoatStatus;
|
||||||
import seng302.gameServer.messages.*;
|
import seng302.gameServer.messages.ChatterMessage;
|
||||||
import seng302.model.*;
|
import seng302.gameServer.messages.CustomizeRequestType;
|
||||||
|
import seng302.gameServer.messages.MarkRoundingMessage;
|
||||||
|
import seng302.gameServer.messages.MarkType;
|
||||||
|
import seng302.gameServer.messages.Message;
|
||||||
|
import seng302.gameServer.messages.RoundingBoatStatus;
|
||||||
|
import seng302.gameServer.messages.YachtEventCodeMessage;
|
||||||
|
import seng302.gameServer.messages.YachtEventType;
|
||||||
|
import seng302.model.GeoPoint;
|
||||||
|
import seng302.model.Limit;
|
||||||
|
import seng302.model.Player;
|
||||||
|
import seng302.model.PolarTable;
|
||||||
|
import seng302.model.ServerYacht;
|
||||||
import seng302.model.mark.CompoundMark;
|
import seng302.model.mark.CompoundMark;
|
||||||
import seng302.model.mark.Mark;
|
import seng302.model.mark.Mark;
|
||||||
import seng302.model.mark.MarkOrder;
|
import seng302.model.mark.MarkOrder;
|
||||||
|
import seng302.model.stream.xml.parser.RaceXMLData;
|
||||||
import seng302.model.token.Token;
|
import seng302.model.token.Token;
|
||||||
import seng302.model.token.TokenType;
|
import seng302.model.token.TokenType;
|
||||||
import seng302.utilities.GeoUtility;
|
import seng302.utilities.GeoUtility;
|
||||||
import seng302.utilities.XMLParser;
|
import seng302.visualiser.fxObjects.assets_3D.BoatMeshType;
|
||||||
|
|
||||||
import javax.xml.parsers.DocumentBuilder;
|
|
||||||
import javax.xml.parsers.DocumentBuilderFactory;
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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)
|
||||||
@@ -56,7 +73,6 @@ public class GameState implements Runnable {
|
|||||||
private static Boolean customizationFlag; // dirty flag to tell if a player has customized their boat.
|
private static Boolean customizationFlag; // dirty flag to tell if a player has customized their boat.
|
||||||
private static Boolean playerHasLeftFlag;
|
private static Boolean playerHasLeftFlag;
|
||||||
|
|
||||||
private static String hostIpAddress;
|
|
||||||
private static List<Player> players;
|
private static List<Player> players;
|
||||||
private static Map<Integer, ServerYacht> yachts;
|
private static Map<Integer, ServerYacht> yachts;
|
||||||
private static Boolean isRaceStarted;
|
private static Boolean isRaceStarted;
|
||||||
@@ -75,14 +91,13 @@ public class GameState implements Runnable {
|
|||||||
|
|
||||||
private static Map<Player, String> playerStringMap = new HashMap<>();
|
private static Map<Player, String> playerStringMap = new HashMap<>();
|
||||||
|
|
||||||
public GameState(String hostIpAddress) {
|
public GameState() {
|
||||||
windDirection = 180d;
|
windDirection = 180d;
|
||||||
windSpeed = 10000d;
|
windSpeed = 10000d;
|
||||||
yachts = new HashMap<>();
|
yachts = new HashMap<>();
|
||||||
tokensInPlay = new ArrayList<>();
|
tokensInPlay = new ArrayList<>();
|
||||||
|
marks = new HashSet<>();
|
||||||
players = new ArrayList<>();
|
players = new ArrayList<>();
|
||||||
GameState.hostIpAddress = hostIpAddress;
|
|
||||||
customizationFlag = false;
|
customizationFlag = false;
|
||||||
playerHasLeftFlag = false;
|
playerHasLeftFlag = false;
|
||||||
speedMultiplier = 1.0;
|
speedMultiplier = 1.0;
|
||||||
@@ -90,34 +105,20 @@ 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();
|
||||||
markOrder = new MarkOrder(); //This could be instantiated at some point with a select map?
|
|
||||||
newMessageListeners = new ArrayList<>();
|
newMessageListeners = new ArrayList<>();
|
||||||
allTokens = makeTokens();
|
allTokens = makeTokens();
|
||||||
|
|
||||||
resetStartTime();
|
resetStartTime();
|
||||||
|
|
||||||
new Thread(this, "GameState").start(); //Run the auto updates on the game state
|
new Thread(this, "GameState").start(); //Run the auto updates on the game state
|
||||||
|
|
||||||
marks = new MarkOrder().getAllMarks();
|
|
||||||
setCourseLimit("/server_config/race.xml");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setCourseLimit(String url) {
|
public static void setRace(RaceXMLData raceXMLData) {
|
||||||
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
|
markOrder = new MarkOrder(raceXMLData);
|
||||||
documentBuilderFactory.setNamespaceAware(true);
|
for (CompoundMark compoundMark : raceXMLData.getCompoundMarks().values()){
|
||||||
DocumentBuilder documentBuilder;
|
marks.addAll(compoundMark.getMarks());
|
||||||
Document document = null;
|
|
||||||
try {
|
|
||||||
documentBuilder = documentBuilderFactory.newDocumentBuilder();
|
|
||||||
document = documentBuilder.parse(new InputSource(getClass().getResourceAsStream(url)));
|
|
||||||
} catch (Exception e) {
|
|
||||||
// sorry, we have to catch general one, otherwise we have to catch five different exceptions.
|
|
||||||
logger.trace("Failed to load course limit for boundary collision detection.", e);
|
|
||||||
}
|
}
|
||||||
courseLimit = XMLParser.parseRace(document).getCourseLimit();
|
courseLimit = raceXMLData.getCourseLimit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Make a pre defined set of tokensInPlay. //TODO wmu16 - Should read from some file for each
|
* Make a pre defined set of tokensInPlay. //TODO wmu16 - Should read from some file for each
|
||||||
* race ideally
|
* race ideally
|
||||||
@@ -132,10 +133,6 @@ public class GameState implements Runnable {
|
|||||||
return new ArrayList<>(Arrays.asList(token1, token2, token3, token4));
|
return new ArrayList<>(Arrays.asList(token1, token2, token3, token4));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String getHostIpAddress() {
|
|
||||||
return hostIpAddress;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Set<Mark> getMarks() {
|
public static Set<Mark> getMarks() {
|
||||||
return Collections.unmodifiableSet(marks);
|
return Collections.unmodifiableSet(marks);
|
||||||
}
|
}
|
||||||
@@ -243,10 +240,6 @@ public class GameState implements Runnable {
|
|||||||
if (currentStage == GameStages.PRE_RACE || currentStage == GameStages.RACING) {
|
if (currentStage == GameStages.PRE_RACE || currentStage == GameStages.RACING) {
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (currentStage == GameStages.RACING) {
|
|
||||||
update();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -271,6 +264,12 @@ public class GameState implements Runnable {
|
|||||||
case DOWNWIND:
|
case DOWNWIND:
|
||||||
playerYacht.turnDownwind();
|
playerYacht.turnDownwind();
|
||||||
break;
|
break;
|
||||||
|
case CONTINUOUSLY_TURNING:
|
||||||
|
playerYacht.setContinuouslyTurning(true);
|
||||||
|
break;
|
||||||
|
case DEFAULT_TURNING:
|
||||||
|
playerYacht.setContinuouslyTurning(false);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -323,6 +322,7 @@ public class GameState implements Runnable {
|
|||||||
if (yacht.getPowerUp() != null) {
|
if (yacht.getPowerUp() != null) {
|
||||||
if (System.currentTimeMillis() - yacht.getPowerUpStartTime() > POWERUP_TIMEOUT_MS) {
|
if (System.currentTimeMillis() - yacht.getPowerUpStartTime() > POWERUP_TIMEOUT_MS) {
|
||||||
yacht.powerDown();
|
yacht.powerDown();
|
||||||
|
sendServerMessage(yacht.getSourceId(), yacht.getBoatName() + "'s power-up token expired");
|
||||||
logger.debug("Yacht: " + yacht.getShortName() + " powered down!");
|
logger.debug("Yacht: " + yacht.getShortName() + " powered down!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -433,10 +433,12 @@ public class GameState implements Runnable {
|
|||||||
//Token Collision
|
//Token Collision
|
||||||
Token collidedToken = checkTokenPickUp(serverYacht);
|
Token collidedToken = checkTokenPickUp(serverYacht);
|
||||||
if (collidedToken != null) {
|
if (collidedToken != null) {
|
||||||
|
sendServerMessage(serverYacht.getSourceId(), serverYacht.getBoatName() + " has picked speed-up token");
|
||||||
tokensInPlay.remove(collidedToken);
|
tokensInPlay.remove(collidedToken);
|
||||||
serverYacht.powerUp(collidedToken.getTokenType());
|
serverYacht.powerUp(collidedToken.getTokenType());
|
||||||
logger.debug("Yacht: " + serverYacht.getShortName() + " got powerup " + collidedToken
|
logger.debug("Yacht: " + serverYacht.getShortName() + " got powerup " + collidedToken
|
||||||
.getTokenType());
|
.getTokenType());
|
||||||
|
System.out.println("AGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG");
|
||||||
notifyMessageListeners(MessageFactory.getRaceXML());
|
notifyMessageListeners(MessageFactory.getRaceXML());
|
||||||
notifyMessageListeners(
|
notifyMessageListeners(
|
||||||
new YachtEventCodeMessage(serverYacht.getSourceId(), YachtEventType.TOKEN));
|
new YachtEventCodeMessage(serverYacht.getSourceId(), YachtEventType.TOKEN));
|
||||||
@@ -447,7 +449,7 @@ public class GameState implements Runnable {
|
|||||||
private void updateVelocity(ServerYacht yacht) {
|
private void updateVelocity(ServerYacht yacht) {
|
||||||
Double trueWindAngle = Math.abs(windDirection - yacht.getHeading());
|
Double trueWindAngle = Math.abs(windDirection - yacht.getHeading());
|
||||||
Double boatSpeedInKnots = PolarTable.getBoatSpeed(getWindSpeedKnots(), trueWindAngle);
|
Double boatSpeedInKnots = PolarTable.getBoatSpeed(getWindSpeedKnots(), trueWindAngle);
|
||||||
Double maxBoatSpeed = GeoUtility.knotsToMMS(boatSpeedInKnots) * speedMultiplier;
|
Double maxBoatSpeed = GeoUtility.knotsToMMS(boatSpeedInKnots) * speedMultiplier * yacht.getMaxSpeedMultiplier();
|
||||||
if (yacht.getPowerUp() != null) {
|
if (yacht.getPowerUp() != null) {
|
||||||
if (yacht.getPowerUp().equals(TokenType.BOOST)) {
|
if (yacht.getPowerUp().equals(TokenType.BOOST)) {
|
||||||
// TODO: 11/09/17 wmu16 CHANGE THIS TO MAGIC NUMBER
|
// TODO: 11/09/17 wmu16 CHANGE THIS TO MAGIC NUMBER
|
||||||
@@ -459,17 +461,17 @@ public class GameState implements Runnable {
|
|||||||
// TODO: 15/08/17 remove magic numbers from these equations.
|
// TODO: 15/08/17 remove magic numbers from these equations.
|
||||||
if (yacht.getSailIn()) {
|
if (yacht.getSailIn()) {
|
||||||
if (currentVelocity < maxBoatSpeed - 500) {
|
if (currentVelocity < maxBoatSpeed - 500) {
|
||||||
yacht.changeVelocity(maxBoatSpeed / 100);
|
yacht.changeVelocity((maxBoatSpeed / 100) * yacht.getAccelerationMultiplier());
|
||||||
} else if (currentVelocity > maxBoatSpeed + 500) {
|
} else if (currentVelocity > maxBoatSpeed + 500) {
|
||||||
yacht.changeVelocity(-currentVelocity / 200);
|
yacht.changeVelocity((-currentVelocity / 200) * yacht.getAccelerationMultiplier());
|
||||||
} else {
|
} else {
|
||||||
yacht.setCurrentVelocity(maxBoatSpeed);
|
yacht.setCurrentVelocity((maxBoatSpeed) * yacht.getAccelerationMultiplier());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (currentVelocity > 3000) {
|
if (currentVelocity > 3000) {
|
||||||
yacht.changeVelocity(-currentVelocity / 200);
|
yacht.changeVelocity((-currentVelocity / 200) * yacht.getAccelerationMultiplier());
|
||||||
} else if (currentVelocity > 100) {
|
} else if (currentVelocity > 100) {
|
||||||
yacht.changeVelocity(-currentVelocity / 50);
|
yacht.changeVelocity((-currentVelocity / 50) * yacht.getAccelerationMultiplier());
|
||||||
} else if (currentVelocity <= 100) {
|
} else if (currentVelocity <= 100) {
|
||||||
yacht.setCurrentVelocity(0d);
|
yacht.setCurrentVelocity(0d);
|
||||||
}
|
}
|
||||||
@@ -531,6 +533,9 @@ public class GameState implements Runnable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (hasProgressed) {
|
if (hasProgressed) {
|
||||||
|
if (currentMarkSeqID != 0 && !markOrder.isLastMark(currentMarkSeqID)) {
|
||||||
|
sendServerMessage(yacht.getSourceId(), yacht.getBoatName() + " passed leg " + yacht.getLegNumber());
|
||||||
|
}
|
||||||
yacht.incrementLegNumber();
|
yacht.incrementLegNumber();
|
||||||
sendMarkRoundingMessage(yacht);
|
sendMarkRoundingMessage(yacht);
|
||||||
logMarkRounding(yacht);
|
logMarkRounding(yacht);
|
||||||
@@ -565,6 +570,7 @@ public class GameState implements Runnable {
|
|||||||
if (crossedLine == 2 && isClockwiseCross || crossedLine == 1 && !isClockwiseCross) {
|
if (crossedLine == 2 && isClockwiseCross || crossedLine == 1 && !isClockwiseCross) {
|
||||||
yacht.setClosestCurrentMark(mark1);
|
yacht.setClosestCurrentMark(mark1);
|
||||||
yacht.setBoatStatus(BoatStatus.RACING);
|
yacht.setBoatStatus(BoatStatus.RACING);
|
||||||
|
sendServerMessage(yacht.getSourceId(), yacht.getBoatName() + " passed start line");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -668,6 +674,7 @@ public class GameState implements Runnable {
|
|||||||
if (crossedLine == 1 && isClockwiseCross || crossedLine == 2 && !isClockwiseCross) {
|
if (crossedLine == 1 && isClockwiseCross || crossedLine == 2 && !isClockwiseCross) {
|
||||||
yacht.setClosestCurrentMark(mark1);
|
yacht.setClosestCurrentMark(mark1);
|
||||||
yacht.setBoatStatus(BoatStatus.FINISHED);
|
yacht.setBoatStatus(BoatStatus.FINISHED);
|
||||||
|
sendServerMessage(yacht.getSourceId(), yacht.getBoatName() + " passed finish line");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -695,6 +702,9 @@ public class GameState implements Runnable {
|
|||||||
int blue = customizeData[2] & 0xFF;
|
int blue = customizeData[2] & 0xFF;
|
||||||
Color yachtColor = Color.rgb(red, green, blue);
|
Color yachtColor = Color.rgb(red, green, blue);
|
||||||
playerYacht.setBoatColor(yachtColor);
|
playerYacht.setBoatColor(yachtColor);
|
||||||
|
} else if (requestType.equals(CustomizeRequestType.SHAPE)) {
|
||||||
|
String type = new String(customizeData);
|
||||||
|
playerYacht.setBoatType(BoatMeshType.valueOf(type));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -788,12 +798,7 @@ public class GameState implements Runnable {
|
|||||||
try {
|
try {
|
||||||
setSpeedMultiplier(Double.valueOf(words[3]));
|
setSpeedMultiplier(Double.valueOf(words[3]));
|
||||||
sendServerMessage(chatterMessage.getMessage_type(),
|
sendServerMessage(chatterMessage.getMessage_type(),
|
||||||
"SERVER: Speed modifier set to x" + words[3]);
|
"Speed modifier set to x" + words[3]);
|
||||||
System.out.println(chatterMessage.getMessage_type());
|
|
||||||
// notifyMessageListeners(new ChatterMessage(
|
|
||||||
// chatterMessage.getMessage_type(),
|
|
||||||
// "SERVER: Speed modifier set to x" + words[3]
|
|
||||||
// ));
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Logger logger = LoggerFactory.getLogger(GameState.class);
|
Logger logger = LoggerFactory.getLogger(GameState.class);
|
||||||
logger.error("cannot parse >speed value");
|
logger.error("cannot parse >speed value");
|
||||||
@@ -801,12 +806,7 @@ public class GameState implements Runnable {
|
|||||||
return;
|
return;
|
||||||
case "/finish":
|
case "/finish":
|
||||||
sendServerMessage(chatterMessage.getMessage_type(),
|
sendServerMessage(chatterMessage.getMessage_type(),
|
||||||
"SERVER: Game will now finish");
|
"Game will now finish");
|
||||||
System.out.println(chatterMessage.getMessage_type());
|
|
||||||
// notifyMessageListeners(new ChatterMessage(
|
|
||||||
// chatterMessage.getMessage_type(),
|
|
||||||
// "SERVER: Game will now finish"
|
|
||||||
// ));
|
|
||||||
endRace();
|
endRace();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,30 +1,23 @@
|
|||||||
package seng302.gameServer;
|
package seng302.gameServer;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.StringReader;
|
|
||||||
import java.net.ServerSocket;
|
import java.net.ServerSocket;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
import java.util.Timer;
|
import java.util.Timer;
|
||||||
import java.util.TimerTask;
|
import java.util.TimerTask;
|
||||||
import javax.xml.parsers.DocumentBuilder;
|
|
||||||
import javax.xml.parsers.DocumentBuilderFactory;
|
|
||||||
import javax.xml.parsers.ParserConfigurationException;
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.w3c.dom.Document;
|
|
||||||
import org.xml.sax.InputSource;
|
|
||||||
import org.xml.sax.SAXException;
|
|
||||||
import seng302.gameServer.messages.Message;
|
import seng302.gameServer.messages.Message;
|
||||||
import seng302.model.GeoPoint;
|
import seng302.model.GeoPoint;
|
||||||
import seng302.model.Player;
|
import seng302.model.Player;
|
||||||
import seng302.model.PolarTable;
|
import seng302.model.PolarTable;
|
||||||
import seng302.model.ServerYacht;
|
import seng302.model.ServerYacht;
|
||||||
import seng302.model.mark.CompoundMark;
|
import seng302.model.stream.xml.parser.RaceXMLData;
|
||||||
import seng302.model.stream.xml.parser.RegattaXMLData;
|
import seng302.model.stream.xml.parser.RegattaXMLData;
|
||||||
import seng302.utilities.GeoUtility;
|
import seng302.utilities.GeoUtility;
|
||||||
import seng302.utilities.XMLGenerator;
|
|
||||||
import seng302.utilities.XMLParser;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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
|
||||||
@@ -45,29 +38,13 @@ public class MainServerThread implements Runnable, ClientConnectionDelegate {
|
|||||||
private Thread thread;
|
private Thread thread;
|
||||||
|
|
||||||
private ServerSocket serverSocket = null;
|
private ServerSocket serverSocket = null;
|
||||||
private ArrayList<ServerToClientThread> serverToClientThreads = new ArrayList<>();;
|
private ArrayList<ServerToClientThread> serverToClientThreads = new ArrayList<>();
|
||||||
private static Integer capacity;
|
private static Integer capacity;
|
||||||
|
private RaceXMLData raceXMLData;
|
||||||
|
private RegattaXMLData regattaXMLData;
|
||||||
|
private boolean serverStarted = false;
|
||||||
|
|
||||||
private void startAdvertisingServer() {
|
private void startAdvertisingServer() {
|
||||||
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
|
|
||||||
DocumentBuilder db;
|
|
||||||
Document doc;
|
|
||||||
XMLGenerator generator = new XMLGenerator();
|
|
||||||
|
|
||||||
try {
|
|
||||||
db = dbf.newDocumentBuilder();
|
|
||||||
String regatta = generator.getRegattaAsXml();
|
|
||||||
StringReader stringReader = new StringReader(regatta);
|
|
||||||
InputSource is = new InputSource(stringReader);
|
|
||||||
doc = db.parse(is);
|
|
||||||
} catch (ParserConfigurationException | IOException | SAXException e) {
|
|
||||||
logger.warn("Couldn't load race regatta");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
RegattaXMLData regattaXMLData = XMLParser.parseRegatta(doc);
|
|
||||||
|
|
||||||
|
|
||||||
Integer capacity = GameState.getCapacity();
|
Integer capacity = GameState.getCapacity();
|
||||||
Integer numPlayers = GameState.getNumberOfPlayers();
|
Integer numPlayers = GameState.getNumberOfPlayers();
|
||||||
Integer spacesLeft = capacity - numPlayers;
|
Integer spacesLeft = capacity - numPlayers;
|
||||||
@@ -79,33 +56,42 @@ public class MainServerThread implements Runnable, ClientConnectionDelegate {
|
|||||||
|
|
||||||
// Start advertising server
|
// Start advertising server
|
||||||
try {
|
try {
|
||||||
ServerAdvertiser.getInstance().setMapName(regattaXMLData.getCourseName()).setCapacity(capacity).setNumberOfPlayers(numPlayers);
|
ServerAdvertiser.getInstance()
|
||||||
ServerAdvertiser.getInstance().registerGame(PORT, regattaXMLData.getRegattaName());
|
.setMapName(regattaXMLData.getCourseName())
|
||||||
|
.setCapacity(capacity)
|
||||||
|
.setNumberOfPlayers(numPlayers)
|
||||||
|
.registerGame(PORT, regattaXMLData.getRegattaName());
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
logger.warn("Could not register server");
|
logger.warn("Could not register server");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public MainServerThread() {
|
public MainServerThread() {
|
||||||
new GameState("localhost");
|
new GameState();
|
||||||
try {
|
try {
|
||||||
serverSocket = new ServerSocket(PORT);
|
serverSocket = new ServerSocket(PORT);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
logger.trace("IO error in server thread handler upon trying to make new server socket",
|
logger.trace("IO error in server thread handler upon trying to make new server socket",
|
||||||
0);
|
0);
|
||||||
}
|
}
|
||||||
|
|
||||||
startAdvertisingServer();
|
|
||||||
|
|
||||||
PolarTable.parsePolarFile(getClass().getResourceAsStream("/config/acc_polars.csv"));
|
|
||||||
GameState.addMessageEventListener(this::broadcastMessage);
|
|
||||||
terminated = false;
|
terminated = false;
|
||||||
thread = new Thread(this, "MainServer");
|
thread = new Thread(this, "MainServer");
|
||||||
startUpdatingWind();
|
|
||||||
startSpawningTokens();
|
|
||||||
thread.start();
|
thread.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void startServer() {
|
||||||
|
MessageFactory.updateXMLGenerator(raceXMLData, regattaXMLData);
|
||||||
|
GameState.setRace(raceXMLData);
|
||||||
|
MessageFactory.updateBoats(new ArrayList<>(GameState.getYachts().values()));
|
||||||
|
startAdvertisingServer();
|
||||||
|
PolarTable
|
||||||
|
.parsePolarFile(getClass().getResourceAsStream("/server_config/acc_polars.csv"));
|
||||||
|
GameState.addMessageEventListener(this::broadcastMessage);
|
||||||
|
startUpdatingWind();
|
||||||
|
startSpawningTokens();
|
||||||
|
System.out.println("SAAAANNNNNNNNNDDDDDDDDDDDDDDDDDDDDDDDDDDdd");
|
||||||
|
sendSetupMessages();
|
||||||
|
}
|
||||||
|
|
||||||
public void run() {
|
public void run() {
|
||||||
|
|
||||||
@@ -118,6 +104,7 @@ public class MainServerThread implements Runnable, ClientConnectionDelegate {
|
|||||||
for (ServerToClientThread stc : serverToClientThreads) {
|
for (ServerToClientThread stc : serverToClientThreads) {
|
||||||
if (!stc.isSocketOpen()) {
|
if (!stc.isSocketOpen()) {
|
||||||
GameState.getYachts().remove(stc.getSourceId());
|
GameState.getYachts().remove(stc.getSourceId());
|
||||||
|
System.out.println("AAAAAAAFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF");
|
||||||
sendSetupMessages();
|
sendSetupMessages();
|
||||||
try {
|
try {
|
||||||
stc.getSocket().close();
|
stc.getSocket().close();
|
||||||
@@ -133,8 +120,9 @@ public class MainServerThread implements Runnable, ClientConnectionDelegate {
|
|||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
logger.trace("Interrupted exception in Main Server Thread thread sleep", 1);
|
logger.trace("Interrupted exception in Main Server Thread thread sleep", 1);
|
||||||
}
|
}
|
||||||
if (GameState.getCurrentStage() == GameStages.LOBBYING && GameState
|
if (GameState.getCurrentStage() == GameStages.LOBBYING && GameState.getCustomizationFlag()) {
|
||||||
.getCustomizationFlag()) {
|
MessageFactory.updateBoats(new ArrayList<>(GameState.getYachts().values()));
|
||||||
|
System.out.println("gfdgfdgfdg");
|
||||||
sendSetupMessages();
|
sendSetupMessages();
|
||||||
GameState.resetCustomizationFlag();
|
GameState.resetCustomizationFlag();
|
||||||
}
|
}
|
||||||
@@ -254,11 +242,34 @@ public class MainServerThread implements Runnable, ClientConnectionDelegate {
|
|||||||
logger.debug("Player Connected From " + serverToClientThread.getThread().getName(), 0);
|
logger.debug("Player Connected From " + serverToClientThread.getThread().getName(), 0);
|
||||||
if (serverToClientThreads.size() == 0) { //Sets first client as host.
|
if (serverToClientThreads.size() == 0) { //Sets first client as host.
|
||||||
serverToClientThread.setAsHost();
|
serverToClientThread.setAsHost();
|
||||||
|
serverToClientThread.raceXMLProperty().addListener((obs, oldVal, race) -> {
|
||||||
|
if (race != null) {
|
||||||
|
raceXMLData = race;
|
||||||
|
}
|
||||||
|
if (regattaXMLData != null) {
|
||||||
|
startServer();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
serverToClientThread.regattaXMLProperty().addListener((obs, oldVal, regatta) -> {
|
||||||
|
if (regatta != null) {
|
||||||
|
regattaXMLData = regatta;
|
||||||
|
}
|
||||||
|
if (raceXMLData != null) {
|
||||||
|
startServer();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
MessageFactory.updateBoats(new ArrayList<>(GameState.getYachts().values()));
|
||||||
|
for (ServerYacht serverYacht : GameState.getYachts().values()) {
|
||||||
|
System.out.println("Connecterino" + serverYacht);
|
||||||
|
}
|
||||||
|
serverToClientThread.addConnectionListener(() -> {
|
||||||
|
System.out.println("LUSTENER");
|
||||||
|
sendSetupMessages();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
serverToClientThreads.add(serverToClientThread);
|
serverToClientThreads.add(serverToClientThread);
|
||||||
serverToClientThread.addConnectionListener(this::sendSetupMessages);
|
|
||||||
serverToClientThread.addDisconnectListener(this::clientDisconnected);
|
serverToClientThread.addDisconnectListener(this::clientDisconnected);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
ServerAdvertiser.getInstance().setNumberOfPlayers(GameState.getNumberOfPlayers());
|
ServerAdvertiser.getInstance().setNumberOfPlayers(GameState.getNumberOfPlayers());
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
@@ -317,9 +328,9 @@ public class MainServerThread implements Runnable, ClientConnectionDelegate {
|
|||||||
}, 0, 500);
|
}, 0, 500);
|
||||||
|
|
||||||
|
|
||||||
if (GameState.getCurrentStage() == GameStages.LOBBYING) {
|
// if (GameState.getCurrentStage() == GameStages.LOBBYING) {
|
||||||
sendSetupMessages();
|
// sendSetupMessages();
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
public void terminate() {
|
public void terminate() {
|
||||||
@@ -330,39 +341,166 @@ public class MainServerThread implements Runnable, ClientConnectionDelegate {
|
|||||||
* Initialise boats to specific spaced out geopoints behind starting line.
|
* Initialise boats to specific spaced out geopoints behind starting line.
|
||||||
*/
|
*/
|
||||||
private void initialiseBoatPositions() {
|
private void initialiseBoatPositions() {
|
||||||
CompoundMark cm = GameState.getMarkOrder().getMarkOrder().get(0);
|
// CompoundMark cm = GameState.getMarkOrder().getMarkOrder().get(0);
|
||||||
GeoPoint startMark1 = cm.getSubMark(1);
|
// GeoPoint startMark1 = cm.getSubMark(1);
|
||||||
GeoPoint startMark2 = cm.getSubMark(2);
|
// GeoPoint startMark2 = cm.getSubMark(2);
|
||||||
|
//
|
||||||
|
// // Calculating midpoint
|
||||||
|
// Double perpendicularAngle = GeoUtility.getBearing(startMark1, startMark2);
|
||||||
|
// Double length = GeoUtility.getDistance(startMark1, startMark2);
|
||||||
|
// GeoPoint midpoint = GeoUtility.getGeoCoordinate(startMark1, perpendicularAngle, length / 2);
|
||||||
|
//
|
||||||
|
// // Setting each boats position side by side
|
||||||
|
// final double SEPARATION = 50.0; // distance apart in meters
|
||||||
|
//
|
||||||
|
// int boatIndex = 0;
|
||||||
|
// for (ServerYacht yacht : GameState.getYachts().values()) {
|
||||||
|
// int distanceApart = boatIndex / 2;
|
||||||
|
//
|
||||||
|
// if (boatIndex % 2 == 1 && boatIndex != 0) {
|
||||||
|
// distanceApart++;
|
||||||
|
// distanceApart *= -1;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// GeoPoint spawnMark = GeoUtility
|
||||||
|
// .getGeoCoordinate(midpoint, perpendicularAngle, distanceApart * SEPARATION);
|
||||||
|
//
|
||||||
|
// if (yacht.getHeading() < perpendicularAngle) {
|
||||||
|
// spawnMark = GeoUtility
|
||||||
|
// .getGeoCoordinate(spawnMark, perpendicularAngle + 90, SEPARATION);
|
||||||
|
// } else {
|
||||||
|
// spawnMark = GeoUtility
|
||||||
|
// .getGeoCoordinate(spawnMark, perpendicularAngle + 270, SEPARATION);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// yacht.setLocation(spawnMark);
|
||||||
|
// boatIndex++;
|
||||||
|
// }
|
||||||
|
|
||||||
// Calculating midpoint
|
// final double SEPARATION = 50.0; // distance apart in meters
|
||||||
Double perpendicularAngle = GeoUtility.getBearing(startMark1, startMark2);
|
//
|
||||||
Double length = GeoUtility.getDistance(startMark1, startMark2);
|
// //Reverse of the angle from start to first mark
|
||||||
GeoPoint midpoint = GeoUtility.getGeoCoordinate(startMark1, perpendicularAngle, length / 2);
|
// double angleToFirstMark = 360 - GeoUtility.getBearing(
|
||||||
|
// GameState.getMarkOrder().getMarkOrder().get(0).getMidPoint(),
|
||||||
|
// GameState.getMarkOrder().getMarkOrder().get(1).getMidPoint()
|
||||||
|
// );
|
||||||
|
//
|
||||||
|
// //Length of start line
|
||||||
|
// double startLineLength = GeoUtility.getDistance(
|
||||||
|
// GameState.getMarkOrder().getMarkOrder().get(0).getSubMark(1),
|
||||||
|
// GameState.getMarkOrder().getMarkOrder().get(0).getSubMark(2)
|
||||||
|
// );
|
||||||
|
//
|
||||||
|
// //Angle of start line
|
||||||
|
// double startMarkToMarkAngle = GeoUtility.getBearing(
|
||||||
|
// GameState.getMarkOrder().getMarkOrder().get(0).getSubMark(1),
|
||||||
|
// GameState.getMarkOrder().getMarkOrder().get(0).getSubMark(2)
|
||||||
|
// );
|
||||||
|
//
|
||||||
|
// //How many yachts can fit along the start line
|
||||||
|
// int spacesAlongLine = (int) Math.round(startLineLength / SEPARATION);
|
||||||
|
// //The free space left by the boats.
|
||||||
|
// double buffer = (startLineLength % SEPARATION) / 2;
|
||||||
|
//
|
||||||
|
// //Randomize starting order.
|
||||||
|
// List<ServerYacht> serverYachtList = new ArrayList<>(GameState.getYachts().values());
|
||||||
|
// Collections.shuffle(serverYachtList);
|
||||||
|
//
|
||||||
|
// //set the starting point away from start line.
|
||||||
|
// GeoPoint startingPoint = GeoUtility.getGeoCoordinate(
|
||||||
|
// GameState.getMarkOrder().getMarkOrder().get(0).getSubMark(1),
|
||||||
|
// angleToFirstMark, SEPARATION
|
||||||
|
// );
|
||||||
|
//
|
||||||
|
// //Move it along the start line
|
||||||
|
// startingPoint = GeoUtility.getGeoCoordinate(
|
||||||
|
// startingPoint, startMarkToMarkAngle, buffer
|
||||||
|
// );
|
||||||
|
//
|
||||||
|
// int yachtCount = 0;
|
||||||
|
// int repeats = 0;
|
||||||
|
//
|
||||||
|
// GeoPoint yachtLocation;
|
||||||
|
//
|
||||||
|
// for (ServerYacht serverYacht : serverYachtList) {
|
||||||
|
//
|
||||||
|
// //Move away from start line
|
||||||
|
// yachtLocation = GeoUtility.getGeoCoordinate(
|
||||||
|
// startingPoint, angleToFirstMark,repeats * SEPARATION
|
||||||
|
// );
|
||||||
|
// //Move along start line
|
||||||
|
// yachtLocation = GeoUtility.getGeoCoordinate(
|
||||||
|
// yachtLocation, startMarkToMarkAngle, yachtCount * SEPARATION
|
||||||
|
// );
|
||||||
|
// serverYacht.setLocation(yachtLocation);
|
||||||
|
// serverYacht.setHeading(GeoUtility.getBearing(
|
||||||
|
// yachtLocation, GameState.getMarkOrder().getMarkOrder().get(1).getMidPoint()
|
||||||
|
// ));
|
||||||
|
// //Set location for next yacht
|
||||||
|
// yachtCount++;
|
||||||
|
// if (yachtCount > spacesAlongLine) {
|
||||||
|
// yachtCount = 0;
|
||||||
|
// repeats++;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
// Setting each boats position side by side
|
final double DISTANCE_TO_START = 75d;
|
||||||
double DISTANCE_FACTOR = 50.0; // distance apart in meters
|
final double YACHT_SEPARATION = 20d;
|
||||||
int boatIndex = 0;
|
|
||||||
for (ServerYacht yacht : GameState.getYachts().values()) {
|
|
||||||
int distanceApart = boatIndex / 2;
|
|
||||||
|
|
||||||
if (boatIndex % 2 == 1 && boatIndex != 0) {
|
//Length of start line
|
||||||
distanceApart++;
|
double startLineLength = GeoUtility.getDistance(
|
||||||
distanceApart *= -1;
|
GameState.getMarkOrder().getMarkOrder().get(0).getSubMark(1),
|
||||||
|
GameState.getMarkOrder().getMarkOrder().get(0).getSubMark(2)
|
||||||
|
);
|
||||||
|
|
||||||
|
//How many yachts can fit along the start line
|
||||||
|
int spacesAlongLine = (int) Math.round(startLineLength / YACHT_SEPARATION);
|
||||||
|
|
||||||
|
//Angle of start line
|
||||||
|
double startMarkToMarkAngle = GeoUtility.getBearing(
|
||||||
|
GameState.getMarkOrder().getMarkOrder().get(0).getSubMark(1),
|
||||||
|
GameState.getMarkOrder().getMarkOrder().get(0).getSubMark(2)
|
||||||
|
);
|
||||||
|
|
||||||
|
//angle from first mark to the start
|
||||||
|
double angleToStart = GeoUtility.getBearing(
|
||||||
|
GameState.getMarkOrder().getMarkOrder().get(1).getMidPoint(),
|
||||||
|
GameState.getMarkOrder().getMarkOrder().get(0).getMidPoint()
|
||||||
|
);
|
||||||
|
|
||||||
|
double angleFromStart = GeoUtility.getBearing(
|
||||||
|
GameState.getMarkOrder().getMarkOrder().get(0).getMidPoint(),
|
||||||
|
GameState.getMarkOrder().getMarkOrder().get(1).getMidPoint()
|
||||||
|
);
|
||||||
|
|
||||||
|
GeoPoint startingPoint = GeoUtility.getGeoCoordinate(
|
||||||
|
GameState.getMarkOrder().getMarkOrder().get(0).getMidPoint(),
|
||||||
|
angleToStart, DISTANCE_TO_START
|
||||||
|
);
|
||||||
|
|
||||||
|
List<ServerYacht> randomisedYachts = new ArrayList<>(GameState.getYachts().values());
|
||||||
|
Collections.shuffle(randomisedYachts);
|
||||||
|
while (randomisedYachts.size() > 0) {
|
||||||
|
|
||||||
|
int numYachtsInLine = spacesAlongLine > randomisedYachts.size() ? randomisedYachts.size() : spacesAlongLine;
|
||||||
|
double yachtSpace = numYachtsInLine * YACHT_SEPARATION / 2;
|
||||||
|
|
||||||
|
GeoPoint firstYachtPoint = GeoUtility.getGeoCoordinate(
|
||||||
|
startingPoint, startMarkToMarkAngle + 180, yachtSpace
|
||||||
|
);
|
||||||
|
|
||||||
|
for (int i=0; i<numYachtsInLine; i++){
|
||||||
|
randomisedYachts.get(0).setHeading(angleFromStart);
|
||||||
|
randomisedYachts.get(0).setLocation(firstYachtPoint);
|
||||||
|
firstYachtPoint = GeoUtility.getGeoCoordinate(
|
||||||
|
firstYachtPoint, startMarkToMarkAngle, yachtSpace
|
||||||
|
);
|
||||||
|
randomisedYachts.remove(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
GeoPoint spawnMark = GeoUtility
|
startingPoint = GeoUtility.getGeoCoordinate(
|
||||||
.getGeoCoordinate(midpoint, perpendicularAngle, distanceApart * DISTANCE_FACTOR);
|
startingPoint, angleToStart, DISTANCE_TO_START
|
||||||
|
);
|
||||||
if (yacht.getHeading() < perpendicularAngle) {
|
|
||||||
spawnMark = GeoUtility
|
|
||||||
.getGeoCoordinate(spawnMark, perpendicularAngle + 90, DISTANCE_FACTOR);
|
|
||||||
} else {
|
|
||||||
spawnMark = GeoUtility
|
|
||||||
.getGeoCoordinate(spawnMark, perpendicularAngle + 270, DISTANCE_FACTOR);
|
|
||||||
}
|
|
||||||
|
|
||||||
yacht.setLocation(spawnMark);
|
|
||||||
boatIndex++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,8 @@ import seng302.model.Player;
|
|||||||
import seng302.model.ServerYacht;
|
import seng302.model.ServerYacht;
|
||||||
import seng302.model.stream.xml.generator.RaceXMLTemplate;
|
import seng302.model.stream.xml.generator.RaceXMLTemplate;
|
||||||
import seng302.model.stream.xml.generator.RegattaXMLTemplate;
|
import seng302.model.stream.xml.generator.RegattaXMLTemplate;
|
||||||
|
import seng302.model.stream.xml.parser.RaceXMLData;
|
||||||
|
import seng302.model.stream.xml.parser.RegattaXMLData;
|
||||||
import seng302.model.token.Token;
|
import seng302.model.token.Token;
|
||||||
import seng302.utilities.XMLGenerator;
|
import seng302.utilities.XMLGenerator;
|
||||||
|
|
||||||
@@ -35,6 +37,51 @@ Ideally this class would be created with an instance of the GameState (I tried i
|
|||||||
public class MessageFactory {
|
public class MessageFactory {
|
||||||
|
|
||||||
private static XMLGenerator xmlGenerator = new XMLGenerator();
|
private static XMLGenerator xmlGenerator = new XMLGenerator();
|
||||||
|
private static XMLMessage race;
|
||||||
|
private static XMLMessage regatta;
|
||||||
|
private static XMLMessage boats;
|
||||||
|
|
||||||
|
public static void updateXMLGenerator(RaceXMLData race, RegattaXMLData regatta) {
|
||||||
|
xmlGenerator.setRegattaTemplate(
|
||||||
|
new RegattaXMLTemplate(
|
||||||
|
regatta.getRegattaName(),
|
||||||
|
regatta.getCourseName(),
|
||||||
|
regatta.getCentralLat(),
|
||||||
|
regatta.getCentralLng()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
xmlGenerator.setRaceTemplate(
|
||||||
|
new RaceXMLTemplate(
|
||||||
|
new ArrayList<>(),
|
||||||
|
new ArrayList<>(),
|
||||||
|
race.getMarkSequence(),
|
||||||
|
race.getCourseLimit(),
|
||||||
|
new ArrayList<>(race.getCompoundMarks().values()),
|
||||||
|
GameState.getCapacity(), true
|
||||||
|
)
|
||||||
|
);
|
||||||
|
String xmlStr = xmlGenerator.getRaceAsXml();
|
||||||
|
MessageFactory.race = new XMLMessage(xmlStr, XMLMessageSubType.RACE, xmlStr.length());
|
||||||
|
xmlStr = xmlGenerator.getRegattaAsXml();
|
||||||
|
MessageFactory.regatta = new XMLMessage(xmlStr, XMLMessageSubType.REGATTA, xmlStr.length());
|
||||||
|
xmlStr = xmlGenerator.getBoatsAsXml();
|
||||||
|
MessageFactory.boats = new XMLMessage(xmlStr, XMLMessageSubType.BOAT, xmlStr.length());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void updateBoats(List<ServerYacht> yachts) {
|
||||||
|
for (ServerYacht serverYacht : yachts) {
|
||||||
|
System.out.println(serverYacht);
|
||||||
|
}
|
||||||
|
xmlGenerator.getRace().setBoats(yachts);
|
||||||
|
String xmlStr = xmlGenerator.getBoatsAsXml();
|
||||||
|
MessageFactory.boats = new XMLMessage(xmlStr, XMLMessageSubType.BOAT, xmlStr.length());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void updateTokens(List<Token> tokens) {
|
||||||
|
xmlGenerator.getRace().setTokens(tokens);
|
||||||
|
String xmlStr = xmlGenerator.getRaceAsXml();
|
||||||
|
MessageFactory.race = new XMLMessage(xmlStr, XMLMessageSubType.RACE, xmlStr.length());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public static RaceStartStatusMessage getRaceStartStatusMessage() {
|
public static RaceStartStatusMessage getRaceStartStatusMessage() {
|
||||||
@@ -95,37 +142,14 @@ public class MessageFactory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static XMLMessage getRaceXML() {
|
public static XMLMessage getRaceXML() {
|
||||||
List<ServerYacht> yachts = new ArrayList<>(GameState.getYachts().values());
|
return race;
|
||||||
List<Token> tokens = GameState.getTokensInPlay();
|
|
||||||
RaceXMLTemplate raceXMLTemplate = new RaceXMLTemplate(yachts, tokens);
|
|
||||||
xmlGenerator.setRaceTemplate(raceXMLTemplate);
|
|
||||||
|
|
||||||
XMLMessage raceXMLMessage = new XMLMessage(
|
|
||||||
xmlGenerator.getRaceAsXml(),
|
|
||||||
XMLMessageSubType.RACE,
|
|
||||||
xmlGenerator.getRaceAsXml().length());
|
|
||||||
|
|
||||||
return raceXMLMessage;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static XMLMessage getRegattaXML() {
|
public static XMLMessage getRegattaXML() {
|
||||||
//@TODO calculate lat/lng values
|
return regatta;
|
||||||
|
|
||||||
return new XMLMessage(
|
|
||||||
xmlGenerator.getRegattaAsXml(),
|
|
||||||
XMLMessageSubType.REGATTA,
|
|
||||||
xmlGenerator.getRegattaAsXml().length());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static XMLMessage getBoatXML() {
|
public static XMLMessage getBoatXML() {
|
||||||
List<ServerYacht> yachts = new ArrayList<>(GameState.getYachts().values());
|
return boats;
|
||||||
List<Token> tokens = GameState.getTokensInPlay();
|
|
||||||
RaceXMLTemplate raceXMLTemplate = new RaceXMLTemplate(yachts, tokens);
|
|
||||||
xmlGenerator.setRaceTemplate(raceXMLTemplate);
|
|
||||||
|
|
||||||
return new XMLMessage(
|
|
||||||
xmlGenerator.getBoatsAsXml(),
|
|
||||||
XMLMessageSubType.BOAT,
|
|
||||||
xmlGenerator.getBoatsAsXml().length());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,23 +1,21 @@
|
|||||||
package seng302.gameServer;
|
package seng302.gameServer;
|
||||||
|
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.InputStreamReader;
|
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
import java.net.SocketException;
|
import java.net.SocketException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.ThreadLocalRandom;
|
|
||||||
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 javafx.beans.property.SimpleObjectProperty;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.w3c.dom.Document;
|
||||||
import seng302.gameServer.messages.BoatAction;
|
import seng302.gameServer.messages.BoatAction;
|
||||||
import seng302.gameServer.messages.ChatterMessage;
|
import seng302.gameServer.messages.ChatterMessage;
|
||||||
import seng302.gameServer.messages.ClientType;
|
import seng302.gameServer.messages.ClientType;
|
||||||
@@ -25,14 +23,16 @@ import seng302.gameServer.messages.CustomizeRequestType;
|
|||||||
import seng302.gameServer.messages.Message;
|
import seng302.gameServer.messages.Message;
|
||||||
import seng302.gameServer.messages.RegistrationResponseMessage;
|
import seng302.gameServer.messages.RegistrationResponseMessage;
|
||||||
import seng302.gameServer.messages.RegistrationResponseStatus;
|
import seng302.gameServer.messages.RegistrationResponseStatus;
|
||||||
import seng302.gameServer.messages.XMLMessage;
|
|
||||||
import seng302.gameServer.messages.XMLMessageSubType;
|
|
||||||
import seng302.model.Player;
|
import seng302.model.Player;
|
||||||
import seng302.model.ServerYacht;
|
import seng302.model.ServerYacht;
|
||||||
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.xml.generator.RaceXMLTemplate;
|
import seng302.model.stream.xml.parser.RaceXMLData;
|
||||||
|
import seng302.model.stream.xml.parser.RegattaXMLData;
|
||||||
|
import seng302.utilities.StreamParser;
|
||||||
import seng302.utilities.XMLGenerator;
|
import seng302.utilities.XMLGenerator;
|
||||||
|
import seng302.visualiser.fxObjects.assets_3D.BoatMeshType;
|
||||||
|
import seng302.utilities.XMLParser;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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
|
||||||
@@ -80,6 +80,9 @@ public class ServerToClientThread implements Runnable {
|
|||||||
private ServerYacht yacht;
|
private ServerYacht yacht;
|
||||||
private Player player;
|
private Player player;
|
||||||
|
|
||||||
|
private SimpleObjectProperty<RaceXMLData> raceXMLProperty = new SimpleObjectProperty<>();
|
||||||
|
private SimpleObjectProperty<RegattaXMLData> regattaXMLProperty = new SimpleObjectProperty<>();
|
||||||
|
|
||||||
public ServerToClientThread(Socket socket) {
|
public ServerToClientThread(Socket socket) {
|
||||||
this.socket = socket;
|
this.socket = socket;
|
||||||
seqNo = 0;
|
seqNo = 0;
|
||||||
@@ -100,37 +103,16 @@ public class ServerToClientThread implements Runnable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void setUpPlayer(){
|
private void setUpPlayer(){
|
||||||
BufferedReader fn;
|
String fName = "Player" + GameState.getNumberOfPlayers().toString();
|
||||||
String fName = "";
|
|
||||||
BufferedReader ln;
|
|
||||||
String lName = "";
|
String lName = "";
|
||||||
|
|
||||||
fn = new BufferedReader(
|
|
||||||
new InputStreamReader(
|
|
||||||
ServerToClientThread.class.getResourceAsStream(
|
|
||||||
"/server_config/CSV_Database_of_First_Names.csv"
|
|
||||||
)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
List<String> all = fn.lines().collect(Collectors.toList());
|
|
||||||
fName = all.get(ThreadLocalRandom.current().nextInt(0, all.size()));
|
|
||||||
ln = new BufferedReader(
|
|
||||||
new InputStreamReader(
|
|
||||||
ServerToClientThread.class.getResourceAsStream(
|
|
||||||
"/server_config/CSV_Database_of_Last_Names.csv"
|
|
||||||
)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
all = ln.lines().collect(Collectors.toList());
|
|
||||||
lName = all.get(ThreadLocalRandom.current().nextInt(0, all.size()));
|
|
||||||
|
|
||||||
ServerYacht yacht = new ServerYacht(
|
ServerYacht yacht = new ServerYacht(
|
||||||
"Yacht", sourceId, sourceId.toString(), fName, fName + " " + lName, "NZ"
|
BoatMeshType.DINGHY, sourceId, sourceId.toString(), fName, fName + " " + lName, "NZ"
|
||||||
);
|
);
|
||||||
|
System.out.println(yacht);
|
||||||
player = new Player(socket, yacht);
|
player = new Player(socket, yacht);
|
||||||
GameState.addYacht(sourceId, yacht);
|
GameState.addYacht(sourceId, yacht);
|
||||||
GameState.addPlayer(player);
|
GameState.addPlayer(player);
|
||||||
|
System.out.println(GameState.getYachts().size());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void completeRegistration(ClientType clientType) throws IOException {
|
private void completeRegistration(ClientType clientType) throws IOException {
|
||||||
@@ -154,8 +136,9 @@ public class ServerToClientThread implements Runnable {
|
|||||||
this.sourceId = sourceId;
|
this.sourceId = sourceId;
|
||||||
isRegistered = true;
|
isRegistered = true;
|
||||||
os.write(responseMessage.getBuffer());
|
os.write(responseMessage.getBuffer());
|
||||||
|
System.out.println("MAKING A PLAYER");
|
||||||
setUpPlayer();
|
setUpPlayer();
|
||||||
|
System.out.println("DONE MAKING A PLAYER");
|
||||||
|
|
||||||
for (ConnectionListener listener : connectionListeners) {
|
for (ConnectionListener listener : connectionListeners) {
|
||||||
listener.notifyConnection();
|
listener.notifyConnection();
|
||||||
@@ -185,37 +168,51 @@ public class ServerToClientThread implements Runnable {
|
|||||||
long computedCrc = checksum.getValue();
|
long computedCrc = checksum.getValue();
|
||||||
long packetCrc = Message.bytesToLong(getBytes(4));
|
long packetCrc = Message.bytesToLong(getBytes(4));
|
||||||
if (computedCrc == packetCrc) {
|
if (computedCrc == packetCrc) {
|
||||||
|
StreamPacket packet = new StreamPacket(type, payloadLength, timeStamp, payload);
|
||||||
switch (PacketType.assignPacketType(type, payload)) {
|
switch (PacketType.assignPacketType(type, payload)) {
|
||||||
case BOAT_ACTION:
|
case BOAT_ACTION:
|
||||||
BoatAction actionType = ServerPacketParser
|
BoatAction actionType = ServerPacketParser.extractBoatAction(packet);
|
||||||
.extractBoatAction(
|
|
||||||
new StreamPacket(type, payloadLength, timeStamp, payload));
|
|
||||||
GameState.updateBoat(sourceId, actionType);
|
GameState.updateBoat(sourceId, actionType);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case RACE_REGISTRATION_REQUEST:
|
case RACE_REGISTRATION_REQUEST:
|
||||||
ClientType requestedType = ServerPacketParser.extractClientType(
|
ClientType requestedType = ServerPacketParser
|
||||||
new StreamPacket(type, payloadLength, timeStamp, payload));
|
.extractClientType(packet);
|
||||||
|
|
||||||
completeRegistration(requestedType);
|
completeRegistration(requestedType);
|
||||||
break;
|
break;
|
||||||
case CHATTER_TEXT:
|
case CHATTER_TEXT:
|
||||||
ChatterMessage chatterMessage = ServerPacketParser
|
ChatterMessage chatterMessage = ServerPacketParser
|
||||||
.extractChatterText(
|
.extractChatterText(packet);
|
||||||
new StreamPacket(type, payloadLength, timeStamp, payload));
|
|
||||||
GameState.processChatter(chatterMessage, isHost);
|
GameState.processChatter(chatterMessage, isHost);
|
||||||
break;
|
break;
|
||||||
case RACE_CUSTOMIZATION_REQUEST:
|
case RACE_CUSTOMIZATION_REQUEST:
|
||||||
Long sourceID = Message
|
Long sourceID = Message.bytesToLong(
|
||||||
.bytesToLong(Arrays.copyOfRange(payload, 0, 3));
|
Arrays.copyOfRange(payload, 0, 3)
|
||||||
|
);
|
||||||
CustomizeRequestType requestType = ServerPacketParser
|
CustomizeRequestType requestType = ServerPacketParser
|
||||||
.extractCustomizationType(
|
.extractCustomizationType(packet);
|
||||||
new StreamPacket(type, payloadLength, timeStamp, payload));
|
|
||||||
GameState.customizePlayer(sourceID, requestType,
|
GameState.customizePlayer(sourceID, requestType,
|
||||||
Arrays.copyOfRange(payload, 6, payload.length));
|
Arrays.copyOfRange(payload, 6, payload.length)
|
||||||
|
);
|
||||||
GameState.setCustomizationFlag();
|
GameState.setCustomizationFlag();
|
||||||
// TODO: 17/08/2017 ajm412: Send a response packet here, not really necessary until we do shapes.
|
// TODO: 17/08/2017 ajm412: Send a response packet here, not really necessary until we do shapes.
|
||||||
break;
|
break;
|
||||||
|
case RACE_XML:
|
||||||
|
Document document = StreamParser.extractXmlMessage(packet);
|
||||||
|
raceXMLProperty.set(
|
||||||
|
XMLParser.parseRace(document)
|
||||||
|
);
|
||||||
|
GameState.setMaxPlayers(XMLParser.getMaxPlayers(document));
|
||||||
|
break;
|
||||||
|
case REGATTA_XML:
|
||||||
|
regattaXMLProperty.set(
|
||||||
|
XMLParser.parseRegatta(
|
||||||
|
StreamParser.extractXmlMessage(packet)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
logger.warn("Packet has been dropped", 1);
|
logger.warn("Packet has been dropped", 1);
|
||||||
@@ -232,23 +229,9 @@ public class ServerToClientThread implements Runnable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void sendSetupMessages() {
|
public void sendSetupMessages() {
|
||||||
xmlGenerator = new XMLGenerator();
|
sendMessage(MessageFactory.getRegattaXML());
|
||||||
RaceXMLTemplate race = new RaceXMLTemplate(new ArrayList<>(GameState.getYachts().values()), new ArrayList<>());
|
sendMessage(MessageFactory.getBoatXML());
|
||||||
|
sendMessage(MessageFactory.getRaceXML());
|
||||||
xmlGenerator.setRaceTemplate(race);
|
|
||||||
|
|
||||||
XMLMessage xmlMessage;
|
|
||||||
xmlMessage = new XMLMessage(xmlGenerator.getRegattaAsXml(), XMLMessageSubType.REGATTA,
|
|
||||||
xmlGenerator.getRegattaAsXml().length());
|
|
||||||
sendMessage(xmlMessage);
|
|
||||||
|
|
||||||
xmlMessage = new XMLMessage(xmlGenerator.getBoatsAsXml(), XMLMessageSubType.BOAT,
|
|
||||||
xmlGenerator.getBoatsAsXml().length());
|
|
||||||
sendMessage(xmlMessage);
|
|
||||||
|
|
||||||
xmlMessage = new XMLMessage(xmlGenerator.getRaceAsXml(), XMLMessageSubType.RACE,
|
|
||||||
xmlGenerator.getRaceAsXml().length());
|
|
||||||
sendMessage(xmlMessage);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void closeSocket() {
|
private void closeSocket() {
|
||||||
@@ -344,4 +327,12 @@ public class ServerToClientThread implements Runnable {
|
|||||||
public void setAsHost() {
|
public void setAsHost() {
|
||||||
isHost = true;
|
isHost = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public SimpleObjectProperty<RaceXMLData> raceXMLProperty() {
|
||||||
|
return raceXMLProperty;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SimpleObjectProperty<RegattaXMLData> regattaXMLProperty() {
|
||||||
|
return regattaXMLProperty;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,7 +14,9 @@ public enum BoatAction {
|
|||||||
TACK_GYBE(4),
|
TACK_GYBE(4),
|
||||||
UPWIND(5),
|
UPWIND(5),
|
||||||
DOWNWIND(6),
|
DOWNWIND(6),
|
||||||
MAINTAIN_HEADING(7);
|
MAINTAIN_HEADING(7),
|
||||||
|
CONTINUOUSLY_TURNING(8),
|
||||||
|
DEFAULT_TURNING(9);
|
||||||
|
|
||||||
private final int type;
|
private final int type;
|
||||||
private static final Map<Integer, BoatAction> intToTypeMap = new HashMap<>();
|
private static final Map<Integer, BoatAction> intToTypeMap = new HashMap<>();
|
||||||
|
|||||||
@@ -5,19 +5,19 @@ package seng302.gameServer.messages;
|
|||||||
*/
|
*/
|
||||||
public class BoatActionMessage extends Message{
|
public class BoatActionMessage extends Message{
|
||||||
private final MessageType MESSAGE_TYPE = MessageType.BOAT_ACTION;
|
private final MessageType MESSAGE_TYPE = MessageType.BOAT_ACTION;
|
||||||
private final int MESSAGE_SIZE = 1;
|
private final int MESSAGE_SIZE = 5;
|
||||||
private BoatAction actionType;
|
private BoatAction actionType;
|
||||||
|
|
||||||
public BoatActionMessage(BoatAction actionType) {
|
public BoatActionMessage(BoatAction actionType, int sourceId) {
|
||||||
this.actionType = actionType;
|
this.actionType = actionType;
|
||||||
setHeader(new Header(MessageType.BOAT_ACTION, 0, (short) 1)); // the second variable is the source id
|
setHeader(new Header(MessageType.BOAT_ACTION, sourceId, (short) MESSAGE_SIZE)); // the second variable is the source id
|
||||||
allocateBuffer();
|
allocateBuffer();
|
||||||
writeHeaderToBuffer();
|
writeHeaderToBuffer();
|
||||||
// Write message fields
|
// Write message fields
|
||||||
putInt(actionType.getValue(), 1);
|
putInt(actionType.getValue(), 1);
|
||||||
|
putInt(sourceId, 4);
|
||||||
writeCRC();
|
writeCRC();
|
||||||
rewind();
|
rewind();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -4,8 +4,8 @@ package seng302.gameServer.messages;
|
|||||||
public class RegistrationRequestMessage extends Message {
|
public class RegistrationRequestMessage extends Message {
|
||||||
private static int MESSAGE_LENGTH = 2;
|
private static int MESSAGE_LENGTH = 2;
|
||||||
|
|
||||||
public RegistrationRequestMessage(ClientType type){
|
public RegistrationRequestMessage(ClientType type, int clientID){
|
||||||
setHeader(new Header(MessageType.REGISTRATION_REQUEST, 1, (short) getSize()));
|
setHeader(new Header(MessageType.REGISTRATION_REQUEST, clientID, (short) getSize()));
|
||||||
|
|
||||||
allocateBuffer();
|
allocateBuffer();
|
||||||
writeHeaderToBuffer();
|
writeHeaderToBuffer();
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import java.util.ArrayList;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Observable;
|
import java.util.Observable;
|
||||||
import java.util.Observer;
|
import java.util.Observer;
|
||||||
|
import java.util.Timer;
|
||||||
import javafx.beans.property.ReadOnlyDoubleProperty;
|
import javafx.beans.property.ReadOnlyDoubleProperty;
|
||||||
import javafx.beans.property.ReadOnlyDoubleWrapper;
|
import javafx.beans.property.ReadOnlyDoubleWrapper;
|
||||||
import javafx.beans.property.ReadOnlyIntegerProperty;
|
import javafx.beans.property.ReadOnlyIntegerProperty;
|
||||||
@@ -15,6 +16,8 @@ import javafx.beans.property.ReadOnlyLongWrapper;
|
|||||||
import javafx.scene.paint.Color;
|
import javafx.scene.paint.Color;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
import seng302.visualiser.fxObjects.assets_3D.BoatMeshType;
|
||||||
|
import seng302.visualiser.fxObjects.assets_3D.BoatObject;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Yacht class for the racing boat. <p> Class created to store more variables (eg. boat statuses)
|
* Yacht class for the racing boat. <p> Class created to store more variables (eg. boat statuses)
|
||||||
@@ -37,7 +40,7 @@ public class ClientYacht extends Observable {
|
|||||||
private Logger logger = LoggerFactory.getLogger(ClientYacht.class);
|
private Logger logger = LoggerFactory.getLogger(ClientYacht.class);
|
||||||
|
|
||||||
|
|
||||||
private String boatType;
|
private BoatMeshType boatType;
|
||||||
private Integer sourceId;
|
private Integer sourceId;
|
||||||
private String hullID; //matches HullNum in the XML spec.
|
private String hullID; //matches HullNum in the XML spec.
|
||||||
private String shortName;
|
private String shortName;
|
||||||
@@ -46,7 +49,7 @@ public class ClientYacht extends Observable {
|
|||||||
private Integer position;
|
private Integer position;
|
||||||
|
|
||||||
private Long estimateTimeAtFinish;
|
private Long estimateTimeAtFinish;
|
||||||
private Boolean sailIn = false;
|
private Boolean sailIn = true;
|
||||||
private Integer currentMarkSeqID = 0;
|
private Integer currentMarkSeqID = 0;
|
||||||
private Long markRoundTime;
|
private Long markRoundTime;
|
||||||
private Long timeTillNext;
|
private Long timeTillNext;
|
||||||
@@ -56,15 +59,20 @@ public class ClientYacht extends Observable {
|
|||||||
private Integer boatStatus;
|
private Integer boatStatus;
|
||||||
private Double currentVelocity;
|
private Double currentVelocity;
|
||||||
|
|
||||||
|
Timer t;
|
||||||
|
|
||||||
|
private BoatObject boatObject;
|
||||||
|
|
||||||
private List<YachtLocationListener> locationListeners = new ArrayList<>();
|
private List<YachtLocationListener> locationListeners = new ArrayList<>();
|
||||||
private List<MarkRoundingListener> markRoundingListeners = new ArrayList<>();
|
private List<MarkRoundingListener> markRoundingListeners = new ArrayList<>();
|
||||||
private ReadOnlyDoubleWrapper velocityProperty = new ReadOnlyDoubleWrapper();
|
private ReadOnlyDoubleWrapper velocityProperty = new ReadOnlyDoubleWrapper();
|
||||||
private ReadOnlyLongWrapper timeTillNextProperty = new ReadOnlyLongWrapper();
|
private ReadOnlyLongWrapper timeTillNextProperty = new ReadOnlyLongWrapper();
|
||||||
private ReadOnlyLongWrapper timeSinceLastMarkProperty = new ReadOnlyLongWrapper();
|
private ReadOnlyLongWrapper timeSinceLastMarkProperty = new ReadOnlyLongWrapper();
|
||||||
private ReadOnlyIntegerWrapper placingProperty = new ReadOnlyIntegerWrapper();
|
private ReadOnlyIntegerWrapper placingProperty = new ReadOnlyIntegerWrapper();
|
||||||
|
private ReadOnlyDoubleWrapper headingProperty = new ReadOnlyDoubleWrapper();
|
||||||
private Color colour;
|
private Color colour;
|
||||||
|
|
||||||
public ClientYacht(String boatType, Integer sourceId, String hullID, String shortName,
|
public ClientYacht(BoatMeshType boatType, Integer sourceId, String hullID, String shortName,
|
||||||
String boatName, String country) {
|
String boatName, String country) {
|
||||||
this.boatType = boatType;
|
this.boatType = boatType;
|
||||||
this.sourceId = sourceId;
|
this.sourceId = sourceId;
|
||||||
@@ -74,6 +82,7 @@ public class ClientYacht extends Observable {
|
|||||||
this.country = country;
|
this.country = country;
|
||||||
this.location = new GeoPoint(57.670341, 11.826856);
|
this.location = new GeoPoint(57.670341, 11.826856);
|
||||||
this.heading = 120.0; //In degrees
|
this.heading = 120.0; //In degrees
|
||||||
|
this.headingProperty.set(this.heading);
|
||||||
this.currentVelocity = 0d;
|
this.currentVelocity = 0d;
|
||||||
this.boatStatus = 1;
|
this.boatStatus = 1;
|
||||||
this.colour = Color.rgb(0, 0, 0, 1.0);
|
this.colour = Color.rgb(0, 0, 0, 1.0);
|
||||||
@@ -88,7 +97,7 @@ public class ClientYacht extends Observable {
|
|||||||
super.addObserver(o);
|
super.addObserver(o);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getBoatType() {
|
public BoatMeshType getBoatType() {
|
||||||
return boatType;
|
return boatType;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -221,6 +230,7 @@ public class ClientYacht extends Observable {
|
|||||||
|
|
||||||
public void setHeading(Double heading) {
|
public void setHeading(Double heading) {
|
||||||
this.heading = heading;
|
this.heading = heading;
|
||||||
|
setHeadingProperty();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -249,10 +259,10 @@ public class ClientYacht extends Observable {
|
|||||||
this.colour = colour;
|
this.colour = colour;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void updateLocation(double lat, double lng, double heading, double velocity) {
|
public void updateLocation(double lat, double lng, double heading, double velocity) {
|
||||||
setLocation(lat, lng);
|
setLocation(lat, lng);
|
||||||
this.heading = heading;
|
this.heading = heading;
|
||||||
|
setHeadingProperty();
|
||||||
this.currentVelocity = velocity;
|
this.currentVelocity = velocity;
|
||||||
updateVelocityProperty(velocity);
|
updateVelocityProperty(velocity);
|
||||||
for (YachtLocationListener yll : locationListeners) {
|
for (YachtLocationListener yll : locationListeners) {
|
||||||
@@ -260,6 +270,10 @@ public class ClientYacht extends Observable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void setHeadingProperty() {
|
||||||
|
headingProperty.set(heading);
|
||||||
|
}
|
||||||
|
|
||||||
public void addLocationListener(YachtLocationListener listener) {
|
public void addLocationListener(YachtLocationListener listener) {
|
||||||
locationListeners.add(listener);
|
locationListeners.add(listener);
|
||||||
}
|
}
|
||||||
@@ -288,4 +302,17 @@ public class ClientYacht extends Observable {
|
|||||||
public Double getCurrentVelocity() {
|
public Double getCurrentVelocity() {
|
||||||
return currentVelocity;
|
return currentVelocity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setBoatObject(BoatObject newBoatObject) {
|
||||||
|
this.boatObject = newBoatObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BoatObject getBoatObject() {
|
||||||
|
return this.boatObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ReadOnlyDoubleWrapper getHeadingProperty() {
|
||||||
|
return headingProperty;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,87 @@
|
|||||||
|
package seng302.model;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import javafx.scene.input.KeyCode;
|
||||||
|
|
||||||
|
public class GameKeyBind {
|
||||||
|
|
||||||
|
private static GameKeyBind instance;
|
||||||
|
private Map<KeyCode, KeyAction> keyToActionMap;
|
||||||
|
private Map<KeyAction, KeyCode> actionToKeyMap;
|
||||||
|
private Boolean continuouslyTurning;
|
||||||
|
|
||||||
|
|
||||||
|
private GameKeyBind() {
|
||||||
|
setToDefault();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setToDefault() {
|
||||||
|
actionToKeyMap = new HashMap<>();
|
||||||
|
keyToActionMap = new HashMap<>();
|
||||||
|
continuouslyTurning = false;
|
||||||
|
// default key bindings
|
||||||
|
ArrayList<KeyCode> keys = new ArrayList<>();
|
||||||
|
keys.add(KeyCode.Z);
|
||||||
|
keys.add(KeyCode.X);
|
||||||
|
keys.add(KeyCode.SPACE);
|
||||||
|
keys.add(KeyCode.SHIFT);
|
||||||
|
keys.add(KeyCode.ENTER);
|
||||||
|
keys.add(KeyCode.PAGE_UP);
|
||||||
|
keys.add(KeyCode.PAGE_DOWN);
|
||||||
|
keys.add(KeyCode.F1);
|
||||||
|
keys.add(KeyCode.D);
|
||||||
|
keys.add(KeyCode.A);
|
||||||
|
keys.add(KeyCode.W);
|
||||||
|
keys.add(KeyCode.S);
|
||||||
|
for (int i = 0; i < 12; i++) {
|
||||||
|
actionToKeyMap.put(KeyAction.getType(i + 1), keys.get(i));
|
||||||
|
keyToActionMap.put(keys.get(i), KeyAction.getType(i + 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static GameKeyBind getInstance() {
|
||||||
|
if (instance == null) {
|
||||||
|
instance = new GameKeyBind();
|
||||||
|
}
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public KeyCode getKeyCode(KeyAction keyAction) {
|
||||||
|
return instance.actionToKeyMap.get(keyAction);
|
||||||
|
}
|
||||||
|
|
||||||
|
public KeyAction getKeyAction(KeyCode keyCode) {
|
||||||
|
return instance.keyToActionMap.get(keyCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Binds a key to a key action
|
||||||
|
*
|
||||||
|
* @return true if successfully bind
|
||||||
|
*/
|
||||||
|
public boolean bindKeyToAction(KeyCode keyCode, KeyAction keyAction) {
|
||||||
|
if (instance.keyToActionMap.containsKey(keyCode)) {
|
||||||
|
// if the key has been bound to other action, return false
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
instance.keyToActionMap.put(keyCode, keyAction); // add key -> action
|
||||||
|
KeyCode oldKeyCode = instance.actionToKeyMap
|
||||||
|
.get(keyAction); // get old key for the action
|
||||||
|
instance.keyToActionMap.remove(oldKeyCode); // remove the old key -> action
|
||||||
|
instance.actionToKeyMap
|
||||||
|
.replace(keyAction, keyCode); // replace the old key by the newer one
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void toggleTurningMode() {
|
||||||
|
continuouslyTurning = !continuouslyTurning;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean isContinuouslyTurning() {
|
||||||
|
return continuouslyTurning;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
package seng302.model;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public enum KeyAction {
|
||||||
|
ZOOM_IN(1),
|
||||||
|
ZOOM_OUT(2),
|
||||||
|
VMG(3),
|
||||||
|
SAILS_STATE(4),
|
||||||
|
TACK_GYBE(5),
|
||||||
|
UPWIND(6),
|
||||||
|
DOWNWIND(7),
|
||||||
|
VIEW(8),
|
||||||
|
RIGHT(9),
|
||||||
|
LEFT(10),
|
||||||
|
FORWARD(11),
|
||||||
|
BACKWARD(12);
|
||||||
|
|
||||||
|
private final int type;
|
||||||
|
private static final Map<Integer, KeyAction> intToTypeMap = new HashMap<>();
|
||||||
|
|
||||||
|
static {
|
||||||
|
for (KeyAction type : KeyAction.values()) {
|
||||||
|
intToTypeMap.put(type.getValue(), type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
KeyAction(int type) {
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static KeyAction getType(int value) {
|
||||||
|
return intToTypeMap.get(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getValue() {
|
||||||
|
return this.type;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -15,4 +15,9 @@ public class Limit extends GeoPoint {
|
|||||||
public Integer getSeqID() {
|
public Integer getSeqID() {
|
||||||
return seqID;
|
return seqID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString(){
|
||||||
|
return "Limit = {seqID=" + seqID + ", lat=" + getLat() + ", lng=" + getLng() + "}";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,122 @@
|
|||||||
|
package seng302.model;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.List;
|
||||||
|
import javafx.geometry.Point2D;
|
||||||
|
import seng302.utilities.GeoUtility;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Contains information on a scaled lat lon point for use with mapping geographical elements to a 2d plane.
|
||||||
|
*/
|
||||||
|
public class ScaledPoint extends GeoPoint {
|
||||||
|
|
||||||
|
public enum ScaleDirection {
|
||||||
|
HORIZONTAL,
|
||||||
|
VERTICAL
|
||||||
|
}
|
||||||
|
|
||||||
|
private double x, y, scaleFactor;
|
||||||
|
private ScaleDirection scaleDirection;
|
||||||
|
|
||||||
|
private ScaledPoint(double lat, double lng, double x, double y, double scaleFactor, ScaleDirection direction) {
|
||||||
|
super(lat, lng);
|
||||||
|
this.x = x;
|
||||||
|
this.y = y;
|
||||||
|
this.scaleFactor = scaleFactor;
|
||||||
|
this.scaleDirection = direction;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getX() {
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getY() {
|
||||||
|
return y;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getScaleFactor() {
|
||||||
|
return scaleFactor;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ScaleDirection getScaleDirection() {
|
||||||
|
return scaleDirection;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Point2D findScaledXY(GeoPoint unscaled) {
|
||||||
|
return findScaledXY(unscaled.getLat(), unscaled.getLng());
|
||||||
|
}
|
||||||
|
|
||||||
|
public Point2D findScaledXY(double unscaledLat, double unscaledLon) {
|
||||||
|
double distanceFromReference;
|
||||||
|
double angleFromReference;
|
||||||
|
double xReference = this.getX();
|
||||||
|
double yReference = this.getY();
|
||||||
|
|
||||||
|
angleFromReference = GeoUtility.getBearingRad(
|
||||||
|
this, new GeoPoint(unscaledLat, unscaledLon)
|
||||||
|
);
|
||||||
|
distanceFromReference = GeoUtility.getDistance(
|
||||||
|
this, new GeoPoint(unscaledLat, unscaledLon)
|
||||||
|
);
|
||||||
|
if (angleFromReference >= 0 && angleFromReference <= Math.PI / 2) {
|
||||||
|
xReference += scaleFactor * Math.sin(angleFromReference) * distanceFromReference;
|
||||||
|
yReference -= scaleFactor * Math.cos(angleFromReference) * distanceFromReference;
|
||||||
|
} else if (angleFromReference >= 0) {
|
||||||
|
angleFromReference = angleFromReference - Math.PI / 2;
|
||||||
|
xReference += scaleFactor * Math.cos(angleFromReference) * distanceFromReference;
|
||||||
|
yReference += scaleFactor * Math.sin(angleFromReference) * distanceFromReference;
|
||||||
|
} else if (angleFromReference < 0 && angleFromReference >= -Math.PI / 2) {
|
||||||
|
angleFromReference = Math.abs(angleFromReference);
|
||||||
|
xReference -= scaleFactor * Math.sin(angleFromReference) * distanceFromReference;
|
||||||
|
yReference -= scaleFactor * Math.cos(angleFromReference) * distanceFromReference;
|
||||||
|
} else {
|
||||||
|
angleFromReference = Math.abs(angleFromReference) - Math.PI / 2;
|
||||||
|
xReference -= scaleFactor * Math.cos(angleFromReference) * distanceFromReference;
|
||||||
|
yReference += scaleFactor * Math.sin(angleFromReference) * distanceFromReference;
|
||||||
|
}
|
||||||
|
return new Point2D(xReference, yReference);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ScaledPoint makeScaledPoint(double width, double height,
|
||||||
|
List<? extends GeoPoint> points, boolean centered) {
|
||||||
|
|
||||||
|
double referencePointX, referencePointY, scaleFactor, lat, lng;
|
||||||
|
ScaleDirection scaleDirection;
|
||||||
|
points = new ArrayList<>(points);
|
||||||
|
points.sort(Comparator.comparingDouble(GeoPoint::getLat));
|
||||||
|
GeoPoint minLatPoint = points.get(0);
|
||||||
|
GeoPoint maxLatPoint = points.get(points.size() - 1);
|
||||||
|
|
||||||
|
points.sort(Comparator.comparingDouble(GeoPoint::getLng));
|
||||||
|
GeoPoint minLonPoint = points.get(0);
|
||||||
|
GeoPoint maxLonPoint = points.get(points.size() - 1);
|
||||||
|
|
||||||
|
referencePointX = centered ? 0 : width / 2;
|
||||||
|
referencePointY = centered ? 0 : height / 2;
|
||||||
|
|
||||||
|
lat = (maxLatPoint.getLat() - minLatPoint.getLat()) / 2 + minLatPoint.getLat();
|
||||||
|
lng = (maxLonPoint.getLng() - minLonPoint.getLng()) / 2 + minLonPoint.getLng();
|
||||||
|
|
||||||
|
GeoPoint ref = new GeoPoint(lat, lng);
|
||||||
|
|
||||||
|
double vertDistance = GeoUtility.getDistance(
|
||||||
|
ref, new GeoPoint(ref.getLat(), maxLonPoint.getLng())
|
||||||
|
) * 2.1;
|
||||||
|
|
||||||
|
double horiDistance = GeoUtility.getDistance(
|
||||||
|
ref, new GeoPoint(maxLatPoint.getLat(), ref.getLng())
|
||||||
|
) * 2.1;
|
||||||
|
|
||||||
|
double vertScale = height / vertDistance;
|
||||||
|
|
||||||
|
if (horiDistance * vertScale > width) {
|
||||||
|
scaleFactor = width / horiDistance;
|
||||||
|
scaleDirection = ScaleDirection.HORIZONTAL;
|
||||||
|
} else {
|
||||||
|
scaleFactor = vertScale;
|
||||||
|
scaleDirection = ScaleDirection.VERTICAL;
|
||||||
|
}
|
||||||
|
return new ScaledPoint(lat, lng, referencePointX, referencePointY, scaleFactor, scaleDirection);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
package seng302.model;
|
package seng302.model;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
import javafx.scene.paint.Color;
|
import javafx.scene.paint.Color;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
@@ -8,10 +9,7 @@ import seng302.gameServer.messages.BoatStatus;
|
|||||||
import seng302.model.mark.Mark;
|
import seng302.model.mark.Mark;
|
||||||
import seng302.model.token.TokenType;
|
import seng302.model.token.TokenType;
|
||||||
import seng302.utilities.GeoUtility;
|
import seng302.utilities.GeoUtility;
|
||||||
|
import seng302.visualiser.fxObjects.assets_3D.BoatMeshType;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Observable;
|
|
||||||
import java.util.Observer;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Yacht class for the racing boat. <p> Class created to store more variables (eg. boat statuses)
|
* Yacht class for the racing boat. <p> Class created to store more variables (eg. boat statuses)
|
||||||
@@ -20,12 +18,14 @@ import java.util.Observer;
|
|||||||
*/
|
*/
|
||||||
public class ServerYacht {
|
public class ServerYacht {
|
||||||
|
|
||||||
private Logger logger = LoggerFactory.getLogger(ClientYacht.class);
|
private Logger logger = LoggerFactory.getLogger(ServerYacht.class);
|
||||||
|
|
||||||
public static final Double TURN_STEP = 5.0;
|
|
||||||
|
|
||||||
//Boat info
|
//Boat info
|
||||||
private String boatType;
|
private BoatMeshType boatType;
|
||||||
|
private Double turnStep = 5.0;
|
||||||
|
private Double maxSpeedMultiplier = 1.0;
|
||||||
|
private Double turnStepMultiplier = 1.0;
|
||||||
|
private Double accelerationMultiplier = 1.0;
|
||||||
private Integer sourceId;
|
private Integer sourceId;
|
||||||
private String hullID; //matches HullNum in the XML spec.
|
private String hullID; //matches HullNum in the XML spec.
|
||||||
private String shortName;
|
private String shortName;
|
||||||
@@ -56,10 +56,12 @@ public class ServerYacht {
|
|||||||
private TokenType powerUp;
|
private TokenType powerUp;
|
||||||
private Long powerUpStartTime;
|
private Long powerUpStartTime;
|
||||||
|
|
||||||
|
//turning mode
|
||||||
|
private Boolean continuouslyTurning;
|
||||||
|
|
||||||
public ServerYacht(String boatType, Integer sourceId, String hullID, String shortName,
|
public ServerYacht(BoatMeshType boatType, Integer sourceId, String hullID, String shortName,
|
||||||
String boatName, String country) {
|
String boatName, String country) {
|
||||||
this.boatType = boatType;
|
setBoatType(boatType);
|
||||||
this.boatStatus = BoatStatus.PRESTART;
|
this.boatStatus = BoatStatus.PRESTART;
|
||||||
this.sourceId = sourceId;
|
this.sourceId = sourceId;
|
||||||
this.hullID = hullID;
|
this.hullID = hullID;
|
||||||
@@ -80,6 +82,8 @@ public class ServerYacht {
|
|||||||
this.hasEnteredRoundingZone = false;
|
this.hasEnteredRoundingZone = false;
|
||||||
this.hasPassedLine = false;
|
this.hasPassedLine = false;
|
||||||
this.hasPassedThroughGate = false;
|
this.hasPassedThroughGate = false;
|
||||||
|
|
||||||
|
this.continuouslyTurning = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -129,7 +133,7 @@ public class ServerYacht {
|
|||||||
* @param amount the amount by which to adjust the boat heading.
|
* @param amount the amount by which to adjust the boat heading.
|
||||||
*/
|
*/
|
||||||
public void adjustHeading(Double amount) {
|
public void adjustHeading(Double amount) {
|
||||||
Double newVal = heading + amount;
|
Double newVal = heading + (amount * turnStepMultiplier);
|
||||||
lastHeading = heading;
|
lastHeading = heading;
|
||||||
heading = (double) Math.floorMod(newVal.longValue(), 360L);
|
heading = (double) Math.floorMod(newVal.longValue(), 360L);
|
||||||
}
|
}
|
||||||
@@ -152,11 +156,11 @@ public class ServerYacht {
|
|||||||
/**
|
/**
|
||||||
* Enables the boats auto pilot feature, which will move the boat towards a given heading.
|
* Enables the boats auto pilot feature, which will move the boat towards a given heading.
|
||||||
*
|
*
|
||||||
* @param thisHeading The heading to move the boat towards.
|
* @param newHeading The heading to move the boat towards.
|
||||||
*/
|
*/
|
||||||
private void setAutoPilot(Double thisHeading) {
|
private void setAutoPilot(Double newHeading) {
|
||||||
isAuto = true;
|
isAuto = true;
|
||||||
autoHeading = thisHeading;
|
autoHeading = newHeading;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -174,8 +178,9 @@ public class ServerYacht {
|
|||||||
if (isAuto) {
|
if (isAuto) {
|
||||||
turnTowardsHeading(autoHeading);
|
turnTowardsHeading(autoHeading);
|
||||||
if (Math.abs(heading - autoHeading)
|
if (Math.abs(heading - autoHeading)
|
||||||
<= TURN_STEP) { //Cancel when within 1 turn step of target.
|
<= turnStep*1.5) {
|
||||||
isAuto = false;
|
isAuto = false;
|
||||||
|
setHeading(autoHeading);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -187,44 +192,52 @@ public class ServerYacht {
|
|||||||
public void turnUpwind() {
|
public void turnUpwind() {
|
||||||
disableAutoPilot();
|
disableAutoPilot();
|
||||||
Double normalizedHeading = normalizeHeading();
|
Double normalizedHeading = normalizeHeading();
|
||||||
if (normalizedHeading == 0) {
|
if (continuouslyTurning) {
|
||||||
if (lastHeading < 180) {
|
adjustHeading(turnStep);
|
||||||
adjustHeading(-TURN_STEP);
|
|
||||||
} else {
|
|
||||||
adjustHeading(TURN_STEP);
|
|
||||||
}
|
|
||||||
} else if (normalizedHeading == 180) {
|
|
||||||
if (lastHeading < 180) {
|
|
||||||
adjustHeading(TURN_STEP);
|
|
||||||
} else {
|
|
||||||
adjustHeading(-TURN_STEP);
|
|
||||||
}
|
|
||||||
} else if (normalizedHeading < 180) {
|
|
||||||
adjustHeading(-TURN_STEP);
|
|
||||||
} else {
|
} else {
|
||||||
adjustHeading(TURN_STEP);
|
if (normalizedHeading == 0) {
|
||||||
|
if (lastHeading < 180) {
|
||||||
|
adjustHeading(-turnStep);
|
||||||
|
} else {
|
||||||
|
adjustHeading(turnStep);
|
||||||
|
}
|
||||||
|
} else if (normalizedHeading == 180) {
|
||||||
|
if (lastHeading < 180) {
|
||||||
|
adjustHeading(turnStep);
|
||||||
|
} else {
|
||||||
|
adjustHeading(-turnStep);
|
||||||
|
}
|
||||||
|
} else if (normalizedHeading < 180) {
|
||||||
|
adjustHeading(-turnStep);
|
||||||
|
} else {
|
||||||
|
adjustHeading(turnStep);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void turnDownwind() {
|
public void turnDownwind() {
|
||||||
disableAutoPilot();
|
disableAutoPilot();
|
||||||
Double normalizedHeading = normalizeHeading();
|
Double normalizedHeading = normalizeHeading();
|
||||||
if (normalizedHeading == 0) {
|
if (continuouslyTurning) {
|
||||||
if (lastHeading < 180) {
|
adjustHeading(-turnStep);
|
||||||
adjustHeading(TURN_STEP);
|
|
||||||
} else {
|
|
||||||
adjustHeading(-TURN_STEP);
|
|
||||||
}
|
|
||||||
} else if (normalizedHeading == 180) {
|
|
||||||
if (lastHeading < 180) {
|
|
||||||
adjustHeading(-TURN_STEP);
|
|
||||||
} else {
|
|
||||||
adjustHeading(TURN_STEP);
|
|
||||||
}
|
|
||||||
} else if (normalizedHeading < 180) {
|
|
||||||
adjustHeading(TURN_STEP);
|
|
||||||
} else {
|
} else {
|
||||||
adjustHeading(-TURN_STEP);
|
if (normalizedHeading == 0) {
|
||||||
|
if (lastHeading < 180) {
|
||||||
|
adjustHeading(turnStep);
|
||||||
|
} else {
|
||||||
|
adjustHeading(-turnStep);
|
||||||
|
}
|
||||||
|
} else if (normalizedHeading == 180) {
|
||||||
|
if (lastHeading < 180) {
|
||||||
|
adjustHeading(-turnStep);
|
||||||
|
} else {
|
||||||
|
adjustHeading(turnStep);
|
||||||
|
}
|
||||||
|
} else if (normalizedHeading < 180) {
|
||||||
|
adjustHeading(turnStep);
|
||||||
|
} else {
|
||||||
|
adjustHeading(-turnStep);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -253,7 +266,7 @@ public class ServerYacht {
|
|||||||
|
|
||||||
// Take optimal heading and turn into a boat heading rather than a wind heading.
|
// Take optimal heading and turn into a boat heading rather than a wind heading.
|
||||||
optimalHeading =
|
optimalHeading =
|
||||||
optimalHeading + GameState.getWindDirection();
|
(optimalHeading + GameState.getWindDirection()) % 360;
|
||||||
|
|
||||||
setAutoPilot(optimalHeading);
|
setAutoPilot(optimalHeading);
|
||||||
}
|
}
|
||||||
@@ -268,9 +281,9 @@ public class ServerYacht {
|
|||||||
private void turnTowardsHeading(Double newHeading) {
|
private void turnTowardsHeading(Double newHeading) {
|
||||||
Double newVal = heading - newHeading;
|
Double newVal = heading - newHeading;
|
||||||
if (Math.floorMod(newVal.longValue(), 360L) > 180) {
|
if (Math.floorMod(newVal.longValue(), 360L) > 180) {
|
||||||
adjustHeading(TURN_STEP / 5);
|
adjustHeading(turnStep / 5);
|
||||||
} else {
|
} else {
|
||||||
adjustHeading(-TURN_STEP / 5);
|
adjustHeading(-turnStep / 5);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -421,4 +434,27 @@ public class ServerYacht {
|
|||||||
return boatColor;
|
return boatColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setBoatType(BoatMeshType boatType) {
|
||||||
|
this.accelerationMultiplier = boatType.accelerationMultiplier;
|
||||||
|
this.maxSpeedMultiplier = boatType.maxSpeedMultiplier;
|
||||||
|
this.turnStepMultiplier = boatType.turnStep;
|
||||||
|
this.boatType = boatType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Double getMaxSpeedMultiplier() {
|
||||||
|
return maxSpeedMultiplier;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Double getAccelerationMultiplier(){
|
||||||
|
return accelerationMultiplier;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public BoatMeshType getBoatType() {
|
||||||
|
return boatType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setContinuouslyTurning(Boolean continuouslyTurning) {
|
||||||
|
this.continuouslyTurning = continuouslyTurning;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package seng302.model.mark;
|
package seng302.model.mark;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import seng302.gameServer.messages.RoundingSide;
|
import seng302.gameServer.messages.RoundingSide;
|
||||||
import seng302.model.GeoPoint;
|
import seng302.model.GeoPoint;
|
||||||
@@ -10,13 +10,13 @@ public class CompoundMark {
|
|||||||
|
|
||||||
private int compoundMarkId;
|
private int compoundMarkId;
|
||||||
private String name;
|
private String name;
|
||||||
private List<Mark> marks = new ArrayList<>();
|
private List<Mark> marks;
|
||||||
private GeoPoint midPoint;
|
private GeoPoint midPoint;
|
||||||
|
|
||||||
public CompoundMark(int markID, String name, List<Mark> marks) {
|
public CompoundMark(int markID, String name, List<Mark> marks) {
|
||||||
this.compoundMarkId = markID;
|
this.compoundMarkId = markID;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.marks.addAll(marks);
|
this.marks = Collections.unmodifiableList(marks);
|
||||||
if (marks.size() > 1) {
|
if (marks.size() > 1) {
|
||||||
this.midPoint = GeoUtility.getDirtyMidPoint(marks.get(0), marks.get(1));
|
this.midPoint = GeoUtility.getDirtyMidPoint(marks.get(0), marks.get(1));
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -32,4 +32,10 @@ public class Corner {
|
|||||||
public Integer getZoneSize() {
|
public Integer getZoneSize() {
|
||||||
return zoneSize;
|
return zoneSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "Corner = {seqID=" + seqID + ", compoundMarkID=" + compoundMarkID + ", rounding="
|
||||||
|
+ rounding +", zoneSize=" + zoneSize + "}";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,23 +1,12 @@
|
|||||||
package seng302.model.mark;
|
package seng302.model.mark;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.util.ArrayList;
|
||||||
import java.io.StringReader;
|
import java.util.Collections;
|
||||||
import javax.xml.parsers.DocumentBuilder;
|
import java.util.List;
|
||||||
import javax.xml.parsers.DocumentBuilderFactory;
|
|
||||||
import javax.xml.parsers.ParserConfigurationException;
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.w3c.dom.Document;
|
|
||||||
import org.xml.sax.InputSource;
|
|
||||||
import org.xml.sax.SAXException;
|
|
||||||
import seng302.gameServer.messages.RoundingSide;
|
import seng302.gameServer.messages.RoundingSide;
|
||||||
import seng302.model.ServerYacht;
|
|
||||||
import seng302.model.stream.xml.generator.RaceXMLTemplate;
|
|
||||||
import seng302.model.stream.xml.parser.RaceXMLData;
|
import seng302.model.stream.xml.parser.RaceXMLData;
|
||||||
import seng302.model.token.Token;
|
|
||||||
import seng302.utilities.XMLGenerator;
|
|
||||||
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.
|
||||||
@@ -25,10 +14,17 @@ import java.util.*;
|
|||||||
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(){
|
|
||||||
loadRaceProperties();
|
public MarkOrder(RaceXMLData raceXMLData){
|
||||||
|
raceMarkOrder = new ArrayList<>();
|
||||||
|
for (Corner corner : raceXMLData.getMarkSequence()){
|
||||||
|
CompoundMark compoundMark = raceXMLData.getCompoundMarks().get(corner.getCompoundMarkID());
|
||||||
|
compoundMark.setRoundingSide(
|
||||||
|
RoundingSide.getRoundingSide(corner.getRounding())
|
||||||
|
);
|
||||||
|
raceMarkOrder.add(compoundMark);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -40,7 +36,6 @@ public class MarkOrder {
|
|||||||
logger.warn("Race order accessed but not instantiated");
|
logger.warn("Race order accessed but not instantiated");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Collections.unmodifiableList(raceMarkOrder);
|
return Collections.unmodifiableList(raceMarkOrder);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -74,70 +69,4 @@ public class MarkOrder {
|
|||||||
public CompoundMark getNextMark(Integer currentSeqID) throws IndexOutOfBoundsException {
|
public CompoundMark getNextMark(Integer currentSeqID) throws IndexOutOfBoundsException {
|
||||||
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
|
|
||||||
* @param xml An AC35 RaceXML
|
|
||||||
* @return An ordered list of marks in the race
|
|
||||||
*/
|
|
||||||
private List<CompoundMark> loadRaceOrderFromXML(String xml) {
|
|
||||||
|
|
||||||
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
|
|
||||||
DocumentBuilder db;
|
|
||||||
Document doc;
|
|
||||||
allMarks = new HashSet<>();
|
|
||||||
|
|
||||||
try {
|
|
||||||
db = dbf.newDocumentBuilder();
|
|
||||||
doc = db.parse(new InputSource(new StringReader(xml)));
|
|
||||||
} catch (ParserConfigurationException | IOException | SAXException e) {
|
|
||||||
logger.error("Failed to read generated race XML");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
RaceXMLData data = XMLParser.parseRace(doc);
|
|
||||||
|
|
||||||
if (data != null){
|
|
||||||
logger.debug("Loaded RaceXML for mark order");
|
|
||||||
List<Corner> corners = data.getMarkSequence();
|
|
||||||
Map<Integer, CompoundMark> marks = data.getCompoundMarks();
|
|
||||||
List<CompoundMark> course = new ArrayList<>();
|
|
||||||
for (Corner corner : corners){
|
|
||||||
CompoundMark compoundMark = marks.get(corner.getCompoundMarkID());
|
|
||||||
compoundMark.setRoundingSide(
|
|
||||||
RoundingSide.getRoundingSide(corner.getRounding())
|
|
||||||
);
|
|
||||||
course.add(compoundMark);
|
|
||||||
allMarks.addAll(compoundMark.getMarks());
|
|
||||||
}
|
|
||||||
|
|
||||||
return course;
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Load the raceXML and mark order
|
|
||||||
*/
|
|
||||||
private void loadRaceProperties(){
|
|
||||||
XMLGenerator generator = new XMLGenerator();
|
|
||||||
|
|
||||||
// TODO: 29/08/17 wmu16 - This is terrible, having to make a template just to receive constant data
|
|
||||||
generator.setRaceTemplate(new RaceXMLTemplate(
|
|
||||||
new ArrayList<>(),
|
|
||||||
new ArrayList<>()));
|
|
||||||
|
|
||||||
String raceXML = generator.getRaceAsXml();
|
|
||||||
|
|
||||||
if (raceXML == null){
|
|
||||||
logger.error("Failed to generate raceXML (for race properties)");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
raceMarkOrder = loadRaceOrderFromXML(raceXML);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -1,10 +1,12 @@
|
|||||||
package seng302.model.stream.xml.generator;
|
package seng302.model.stream.xml.generator;
|
||||||
|
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import seng302.model.Limit;
|
||||||
import seng302.model.ServerYacht;
|
import seng302.model.ServerYacht;
|
||||||
|
import seng302.model.mark.CompoundMark;
|
||||||
|
import seng302.model.mark.Corner;
|
||||||
import seng302.model.token.Token;
|
import seng302.model.token.Token;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -15,11 +17,22 @@ public class RaceXMLTemplate {
|
|||||||
private List<ServerYacht> yachts;
|
private List<ServerYacht> yachts;
|
||||||
private LocalDateTime startTime;
|
private LocalDateTime startTime;
|
||||||
private List<Token> tokens;
|
private List<Token> tokens;
|
||||||
|
private List<Corner> roundings;
|
||||||
|
private List<Limit> courseLimit;
|
||||||
|
private List<CompoundMark> course;
|
||||||
|
private Integer maxPlayers;
|
||||||
|
private Boolean tokensEnabled;
|
||||||
|
|
||||||
public RaceXMLTemplate(List<ServerYacht> yachts, List<Token> tokens) {
|
public RaceXMLTemplate(List<ServerYacht> yachts, List<Token> tokens, List<Corner> roundings,
|
||||||
|
List<Limit> limit, List<CompoundMark> course, Integer maxPlayers, Boolean tokensEnabled) {
|
||||||
this.yachts = yachts;
|
this.yachts = yachts;
|
||||||
this.tokens = tokens;
|
this.tokens = tokens;
|
||||||
|
this.roundings = roundings;
|
||||||
|
this.courseLimit = limit;
|
||||||
|
this.course = course;
|
||||||
startTime = LocalDateTime.now();
|
startTime = LocalDateTime.now();
|
||||||
|
this.maxPlayers = maxPlayers;
|
||||||
|
this.tokensEnabled = tokensEnabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -39,6 +52,18 @@ public class RaceXMLTemplate {
|
|||||||
return Collections.unmodifiableList(tokens);
|
return Collections.unmodifiableList(tokens);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<CompoundMark> getCompoundMarks() {
|
||||||
|
return Collections.unmodifiableList(course);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Limit> getCourseLimit() {
|
||||||
|
return Collections.unmodifiableList(courseLimit);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Corner> getRoundings() {
|
||||||
|
return Collections.unmodifiableList(roundings);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the time until the race starts
|
* Set the time until the race starts
|
||||||
* @param seconds The time in seconds until the race starts
|
* @param seconds The time in seconds until the race starts
|
||||||
@@ -54,4 +79,20 @@ public class RaceXMLTemplate {
|
|||||||
public String getRaceStartTime(){
|
public String getRaceStartTime(){
|
||||||
return startTime.toString();
|
return startTime.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setBoats(List<ServerYacht> boats) {
|
||||||
|
yachts = boats;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTokens(List<Token> tokens) {
|
||||||
|
this.tokens = tokens;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTokensEnabled() {
|
||||||
|
return tokensEnabled.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMaxPlayers() {
|
||||||
|
return maxPlayers.toString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,8 +14,10 @@ public class Sounds {
|
|||||||
private static MediaPlayer soundEffect;
|
private static MediaPlayer soundEffect;
|
||||||
private static MediaPlayer soundPlayer;
|
private static MediaPlayer soundPlayer;
|
||||||
private static MediaPlayer hoverSoundPlayer;
|
private static MediaPlayer hoverSoundPlayer;
|
||||||
|
private static MediaPlayer crashSoundPlayer;
|
||||||
|
|
||||||
private static boolean hoverInitialized = false;
|
private static boolean hoverInitialized = false;
|
||||||
|
private static boolean crashInitialized = false;
|
||||||
private static boolean musicMuted = false;
|
private static boolean musicMuted = false;
|
||||||
private static boolean soundEffectsMuted = false;
|
private static boolean soundEffectsMuted = false;
|
||||||
|
|
||||||
@@ -155,11 +157,17 @@ public class Sounds {
|
|||||||
|
|
||||||
public static void playCrashSound() {
|
public static void playCrashSound() {
|
||||||
if (!soundEffectsMuted) {
|
if (!soundEffectsMuted) {
|
||||||
Media crashSound = new Media(
|
if (!crashInitialized) {
|
||||||
Sounds.class.getClassLoader().getResource("sounds/Large-metal-door-slam.mp3")
|
Media pickupSound = new Media(
|
||||||
.toString());
|
Sounds.class.getClassLoader().getResource("sounds/Large-metal-door-slam.mp3")
|
||||||
soundPlayer = new MediaPlayer(crashSound);
|
.toString());
|
||||||
soundPlayer.play();
|
crashSoundPlayer = new MediaPlayer(pickupSound);
|
||||||
|
crashInitialized = true;
|
||||||
|
}
|
||||||
|
if (crashSoundPlayer != null) {
|
||||||
|
crashSoundPlayer.stop();
|
||||||
|
}
|
||||||
|
crashSoundPlayer.play();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -176,10 +184,10 @@ public class Sounds {
|
|||||||
public static void playHoverSound() {
|
public static void playHoverSound() {
|
||||||
if (!soundEffectsMuted) {
|
if (!soundEffectsMuted) {
|
||||||
if (!hoverInitialized) {
|
if (!hoverInitialized) {
|
||||||
Media crashSound = new Media(
|
Media hoverSound = new Media(
|
||||||
Sounds.class.getClassLoader().getResource("sounds/Error-sound-effect.mp3")
|
Sounds.class.getClassLoader().getResource("sounds/Error-sound-effect.mp3")
|
||||||
.toString());
|
.toString());
|
||||||
hoverSoundPlayer = new MediaPlayer(crashSound);
|
hoverSoundPlayer = new MediaPlayer(hoverSound);
|
||||||
hoverInitialized = true;
|
hoverInitialized = true;
|
||||||
}
|
}
|
||||||
hoverSoundPlayer.setVolume(0.5);
|
hoverSoundPlayer.setVolume(0.5);
|
||||||
|
|||||||
@@ -136,7 +136,7 @@ public class StreamParser {
|
|||||||
long messageLength = bytesToLong(Arrays.copyOfRange(payload, 12, 14));
|
long messageLength = bytesToLong(Arrays.copyOfRange(payload, 12, 14));
|
||||||
String xmlMessage = new String(
|
String xmlMessage = new String(
|
||||||
(Arrays.copyOfRange(payload, 14, (int) (14 + messageLength)))).trim();
|
(Arrays.copyOfRange(payload, 14, (int) (14 + messageLength)))).trim();
|
||||||
|
System.out.println(xmlMessage);
|
||||||
//Create XML document Object
|
//Create XML document Object
|
||||||
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
|
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
|
||||||
DocumentBuilder db;
|
DocumentBuilder db;
|
||||||
|
|||||||
@@ -179,4 +179,8 @@ public class XMLGenerator {
|
|||||||
public RegattaXMLTemplate getRegatta() {
|
public RegattaXMLTemplate getRegatta() {
|
||||||
return regatta;
|
return regatta;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public RaceXMLTemplate getRace() {
|
||||||
|
return race;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,29 +1,43 @@
|
|||||||
package seng302.utilities;
|
package seng302.utilities;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
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.Random;
|
||||||
import javafx.scene.paint.Color;
|
import javafx.scene.paint.Color;
|
||||||
|
import javafx.util.Pair;
|
||||||
|
import javax.xml.parsers.DocumentBuilder;
|
||||||
|
import javax.xml.parsers.DocumentBuilderFactory;
|
||||||
|
import javax.xml.parsers.ParserConfigurationException;
|
||||||
import org.w3c.dom.Document;
|
import org.w3c.dom.Document;
|
||||||
import org.w3c.dom.Element;
|
import org.w3c.dom.Element;
|
||||||
|
import org.w3c.dom.NamedNodeMap;
|
||||||
import org.w3c.dom.Node;
|
import org.w3c.dom.Node;
|
||||||
import org.w3c.dom.NodeList;
|
import org.w3c.dom.NodeList;
|
||||||
|
import org.xml.sax.SAXException;
|
||||||
import seng302.model.ClientYacht;
|
import seng302.model.ClientYacht;
|
||||||
|
import seng302.model.Colors;
|
||||||
import seng302.model.Limit;
|
import seng302.model.Limit;
|
||||||
import seng302.model.mark.CompoundMark;
|
import seng302.model.mark.CompoundMark;
|
||||||
import seng302.model.mark.Corner;
|
import seng302.model.mark.Corner;
|
||||||
import seng302.model.mark.Mark;
|
import seng302.model.mark.Mark;
|
||||||
|
import seng302.model.stream.xml.generator.RaceXMLTemplate;
|
||||||
|
import seng302.model.stream.xml.generator.RegattaXMLTemplate;
|
||||||
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.model.token.Token;
|
import seng302.model.token.Token;
|
||||||
import seng302.model.token.TokenType;
|
import seng302.model.token.TokenType;
|
||||||
|
import seng302.visualiser.fxObjects.assets_3D.BoatMeshType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Utilities for parsing XML documents
|
* Utilities for parsing XML documents
|
||||||
*/
|
*/
|
||||||
public class XMLParser {
|
public class XMLParser {
|
||||||
|
|
||||||
|
private static final int MAX_PLAYERS = 8;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the text content of a given child element tag, assuming it exists, as an Integer.
|
* Returns the text content of a given child element tag, assuming it exists, as an Integer.
|
||||||
*
|
*
|
||||||
@@ -34,7 +48,7 @@ public class XMLParser {
|
|||||||
private static Integer getElementInt(Element ele, String tag) {
|
private static Integer getElementInt(Element ele, String tag) {
|
||||||
NodeList tagList = ele.getElementsByTagName(tag);
|
NodeList tagList = ele.getElementsByTagName(tag);
|
||||||
if (tagList.getLength() > 0) {
|
if (tagList.getLength() > 0) {
|
||||||
return Integer.parseInt(tagList.item(0).getTextContent());
|
return Integer.parseInt(tagList.item(0).getTextContent().replaceAll("\\s+",""));
|
||||||
} else {
|
} else {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -66,7 +80,7 @@ public class XMLParser {
|
|||||||
private static Double getElementDouble(Element ele, String tag) {
|
private static Double getElementDouble(Element ele, String tag) {
|
||||||
NodeList tagList = ele.getElementsByTagName(tag);
|
NodeList tagList = ele.getElementsByTagName(tag);
|
||||||
if (tagList.getLength() > 0) {
|
if (tagList.getLength() > 0) {
|
||||||
return Double.parseDouble(tagList.item(0).getTextContent());
|
return Double.parseDouble(tagList.item(0).getTextContent().replaceAll("\\s+",""));
|
||||||
} else {
|
} else {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -138,17 +152,27 @@ public class XMLParser {
|
|||||||
Node currentBoat = boatsList.item(i);
|
Node currentBoat = boatsList.item(i);
|
||||||
if (currentBoat.getNodeName().equals("Boat")) {
|
if (currentBoat.getNodeName().equals("Boat")) {
|
||||||
// Boat boat = new Boat(currentBoat);
|
// Boat boat = new Boat(currentBoat);
|
||||||
|
BoatMeshType boatMeshType;
|
||||||
|
try {
|
||||||
|
boatMeshType = BoatMeshType.valueOf(XMLParser.getNodeAttributeString(currentBoat, "Type"));
|
||||||
|
} catch (IllegalArgumentException e){
|
||||||
|
boatMeshType = BoatMeshType.DINGHY;
|
||||||
|
}
|
||||||
|
Color color;
|
||||||
|
try {
|
||||||
|
color = Color.web(getNodeAttributeString(currentBoat, "Color"));
|
||||||
|
} catch (NullPointerException npe) {
|
||||||
|
color = Colors.getColor(new Random().nextInt(8));
|
||||||
|
}
|
||||||
ClientYacht yacht = new ClientYacht(
|
ClientYacht yacht = new ClientYacht(
|
||||||
XMLParser.getNodeAttributeString(currentBoat, "Type"),
|
boatMeshType,
|
||||||
XMLParser.getNodeAttributeInt(currentBoat, "SourceID"),
|
XMLParser.getNodeAttributeInt(currentBoat, "SourceID"),
|
||||||
XMLParser.getNodeAttributeString(currentBoat, "HullNum"),
|
XMLParser.getNodeAttributeString(currentBoat, "HullNum"),
|
||||||
XMLParser.getNodeAttributeString(currentBoat, "ShortName"),
|
XMLParser.getNodeAttributeString(currentBoat, "ShortName"),
|
||||||
XMLParser.getNodeAttributeString(currentBoat, "BoatName"),
|
XMLParser.getNodeAttributeString(currentBoat, "BoatName"),
|
||||||
XMLParser.getNodeAttributeString(currentBoat, "Country"));
|
XMLParser.getNodeAttributeString(currentBoat, "Country"));
|
||||||
yacht.setColour(Color.web(getNodeAttributeString(currentBoat, "Color")));
|
yacht.setColour(color);
|
||||||
if (yacht.getBoatType().equals("Yacht")) {
|
competingBoats.put(yacht.getSourceId(), yacht);
|
||||||
competingBoats.put(yacht.getSourceId(), yacht);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return competingBoats;
|
return competingBoats;
|
||||||
@@ -174,6 +198,31 @@ public class XMLParser {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Boolean tokensEnabled(Document doc) {
|
||||||
|
Element docEle = doc.getDocumentElement();
|
||||||
|
try {
|
||||||
|
Node tokenNode = docEle.getAttributeNode("Tokens");
|
||||||
|
return Boolean.valueOf(XMLParser.getNodeAttributeString(tokenNode, "Enabled"));
|
||||||
|
} catch (NullPointerException npe) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Integer getMaxPlayers(Document doc) {
|
||||||
|
Element docEle = doc.getDocumentElement();
|
||||||
|
try {
|
||||||
|
NamedNodeMap namedNodeMap = docEle.getElementsByTagName("Participants").item(0).getAttributes();
|
||||||
|
Node node = namedNodeMap.getNamedItem("MaxPlayers");
|
||||||
|
if (node != null) {
|
||||||
|
return Integer.parseInt(node.getNodeValue());
|
||||||
|
}
|
||||||
|
} catch (NullPointerException npe) {
|
||||||
|
npe.printStackTrace();
|
||||||
|
return MAX_PLAYERS;
|
||||||
|
}
|
||||||
|
return MAX_PLAYERS;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns an object containing the data extracted from the given xml formatted document
|
* Returns an object containing the data extracted from the given xml formatted document
|
||||||
*
|
*
|
||||||
@@ -183,7 +232,7 @@ public class XMLParser {
|
|||||||
public static RaceXMLData parseRace(Document doc) {
|
public static RaceXMLData parseRace(Document doc) {
|
||||||
Element docEle = doc.getDocumentElement();
|
Element docEle = doc.getDocumentElement();
|
||||||
return new RaceXMLData(
|
return new RaceXMLData(
|
||||||
extractParticpantIDs(docEle),
|
extractParticipantIDs(docEle),
|
||||||
extractTokens(docEle),
|
extractTokens(docEle),
|
||||||
extractCompoundMarks(docEle),
|
extractCompoundMarks(docEle),
|
||||||
extractMarkOrder(docEle),
|
extractMarkOrder(docEle),
|
||||||
@@ -196,17 +245,20 @@ public class XMLParser {
|
|||||||
*/
|
*/
|
||||||
private static List<Token> extractTokens(Element docEle) {
|
private static List<Token> extractTokens(Element docEle) {
|
||||||
List<Token> tokens = new ArrayList<>();
|
List<Token> tokens = new ArrayList<>();
|
||||||
NodeList tokenList = docEle.getElementsByTagName("Tokens").item(0).getChildNodes();
|
try {
|
||||||
for (int i = 0; i < tokenList.getLength(); i++) {
|
NodeList tokenList = docEle.getElementsByTagName("Tokens").item(0).getChildNodes();
|
||||||
Node tokenNode = tokenList.item(i);
|
for (int i = 0; i < tokenList.getLength(); i++) {
|
||||||
if (tokenNode.getNodeName().equals("Token")) {
|
Node tokenNode = tokenList.item(i);
|
||||||
String tokenType = getNodeAttributeString(tokenNode, "TokenType");
|
if (tokenNode.getNodeName().equals("Token")) {
|
||||||
Double lat = getNodeAttributeDouble(tokenNode, "TargetLat");
|
String tokenType = getNodeAttributeString(tokenNode, "TokenType");
|
||||||
Double lng = getNodeAttributeDouble(tokenNode, "TargetLng");
|
Double lat = getNodeAttributeDouble(tokenNode, "TargetLat");
|
||||||
tokens.add(new Token(TokenType.valueOf(tokenType), lat, lng));
|
Double lng = getNodeAttributeDouble(tokenNode, "TargetLng");
|
||||||
|
tokens.add(new Token(TokenType.valueOf(tokenType), lat, lng));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
} catch (NullPointerException npe) {
|
||||||
|
return new ArrayList<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
return tokens;
|
return tokens;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -219,13 +271,11 @@ public class XMLParser {
|
|||||||
for (int i = 0; i < limitList.getLength(); i++) {
|
for (int i = 0; i < limitList.getLength(); i++) {
|
||||||
Node limitNode = limitList.item(i);
|
Node limitNode = limitList.item(i);
|
||||||
if (limitNode.getNodeName().equals("Limit")) {
|
if (limitNode.getNodeName().equals("Limit")) {
|
||||||
courseLimit.add(
|
courseLimit.add(new Limit(
|
||||||
new Limit(
|
XMLParser.getNodeAttributeInt(limitNode, "SeqID"),
|
||||||
XMLParser.getNodeAttributeInt(limitNode, "SeqID"),
|
XMLParser.getNodeAttributeDouble(limitNode, "Lat"),
|
||||||
XMLParser.getNodeAttributeDouble(limitNode, "Lat"),
|
XMLParser.getNodeAttributeDouble(limitNode, "Lon")
|
||||||
XMLParser.getNodeAttributeDouble(limitNode, "Lon")
|
));
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return courseLimit;
|
return courseLimit;
|
||||||
@@ -257,7 +307,7 @@ public class XMLParser {
|
|||||||
/**
|
/**
|
||||||
* Extracts course participants data
|
* Extracts course participants data
|
||||||
*/
|
*/
|
||||||
private static List<Integer> extractParticpantIDs (Element docEle) {
|
private static List<Integer> extractParticipantIDs(Element docEle) {
|
||||||
List<Integer> boatIDs = new ArrayList<>();
|
List<Integer> boatIDs = new ArrayList<>();
|
||||||
NodeList pList = docEle.getElementsByTagName("Participants").item(0).getChildNodes();
|
NodeList pList = docEle.getElementsByTagName("Participants").item(0).getChildNodes();
|
||||||
for (int i = 0; i < pList.getLength(); i++) {
|
for (int i = 0; i < pList.getLength(); i++) {
|
||||||
@@ -279,10 +329,11 @@ public class XMLParser {
|
|||||||
for (int i = 0; i < cMarkList.getLength(); i++) {
|
for (int i = 0; i < cMarkList.getLength(); i++) {
|
||||||
Node cMarkNode = cMarkList.item(i);
|
Node cMarkNode = cMarkList.item(i);
|
||||||
if (cMarkNode.getNodeName().equals("CompoundMark")) {
|
if (cMarkNode.getNodeName().equals("CompoundMark")) {
|
||||||
|
String name = XMLParser.getNodeAttributeString(cMarkNode, "Name");
|
||||||
|
name = (name == null || name.equals("")) ? "Mark " + i+1: name;
|
||||||
cMark = new CompoundMark(
|
cMark = new CompoundMark(
|
||||||
XMLParser.getNodeAttributeInt(cMarkNode, "CompoundMarkID"),
|
XMLParser.getNodeAttributeInt(cMarkNode, "CompoundMarkID"),
|
||||||
XMLParser.getNodeAttributeString(cMarkNode, "Name"),
|
name, createMarks(cMarkNode)
|
||||||
createMarks(cMarkNode)
|
|
||||||
);
|
);
|
||||||
allMarks.add(cMark);
|
allMarks.add(cMark);
|
||||||
}
|
}
|
||||||
@@ -303,14 +354,169 @@ public class XMLParser {
|
|||||||
Node markNode = childMarks.item(i);
|
Node markNode = childMarks.item(i);
|
||||||
if (markNode.getNodeName().equals("Mark")) {
|
if (markNode.getNodeName().equals("Mark")) {
|
||||||
Integer seqID = XMLParser.getNodeAttributeInt(markNode, "SeqID");
|
Integer seqID = XMLParser.getNodeAttributeInt(markNode, "SeqID");
|
||||||
|
seqID = (seqID == null) ? i+1 : seqID;
|
||||||
|
|
||||||
Integer sourceID = XMLParser.getNodeAttributeInt(markNode, "SourceID");
|
Integer sourceID = XMLParser.getNodeAttributeInt(markNode, "SourceID");
|
||||||
|
sourceID = (sourceID == null) ? i+1 : sourceID;
|
||||||
|
|
||||||
String markName = XMLParser.getNodeAttributeString(markNode, "Name");
|
String markName = XMLParser.getNodeAttributeString(markNode, "Name");
|
||||||
|
markName = (markName == null || markName.equals("")) ? cMarkName + " " + i+1: markName;
|
||||||
|
|
||||||
Double targetLat = XMLParser.getNodeAttributeDouble(markNode, "TargetLat");
|
Double targetLat = XMLParser.getNodeAttributeDouble(markNode, "TargetLat");
|
||||||
Double targetLng = XMLParser.getNodeAttributeDouble(markNode, "TargetLng");
|
Double targetLng = XMLParser.getNodeAttributeDouble(markNode, "TargetLng");
|
||||||
|
|
||||||
Mark mark = new Mark(markName, seqID, targetLat, targetLng, sourceID);
|
Mark mark = new Mark(markName, seqID, targetLat, targetLng, sourceID);
|
||||||
subMarks.add(mark);
|
subMarks.add(mark);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return subMarks;
|
return subMarks;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This ungodly combination of existing methods and code blocks parses a race definition file.
|
||||||
|
* Look upon it and despair.
|
||||||
|
* @param url the location of the race def file
|
||||||
|
* @param serverName the name of the server
|
||||||
|
* @param repetitions the repetitions of a segment of the race def file.
|
||||||
|
* @param maxPlayers max number of players. uses the default race max if null or greater than the actual max.
|
||||||
|
* @param tokensEnabled if tokens are enabled
|
||||||
|
* @return a pair which contains regatta string, race string as key, value pair.
|
||||||
|
*/
|
||||||
|
public static Pair<RegattaXMLTemplate, RaceXMLTemplate> parseRaceDef(
|
||||||
|
String url, String serverName, Integer repetitions, Integer maxPlayers, Boolean tokensEnabled
|
||||||
|
) {
|
||||||
|
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
|
||||||
|
DocumentBuilder db;
|
||||||
|
Document doc = null;
|
||||||
|
try {
|
||||||
|
db = dbf.newDocumentBuilder();
|
||||||
|
doc = db.parse(url);
|
||||||
|
} catch (ParserConfigurationException | IOException | SAXException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
Element docEle = doc.getDocumentElement();
|
||||||
|
|
||||||
|
RegattaXMLTemplate regattaXMLTemplate = new RegattaXMLTemplate(
|
||||||
|
serverName, XMLParser.getElementString(docEle, "CourseName"),
|
||||||
|
XMLParser.getElementDouble(docEle, "CentralLat"),
|
||||||
|
XMLParser.getElementDouble(docEle, "CentralLng")
|
||||||
|
);
|
||||||
|
|
||||||
|
XMLGenerator xmlGenerator = new XMLGenerator();
|
||||||
|
xmlGenerator.setRegattaTemplate(regattaXMLTemplate);
|
||||||
|
|
||||||
|
if (maxPlayers == null) {
|
||||||
|
maxPlayers = XMLParser.getElementInt(docEle, "MaxPlayers");
|
||||||
|
} else if (maxPlayers > XMLParser.getElementInt(docEle, "MaxPlayers")) {
|
||||||
|
maxPlayers = XMLParser.getElementInt(docEle, "MaxPlayers");
|
||||||
|
}
|
||||||
|
|
||||||
|
RaceXMLTemplate raceXMLTemplate = new RaceXMLTemplate(
|
||||||
|
new ArrayList<>(), new ArrayList<>(),
|
||||||
|
XMLParser.extractMarkOrderRaceDef(docEle, repetitions),
|
||||||
|
XMLParser.extractCourseLimitRaceDef(docEle),
|
||||||
|
XMLParser.extractCompoundMarksRaceDef(docEle),
|
||||||
|
maxPlayers, tokensEnabled
|
||||||
|
);
|
||||||
|
xmlGenerator.setRaceTemplate(raceXMLTemplate);
|
||||||
|
return new Pair<>(regattaXMLTemplate, raceXMLTemplate);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<Corner> extractMarkOrderRaceDef(Element docEle, int repitions){
|
||||||
|
List<Corner> compoundMarkSequence = new ArrayList<>();
|
||||||
|
NodeList cornerList = docEle.getElementsByTagName("Course").item(0).getChildNodes();
|
||||||
|
|
||||||
|
int seqId = 1;
|
||||||
|
final int zoneSize = 3;
|
||||||
|
|
||||||
|
for (int i=0; i<cornerList.getLength(); i++) {
|
||||||
|
Node segment = cornerList.item(i);
|
||||||
|
if (segment.getNodeName().equals("OpeningSegment") ||
|
||||||
|
segment.getNodeName().equals("ClosingSegment")) {
|
||||||
|
|
||||||
|
seqId = parseCourseSegment(segment, seqId, compoundMarkSequence);
|
||||||
|
|
||||||
|
} else if (segment.getNodeName().equals("RepeatingSegment")) {
|
||||||
|
for (int k = 0; k < repitions; k++) {
|
||||||
|
seqId = parseCourseSegment(segment, seqId, compoundMarkSequence);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return compoundMarkSequence;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a segment of the course adding new Corners to the given list.
|
||||||
|
* @param segment Segment to parse
|
||||||
|
* @param seqID initial sequence ID
|
||||||
|
* @param course course to add corners to
|
||||||
|
* @return the last sequence id.
|
||||||
|
*/
|
||||||
|
private static int parseCourseSegment(Node segment, int seqID, List<Corner> course) {
|
||||||
|
NodeList segmentList = segment.getChildNodes();
|
||||||
|
for (int j = 0; j < segmentList.getLength(); j++) {
|
||||||
|
Node corner = segmentList.item(j);
|
||||||
|
if (corner.getNodeName().equals("Corner")) {
|
||||||
|
String rounding = XMLParser.getNodeAttributeString(corner, "Rounding");
|
||||||
|
rounding = //Converting "P" to "Port" and "S" to "Stbd"
|
||||||
|
rounding.equals("P") ? "Port" :
|
||||||
|
rounding.equals("S") ? "Stbd" : rounding;
|
||||||
|
course.add(new Corner(
|
||||||
|
seqID++, XMLParser.getNodeAttributeInt(corner, "CompoundMarkID"),
|
||||||
|
rounding, 3
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return seqID;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<Limit> extractCourseLimitRaceDef(Element docEle) {
|
||||||
|
List<Limit> courseLimit = new ArrayList<>();
|
||||||
|
NodeList limitList = docEle.getElementsByTagName("CourseLimit").item(0).getChildNodes();
|
||||||
|
int seqId = 1;
|
||||||
|
for (int i = 0; i < limitList.getLength(); i++) {
|
||||||
|
Node limitNode = limitList.item(i);
|
||||||
|
if (limitNode.getNodeName().equals("Limit")) {
|
||||||
|
courseLimit.add(new Limit(
|
||||||
|
seqId++, XMLParser.getNodeAttributeDouble(limitNode, "Lat"),
|
||||||
|
XMLParser.getNodeAttributeDouble(limitNode, "Lng")
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return courseLimit;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<CompoundMark> extractCompoundMarksRaceDef(Element docEle){
|
||||||
|
List<CompoundMark> allMarks = new ArrayList<>();
|
||||||
|
NodeList cMarkList = docEle.getElementsByTagName("Marks").item(0).getChildNodes();
|
||||||
|
CompoundMark cMark;
|
||||||
|
int markCount = 200;
|
||||||
|
for (int i = 0; i < cMarkList.getLength(); i++) {
|
||||||
|
Node cMarkNode = cMarkList.item(i);
|
||||||
|
if (cMarkNode.getNodeName().equals("CompoundMark")) {
|
||||||
|
Integer id = XMLParser.getNodeAttributeInt(cMarkNode, "CompoundMarkID");
|
||||||
|
List<Mark> subMarks = createMarksRaceDef(cMarkNode, markCount,"Mark " + id);
|
||||||
|
markCount += subMarks.size();
|
||||||
|
allMarks.add(new CompoundMark(id, "Mark " + id, subMarks));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return allMarks;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<Mark> createMarksRaceDef(Node compoundMark, int markCount, String markName) {
|
||||||
|
List<Mark> subMarks = new ArrayList<>();
|
||||||
|
NodeList childMarks = compoundMark.getChildNodes();
|
||||||
|
int seqID = 1;
|
||||||
|
for (int i = 0; i < childMarks.getLength(); i++) {
|
||||||
|
Node markNode = childMarks.item(i);
|
||||||
|
if (markNode.getNodeName().equals("Mark")) {
|
||||||
|
Double targetLat = XMLParser.getNodeAttributeDouble(markNode, "Lat");
|
||||||
|
Double targetLng = XMLParser.getNodeAttributeDouble(markNode, "Lng");
|
||||||
|
Mark mark = new Mark(markName + " subMark " + seqID, seqID, targetLat, targetLng, markCount++);
|
||||||
|
subMarks.add(mark);
|
||||||
|
seqID += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return subMarks;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -14,6 +14,7 @@ import java.util.TimerTask;
|
|||||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||||
import java.util.zip.CRC32;
|
import java.util.zip.CRC32;
|
||||||
import java.util.zip.Checksum;
|
import java.util.zip.Checksum;
|
||||||
|
import javafx.util.Pair;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import seng302.gameServer.messages.BoatAction;
|
import seng302.gameServer.messages.BoatAction;
|
||||||
@@ -25,8 +26,14 @@ import seng302.gameServer.messages.CustomizeRequestType;
|
|||||||
import seng302.gameServer.messages.Message;
|
import seng302.gameServer.messages.Message;
|
||||||
import seng302.gameServer.messages.RegistrationRequestMessage;
|
import seng302.gameServer.messages.RegistrationRequestMessage;
|
||||||
import seng302.gameServer.messages.RegistrationResponseStatus;
|
import seng302.gameServer.messages.RegistrationResponseStatus;
|
||||||
|
import seng302.gameServer.messages.XMLMessage;
|
||||||
|
import seng302.gameServer.messages.XMLMessageSubType;
|
||||||
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.xml.generator.RaceXMLTemplate;
|
||||||
|
import seng302.model.stream.xml.generator.RegattaXMLTemplate;
|
||||||
|
import seng302.utilities.XMLGenerator;
|
||||||
|
import seng302.utilities.XMLParser;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A class describing a single connection to a Server for the purposes of sending and receiving on
|
* A class describing a single connection to a Server for the purposes of sending and receiving on
|
||||||
@@ -44,7 +51,7 @@ public class ClientToServerThread implements Runnable {
|
|||||||
|
|
||||||
@FunctionalInterface
|
@FunctionalInterface
|
||||||
public interface DisconnectedFromHostListener {
|
public interface DisconnectedFromHostListener {
|
||||||
void notifYDisconnection (String message);
|
void notifyDisconnection(String message);
|
||||||
}
|
}
|
||||||
|
|
||||||
private class ByteReadException extends Exception {
|
private class ByteReadException extends Exception {
|
||||||
@@ -68,7 +75,7 @@ public class ClientToServerThread implements Runnable {
|
|||||||
private Timer upWindPacketTimer = new Timer();
|
private Timer upWindPacketTimer = new Timer();
|
||||||
private Timer downWindPacketTimer = new Timer();
|
private Timer downWindPacketTimer = new Timer();
|
||||||
private boolean upwindTimerFlag = false, downwindTimerFlag = false;
|
private boolean upwindTimerFlag = false, downwindTimerFlag = false;
|
||||||
static public final int PACKET_SENDING_INTERVAL_MS = 100;
|
public static final int PACKET_SENDING_INTERVAL_MS = 100;
|
||||||
|
|
||||||
private int clientId = -1;
|
private int clientId = -1;
|
||||||
|
|
||||||
@@ -166,7 +173,7 @@ public class ClientToServerThread implements Runnable {
|
|||||||
private void notifyDisconnectListeners (String message) {
|
private void notifyDisconnectListeners (String message) {
|
||||||
if (socketOpen) {
|
if (socketOpen) {
|
||||||
for (DisconnectedFromHostListener listener : disconnectionListeners) {
|
for (DisconnectedFromHostListener listener : disconnectionListeners) {
|
||||||
listener.notifYDisconnection(message);
|
listener.notifyDisconnection(message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -175,7 +182,7 @@ public class ClientToServerThread implements Runnable {
|
|||||||
* Sends a request to the server asking for a source ID
|
* Sends a request to the server asking for a source ID
|
||||||
*/
|
*/
|
||||||
private void sendRegistrationRequest() {
|
private void sendRegistrationRequest() {
|
||||||
RegistrationRequestMessage requestMessage = new RegistrationRequestMessage(ClientType.PLAYER);
|
RegistrationRequestMessage requestMessage = new RegistrationRequestMessage(ClientType.PLAYER, clientId);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
os.write(requestMessage.getBuffer());
|
os.write(requestMessage.getBuffer());
|
||||||
@@ -191,9 +198,8 @@ public class ClientToServerThread implements Runnable {
|
|||||||
* @param packet The registration requests packet
|
* @param packet The registration requests packet
|
||||||
*/
|
*/
|
||||||
private void processRegistrationResponse(StreamPacket packet){
|
private void processRegistrationResponse(StreamPacket packet){
|
||||||
int sourceId = (int) Message.bytesToLong(Arrays.copyOfRange(packet.getPayload(), 0, 3));
|
int sourceId = (int) Message.bytesToLong(Arrays.copyOfRange(packet.getPayload(), 0, 4));
|
||||||
int statusCode = (int) Message.bytesToLong(Arrays.copyOfRange(packet.getPayload(), 4,5));
|
int statusCode = (int) Message.bytesToLong(Arrays.copyOfRange(packet.getPayload(), 4,5));
|
||||||
|
|
||||||
RegistrationResponseStatus status = RegistrationResponseStatus.getResponseStatus(statusCode);
|
RegistrationResponseStatus status = RegistrationResponseStatus.getResponseStatus(statusCode);
|
||||||
|
|
||||||
if (status.equals(RegistrationResponseStatus.SUCCESS_PLAYING)){
|
if (status.equals(RegistrationResponseStatus.SUCCESS_PLAYING)){
|
||||||
@@ -243,7 +249,7 @@ public class ClientToServerThread implements Runnable {
|
|||||||
new TimerTask() {
|
new TimerTask() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
sendBoatActionMessage(new BoatActionMessage(BoatAction.DOWNWIND));
|
sendBoatActionMessage(new BoatActionMessage(BoatAction.DOWNWIND, clientId));
|
||||||
}
|
}
|
||||||
}, 0, PACKET_SENDING_INTERVAL_MS
|
}, 0, PACKET_SENDING_INTERVAL_MS
|
||||||
);
|
);
|
||||||
@@ -256,14 +262,14 @@ public class ClientToServerThread implements Runnable {
|
|||||||
new TimerTask() {
|
new TimerTask() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
sendBoatActionMessage(new BoatActionMessage(BoatAction.UPWIND));
|
sendBoatActionMessage(new BoatActionMessage(BoatAction.UPWIND, clientId));
|
||||||
}
|
}
|
||||||
}, 0, PACKET_SENDING_INTERVAL_MS
|
}, 0, PACKET_SENDING_INTERVAL_MS
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
sendBoatActionMessage(new BoatActionMessage(actionType));
|
sendBoatActionMessage(new BoatActionMessage(actionType, clientId));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -369,4 +375,25 @@ public class ClientToServerThread implements Runnable {
|
|||||||
public int getClientId () {
|
public int getClientId () {
|
||||||
return clientId;
|
return clientId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void sendXML(String path, String serverName, Integer legRepeats, Integer maxPlayers, Boolean tokensEnabled) {
|
||||||
|
Pair<RegattaXMLTemplate, RaceXMLTemplate> regattaRace = XMLParser.parseRaceDef(
|
||||||
|
path, serverName, legRepeats, maxPlayers, tokensEnabled
|
||||||
|
);
|
||||||
|
XMLGenerator xmlGenerator = new XMLGenerator();
|
||||||
|
xmlGenerator.setRegattaTemplate(regattaRace.getKey());
|
||||||
|
xmlGenerator.setRaceTemplate(regattaRace.getValue());
|
||||||
|
String regatta = xmlGenerator.getRegattaAsXml();
|
||||||
|
String race = xmlGenerator.getRaceAsXml();
|
||||||
|
sendByteBuffer(
|
||||||
|
new XMLMessage(
|
||||||
|
regatta, XMLMessageSubType.REGATTA, regatta.length()
|
||||||
|
).getBuffer()
|
||||||
|
);
|
||||||
|
sendByteBuffer(
|
||||||
|
new XMLMessage(
|
||||||
|
race, XMLMessageSubType.RACE, race.length()
|
||||||
|
).getBuffer()
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,8 +14,6 @@ import javafx.application.Platform;
|
|||||||
import javafx.collections.FXCollections;
|
import javafx.collections.FXCollections;
|
||||||
import javafx.collections.ObservableList;
|
import javafx.collections.ObservableList;
|
||||||
import javafx.fxml.FXMLLoader;
|
import javafx.fxml.FXMLLoader;
|
||||||
import javafx.scene.control.Alert;
|
|
||||||
import javafx.scene.control.Alert.AlertType;
|
|
||||||
import javafx.scene.input.KeyCode;
|
import javafx.scene.input.KeyCode;
|
||||||
import javafx.scene.input.KeyEvent;
|
import javafx.scene.input.KeyEvent;
|
||||||
import javafx.scene.layout.Pane;
|
import javafx.scene.layout.Pane;
|
||||||
@@ -28,6 +26,8 @@ import seng302.gameServer.messages.BoatAction;
|
|||||||
import seng302.gameServer.messages.BoatStatus;
|
import seng302.gameServer.messages.BoatStatus;
|
||||||
import seng302.gameServer.messages.YachtEventType;
|
import seng302.gameServer.messages.YachtEventType;
|
||||||
import seng302.model.ClientYacht;
|
import seng302.model.ClientYacht;
|
||||||
|
import seng302.model.GameKeyBind;
|
||||||
|
import seng302.model.KeyAction;
|
||||||
import seng302.model.RaceState;
|
import seng302.model.RaceState;
|
||||||
import seng302.model.stream.packets.StreamPacket;
|
import seng302.model.stream.packets.StreamPacket;
|
||||||
import seng302.model.stream.parser.MarkRoundingData;
|
import seng302.model.stream.parser.MarkRoundingData;
|
||||||
@@ -44,6 +44,7 @@ import seng302.utilities.XMLParser;
|
|||||||
import seng302.visualiser.controllers.LobbyController;
|
import seng302.visualiser.controllers.LobbyController;
|
||||||
import seng302.visualiser.controllers.RaceViewController;
|
import seng302.visualiser.controllers.RaceViewController;
|
||||||
import seng302.visualiser.controllers.ViewManager;
|
import seng302.visualiser.controllers.ViewManager;
|
||||||
|
import seng302.visualiser.controllers.dialogs.PopupDialogController;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class is a client side instance of a yacht racing game in JavaFX. The game is instantiated
|
* This class is a client side instance of a yacht racing game in JavaFX. The game is instantiated
|
||||||
@@ -66,6 +67,8 @@ public class GameClient {
|
|||||||
|
|
||||||
private ArrayList<ClientYacht> finishedBoats = new ArrayList<>();
|
private ArrayList<ClientYacht> finishedBoats = new ArrayList<>();
|
||||||
|
|
||||||
|
private GameKeyBind gameKeyBind; // all the key binding setting.
|
||||||
|
|
||||||
private ObservableList<String> clientLobbyList = FXCollections.observableArrayList();
|
private ObservableList<String> clientLobbyList = FXCollections.observableArrayList();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -75,6 +78,7 @@ public class GameClient {
|
|||||||
*/
|
*/
|
||||||
public GameClient(Pane holder) {
|
public GameClient(Pane holder) {
|
||||||
this.holderPane = holder;
|
this.holderPane = holder;
|
||||||
|
this.gameKeyBind = GameKeyBind.getInstance();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -117,9 +121,11 @@ public class GameClient {
|
|||||||
* @param ipAddress IP to connect to.
|
* @param ipAddress IP to connect to.
|
||||||
* @param portNumber Port to connect to.
|
* @param portNumber Port to connect to.
|
||||||
*/
|
*/
|
||||||
public ServerDescription runAsHost(String ipAddress, Integer portNumber, String serverName, Integer maxPlayers) {
|
public ServerDescription runAsHost(
|
||||||
|
String ipAddress, Integer portNumber, String serverName, Integer maxPlayers, String race,
|
||||||
|
Integer numLegs, Boolean tokensEnabled
|
||||||
|
) {
|
||||||
XMLGenerator.setDefaultRaceName(serverName);
|
XMLGenerator.setDefaultRaceName(serverName);
|
||||||
GameState.setMaxPlayers(maxPlayers);
|
|
||||||
|
|
||||||
server = new MainServerThread();
|
server = new MainServerThread();
|
||||||
|
|
||||||
@@ -128,7 +134,7 @@ public class GameClient {
|
|||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
showConnectionError("Cannot connect to server as host");
|
showConnectionError("Cannot connect to server as host");
|
||||||
}
|
}
|
||||||
|
socketThread.sendXML(race, serverName, numLegs, maxPlayers, tokensEnabled);
|
||||||
while (regattaData == null){
|
while (regattaData == null){
|
||||||
try {
|
try {
|
||||||
Thread.sleep(100);
|
Thread.sleep(100);
|
||||||
@@ -164,10 +170,12 @@ public class GameClient {
|
|||||||
|
|
||||||
private void showConnectionError (String message) {
|
private void showConnectionError (String message) {
|
||||||
Platform.runLater(() -> {
|
Platform.runLater(() -> {
|
||||||
Alert alert = new Alert(AlertType.ERROR);
|
PopupDialogController controller = ViewManager.getInstance().showPopupDialog();
|
||||||
alert.setHeaderText("Connection Error");
|
controller.setHeader("Oops");
|
||||||
alert.setContentText(message);
|
controller.setContent(message);
|
||||||
alert.showAndWait();
|
controller.setOptionButtonText("GO HOME");
|
||||||
|
controller
|
||||||
|
.setOptionButtonEventHandler(event -> ViewManager.getInstance().goToStartView());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -206,6 +214,7 @@ public class GameClient {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case RACE_XML:
|
case RACE_XML:
|
||||||
|
System.out.println("HEY I GOT A RACE MANG AND I AM CLIENT " + ((Boolean) (server==null)).toString());
|
||||||
RaceXMLData raceXMLData = XMLParser.parseRace(
|
RaceXMLData raceXMLData = XMLParser.parseRace(
|
||||||
StreamParser.extractXmlMessage(packet)
|
StreamParser.extractXmlMessage(packet)
|
||||||
);
|
);
|
||||||
@@ -373,16 +382,16 @@ public class GameClient {
|
|||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
switch (e.getCode()) {
|
|
||||||
case SPACE: // align with vmg
|
if (gameKeyBind.getKeyCode(KeyAction.VMG) == e.getCode()) { // align with vmg
|
||||||
socketThread.sendBoatAction(BoatAction.VMG); break;
|
socketThread.sendBoatAction(BoatAction.VMG);
|
||||||
case PAGE_UP: // upwind
|
} else if (gameKeyBind.getKeyCode(KeyAction.UPWIND) == e.getCode()) { // upwind
|
||||||
socketThread.sendBoatAction(BoatAction.UPWIND); break;
|
socketThread.sendBoatAction(BoatAction.UPWIND);
|
||||||
case PAGE_DOWN: // downwind
|
} else if (gameKeyBind.getKeyCode(KeyAction.DOWNWIND) == e.getCode()) { // downwind
|
||||||
socketThread.sendBoatAction(BoatAction.DOWNWIND); break;
|
socketThread.sendBoatAction(BoatAction.DOWNWIND);
|
||||||
case ENTER: // tack/gybe
|
} else if (gameKeyBind.getKeyCode(KeyAction.TACK_GYBE) == e.getCode()) { // tack/gybe
|
||||||
// if chat box is active take whatever is in there and send it to server
|
// if chat box is active take whatever is in there and send it to server
|
||||||
socketThread.sendBoatAction(BoatAction.TACK_GYBE); break;
|
socketThread.sendBoatAction(BoatAction.TACK_GYBE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -391,15 +400,17 @@ public class GameClient {
|
|||||||
if (raceView.isChatInputFocused()) {
|
if (raceView.isChatInputFocused()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
switch (e.getCode()) {
|
|
||||||
//TODO 12/07/17 Determine the sail state and send the appropriate packet (eg. if sails are in, send a sail out packet)
|
if (gameKeyBind.getKeyCode(KeyAction.SAILS_STATE) == e.getCode()) { // sails in/sails out
|
||||||
case SHIFT: // sails in/sails out
|
if (allBoatsMap.get(socketThread.getClientId()).getSailIn()) {
|
||||||
|
socketThread.sendBoatAction(BoatAction.SAILS_OUT);
|
||||||
|
} else {
|
||||||
socketThread.sendBoatAction(BoatAction.SAILS_IN);
|
socketThread.sendBoatAction(BoatAction.SAILS_IN);
|
||||||
allBoatsMap.get(socketThread.getClientId()).toggleSail();
|
}
|
||||||
break;
|
allBoatsMap.get(socketThread.getClientId()).toggleSail();
|
||||||
case PAGE_UP:
|
} else if (gameKeyBind.getKeyCode(KeyAction.UPWIND) == e.getCode()
|
||||||
case PAGE_DOWN:
|
|| gameKeyBind.getKeyCode(KeyAction.DOWNWIND) == e.getCode()) {
|
||||||
socketThread.sendBoatAction(BoatAction.MAINTAIN_HEADING); break;
|
socketThread.sendBoatAction(BoatAction.MAINTAIN_HEADING);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -456,4 +467,14 @@ public class GameClient {
|
|||||||
public Map<Integer, ClientYacht> getAllBoatsMap() {
|
public Map<Integer, ClientYacht> getAllBoatsMap() {
|
||||||
return allBoatsMap;
|
return allBoatsMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void sendToggleTurningModePacket() {
|
||||||
|
if (socketThread != null) {
|
||||||
|
if (gameKeyBind.isContinuouslyTurning()) {
|
||||||
|
socketThread.sendBoatAction(BoatAction.CONTINUOUSLY_TURNING);
|
||||||
|
} else {
|
||||||
|
socketThread.sendBoatAction(BoatAction.DEFAULT_TURNING);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,443 +1,31 @@
|
|||||||
package seng302.visualiser;
|
package seng302.visualiser;
|
||||||
|
|
||||||
import javafx.application.Platform;
|
import java.util.ArrayList;
|
||||||
import javafx.collections.ObservableList;
|
import java.util.List;
|
||||||
import javafx.geometry.Point2D;
|
import javafx.scene.Group;
|
||||||
import javafx.scene.*;
|
import javafx.scene.Node;
|
||||||
import javafx.scene.image.ImageView;
|
|
||||||
import javafx.scene.layout.Pane;
|
|
||||||
import javafx.scene.paint.Color;
|
|
||||||
import javafx.scene.paint.Paint;
|
|
||||||
import javafx.scene.shape.Polygon;
|
|
||||||
import seng302.gameServer.messages.RoundingSide;
|
|
||||||
import seng302.model.GeoPoint;
|
|
||||||
import seng302.model.Limit;
|
import seng302.model.Limit;
|
||||||
|
import seng302.model.ScaledPoint;
|
||||||
import seng302.model.mark.CompoundMark;
|
import seng302.model.mark.CompoundMark;
|
||||||
import seng302.model.mark.Corner;
|
import seng302.model.mark.Corner;
|
||||||
import seng302.model.mark.Mark;
|
|
||||||
import seng302.utilities.GeoUtility;
|
|
||||||
import seng302.visualiser.fxObjects.MarkArrowFactory;
|
|
||||||
import seng302.visualiser.fxObjects.assets_2D.*;
|
|
||||||
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by cir27 on 20/07/17.
|
* Common elements of game visualizing classes.
|
||||||
*/
|
*/
|
||||||
public class GameView extends Pane {
|
public abstract class GameView {
|
||||||
|
|
||||||
private double bufferSize = 50;
|
double canvasWidth, canvasHeight;
|
||||||
private double horizontalBuffer = 0;
|
ScaledPoint scaledPoint;
|
||||||
|
|
||||||
private double canvasWidth = 1100;
|
List<Limit> borderPoints;
|
||||||
private double canvasHeight = 920;
|
Group gameObjects = new Group();
|
||||||
private boolean horizontalInversion = false;
|
Group markers = new Group();
|
||||||
|
Group tokens = new Group();
|
||||||
|
List<CompoundMark> course = new ArrayList<>();
|
||||||
|
List<CompoundMark> compoundMarks = new ArrayList<>();
|
||||||
|
List<Corner> courseOrder = new ArrayList<>();
|
||||||
|
|
||||||
private double distanceScaleFactor;
|
public abstract Node getAssets();
|
||||||
private ScaleDirection scaleDirection;
|
public abstract void updateCourse(List<CompoundMark> newCourse, List<Corner> sequence);
|
||||||
private GeoPoint minLatPoint, minLonPoint, maxLatPoint, maxLonPoint;
|
public abstract void updateBorder(List<Limit> border);
|
||||||
private double referencePointX, referencePointY;
|
|
||||||
|
|
||||||
private Polygon raceBorder = new CourseBoundary();
|
|
||||||
|
|
||||||
/* Note that if either of these is null then values for it have not been added and the other
|
|
||||||
should be used as the limits of the map. */
|
|
||||||
private List<Limit> borderPoints;
|
|
||||||
private Map<Mark, Marker2D> markerObjects;
|
|
||||||
|
|
||||||
private ObservableList<Node> gameObjects;
|
|
||||||
private Group markers = new Group();
|
|
||||||
private Group tokens = new Group();
|
|
||||||
private List<CompoundMark> course = new ArrayList<>();
|
|
||||||
|
|
||||||
private ImageView mapImage = new ImageView();
|
|
||||||
|
|
||||||
private enum ScaleDirection {
|
|
||||||
HORIZONTAL,
|
|
||||||
VERTICAL
|
|
||||||
}
|
|
||||||
|
|
||||||
public GameView () {
|
|
||||||
gameObjects = this.getChildren();
|
|
||||||
gameObjects.addAll(mapImage, raceBorder, markers, tokens);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds a course to the GameView. The view is scaled accordingly unless a border is set in which
|
|
||||||
* case the course is added relative ot the border.
|
|
||||||
*
|
|
||||||
* @param newCourse the mark objects that make up the course.
|
|
||||||
* @param sequence The sequence the marks travel through
|
|
||||||
*/
|
|
||||||
public void updateCourse(List<CompoundMark> newCourse, List<Corner> sequence) {
|
|
||||||
markerObjects = new HashMap<>();
|
|
||||||
|
|
||||||
for (Corner corner : sequence) { //Makes course out of all compound marks.
|
|
||||||
for (CompoundMark compoundMark : newCourse) {
|
|
||||||
if (corner.getCompoundMarkID() == compoundMark.getId()) {
|
|
||||||
course.add(compoundMark);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: 16/08/17 Updating mark roundings here. It should not happen here. Nor should it be done this way.
|
|
||||||
for (Corner corner : sequence){
|
|
||||||
CompoundMark compoundMark = course.get(corner.getSeqID() - 1);
|
|
||||||
compoundMark.setRoundingSide(
|
|
||||||
RoundingSide.getRoundingSide(corner.getRounding())
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
final List<Gate> gates = new ArrayList<>();
|
|
||||||
Paint colour = Color.BLACK;
|
|
||||||
//Creates new markers
|
|
||||||
for (CompoundMark cMark : newCourse) {
|
|
||||||
//Set start and end colour
|
|
||||||
if (cMark.getId() == sequence.get(0).getCompoundMarkID()) {
|
|
||||||
colour = Color.GREEN;
|
|
||||||
} else if (cMark.getId() == sequence.get(sequence.size() - 1).getCompoundMarkID()) {
|
|
||||||
colour = Color.RED;
|
|
||||||
}
|
|
||||||
//Create mark dots
|
|
||||||
for (Mark mark : cMark.getMarks()) {
|
|
||||||
makeAndBindMarker(mark, colour);
|
|
||||||
}
|
|
||||||
//Create gate line
|
|
||||||
if (cMark.isGate()) {
|
|
||||||
for (int i = 1; i < cMark.getMarks().size(); i++) {
|
|
||||||
gates.add(
|
|
||||||
makeAndBindGate(
|
|
||||||
markerObjects.get(cMark.getSubMark(i)),
|
|
||||||
markerObjects.get(cMark.getSubMark(i + 1)),
|
|
||||||
colour
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
colour = Color.BLACK;
|
|
||||||
}
|
|
||||||
|
|
||||||
createMarkArrows(sequence);
|
|
||||||
|
|
||||||
//Scale race to markers if there is no border.
|
|
||||||
if (borderPoints == null) {
|
|
||||||
rescaleRace(new ArrayList<>(markerObjects.keySet()));
|
|
||||||
}
|
|
||||||
//Move the Markers to initial position.
|
|
||||||
markerObjects.forEach(((mark, marker2D) -> {
|
|
||||||
Point2D p2d = findScaledXY(mark.getLat(), mark.getLng());
|
|
||||||
marker2D.setLayoutX(p2d.getX());
|
|
||||||
marker2D.setLayoutY(p2d.getY());
|
|
||||||
}));
|
|
||||||
Platform.runLater(() -> {
|
|
||||||
markers.getChildren().clear();
|
|
||||||
markers.getChildren().addAll(gates);
|
|
||||||
markers.getChildren().addAll(markerObjects.values());
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Calculates all the data needed for to create mark arrows. Requires that a course has been
|
|
||||||
* added to the gameview.
|
|
||||||
* @param sequence The order in which marks are traversed.
|
|
||||||
*/
|
|
||||||
private void createMarkArrows (List<Corner> sequence) {
|
|
||||||
for (int i=1; i < sequence.size()-1; i++) { //General case.
|
|
||||||
double averageLat = 0;
|
|
||||||
double averageLng = 0;
|
|
||||||
int numMarks = course.get(i-1).getMarks().size();
|
|
||||||
for (Mark mark : course.get(i-1).getMarks()) {
|
|
||||||
averageLat += mark.getLat();
|
|
||||||
averageLng += mark.getLng();
|
|
||||||
}
|
|
||||||
GeoPoint lastMarkAv = new GeoPoint(averageLat / numMarks, averageLng / numMarks);
|
|
||||||
numMarks = course.get(i+1).getMarks().size();
|
|
||||||
averageLat = 0;
|
|
||||||
averageLng = 0;
|
|
||||||
for (Mark mark : course.get(i+1).getMarks()) {
|
|
||||||
averageLat += mark.getLat();
|
|
||||||
averageLng += mark.getLng();
|
|
||||||
}
|
|
||||||
GeoPoint nextMarkAv = new GeoPoint(averageLat / numMarks, averageLng / numMarks);
|
|
||||||
// TODO: 16/08/17 This comparison doesn't need to exist but the alternative is to user server enum client side.
|
|
||||||
for (Mark mark : course.get(i).getMarks()) {
|
|
||||||
markerObjects.get(mark).addArrows(
|
|
||||||
mark.getRoundingSide() == RoundingSide.STARBOARD ? MarkArrowFactory.RoundingSide.STARBOARD : MarkArrowFactory.RoundingSide.PORT,
|
|
||||||
GeoUtility.getBearing(lastMarkAv, mark),
|
|
||||||
GeoUtility.getBearing(mark, nextMarkAv)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
createStartLineArrows();
|
|
||||||
createFinishLineArrows();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void createStartLineArrows () {
|
|
||||||
double averageLat = 0;
|
|
||||||
double averageLng = 0;
|
|
||||||
int numMarks = 0;
|
|
||||||
for (Mark mark : course.get(1).getMarks()) {
|
|
||||||
numMarks += 1;
|
|
||||||
averageLat += mark.getLat();
|
|
||||||
averageLng += mark.getLng();
|
|
||||||
}
|
|
||||||
GeoPoint firstMarkAv = new GeoPoint(averageLat / numMarks, averageLng / numMarks);
|
|
||||||
for (Mark mark : course.get(0).getMarks()) {
|
|
||||||
markerObjects.get(mark).addArrows(
|
|
||||||
mark.getRoundingSide() == RoundingSide.STARBOARD ? MarkArrowFactory.RoundingSide.STARBOARD : MarkArrowFactory.RoundingSide.PORT,
|
|
||||||
0d, //90
|
|
||||||
GeoUtility.getBearing(mark, firstMarkAv)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void createFinishLineArrows () {
|
|
||||||
double numMarks = 0;
|
|
||||||
double averageLat = 0;
|
|
||||||
double averageLng = 0;
|
|
||||||
for (Mark mark : course.get(course.size()-2).getMarks()) {
|
|
||||||
numMarks += 1;
|
|
||||||
averageLat += mark.getLat();
|
|
||||||
averageLng += mark.getLng();
|
|
||||||
}
|
|
||||||
GeoPoint secondToLastMarkAv = new GeoPoint(averageLat / numMarks, averageLng / numMarks);
|
|
||||||
for (Mark mark : course.get(course.size()-1).getMarks()) {
|
|
||||||
markerObjects.get(mark).addArrows(
|
|
||||||
mark.getRoundingSide() == RoundingSide.STARBOARD ? MarkArrowFactory.RoundingSide.STARBOARD : MarkArrowFactory.RoundingSide.PORT,
|
|
||||||
GeoUtility.getBearing(secondToLastMarkAv, mark),
|
|
||||||
GeoUtility.getBearing(mark, mark)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new Marker and binds it's position to the given Mark.
|
|
||||||
*
|
|
||||||
* @param observableMark The mark to bind the marker to.
|
|
||||||
* @param colour The desired colour of the mark
|
|
||||||
*/
|
|
||||||
private void makeAndBindMarker(Mark observableMark, Paint colour) {
|
|
||||||
Marker2D marker2D = new Marker2D(colour);
|
|
||||||
// marker.addArrows(MarkArrowFactory.RoundingSide.PORT, ThreadLocalRandom.current().nextDouble(91, 180), ThreadLocalRandom.current().nextDouble(1, 90));
|
|
||||||
markerObjects.put(observableMark, marker2D);
|
|
||||||
observableMark.addPositionListener((mark, lat, lon) -> {
|
|
||||||
Point2D p2d = findScaledXY(lat, lon);
|
|
||||||
markerObjects.get(mark).setLayoutX(p2d.getX());
|
|
||||||
markerObjects.get(mark).setLayoutY(p2d.getY());
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new gate connecting the given marks.
|
|
||||||
*
|
|
||||||
* @param m1 The first Mark of the gate.
|
|
||||||
* @param m2 The second Mark of the gate.
|
|
||||||
* @param colour The desired colour of the gate.
|
|
||||||
* @return the new gate.
|
|
||||||
*/
|
|
||||||
private Gate makeAndBindGate(Marker2D m1, Marker2D m2, Paint colour) {
|
|
||||||
Gate gate = new Gate(colour);
|
|
||||||
gate.startXProperty().bind(
|
|
||||||
m1.layoutXProperty()
|
|
||||||
);
|
|
||||||
gate.startYProperty().bind(
|
|
||||||
m1.layoutYProperty()
|
|
||||||
);
|
|
||||||
gate.endXProperty().bind(
|
|
||||||
m2.layoutXProperty()
|
|
||||||
);
|
|
||||||
gate.endYProperty().bind(
|
|
||||||
m2.layoutYProperty()
|
|
||||||
);
|
|
||||||
return gate;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds a border to the GameView and rescales to the size of the border, does not rescale if a
|
|
||||||
* border already exists. Assumes the border is larger than the course.
|
|
||||||
*
|
|
||||||
* @param border the race border to be drawn.
|
|
||||||
*/
|
|
||||||
public void updateBorder(List<Limit> border) {
|
|
||||||
if (borderPoints == null) {
|
|
||||||
borderPoints = border;
|
|
||||||
rescaleRace(new ArrayList<>(borderPoints));
|
|
||||||
}
|
|
||||||
|
|
||||||
rescaleRace(new ArrayList<>(border));
|
|
||||||
|
|
||||||
List<Double> boundaryPoints = new ArrayList<>();
|
|
||||||
for (Limit limit : border) {
|
|
||||||
Point2D location = findScaledXY(limit.getLat(), limit.getLng());
|
|
||||||
boundaryPoints.add(location.getX());
|
|
||||||
boundaryPoints.add(location.getY());
|
|
||||||
}
|
|
||||||
raceBorder.getPoints().setAll(boundaryPoints);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Rescales the race to the size of the window.
|
|
||||||
*
|
|
||||||
* @param limitingCoordinates the set of geo points that contains the extremities of the race.
|
|
||||||
*/
|
|
||||||
public void rescaleRace(List<GeoPoint> limitingCoordinates) {
|
|
||||||
//Check is called once to avoid unnecessarily change the course limits once the race is running
|
|
||||||
findMinMaxPoint(limitingCoordinates);
|
|
||||||
double minLonToMaxLon = scaleRaceExtremities();
|
|
||||||
calculateReferencePointLocation(minLonToMaxLon);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the class variables minLatPoint, maxLatPoint, minLonPoint, maxLonPoint to the point with
|
|
||||||
* the leftmost point, rightmost point, southern most point and northern most point
|
|
||||||
* respectively.
|
|
||||||
*/
|
|
||||||
private void findMinMaxPoint(List<GeoPoint> points) {
|
|
||||||
List<GeoPoint> sortedPoints = new ArrayList<>(points);
|
|
||||||
sortedPoints.sort(Comparator.comparingDouble(GeoPoint::getLat));
|
|
||||||
minLatPoint = new GeoPoint(sortedPoints.get(0).getLat(), sortedPoints.get(0).getLng());
|
|
||||||
GeoPoint maxLat = sortedPoints.get(sortedPoints.size() - 1);
|
|
||||||
maxLatPoint = new GeoPoint(maxLat.getLat(), maxLat.getLng());
|
|
||||||
|
|
||||||
sortedPoints.sort(Comparator.comparingDouble(GeoPoint::getLng));
|
|
||||||
minLonPoint = new GeoPoint(sortedPoints.get(0).getLat(), sortedPoints.get(0).getLng());
|
|
||||||
GeoPoint maxLon = sortedPoints.get(sortedPoints.size() - 1);
|
|
||||||
maxLonPoint = new GeoPoint(maxLon.getLat(), maxLon.getLng());
|
|
||||||
if (maxLonPoint.getLng() - minLonPoint.getLng() > 180) {
|
|
||||||
horizontalInversion = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Calculates the location of a reference point, this is always the point with minimum latitude,
|
|
||||||
* in relation to the canvas.
|
|
||||||
*
|
|
||||||
* @param minLonToMaxLon The horizontal distance between the point of minimum longitude to
|
|
||||||
* maximum longitude.
|
|
||||||
*/
|
|
||||||
private void calculateReferencePointLocation(double minLonToMaxLon) {
|
|
||||||
GeoPoint referencePoint = minLatPoint;
|
|
||||||
double referenceAngle;
|
|
||||||
|
|
||||||
if (scaleDirection == ScaleDirection.HORIZONTAL) {
|
|
||||||
referenceAngle = Math.abs(
|
|
||||||
GeoUtility.getBearingRad(referencePoint, minLonPoint)
|
|
||||||
);
|
|
||||||
referencePointX =
|
|
||||||
bufferSize + distanceScaleFactor * Math.sin(referenceAngle) * GeoUtility
|
|
||||||
.getDistance(referencePoint, minLonPoint);
|
|
||||||
referenceAngle = Math.abs(GeoUtility.getDistance(referencePoint, maxLatPoint));
|
|
||||||
referencePointY = canvasHeight - (bufferSize + bufferSize);
|
|
||||||
referencePointY -= distanceScaleFactor * Math.cos(referenceAngle) * GeoUtility
|
|
||||||
.getDistance(referencePoint, maxLatPoint);
|
|
||||||
referencePointY = referencePointY / 2;
|
|
||||||
referencePointY += bufferSize;
|
|
||||||
referencePointY += distanceScaleFactor * Math.cos(referenceAngle) * GeoUtility
|
|
||||||
.getDistance(referencePoint, maxLatPoint);
|
|
||||||
} else {
|
|
||||||
referencePointY = canvasHeight - bufferSize;
|
|
||||||
referenceAngle = Math.abs(
|
|
||||||
Math.toRadians(
|
|
||||||
GeoUtility.getDistance(referencePoint, minLonPoint)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
referencePointX = bufferSize;
|
|
||||||
referencePointX += distanceScaleFactor * Math.sin(referenceAngle) * GeoUtility
|
|
||||||
.getDistance(referencePoint, minLonPoint);
|
|
||||||
referencePointX +=
|
|
||||||
((canvasWidth - (bufferSize + bufferSize)) - (minLonToMaxLon * distanceScaleFactor))
|
|
||||||
/ 2;
|
|
||||||
referencePointX += horizontalBuffer;
|
|
||||||
}
|
|
||||||
if (horizontalInversion) {
|
|
||||||
referencePointX = canvasWidth - bufferSize - (referencePointX - bufferSize);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Finds the scale factor necessary to fit all race markers within the onscreen map and assigns
|
|
||||||
* it to distanceScaleFactor Returns the max horizontal distance of the map.
|
|
||||||
*/
|
|
||||||
private double scaleRaceExtremities() {
|
|
||||||
|
|
||||||
double vertAngle = Math.abs(
|
|
||||||
GeoUtility.getBearingRad(minLatPoint, maxLatPoint)
|
|
||||||
);
|
|
||||||
double vertDistance =
|
|
||||||
Math.cos(vertAngle) * GeoUtility.getDistance(minLatPoint, maxLatPoint);
|
|
||||||
double horiAngle = Math.abs(
|
|
||||||
GeoUtility.getBearingRad(minLonPoint, maxLonPoint)
|
|
||||||
);
|
|
||||||
if (horiAngle <= (Math.PI / 2)) {
|
|
||||||
horiAngle = (Math.PI / 2) - horiAngle;
|
|
||||||
} else {
|
|
||||||
horiAngle = horiAngle - (Math.PI / 2);
|
|
||||||
}
|
|
||||||
double horiDistance =
|
|
||||||
Math.cos(horiAngle) * GeoUtility.getDistance(minLonPoint, maxLonPoint);
|
|
||||||
|
|
||||||
double vertScale = (canvasHeight - (bufferSize + bufferSize)) / vertDistance;
|
|
||||||
|
|
||||||
if ((horiDistance * vertScale) > (canvasWidth - (bufferSize + bufferSize))) {
|
|
||||||
distanceScaleFactor = (canvasWidth - (bufferSize + bufferSize)) / horiDistance;
|
|
||||||
scaleDirection = ScaleDirection.HORIZONTAL;
|
|
||||||
} else {
|
|
||||||
distanceScaleFactor = vertScale;
|
|
||||||
scaleDirection = ScaleDirection.VERTICAL;
|
|
||||||
}
|
|
||||||
return horiDistance;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Point2D findScaledXY(double unscaledLat, double unscaledLon) {
|
|
||||||
double distanceFromReference;
|
|
||||||
double angleFromReference;
|
|
||||||
double xAxisLocation = referencePointX;
|
|
||||||
double yAxisLocation = referencePointY;
|
|
||||||
|
|
||||||
angleFromReference = GeoUtility.getBearingRad(
|
|
||||||
minLatPoint, new GeoPoint(unscaledLat, unscaledLon)
|
|
||||||
);
|
|
||||||
distanceFromReference = GeoUtility.getDistance(
|
|
||||||
minLatPoint, new GeoPoint(unscaledLat, unscaledLon)
|
|
||||||
);
|
|
||||||
if (angleFromReference >= 0 && angleFromReference <= Math.PI / 2) {
|
|
||||||
xAxisLocation += Math
|
|
||||||
.round(distanceScaleFactor * Math.sin(angleFromReference) * distanceFromReference);
|
|
||||||
yAxisLocation -= Math
|
|
||||||
.round(distanceScaleFactor * Math.cos(angleFromReference) * distanceFromReference);
|
|
||||||
} else if (angleFromReference >= 0) {
|
|
||||||
angleFromReference = angleFromReference - Math.PI / 2;
|
|
||||||
xAxisLocation += Math
|
|
||||||
.round(distanceScaleFactor * Math.cos(angleFromReference) * distanceFromReference);
|
|
||||||
yAxisLocation += Math
|
|
||||||
.round(distanceScaleFactor * Math.sin(angleFromReference) * distanceFromReference);
|
|
||||||
} else if (angleFromReference < 0 && angleFromReference >= -Math.PI / 2) {
|
|
||||||
angleFromReference = Math.abs(angleFromReference);
|
|
||||||
xAxisLocation -= Math
|
|
||||||
.round(distanceScaleFactor * Math.sin(angleFromReference) * distanceFromReference);
|
|
||||||
yAxisLocation -= Math
|
|
||||||
.round(distanceScaleFactor * Math.cos(angleFromReference) * distanceFromReference);
|
|
||||||
} else {
|
|
||||||
angleFromReference = Math.abs(angleFromReference) - Math.PI / 2;
|
|
||||||
xAxisLocation -= Math
|
|
||||||
.round(distanceScaleFactor * Math.cos(angleFromReference) * distanceFromReference);
|
|
||||||
yAxisLocation += Math
|
|
||||||
.round(distanceScaleFactor * Math.sin(angleFromReference) * distanceFromReference);
|
|
||||||
}
|
|
||||||
if (horizontalInversion) {
|
|
||||||
xAxisLocation = canvasWidth - bufferSize - (xAxisLocation - bufferSize);
|
|
||||||
}
|
|
||||||
return new Point2D(xAxisLocation, yAxisLocation);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void setSize(Double width, Double height){
|
|
||||||
this.canvasWidth = width;
|
|
||||||
this.canvasHeight = height;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setHorizontalBuffer(Double buff){
|
|
||||||
this.horizontalBuffer = buff;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package seng302.visualiser;
|
package seng302.visualiser;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Comparator;
|
import java.util.Arrays;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@@ -9,6 +9,7 @@ import javafx.animation.AnimationTimer;
|
|||||||
import javafx.application.Platform;
|
import javafx.application.Platform;
|
||||||
import javafx.geometry.Point2D;
|
import javafx.geometry.Point2D;
|
||||||
import javafx.geometry.Point3D;
|
import javafx.geometry.Point3D;
|
||||||
|
import javafx.scene.Camera;
|
||||||
import javafx.scene.Group;
|
import javafx.scene.Group;
|
||||||
import javafx.scene.Node;
|
import javafx.scene.Node;
|
||||||
import javafx.scene.PerspectiveCamera;
|
import javafx.scene.PerspectiveCamera;
|
||||||
@@ -21,14 +22,21 @@ import javafx.scene.transform.Scale;
|
|||||||
import javafx.scene.transform.Translate;
|
import javafx.scene.transform.Translate;
|
||||||
import seng302.gameServer.messages.RoundingSide;
|
import seng302.gameServer.messages.RoundingSide;
|
||||||
import seng302.model.ClientYacht;
|
import seng302.model.ClientYacht;
|
||||||
import seng302.model.GeoPoint;
|
import seng302.model.GameKeyBind;
|
||||||
|
import seng302.model.KeyAction;
|
||||||
import seng302.model.Limit;
|
import seng302.model.Limit;
|
||||||
|
import seng302.model.ScaledPoint;
|
||||||
import seng302.model.mark.CompoundMark;
|
import seng302.model.mark.CompoundMark;
|
||||||
import seng302.model.mark.Corner;
|
import seng302.model.mark.Corner;
|
||||||
import seng302.model.mark.Mark;
|
import seng302.model.mark.Mark;
|
||||||
import seng302.model.token.Token;
|
import seng302.model.token.Token;
|
||||||
import seng302.utilities.GeoUtility;
|
import seng302.utilities.GeoUtility;
|
||||||
import seng302.utilities.Sounds;
|
import seng302.utilities.Sounds;
|
||||||
|
import seng302.visualiser.cameras.ChaseCamera;
|
||||||
|
import seng302.visualiser.cameras.IsometricCamera;
|
||||||
|
import seng302.visualiser.cameras.RaceCamera;
|
||||||
|
import seng302.visualiser.cameras.TopDownCamera;
|
||||||
|
import seng302.visualiser.controllers.ViewManager;
|
||||||
import seng302.visualiser.fxObjects.MarkArrowFactory;
|
import seng302.visualiser.fxObjects.MarkArrowFactory;
|
||||||
import seng302.visualiser.fxObjects.assets_3D.BoatObject;
|
import seng302.visualiser.fxObjects.assets_3D.BoatObject;
|
||||||
import seng302.visualiser.fxObjects.assets_3D.Marker3D;
|
import seng302.visualiser.fxObjects.assets_3D.Marker3D;
|
||||||
@@ -38,69 +46,51 @@ import seng302.visualiser.fxObjects.assets_3D.ModelType;
|
|||||||
/**
|
/**
|
||||||
* Collection of animated3D assets that displays a race.
|
* Collection of animated3D assets that displays a race.
|
||||||
*/
|
*/
|
||||||
|
public class GameView3D extends GameView{
|
||||||
public class GameView3D {
|
|
||||||
|
|
||||||
|
|
||||||
private final double FOV = 60;
|
private final double FOV = 60;
|
||||||
private final double DEFAULT_CAMERA_DEPTH = -125;
|
|
||||||
private final double DEFAULT_CAMERA_X = 0;
|
private final double DEFAULT_CAMERA_X = 0;
|
||||||
private final double DEFAULT_CAMERA_Y = 155;
|
private final double DEFAULT_CAMERA_Y = 100;
|
||||||
|
|
||||||
private Group root3D;
|
private Group root3D;
|
||||||
private SubScene view;
|
private SubScene view;
|
||||||
// ParallelCamera camera;
|
|
||||||
private PerspectiveCamera camera;
|
|
||||||
private Group gameObjects;
|
|
||||||
|
|
||||||
private double bufferSize = 0;
|
|
||||||
private double canvasWidth = 200;
|
|
||||||
private double canvasHeight = 200;
|
|
||||||
private boolean horizontalInversion = false;
|
|
||||||
|
|
||||||
private double distanceScaleFactor;
|
|
||||||
private ScaleDirection scaleDirection;
|
|
||||||
private GeoPoint minLatPoint, minLonPoint, maxLatPoint, maxLonPoint;
|
|
||||||
private double referencePointX, referencePointY;
|
|
||||||
private Group raceBorder = new Group();
|
private Group raceBorder = new Group();
|
||||||
|
// Cameras
|
||||||
|
private PerspectiveCamera isometricCam;
|
||||||
|
private PerspectiveCamera topDownCam;
|
||||||
|
private PerspectiveCamera chaseCam;
|
||||||
|
|
||||||
/* Note that if either of these is null then values for it have not been added and the other
|
/* Note that if either of these is null then values for it have not been added and the other
|
||||||
should be used as the limits of the map. */
|
should be used as the limits of the map. */
|
||||||
private List<Limit> borderPoints;
|
|
||||||
private Map<Mark, Marker3D> markerObjects;
|
private Map<Mark, Marker3D> markerObjects;
|
||||||
|
|
||||||
private Map<ClientYacht, BoatObject> boatObjects = new HashMap<>();
|
private Map<ClientYacht, BoatObject> boatObjects = new HashMap<>();
|
||||||
private BoatObject selectedBoat = null;
|
private BoatObject selectedBoat = null;
|
||||||
private Group wakesGroup = new Group();
|
private Group wakesGroup = new Group();
|
||||||
private Group boatObjectGroup = new Group();
|
private Group boatObjectGroup = new Group();
|
||||||
private Group markers = new Group();
|
|
||||||
private Group tokens = new Group();
|
|
||||||
private List<CompoundMark> course = new ArrayList<>();
|
|
||||||
private List<Node> mapTokens;
|
private List<Node> mapTokens;
|
||||||
private AnimationTimer playerBoatAnimationTimer;
|
private AnimationTimer playerBoatAnimationTimer;
|
||||||
private Group trail = new Group();
|
private Group trail = new Group();
|
||||||
private Double windDir;
|
private Double windDir;
|
||||||
|
|
||||||
private enum ScaleDirection {
|
|
||||||
HORIZONTAL,
|
|
||||||
VERTICAL
|
|
||||||
}
|
|
||||||
|
|
||||||
public GameView3D () {
|
public GameView3D () {
|
||||||
camera = new PerspectiveCamera(true);
|
isometricCam = new IsometricCamera(DEFAULT_CAMERA_X, DEFAULT_CAMERA_Y);
|
||||||
camera.getTransforms().addAll(
|
topDownCam = new TopDownCamera();
|
||||||
new Translate(DEFAULT_CAMERA_X,DEFAULT_CAMERA_Y, DEFAULT_CAMERA_DEPTH)
|
chaseCam = new ChaseCamera();
|
||||||
);
|
|
||||||
camera.setFarClip(600);
|
canvasWidth = canvasHeight = 300;
|
||||||
camera.setNearClip(0.1);
|
|
||||||
camera.setFieldOfView(FOV);
|
for (PerspectiveCamera pc : Arrays.asList(isometricCam, topDownCam, chaseCam)) {
|
||||||
|
pc.setFarClip(600);
|
||||||
|
pc.setNearClip(0.1);
|
||||||
|
pc.setFieldOfView(FOV);
|
||||||
|
}
|
||||||
|
|
||||||
gameObjects = new Group();
|
gameObjects = new Group();
|
||||||
root3D = new Group(camera, gameObjects);
|
root3D = new Group(isometricCam, gameObjects);
|
||||||
view = new SubScene(
|
view = new SubScene(
|
||||||
root3D, 1000, 1000, true, SceneAntialiasing.BALANCED
|
root3D, 1000, 1000, true, SceneAntialiasing.BALANCED
|
||||||
);
|
);
|
||||||
view.setCamera(camera);
|
view.setCamera(isometricCam);
|
||||||
camera.getTransforms().add(new Rotate(30, new Point3D(1,0,0)));
|
|
||||||
|
|
||||||
gameObjects.getChildren().addAll(
|
gameObjects.getChildren().addAll(
|
||||||
ModelFactory.importModel(ModelType.OCEAN).getAssets(),
|
ModelFactory.importModel(ModelType.OCEAN).getAssets(),
|
||||||
@@ -111,10 +101,14 @@ public class GameView3D {
|
|||||||
scene.addEventHandler(KeyEvent.KEY_PRESSED, this::cameraMovement);
|
scene.addEventHandler(KeyEvent.KEY_PRESSED, this::cameraMovement);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void updateCourse(List<CompoundMark> newCourse, List<Corner> sequence) {
|
public void updateCourse(List<CompoundMark> newCourse, List<Corner> sequence) {
|
||||||
markerObjects = new HashMap<>();
|
markerObjects = new HashMap<>();
|
||||||
|
compoundMarks = newCourse;
|
||||||
|
|
||||||
for (Corner corner : sequence) { //Makes course out of all compound marks.
|
for (Corner corner : sequence) { //Makes course out of all compound marks.
|
||||||
for (CompoundMark compoundMark : newCourse) {
|
for (CompoundMark compoundMark : newCourse) {
|
||||||
@@ -165,11 +159,13 @@ public class GameView3D {
|
|||||||
|
|
||||||
//Scale race to markers if there is no border.
|
//Scale race to markers if there is no border.
|
||||||
if (borderPoints == null) {
|
if (borderPoints == null) {
|
||||||
rescaleRace(new ArrayList<>(markerObjects.keySet()));
|
scaledPoint = ScaledPoint.makeScaledPoint(
|
||||||
|
canvasWidth, canvasHeight, new ArrayList<>(markerObjects.keySet()), true
|
||||||
|
);
|
||||||
}
|
}
|
||||||
//Move the Markers to initial position.
|
//Move the Markers to initial position.
|
||||||
markerObjects.forEach(((mark, marker) -> {
|
markerObjects.forEach(((mark, marker) -> {
|
||||||
Point2D p2d = findScaledXY(mark.getLat(), mark.getLng());
|
Point2D p2d = scaledPoint.findScaledXY(mark.getLat(), mark.getLng());
|
||||||
marker.setLayoutX(p2d.getX());
|
marker.setLayoutX(p2d.getX());
|
||||||
marker.setLayoutY(p2d.getY());
|
marker.setLayoutY(p2d.getY());
|
||||||
}));
|
}));
|
||||||
@@ -189,7 +185,7 @@ public class GameView3D {
|
|||||||
private void makeAndBindMarker(Mark observableMark, ModelType markerType) {
|
private void makeAndBindMarker(Mark observableMark, ModelType markerType) {
|
||||||
markerObjects.put(observableMark, new Marker3D(markerType));
|
markerObjects.put(observableMark, new Marker3D(markerType));
|
||||||
observableMark.addPositionListener((mark, lat, lon) -> {
|
observableMark.addPositionListener((mark, lat, lon) -> {
|
||||||
Point2D p2d = findScaledXY(lat, lon);
|
Point2D p2d = scaledPoint.findScaledXY(lat, lon);
|
||||||
markerObjects.get(mark).setLayoutX(p2d.getX());
|
markerObjects.get(mark).setLayoutX(p2d.getX());
|
||||||
markerObjects.get(mark).setLayoutY(p2d.getY());
|
markerObjects.get(mark).setLayoutY(p2d.getY());
|
||||||
});
|
});
|
||||||
@@ -204,8 +200,8 @@ public class GameView3D {
|
|||||||
* @return the new gate.
|
* @return the new gate.
|
||||||
*/
|
*/
|
||||||
private Group makeGate(Mark m1, Mark m2, ModelType gateType) {
|
private Group makeGate(Mark m1, Mark m2, ModelType gateType) {
|
||||||
Point2D m1Location = findScaledXY(m1);
|
Point2D m1Location = scaledPoint.findScaledXY(m1);
|
||||||
Point2D m2Location = findScaledXY(m2);
|
Point2D m2Location = scaledPoint.findScaledXY(m2);
|
||||||
|
|
||||||
Group barrier = ModelFactory.importModel(gateType).getAssets();
|
Group barrier = ModelFactory.importModel(gateType).getAssets();
|
||||||
barrier.getTransforms().addAll(
|
barrier.getTransforms().addAll(
|
||||||
@@ -263,191 +259,44 @@ public class GameView3D {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the class variables minLatPoint, maxLatPoint, minLonPoint, maxLonPoint to the point with
|
|
||||||
* the leftmost point, rightmost point, southern most point and northern most point
|
|
||||||
* respectively.
|
|
||||||
*/
|
|
||||||
private void findMinMaxPoint(List<GeoPoint> points) {
|
|
||||||
List<GeoPoint> sortedPoints = new ArrayList<>(points);
|
|
||||||
sortedPoints.sort(Comparator.comparingDouble(GeoPoint::getLat));
|
|
||||||
minLatPoint = new GeoPoint(sortedPoints.get(0).getLat(), sortedPoints.get(0).getLng());
|
|
||||||
GeoPoint maxLat = sortedPoints.get(sortedPoints.size() - 1);
|
|
||||||
maxLatPoint = new GeoPoint(maxLat.getLat(), maxLat.getLng());
|
|
||||||
|
|
||||||
sortedPoints.sort(Comparator.comparingDouble(GeoPoint::getLng));
|
|
||||||
minLonPoint = new GeoPoint(sortedPoints.get(0).getLat(), sortedPoints.get(0).getLng());
|
|
||||||
GeoPoint maxLon = sortedPoints.get(sortedPoints.size() - 1);
|
|
||||||
maxLonPoint = new GeoPoint(maxLon.getLat(), maxLon.getLng());
|
|
||||||
if (maxLonPoint.getLng() - minLonPoint.getLng() > 180) {
|
|
||||||
horizontalInversion = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Calculates the location of a reference point, this is always the point with minimum latitude,
|
|
||||||
* in relation to the canvas.
|
|
||||||
*
|
|
||||||
* @param minLonToMaxLon The horizontal distance between the point of minimum longitude to
|
|
||||||
* maximum longitude.
|
|
||||||
*/
|
|
||||||
private void calculateReferencePointLocation(double minLonToMaxLon) {
|
|
||||||
GeoPoint referencePoint = minLatPoint;
|
|
||||||
double referenceAngle;
|
|
||||||
|
|
||||||
if (scaleDirection == ScaleDirection.HORIZONTAL) {
|
|
||||||
referenceAngle = Math.abs(
|
|
||||||
GeoUtility.getBearingRad(referencePoint, minLonPoint)
|
|
||||||
);
|
|
||||||
referencePointX =
|
|
||||||
-100 + distanceScaleFactor * Math.sin(referenceAngle) * GeoUtility
|
|
||||||
.getDistance(referencePoint, minLonPoint);
|
|
||||||
referenceAngle = Math.abs(GeoUtility.getDistance(referencePoint, maxLatPoint));
|
|
||||||
referencePointY = -100 + canvasHeight - (bufferSize + bufferSize);
|
|
||||||
referencePointY -= distanceScaleFactor * Math.cos(referenceAngle) * GeoUtility
|
|
||||||
.getDistance(referencePoint, maxLatPoint);
|
|
||||||
referencePointY = referencePointY / 2;
|
|
||||||
referencePointY += bufferSize;
|
|
||||||
referencePointY += distanceScaleFactor * Math.cos(referenceAngle) * GeoUtility
|
|
||||||
.getDistance(referencePoint, maxLatPoint);
|
|
||||||
} else {
|
|
||||||
referencePointY = -100 + canvasHeight - bufferSize;
|
|
||||||
referenceAngle = Math.abs(
|
|
||||||
Math.toRadians(
|
|
||||||
GeoUtility.getDistance(referencePoint, minLonPoint)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
referencePointX = -100 + bufferSize;
|
|
||||||
referencePointX += distanceScaleFactor * Math.sin(referenceAngle) * GeoUtility
|
|
||||||
.getDistance(referencePoint, minLonPoint);
|
|
||||||
referencePointX +=
|
|
||||||
((canvasWidth - (bufferSize + bufferSize)) - (minLonToMaxLon * distanceScaleFactor))
|
|
||||||
/ 2;
|
|
||||||
}
|
|
||||||
if (horizontalInversion) {
|
|
||||||
referencePointX = -100 + canvasWidth - bufferSize - (referencePointX - bufferSize);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Finds the scale factor necessary to fit all race markers within the onscreen map and assigns
|
|
||||||
* it to distanceScaleFactor Returns the max horizontal distance of the map.
|
|
||||||
*/
|
|
||||||
private double scaleRaceExtremities() {
|
|
||||||
|
|
||||||
double vertAngle = Math.abs(
|
|
||||||
GeoUtility.getBearingRad(minLatPoint, maxLatPoint)
|
|
||||||
);
|
|
||||||
double vertDistance =
|
|
||||||
Math.cos(vertAngle) * GeoUtility.getDistance(minLatPoint, maxLatPoint);
|
|
||||||
double horiAngle = Math.abs(
|
|
||||||
GeoUtility.getBearingRad(minLonPoint, maxLonPoint)
|
|
||||||
);
|
|
||||||
if (horiAngle <= (Math.PI / 2)) {
|
|
||||||
horiAngle = (Math.PI / 2) - horiAngle;
|
|
||||||
} else {
|
|
||||||
horiAngle = horiAngle - (Math.PI / 2);
|
|
||||||
}
|
|
||||||
double horiDistance =
|
|
||||||
Math.cos(horiAngle) * GeoUtility.getDistance(minLonPoint, maxLonPoint);
|
|
||||||
|
|
||||||
double vertScale = (canvasHeight - (bufferSize + bufferSize)) / vertDistance;
|
|
||||||
|
|
||||||
if ((horiDistance * vertScale) > (canvasWidth - (bufferSize + bufferSize))) {
|
|
||||||
distanceScaleFactor = (canvasWidth - (bufferSize + bufferSize)) / horiDistance;
|
|
||||||
scaleDirection = ScaleDirection.HORIZONTAL;
|
|
||||||
} else {
|
|
||||||
distanceScaleFactor = vertScale;
|
|
||||||
scaleDirection = ScaleDirection.VERTICAL;
|
|
||||||
}
|
|
||||||
return horiDistance;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Point2D findScaledXY(GeoPoint unscaled) {
|
|
||||||
return findScaledXY(unscaled.getLat(), unscaled.getLng());
|
|
||||||
}
|
|
||||||
|
|
||||||
private Point2D findScaledXY(double unscaledLat, double unscaledLon) {
|
|
||||||
double distanceFromReference;
|
|
||||||
double angleFromReference;
|
|
||||||
double xAxisLocation = referencePointX;
|
|
||||||
double yAxisLocation = referencePointY;
|
|
||||||
|
|
||||||
angleFromReference = GeoUtility.getBearingRad(
|
|
||||||
minLatPoint, new GeoPoint(unscaledLat, unscaledLon)
|
|
||||||
);
|
|
||||||
distanceFromReference = GeoUtility.getDistance(
|
|
||||||
minLatPoint, new GeoPoint(unscaledLat, unscaledLon)
|
|
||||||
);
|
|
||||||
if (angleFromReference >= 0 && angleFromReference <= Math.PI / 2) {
|
|
||||||
xAxisLocation += distanceScaleFactor * Math.sin(angleFromReference) * distanceFromReference;
|
|
||||||
yAxisLocation -= distanceScaleFactor * Math.cos(angleFromReference) * distanceFromReference;
|
|
||||||
} else if (angleFromReference >= 0) {
|
|
||||||
angleFromReference = angleFromReference - Math.PI / 2;
|
|
||||||
xAxisLocation += distanceScaleFactor * Math.cos(angleFromReference) * distanceFromReference;
|
|
||||||
yAxisLocation += distanceScaleFactor * Math.sin(angleFromReference) * distanceFromReference;
|
|
||||||
} else if (angleFromReference < 0 && angleFromReference >= -Math.PI / 2) {
|
|
||||||
angleFromReference = Math.abs(angleFromReference);
|
|
||||||
xAxisLocation -= distanceScaleFactor * Math.sin(angleFromReference) * distanceFromReference;
|
|
||||||
yAxisLocation -= distanceScaleFactor * Math.cos(angleFromReference) * distanceFromReference;
|
|
||||||
} else {
|
|
||||||
angleFromReference = Math.abs(angleFromReference) - Math.PI / 2;
|
|
||||||
xAxisLocation -= distanceScaleFactor * Math.cos(angleFromReference) * distanceFromReference;
|
|
||||||
yAxisLocation += distanceScaleFactor * Math.sin(angleFromReference) * distanceFromReference;
|
|
||||||
}
|
|
||||||
if (horizontalInversion) {
|
|
||||||
xAxisLocation = canvasWidth - bufferSize - (xAxisLocation - bufferSize);
|
|
||||||
}
|
|
||||||
return new Point2D(xAxisLocation, yAxisLocation);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void cameraMovement(KeyEvent event) {
|
public void cameraMovement(KeyEvent event) {
|
||||||
switch (event.getCode()) {
|
GameKeyBind keyBinds = GameKeyBind.getInstance();
|
||||||
case NUMPAD8:
|
KeyAction keyPressed = keyBinds.getKeyAction(event.getCode());
|
||||||
camera.getTransforms().addAll(new Rotate(0.5, new Point3D(1,0,0)));
|
switch (keyPressed) {
|
||||||
|
case ZOOM_IN:
|
||||||
|
((RaceCamera) view.getCamera()).zoomIn();
|
||||||
break;
|
break;
|
||||||
case NUMPAD2:
|
case ZOOM_OUT:
|
||||||
camera.getTransforms().addAll(new Rotate(-0.5, new Point3D(1,0,0)));
|
((RaceCamera) view.getCamera()).zoomOut();
|
||||||
break;
|
break;
|
||||||
case NUMPAD4:
|
case FORWARD:
|
||||||
camera.getTransforms().addAll(new Rotate(-0.5, new Point3D(0,1,0)));
|
((RaceCamera) view.getCamera()).panUp();
|
||||||
break;
|
break;
|
||||||
case NUMPAD6:
|
case BACKWARD:
|
||||||
camera.getTransforms().addAll(new Rotate(0.5, new Point3D(0,1,0)));
|
((RaceCamera) view.getCamera()).panDown();
|
||||||
break;
|
break;
|
||||||
case Z:
|
case LEFT:
|
||||||
camera.getTransforms().addAll(new Translate(0, 0, 1.5));
|
((RaceCamera) view.getCamera()).panLeft();
|
||||||
break;
|
break;
|
||||||
case X:
|
case RIGHT:
|
||||||
camera.getTransforms().addAll(new Translate(0, 0, -1.5));
|
((RaceCamera) view.getCamera()).panRight();
|
||||||
break;
|
break;
|
||||||
case W:
|
case VIEW:
|
||||||
camera.getTransforms().addAll(new Translate(0, -1, 0));
|
toggleCamera();
|
||||||
break;
|
|
||||||
case S:
|
|
||||||
camera.getTransforms().addAll(new Translate(0, 1, 0));
|
|
||||||
break;
|
|
||||||
case A:
|
|
||||||
camera.getTransforms().addAll(new Translate(-1, 0, 0));
|
|
||||||
break;
|
|
||||||
case D:
|
|
||||||
camera.getTransforms().addAll(new Translate(1, 0, 0));
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private void toggleCamera() {
|
||||||
* Rescales the race to the size of the window.
|
Camera currCamera = view.getCamera();
|
||||||
*
|
|
||||||
* @param limitingCoordinates the set of geo points that contains the extremities of the race.
|
if (currCamera.equals(isometricCam)) {
|
||||||
*/
|
view.setCamera(topDownCam);
|
||||||
private void rescaleRace(List<GeoPoint> limitingCoordinates) {
|
} else if (currCamera.equals(topDownCam)) {
|
||||||
//Check is called once to avoid unnecessarily change the course limits once the race is running
|
view.setCamera(chaseCam);
|
||||||
findMinMaxPoint(limitingCoordinates);
|
} else {
|
||||||
double minLonToMaxLon = scaleRaceExtremities();
|
view.setCamera(isometricCam);
|
||||||
calculateReferencePointLocation(minLonToMaxLon);
|
}
|
||||||
// drawGoogleMap();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -459,7 +308,7 @@ public class GameView3D {
|
|||||||
final List<Group> wakes = new ArrayList<>();
|
final List<Group> wakes = new ArrayList<>();
|
||||||
for (ClientYacht clientYacht : yachts) {
|
for (ClientYacht clientYacht : yachts) {
|
||||||
Color colour = clientYacht.getColour();
|
Color colour = clientYacht.getColour();
|
||||||
newBoat = new BoatObject();
|
newBoat = new BoatObject(clientYacht.getBoatType());
|
||||||
newBoat.setFill(colour);
|
newBoat.setFill(colour);
|
||||||
boatObjects.put(clientYacht, newBoat);
|
boatObjects.put(clientYacht, newBoat);
|
||||||
wakesGroup.getChildren().add(newBoat.getWake());
|
wakesGroup.getChildren().add(newBoat.getWake());
|
||||||
@@ -467,9 +316,15 @@ public class GameView3D {
|
|||||||
boatObjectGroup.getChildren().add(newBoat);
|
boatObjectGroup.getChildren().add(newBoat);
|
||||||
clientYacht.addLocationListener((boat, lat, lon, heading, sailIn, velocity) -> {
|
clientYacht.addLocationListener((boat, lat, lon, heading, sailIn, velocity) -> {
|
||||||
BoatObject bo = boatObjects.get(boat);
|
BoatObject bo = boatObjects.get(boat);
|
||||||
Point2D p2d = findScaledXY(lat, lon);
|
Point2D p2d = scaledPoint.findScaledXY(lat, lon);
|
||||||
bo.moveTo(p2d.getX(), p2d.getY(), heading, velocity, sailIn, windDir);
|
bo.moveTo(p2d.getX(), p2d.getY(), heading, velocity, sailIn, windDir);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (clientYacht.getSourceId().equals(
|
||||||
|
ViewManager.getInstance().getGameClient().getServerThread().getClientId())) {
|
||||||
|
((ChaseCamera) chaseCam).setPlayerBoat(newBoat);
|
||||||
|
((TopDownCamera) topDownCam).setPlayerBoat(newBoat);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Platform.runLater(() -> {
|
Platform.runLater(() -> {
|
||||||
gameObjects.getChildren().addAll(wakes);
|
gameObjects.getChildren().addAll(wakes);
|
||||||
@@ -490,18 +345,20 @@ public class GameView3D {
|
|||||||
public void updateBorder(List<Limit> border) {
|
public void updateBorder(List<Limit> border) {
|
||||||
if (borderPoints == null) {
|
if (borderPoints == null) {
|
||||||
borderPoints = border;
|
borderPoints = border;
|
||||||
rescaleRace(new ArrayList<>(borderPoints));
|
scaledPoint = ScaledPoint.makeScaledPoint(
|
||||||
|
canvasWidth, canvasHeight, new ArrayList<>(borderPoints), true
|
||||||
|
);
|
||||||
}
|
}
|
||||||
List<Node> boundaryAssets = new ArrayList<>();
|
List<Node> boundaryAssets = new ArrayList<>();
|
||||||
|
|
||||||
Point2D lastLocation = findScaledXY(border.get(0).getLat(), border.get(0).getLng());
|
Point2D lastLocation = scaledPoint.findScaledXY(border.get(0).getLat(), border.get(0).getLng());
|
||||||
Group pylon = ModelFactory.importModel(ModelType.BORDER_PYLON).getAssets();
|
Group pylon = ModelFactory.importModel(ModelType.BORDER_PYLON).getAssets();
|
||||||
pylon.setLayoutX(lastLocation.getX());
|
pylon.setLayoutX(lastLocation.getX());
|
||||||
pylon.setLayoutY(lastLocation.getY());
|
pylon.setLayoutY(lastLocation.getY());
|
||||||
boundaryAssets.add(pylon);
|
boundaryAssets.add(pylon);
|
||||||
|
|
||||||
for (int i=1; i<border.size(); i++) {
|
for (int i=1; i<border.size(); i++) {
|
||||||
Point2D location = findScaledXY(border.get(i).getLat(), border.get(i).getLng());
|
Point2D location = scaledPoint.findScaledXY(border.get(i).getLat(), border.get(i).getLng());
|
||||||
pylon = ModelFactory.importModel(ModelType.BORDER_PYLON).getAssets();
|
pylon = ModelFactory.importModel(ModelType.BORDER_PYLON).getAssets();
|
||||||
pylon.setLayoutX(location.getX());
|
pylon.setLayoutX(location.getX());
|
||||||
pylon.setLayoutY(location.getY());
|
pylon.setLayoutY(location.getY());
|
||||||
@@ -527,7 +384,7 @@ public class GameView3D {
|
|||||||
boundaryAssets.add(pylon);
|
boundaryAssets.add(pylon);
|
||||||
}
|
}
|
||||||
|
|
||||||
Point2D firstLocation = findScaledXY(border.get(0).getLat(), border.get(0).getLng());
|
Point2D firstLocation = scaledPoint.findScaledXY(border.get(0).getLat(), border.get(0).getLng());
|
||||||
Group barrier = ModelFactory.importModel(ModelType.BORDER_BARRIER).getAssets();
|
Group barrier = ModelFactory.importModel(ModelType.BORDER_BARRIER).getAssets();
|
||||||
barrier.getTransforms().addAll(
|
barrier.getTransforms().addAll(
|
||||||
new Rotate(
|
new Rotate(
|
||||||
@@ -555,7 +412,7 @@ public class GameView3D {
|
|||||||
public void updateTokens(List<Token> newTokens) {
|
public void updateTokens(List<Token> newTokens) {
|
||||||
mapTokens = new ArrayList<>();
|
mapTokens = new ArrayList<>();
|
||||||
for (Token token : newTokens) {
|
for (Token token : newTokens) {
|
||||||
Point2D location = findScaledXY(token.getLat(), token.getLng());
|
Point2D location = scaledPoint.findScaledXY(token.getLat(), token.getLng());
|
||||||
Node tokenObject = ModelFactory.importModel(ModelType.VELOCITY_PICKUP).getAssets();
|
Node tokenObject = ModelFactory.importModel(ModelType.VELOCITY_PICKUP).getAssets();
|
||||||
tokenObject.setLayoutX(location.getX());
|
tokenObject.setLayoutX(location.getX());
|
||||||
tokenObject.setLayoutY(location.getY());
|
tokenObject.setLayoutY(location.getY());
|
||||||
@@ -568,21 +425,20 @@ public class GameView3D {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void setBoatAsPlayer (ClientYacht playerYacht) {
|
public void setBoatAsPlayer (ClientYacht playerYacht) {
|
||||||
|
playerYacht.toggleSail();
|
||||||
playerBoatAnimationTimer = new AnimationTimer() {
|
playerBoatAnimationTimer = new AnimationTimer() {
|
||||||
|
|
||||||
double count = 60;
|
Point2D lastLocation = scaledPoint.findScaledXY(playerYacht.getLocation());
|
||||||
Point2D lastLocation = findScaledXY(playerYacht.getLocation());
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handle(long now) {
|
public void handle(long now) {
|
||||||
if (--count == 0) {
|
Point2D location = scaledPoint.findScaledXY(playerYacht.getLocation());
|
||||||
count = 60;
|
if (Math.abs(lastLocation.distance(location)) > 2) {
|
||||||
Node segment = ModelFactory.importModel(ModelType.TRAIL_SEGMENT).getAssets();
|
Node segment = ModelFactory.importModel(ModelType.TRAIL_SEGMENT).getAssets();
|
||||||
Point2D location = findScaledXY(playerYacht.getLocation());
|
location = scaledPoint.findScaledXY(playerYacht.getLocation());
|
||||||
segment.getTransforms().addAll(
|
segment.getTransforms().addAll(
|
||||||
new Translate(location.getX(), location.getY(), 0),
|
new Translate(location.getX(), location.getY(), 0),
|
||||||
new Rotate(playerYacht.getHeading(), new Point3D(0,0,1)),
|
new Rotate(playerYacht.getHeading(), new Point3D(0,0,1))
|
||||||
new Scale(1, lastLocation.distance(location) / 5, 1)
|
|
||||||
);
|
);
|
||||||
trail.getChildren().add(segment);
|
trail.getChildren().add(segment);
|
||||||
if (trail.getChildren().size() > 50) {
|
if (trail.getChildren().size() > 50) {
|
||||||
|
|||||||
@@ -0,0 +1,120 @@
|
|||||||
|
package seng302.visualiser;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.StringReader;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import javafx.scene.Node;
|
||||||
|
import javafx.util.Pair;
|
||||||
|
import javax.xml.parsers.DocumentBuilder;
|
||||||
|
import javax.xml.parsers.DocumentBuilderFactory;
|
||||||
|
import javax.xml.parsers.ParserConfigurationException;
|
||||||
|
import org.w3c.dom.Document;
|
||||||
|
import org.xml.sax.InputSource;
|
||||||
|
import org.xml.sax.SAXException;
|
||||||
|
import seng302.model.stream.xml.generator.RaceXMLTemplate;
|
||||||
|
import seng302.model.stream.xml.generator.RegattaXMLTemplate;
|
||||||
|
import seng302.model.stream.xml.parser.RaceXMLData;
|
||||||
|
import seng302.model.stream.xml.parser.RegattaXMLData;
|
||||||
|
import seng302.utilities.XMLGenerator;
|
||||||
|
import seng302.utilities.XMLParser;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Makes maps from map definition xml files.
|
||||||
|
*/
|
||||||
|
public class MapMaker {
|
||||||
|
|
||||||
|
private List<MapPreview> mapPreviews = new ArrayList<>();
|
||||||
|
private List<RaceXMLData> races = new ArrayList<>();
|
||||||
|
private List<RegattaXMLData> regattas = new ArrayList<>();
|
||||||
|
private List<String> filePaths = new ArrayList<>();
|
||||||
|
private List<Integer> maxPlayers = new ArrayList<>();
|
||||||
|
private static MapMaker instance;
|
||||||
|
private int index = 0;
|
||||||
|
private XMLGenerator xmlGenerator = new XMLGenerator();
|
||||||
|
|
||||||
|
public static MapMaker getInstance() {
|
||||||
|
if (instance == null) {
|
||||||
|
instance = new MapMaker();
|
||||||
|
}
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
private MapMaker() {
|
||||||
|
File dir = new File(MapMaker.class.getResource("/maps/").getPath());
|
||||||
|
File[] directoryListing = dir.listFiles();
|
||||||
|
if (directoryListing != null) {
|
||||||
|
for (File child : directoryListing) {
|
||||||
|
Pair<RegattaXMLTemplate, RaceXMLTemplate> regattaRace = XMLParser.parseRaceDef(
|
||||||
|
child.getAbsolutePath(), "", 1, null, false
|
||||||
|
);
|
||||||
|
filePaths.add(child.getAbsolutePath());
|
||||||
|
RegattaXMLTemplate regattaTemplate = regattaRace.getKey();
|
||||||
|
regattas.add(new RegattaXMLData(
|
||||||
|
regattaTemplate.getRegattaId(),
|
||||||
|
regattaTemplate.getName(),
|
||||||
|
regattaTemplate.getCourseName(),
|
||||||
|
regattaTemplate.getLatitude(),
|
||||||
|
regattaTemplate.getLongitude(),
|
||||||
|
regattaTemplate.getUtcOffset()
|
||||||
|
));
|
||||||
|
|
||||||
|
RaceXMLTemplate raceTemplate = regattaRace.getValue();
|
||||||
|
xmlGenerator.setRaceTemplate(raceTemplate);
|
||||||
|
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
|
||||||
|
DocumentBuilder db;
|
||||||
|
Document doc = null;
|
||||||
|
try {
|
||||||
|
db = dbf.newDocumentBuilder();
|
||||||
|
doc = db.parse(new InputSource(new StringReader(xmlGenerator.getRaceAsXml())));
|
||||||
|
} catch (ParserConfigurationException | IOException | SAXException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
RaceXMLData race = XMLParser.parseRace(doc);
|
||||||
|
maxPlayers.add(XMLParser.getMaxPlayers(doc));
|
||||||
|
|
||||||
|
mapPreviews.add(new MapPreview(
|
||||||
|
new ArrayList<>(race.getCompoundMarks().values()),
|
||||||
|
race.getMarkSequence(), race.getCourseLimit()
|
||||||
|
));
|
||||||
|
races.add(race);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void next() {
|
||||||
|
index += 1;
|
||||||
|
if (index >= mapPreviews.size()) {
|
||||||
|
index = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void previous() {
|
||||||
|
index -= 1;
|
||||||
|
if (index < 0) {
|
||||||
|
index = mapPreviews.size() - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Node getCurrentGameView() {
|
||||||
|
return mapPreviews.get(index).getAssets();
|
||||||
|
}
|
||||||
|
|
||||||
|
public RaceXMLData getCurrentRace() {
|
||||||
|
return races.get(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
public RegattaXMLData getCurrentRegatta() {
|
||||||
|
return regattas.get(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCurrentRacePath() {
|
||||||
|
return filePaths.get(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getMaxPlayers() {
|
||||||
|
return maxPlayers.get(index);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,283 @@
|
|||||||
|
package seng302.visualiser;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import javafx.application.Platform;
|
||||||
|
import javafx.geometry.Point2D;
|
||||||
|
import javafx.scene.Node;
|
||||||
|
import javafx.scene.paint.Color;
|
||||||
|
import javafx.scene.paint.Paint;
|
||||||
|
import javafx.scene.shape.Polygon;
|
||||||
|
import seng302.gameServer.messages.RoundingSide;
|
||||||
|
import seng302.model.GeoPoint;
|
||||||
|
import seng302.model.Limit;
|
||||||
|
import seng302.model.ScaledPoint;
|
||||||
|
import seng302.model.mark.CompoundMark;
|
||||||
|
import seng302.model.mark.Corner;
|
||||||
|
import seng302.model.mark.Mark;
|
||||||
|
import seng302.utilities.GeoUtility;
|
||||||
|
import seng302.visualiser.fxObjects.MarkArrowFactory;
|
||||||
|
import seng302.visualiser.fxObjects.assets_2D.CourseBoundary;
|
||||||
|
import seng302.visualiser.fxObjects.assets_2D.Gate;
|
||||||
|
import seng302.visualiser.fxObjects.assets_2D.Marker2D;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by cir27 on 20/07/17.
|
||||||
|
*/
|
||||||
|
public class MapPreview extends GameView {
|
||||||
|
|
||||||
|
private Polygon raceBorder = new CourseBoundary();
|
||||||
|
private Map<Mark, Marker2D> markerObjects;
|
||||||
|
|
||||||
|
public MapPreview(List<CompoundMark> marks, List<Corner> course, List<Limit> border) {
|
||||||
|
this.compoundMarks = marks;
|
||||||
|
this.courseOrder = course;
|
||||||
|
this.borderPoints = border;
|
||||||
|
gameObjects.getChildren().addAll(raceBorder, markers, tokens);
|
||||||
|
gameObjects.parentProperty().addListener((obs, old, parent) -> {
|
||||||
|
if (parent != null) {
|
||||||
|
canvasWidth = parent.prefWidth(1);
|
||||||
|
canvasHeight = parent.prefHeight(1);
|
||||||
|
updateBorder(borderPoints);
|
||||||
|
updateCourse(compoundMarks, courseOrder);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Node getAssets() {
|
||||||
|
return gameObjects;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSize(double width, double height) {
|
||||||
|
canvasHeight = height;
|
||||||
|
canvasWidth = width;
|
||||||
|
updateBorder(borderPoints);
|
||||||
|
updateCourse(compoundMarks, courseOrder);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a course to the GameView. The view is scaled accordingly unless a border is set in which
|
||||||
|
* case the course is added relative ot the border.
|
||||||
|
*
|
||||||
|
* @param newCourse the mark objects that make up the course.
|
||||||
|
* @param sequence The sequence the marks travel through
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void updateCourse(List<CompoundMark> newCourse, List<Corner> sequence) {
|
||||||
|
|
||||||
|
if (newCourse.size() == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
compoundMarks = newCourse;
|
||||||
|
markerObjects = new HashMap<>();
|
||||||
|
courseOrder = sequence;
|
||||||
|
|
||||||
|
for (Corner corner : courseOrder) { //Makes course out of all compound marks.
|
||||||
|
for (CompoundMark compoundMark : newCourse) {
|
||||||
|
if (corner.getCompoundMarkID() == compoundMark.getId()) {
|
||||||
|
course.add(compoundMark);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: 16/08/17 Updating mark roundings here. It should not happen here. Nor should it be done this way.
|
||||||
|
for (Corner corner : sequence){
|
||||||
|
CompoundMark compoundMark = course.get(corner.getSeqID() - 1);
|
||||||
|
compoundMark.setRoundingSide(
|
||||||
|
RoundingSide.getRoundingSide(corner.getRounding())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
final List<Gate> gates = new ArrayList<>();
|
||||||
|
Paint colour = Color.BLACK;
|
||||||
|
//Creates new markers
|
||||||
|
for (CompoundMark cMark : newCourse) {
|
||||||
|
//Set start and end colour
|
||||||
|
if (cMark.getId() == sequence.get(0).getCompoundMarkID()) {
|
||||||
|
colour = Color.GREEN;
|
||||||
|
} else if (cMark.getId() == sequence.get(sequence.size() - 1).getCompoundMarkID()) {
|
||||||
|
colour = Color.RED;
|
||||||
|
}
|
||||||
|
//Create mark dots
|
||||||
|
for (Mark mark : cMark.getMarks()) {
|
||||||
|
makeAndBindMarker(mark, colour);
|
||||||
|
}
|
||||||
|
//Create gate line
|
||||||
|
if (cMark.isGate()) {
|
||||||
|
for (int i = 1; i < cMark.getMarks().size(); i++) {
|
||||||
|
gates.add(
|
||||||
|
makeAndBindGate(
|
||||||
|
markerObjects.get(cMark.getSubMark(i)),
|
||||||
|
markerObjects.get(cMark.getSubMark(i + 1)),
|
||||||
|
colour
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
colour = Color.BLACK;
|
||||||
|
}
|
||||||
|
|
||||||
|
createMarkArrows(sequence);
|
||||||
|
|
||||||
|
//Scale race to markers if there is no border.
|
||||||
|
if (borderPoints == null) {
|
||||||
|
scaledPoint = ScaledPoint.makeScaledPoint(
|
||||||
|
canvasWidth, canvasHeight, new ArrayList<>(markerObjects.keySet()), false
|
||||||
|
);
|
||||||
|
}
|
||||||
|
//Move the Markers to initial position.
|
||||||
|
markerObjects.forEach(((mark, marker2D) -> {
|
||||||
|
Point2D p2d = scaledPoint.findScaledXY(mark.getLat(), mark.getLng());
|
||||||
|
marker2D.setLayoutX(p2d.getX());
|
||||||
|
marker2D.setLayoutY(p2d.getY());
|
||||||
|
}));
|
||||||
|
Platform.runLater(() -> {
|
||||||
|
markers.getChildren().clear();
|
||||||
|
markers.getChildren().addAll(gates);
|
||||||
|
markers.getChildren().addAll(markerObjects.values());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculates all the data needed for to create mark arrows. Requires that a course has been
|
||||||
|
* added to the gameview.
|
||||||
|
* @param sequence The order in which marks are traversed.
|
||||||
|
*/
|
||||||
|
private void createMarkArrows (List<Corner> sequence) {
|
||||||
|
for (int i=1; i < sequence.size()-1; i++) { //General case.
|
||||||
|
double averageLat = 0;
|
||||||
|
double averageLng = 0;
|
||||||
|
int numMarks = course.get(i-1).getMarks().size();
|
||||||
|
for (Mark mark : course.get(i-1).getMarks()) {
|
||||||
|
averageLat += mark.getLat();
|
||||||
|
averageLng += mark.getLng();
|
||||||
|
}
|
||||||
|
GeoPoint lastMarkAv = new GeoPoint(averageLat / numMarks, averageLng / numMarks);
|
||||||
|
numMarks = course.get(i+1).getMarks().size();
|
||||||
|
averageLat = 0;
|
||||||
|
averageLng = 0;
|
||||||
|
for (Mark mark : course.get(i+1).getMarks()) {
|
||||||
|
averageLat += mark.getLat();
|
||||||
|
averageLng += mark.getLng();
|
||||||
|
}
|
||||||
|
GeoPoint nextMarkAv = new GeoPoint(averageLat / numMarks, averageLng / numMarks);
|
||||||
|
// TODO: 16/08/17 This comparison doesn't need to exist but the alternative is to user server enum client side.
|
||||||
|
for (Mark mark : course.get(i).getMarks()) {
|
||||||
|
markerObjects.get(mark).addArrows(
|
||||||
|
mark.getRoundingSide() == RoundingSide.STARBOARD ? MarkArrowFactory.RoundingSide.STARBOARD : MarkArrowFactory.RoundingSide.PORT,
|
||||||
|
GeoUtility.getBearing(lastMarkAv, mark),
|
||||||
|
GeoUtility.getBearing(mark, nextMarkAv)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
createStartLineArrows();
|
||||||
|
createFinishLineArrows();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createStartLineArrows () {
|
||||||
|
double averageLat = 0;
|
||||||
|
double averageLng = 0;
|
||||||
|
int numMarks = 0;
|
||||||
|
for (Mark mark : course.get(1).getMarks()) {
|
||||||
|
numMarks += 1;
|
||||||
|
averageLat += mark.getLat();
|
||||||
|
averageLng += mark.getLng();
|
||||||
|
}
|
||||||
|
GeoPoint firstMarkAv = new GeoPoint(averageLat / numMarks, averageLng / numMarks);
|
||||||
|
for (Mark mark : course.get(0).getMarks()) {
|
||||||
|
markerObjects.get(mark).addArrows(
|
||||||
|
mark.getRoundingSide() == RoundingSide.STARBOARD ? MarkArrowFactory.RoundingSide.STARBOARD : MarkArrowFactory.RoundingSide.PORT,
|
||||||
|
0d, //90
|
||||||
|
GeoUtility.getBearing(mark, firstMarkAv)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createFinishLineArrows () {
|
||||||
|
double numMarks = 0;
|
||||||
|
double averageLat = 0;
|
||||||
|
double averageLng = 0;
|
||||||
|
for (Mark mark : course.get(course.size()-2).getMarks()) {
|
||||||
|
numMarks += 1;
|
||||||
|
averageLat += mark.getLat();
|
||||||
|
averageLng += mark.getLng();
|
||||||
|
}
|
||||||
|
GeoPoint secondToLastMarkAv = new GeoPoint(averageLat / numMarks, averageLng / numMarks);
|
||||||
|
for (Mark mark : course.get(course.size()-1).getMarks()) {
|
||||||
|
markerObjects.get(mark).addArrows(
|
||||||
|
mark.getRoundingSide() == RoundingSide.STARBOARD ? MarkArrowFactory.RoundingSide.STARBOARD : MarkArrowFactory.RoundingSide.PORT,
|
||||||
|
GeoUtility.getBearing(secondToLastMarkAv, mark),
|
||||||
|
GeoUtility.getBearing(mark, mark)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new Marker and binds it's position to the given Mark.
|
||||||
|
*
|
||||||
|
* @param observableMark The mark to bind the marker to.
|
||||||
|
* @param colour The desired colour of the mark
|
||||||
|
*/
|
||||||
|
private void makeAndBindMarker(Mark observableMark, Paint colour) {
|
||||||
|
Marker2D marker2D = new Marker2D(colour);
|
||||||
|
// marker.addArrows(MarkArrowFactory.RoundingSide.PORT, ThreadLocalRandom.current().nextDouble(91, 180), ThreadLocalRandom.current().nextDouble(1, 90));
|
||||||
|
markerObjects.put(observableMark, marker2D);
|
||||||
|
observableMark.addPositionListener((mark, lat, lon) -> {
|
||||||
|
Point2D p2d = scaledPoint.findScaledXY(lat, lon);
|
||||||
|
markerObjects.get(mark).setLayoutX(p2d.getX());
|
||||||
|
markerObjects.get(mark).setLayoutY(p2d.getY());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new gate connecting the given marks.
|
||||||
|
*
|
||||||
|
* @param m1 The first Mark of the gate.
|
||||||
|
* @param m2 The second Mark of the gate.
|
||||||
|
* @param colour The desired colour of the gate.
|
||||||
|
* @return the new gate.
|
||||||
|
*/
|
||||||
|
private Gate makeAndBindGate(Marker2D m1, Marker2D m2, Paint colour) {
|
||||||
|
Gate gate = new Gate(colour);
|
||||||
|
gate.startXProperty().bind(
|
||||||
|
m1.layoutXProperty()
|
||||||
|
);
|
||||||
|
gate.startYProperty().bind(
|
||||||
|
m1.layoutYProperty()
|
||||||
|
);
|
||||||
|
gate.endXProperty().bind(
|
||||||
|
m2.layoutXProperty()
|
||||||
|
);
|
||||||
|
gate.endYProperty().bind(
|
||||||
|
m2.layoutYProperty()
|
||||||
|
);
|
||||||
|
return gate;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a border to the GameView and rescales to the size of the border, does not rescale if a
|
||||||
|
* border already exists. Assumes the border is larger than the course.
|
||||||
|
*
|
||||||
|
* @param border the race border to be drawn.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void updateBorder(List<Limit> border) {
|
||||||
|
if (border.size() == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
borderPoints = border;
|
||||||
|
scaledPoint = ScaledPoint.makeScaledPoint(canvasWidth, canvasHeight, border, false);
|
||||||
|
|
||||||
|
List<Double> boundaryPoints = new ArrayList<>();
|
||||||
|
for (Limit limit : border) {
|
||||||
|
Point2D location = scaledPoint.findScaledXY(limit.getLat(), limit.getLng());
|
||||||
|
boundaryPoints.add(location.getX());
|
||||||
|
boundaryPoints.add(location.getY());
|
||||||
|
}
|
||||||
|
raceBorder.getPoints().setAll(boundaryPoints);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,130 @@
|
|||||||
|
package seng302.visualiser.cameras;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import javafx.beans.property.DoubleProperty;
|
||||||
|
import javafx.collections.ObservableList;
|
||||||
|
import javafx.geometry.Point3D;
|
||||||
|
import javafx.scene.PerspectiveCamera;
|
||||||
|
import javafx.scene.transform.Rotate;
|
||||||
|
import javafx.scene.transform.Transform;
|
||||||
|
import javafx.scene.transform.Translate;
|
||||||
|
import seng302.visualiser.fxObjects.assets_3D.BoatObject;
|
||||||
|
|
||||||
|
|
||||||
|
public class ChaseCamera extends PerspectiveCamera implements RaceCamera {
|
||||||
|
|
||||||
|
private final Double VERTICAL_PAN_LIMIT = 20.0;
|
||||||
|
private final Double NEAR_ZOOM_LIMIT = -15.0;
|
||||||
|
private final Double FAR_ZOOM_LIMIT = -125.0;
|
||||||
|
|
||||||
|
private final Double ZOOM_STEP = 2.5;
|
||||||
|
private final Double PAN_STEP = 2.5;
|
||||||
|
|
||||||
|
private ObservableList<Transform> transforms;
|
||||||
|
private BoatObject playerBoat;
|
||||||
|
|
||||||
|
private Double zoomFactor;
|
||||||
|
private Double horizontalPan;
|
||||||
|
private Double verticalPan;
|
||||||
|
|
||||||
|
|
||||||
|
public ChaseCamera() {
|
||||||
|
super(true);
|
||||||
|
transforms = this.getTransforms();
|
||||||
|
|
||||||
|
zoomFactor = (FAR_ZOOM_LIMIT + NEAR_ZOOM_LIMIT) / 2.0;
|
||||||
|
this.horizontalPan = 0.0;
|
||||||
|
this.verticalPan = 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets a player boat object to observe and update the camera with.
|
||||||
|
*
|
||||||
|
* @param playerBoat The player boat to be observed.
|
||||||
|
*/
|
||||||
|
public void setPlayerBoat(BoatObject playerBoat) {
|
||||||
|
this.playerBoat = playerBoat;
|
||||||
|
|
||||||
|
for (DoubleProperty o : Arrays
|
||||||
|
.asList(playerBoat.getRotationProperty(), playerBoat.layoutYProperty(),
|
||||||
|
playerBoat.layoutXProperty())) {
|
||||||
|
o.addListener((obs, oldVal, newVal) -> repositionCamera());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Moves the camera to a new position after some change (Zooming or Panning)
|
||||||
|
*/
|
||||||
|
private void repositionCamera() {
|
||||||
|
transforms.clear();
|
||||||
|
transforms.addAll(
|
||||||
|
new Translate(playerBoat.getLayoutX(), playerBoat.getLayoutY(), 0),
|
||||||
|
new Rotate(playerBoat.getRotationProperty().getValue() + horizontalPan,
|
||||||
|
new Point3D(0, 0, 1)),
|
||||||
|
new Rotate(60 + verticalPan, new Point3D(1, 0, 0)),
|
||||||
|
new Translate(0, 0, zoomFactor)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adjusts the zoom amount (camera depth) by some adjustment value
|
||||||
|
* @param adjustment the adjustment to be made to the camera
|
||||||
|
*/
|
||||||
|
private void adjustZoomFactor(Double adjustment) {
|
||||||
|
if (zoomFactor + adjustment < NEAR_ZOOM_LIMIT && zoomFactor + adjustment > FAR_ZOOM_LIMIT) {
|
||||||
|
zoomFactor = zoomFactor + adjustment;
|
||||||
|
repositionCamera();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adjusts the Vertical Panning of the Camera
|
||||||
|
* @param adjustment the adjustment to be made to the camera
|
||||||
|
*/
|
||||||
|
private void adjustVerticalPan(Double adjustment) {
|
||||||
|
if (verticalPan + adjustment >= -VERTICAL_PAN_LIMIT
|
||||||
|
&& verticalPan + adjustment <= VERTICAL_PAN_LIMIT) {
|
||||||
|
verticalPan += adjustment;
|
||||||
|
repositionCamera();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adjusts the Horizontal Panning of the Camera.
|
||||||
|
* @param adjustment the adjustment to be made to the camera
|
||||||
|
*/
|
||||||
|
private void adjustHorizontalPan(Double adjustment) {
|
||||||
|
this.horizontalPan += adjustment;
|
||||||
|
repositionCamera();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void zoomIn() {
|
||||||
|
adjustZoomFactor(ZOOM_STEP);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void zoomOut() {
|
||||||
|
adjustZoomFactor(-ZOOM_STEP);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void panLeft() {
|
||||||
|
adjustHorizontalPan(-PAN_STEP);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void panRight() {
|
||||||
|
adjustHorizontalPan(PAN_STEP);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void panUp() {
|
||||||
|
adjustVerticalPan(-PAN_STEP);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void panDown() {
|
||||||
|
adjustVerticalPan(PAN_STEP);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,113 @@
|
|||||||
|
package seng302.visualiser.cameras;
|
||||||
|
|
||||||
|
import javafx.collections.ObservableList;
|
||||||
|
import javafx.geometry.Point3D;
|
||||||
|
import javafx.scene.PerspectiveCamera;
|
||||||
|
import javafx.scene.transform.Rotate;
|
||||||
|
import javafx.scene.transform.Transform;
|
||||||
|
import javafx.scene.transform.Translate;
|
||||||
|
|
||||||
|
public class IsometricCamera extends PerspectiveCamera implements RaceCamera {
|
||||||
|
|
||||||
|
private final Double MIN_X = -120.0;
|
||||||
|
private final Double MAX_X = 125.0;
|
||||||
|
|
||||||
|
private final Double MIN_Y = 40.0;
|
||||||
|
private final Double MAX_Y = 170.0;
|
||||||
|
|
||||||
|
private final Double PAN_LIMIT = 160.0;
|
||||||
|
private final Double NEAR_ZOOM_LIMIT = -50.0;
|
||||||
|
private final Double FAR_ZOOM_LIMIT = -160.0;
|
||||||
|
|
||||||
|
private Double horizontalPan;
|
||||||
|
private Double verticalPan;
|
||||||
|
private Double zoomFactor;
|
||||||
|
|
||||||
|
private ObservableList<Transform> transforms;
|
||||||
|
|
||||||
|
public IsometricCamera(Double cameraStartX, Double cameraStartY) {
|
||||||
|
super(true);
|
||||||
|
transforms = this.getTransforms();
|
||||||
|
|
||||||
|
zoomFactor = (FAR_ZOOM_LIMIT + NEAR_ZOOM_LIMIT) / 2.0;
|
||||||
|
horizontalPan = cameraStartX;
|
||||||
|
verticalPan = cameraStartY;
|
||||||
|
|
||||||
|
updateCamera();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Moves the camera to a new position after some change (Zooming or Panning)
|
||||||
|
*/
|
||||||
|
private void updateCamera() {
|
||||||
|
transforms.clear();
|
||||||
|
transforms.addAll(
|
||||||
|
new Translate(horizontalPan, verticalPan, zoomFactor),
|
||||||
|
new Rotate(30, new Point3D(1, 0, 0))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adjusts the zoom amount (camera depth) by some adjustment value
|
||||||
|
*
|
||||||
|
* @param adjustment the adjustment to be made to the camera
|
||||||
|
*/
|
||||||
|
private void adjustZoomFactor(Double adjustment) {
|
||||||
|
if (zoomFactor + adjustment < NEAR_ZOOM_LIMIT && zoomFactor + adjustment > FAR_ZOOM_LIMIT) {
|
||||||
|
zoomFactor = zoomFactor + adjustment;
|
||||||
|
updateCamera();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adjusts the Vertical Panning of the Camera
|
||||||
|
* @param adjustment the adjustment to be made to the camera
|
||||||
|
*/
|
||||||
|
private void adjustVerticalPan(Double adjustment) {
|
||||||
|
if (verticalPan + adjustment >= MIN_Y && verticalPan + adjustment <= MAX_Y) {
|
||||||
|
verticalPan += adjustment;
|
||||||
|
updateCamera();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adjusts the Horizontal Panning of the Camera.
|
||||||
|
* @param adjustment the adjustment to be made to the camera
|
||||||
|
*/
|
||||||
|
private void adjustHorizontalPan(Double adjustment) {
|
||||||
|
if (horizontalPan + adjustment >= MIN_X && horizontalPan + adjustment <= MIN_Y) {
|
||||||
|
this.horizontalPan += adjustment;
|
||||||
|
updateCamera();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void zoomIn() {
|
||||||
|
adjustZoomFactor(-2.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void zoomOut() {
|
||||||
|
adjustZoomFactor(2.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void panLeft() {
|
||||||
|
adjustHorizontalPan(-2.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void panRight() {
|
||||||
|
adjustHorizontalPan(2.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void panUp() {
|
||||||
|
adjustVerticalPan(-2.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void panDown() {
|
||||||
|
adjustVerticalPan(2.5);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
package seng302.visualiser.cameras;
|
||||||
|
|
||||||
|
|
||||||
|
public interface RaceCamera {
|
||||||
|
|
||||||
|
void zoomIn();
|
||||||
|
|
||||||
|
void zoomOut();
|
||||||
|
|
||||||
|
void panLeft();
|
||||||
|
|
||||||
|
void panRight();
|
||||||
|
|
||||||
|
void panUp();
|
||||||
|
|
||||||
|
void panDown();
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,123 @@
|
|||||||
|
package seng302.visualiser.cameras;
|
||||||
|
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import javafx.beans.property.DoubleProperty;
|
||||||
|
import javafx.collections.ObservableList;
|
||||||
|
import javafx.scene.PerspectiveCamera;
|
||||||
|
import javafx.scene.transform.Transform;
|
||||||
|
import javafx.scene.transform.Translate;
|
||||||
|
import seng302.visualiser.fxObjects.assets_3D.BoatObject;
|
||||||
|
|
||||||
|
public class TopDownCamera extends PerspectiveCamera implements RaceCamera {
|
||||||
|
|
||||||
|
private final Double PAN_LIMIT = 30.0;
|
||||||
|
private final Double NEAR_ZOOM_LIMIT = -30.0;
|
||||||
|
private final Double FAR_ZOOM_LIMIT = -130.0;
|
||||||
|
private final Double ZOOM_STEP = 2.5;
|
||||||
|
|
||||||
|
private ObservableList<Transform> transforms;
|
||||||
|
private BoatObject playerBoat;
|
||||||
|
|
||||||
|
private Double zoomFactor;
|
||||||
|
private Double horizontalPan;
|
||||||
|
private Double verticalPan;
|
||||||
|
|
||||||
|
public TopDownCamera() {
|
||||||
|
super(true);
|
||||||
|
transforms = this.getTransforms();
|
||||||
|
|
||||||
|
zoomFactor = (FAR_ZOOM_LIMIT + NEAR_ZOOM_LIMIT) / 2.0;
|
||||||
|
horizontalPan = 0.0;
|
||||||
|
verticalPan = 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets a player boat object to observe and update the camera with.
|
||||||
|
*
|
||||||
|
* @param playerBoat The player boat to be observed.
|
||||||
|
*/
|
||||||
|
public void setPlayerBoat(BoatObject playerBoat) {
|
||||||
|
this.playerBoat = playerBoat;
|
||||||
|
|
||||||
|
for (DoubleProperty o : Arrays
|
||||||
|
.asList(playerBoat.layoutXProperty(), playerBoat.layoutYProperty())) {
|
||||||
|
o.addListener((obs, oldVal, newVal) -> updateCamera());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Moves the camera to a new position after some change (Zooming or Panning)
|
||||||
|
*/
|
||||||
|
private void updateCamera() {
|
||||||
|
transforms.clear();
|
||||||
|
transforms.addAll(
|
||||||
|
new Translate(playerBoat.getLayoutX() + horizontalPan,
|
||||||
|
playerBoat.getLayoutY() + verticalPan, zoomFactor)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adjusts the zoom amount (camera depth) by some adjustment value
|
||||||
|
* @param adjustment the adjustment to be made to the camera
|
||||||
|
*/
|
||||||
|
private void adjustZoomFactor(Double adjustment) {
|
||||||
|
if (zoomFactor + adjustment < NEAR_ZOOM_LIMIT && zoomFactor + adjustment > FAR_ZOOM_LIMIT) {
|
||||||
|
zoomFactor = zoomFactor + adjustment;
|
||||||
|
updateCamera();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adjusts the Vertical Panning of the Camera
|
||||||
|
* @param adjustment the adjustment to be made to the camera
|
||||||
|
*/
|
||||||
|
private void adjustVerticalPan(Double adjustment) {
|
||||||
|
if (verticalPan + adjustment >= -PAN_LIMIT && verticalPan + adjustment <= PAN_LIMIT) {
|
||||||
|
verticalPan += adjustment;
|
||||||
|
updateCamera();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adjusts the Horizontal Panning of the Camera.
|
||||||
|
* @param adjustment the adjustment to be made to the camera
|
||||||
|
*/
|
||||||
|
private void adjustHorizontalPan(Double adjustment) {
|
||||||
|
if (horizontalPan + adjustment >= -PAN_LIMIT && horizontalPan + adjustment <= PAN_LIMIT) {
|
||||||
|
horizontalPan += adjustment;
|
||||||
|
updateCamera();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void zoomIn() {
|
||||||
|
adjustZoomFactor(ZOOM_STEP);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void zoomOut() {
|
||||||
|
adjustZoomFactor(-ZOOM_STEP);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void panLeft() {
|
||||||
|
adjustHorizontalPan(-1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void panRight() {
|
||||||
|
adjustHorizontalPan(1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void panUp() {
|
||||||
|
adjustVerticalPan(-1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void panDown() {
|
||||||
|
adjustVerticalPan(1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -88,7 +88,6 @@ public class FinishScreenViewController implements Initializable {
|
|||||||
|
|
||||||
public void switchToStartScreenView() {
|
public void switchToStartScreenView() {
|
||||||
Sounds.playButtonClick();
|
Sounds.playButtonClick();
|
||||||
//TODO merge fix
|
|
||||||
setContentPane("/views/StartScreenView.fxml");
|
setContentPane("/views/StartScreenView.fxml");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,12 @@ package seng302.visualiser.controllers;
|
|||||||
|
|
||||||
import com.jfoenix.controls.JFXButton;
|
import com.jfoenix.controls.JFXButton;
|
||||||
import com.jfoenix.controls.JFXDialog;
|
import com.jfoenix.controls.JFXDialog;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.ResourceBundle;
|
||||||
import javafx.application.Platform;
|
import javafx.application.Platform;
|
||||||
import javafx.collections.ListChangeListener;
|
import javafx.collections.ListChangeListener;
|
||||||
import javafx.fxml.FXML;
|
import javafx.fxml.FXML;
|
||||||
@@ -9,7 +15,7 @@ import javafx.fxml.FXMLLoader;
|
|||||||
import javafx.fxml.Initializable;
|
import javafx.fxml.Initializable;
|
||||||
import javafx.scene.control.Label;
|
import javafx.scene.control.Label;
|
||||||
import javafx.scene.control.ScrollPane;
|
import javafx.scene.control.ScrollPane;
|
||||||
import javafx.scene.layout.Pane;
|
import javafx.scene.layout.AnchorPane;
|
||||||
import javafx.scene.layout.StackPane;
|
import javafx.scene.layout.StackPane;
|
||||||
import javafx.scene.layout.VBox;
|
import javafx.scene.layout.VBox;
|
||||||
import javafx.scene.paint.Color;
|
import javafx.scene.paint.Color;
|
||||||
@@ -23,19 +29,15 @@ import seng302.model.mark.CompoundMark;
|
|||||||
import seng302.model.mark.Corner;
|
import seng302.model.mark.Corner;
|
||||||
import seng302.model.stream.xml.parser.RaceXMLData;
|
import seng302.model.stream.xml.parser.RaceXMLData;
|
||||||
import seng302.utilities.Sounds;
|
import seng302.utilities.Sounds;
|
||||||
import seng302.visualiser.GameView;
|
import seng302.visualiser.MapPreview;
|
||||||
import seng302.visualiser.controllers.cells.PlayerCell;
|
import seng302.visualiser.controllers.cells.PlayerCell;
|
||||||
import seng302.visualiser.controllers.dialogs.BoatCustomizeController;
|
import seng302.visualiser.controllers.dialogs.BoatCustomizeController;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.net.URL;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.ResourceBundle;
|
|
||||||
|
|
||||||
public class LobbyController implements Initializable {
|
public class LobbyController implements Initializable {
|
||||||
|
|
||||||
|
private final double INITIAL_MAP_HEIGHT = 770d;
|
||||||
|
private final double INITIAL_MAP_WIDTH = 574d;
|
||||||
|
|
||||||
//--------FXML BEGIN--------//
|
//--------FXML BEGIN--------//
|
||||||
@FXML
|
@FXML
|
||||||
private VBox playerListVBox;
|
private VBox playerListVBox;
|
||||||
@@ -50,15 +52,15 @@ public class LobbyController implements Initializable {
|
|||||||
@FXML
|
@FXML
|
||||||
private Label mapName;
|
private Label mapName;
|
||||||
@FXML
|
@FXML
|
||||||
private Pane serverMap;
|
private AnchorPane serverMap;
|
||||||
//---------FXML END---------//
|
//---------FXML END---------//
|
||||||
|
|
||||||
private RaceState raceState;
|
private RaceState raceState;
|
||||||
private JFXDialog customizationDialog;
|
private JFXDialog customizationDialog;
|
||||||
public Color playersColor;
|
public Color playersColor;
|
||||||
private Map<Integer, ClientYacht> playerBoats;
|
private Map<Integer, ClientYacht> playerBoats;
|
||||||
private Double mapWidth, mapHeight;
|
private Double mapWidth = INITIAL_MAP_WIDTH, mapHeight = INITIAL_MAP_HEIGHT;
|
||||||
private GameView gameView;
|
private MapPreview mapPreview;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void initialize(URL location, ResourceBundle resources) {
|
public void initialize(URL location, ResourceBundle resources) {
|
||||||
@@ -90,16 +92,16 @@ public class LobbyController implements Initializable {
|
|||||||
ViewManager.getInstance().getPlayerList().setAll(ViewManager.getInstance().getPlayerList().sorted());
|
ViewManager.getInstance().getPlayerList().setAll(ViewManager.getInstance().getPlayerList().sorted());
|
||||||
});
|
});
|
||||||
|
|
||||||
|
customizeButton.setOnMouseReleased(event -> {
|
||||||
|
customizationDialog = createCustomizeDialog();
|
||||||
|
Sounds.playButtonClick();
|
||||||
|
customizationDialog.show();
|
||||||
|
});
|
||||||
|
|
||||||
Platform.runLater(() -> {
|
Platform.runLater(() -> {
|
||||||
Integer playerId = ViewManager.getInstance().getGameClient().getServerThread().getClientId();
|
Integer playerId = ViewManager.getInstance().getGameClient().getServerThread().getClientId();
|
||||||
|
|
||||||
playersColor = Colors.getColor(playerId - 1);
|
playersColor = Colors.getColor(playerId - 1);
|
||||||
customizationDialog = createCustomizeDialog();
|
|
||||||
|
|
||||||
customizeButton.setOnMouseReleased(event -> {
|
|
||||||
Sounds.playButtonClick();
|
|
||||||
customizationDialog.show();
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
leaveLobbyButton.setOnMouseEntered(e -> Sounds.playHoverSound());
|
leaveLobbyButton.setOnMouseEntered(e -> Sounds.playHoverSound());
|
||||||
@@ -129,48 +131,35 @@ public class LobbyController implements Initializable {
|
|||||||
controller.setPlayerName(this.playerBoats
|
controller.setPlayerName(this.playerBoats
|
||||||
.get(ViewManager.getInstance().getGameClient().getServerThread().getClientId())
|
.get(ViewManager.getInstance().getGameClient().getServerThread().getClientId())
|
||||||
.getBoatName());
|
.getBoatName());
|
||||||
|
controller.setCurrentBoat(this.playerBoats.get(ViewManager.getInstance().getGameClient().getServerThread().getClientId())
|
||||||
|
.getBoatType().toString());
|
||||||
|
|
||||||
return customizationDialog;
|
return customizationDialog;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
private void refreshMapView(){
|
|
||||||
RaceXMLData raceData = ViewManager.getInstance().getGameClient().getCourseData();
|
|
||||||
List<Limit> border = raceData.getCourseLimit();
|
|
||||||
List<CompoundMark> marks = new ArrayList<CompoundMark>(raceData.getCompoundMarks().values());
|
|
||||||
List<Corner> corners = raceData.getMarkSequence();
|
|
||||||
|
|
||||||
gameView.setSize(mapWidth, mapHeight);
|
|
||||||
|
|
||||||
// Update game view
|
|
||||||
gameView.updateBorder(border);
|
|
||||||
gameView.updateCourse(marks, corners);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes a top down preview of the race course map.
|
* Initializes a top down preview of the race course map.
|
||||||
*/
|
*/
|
||||||
private void initMapPreview() {
|
private void initMapPreview() {
|
||||||
gameView = new GameView();
|
RaceXMLData raceData = ViewManager.getInstance().getGameClient().getCourseData();
|
||||||
gameView.setHorizontalBuffer(330d);
|
List<Limit> border = raceData.getCourseLimit();
|
||||||
|
List<CompoundMark> marks = new ArrayList<>(raceData.getCompoundMarks().values());
|
||||||
|
List<Corner> corners = raceData.getMarkSequence();
|
||||||
|
|
||||||
mapWidth = 770d;
|
mapPreview = new MapPreview(marks, corners, border);
|
||||||
mapHeight = 574d;
|
|
||||||
|
|
||||||
// Add game view
|
|
||||||
serverMap.getChildren().clear();
|
serverMap.getChildren().clear();
|
||||||
serverMap.getChildren().add(gameView);
|
serverMap.getChildren().add(mapPreview.getAssets());
|
||||||
|
|
||||||
|
mapPreview.setSize(mapWidth, mapHeight);
|
||||||
|
|
||||||
serverMap.widthProperty().addListener((observable, oldValue, newValue) -> {
|
serverMap.widthProperty().addListener((observable, oldValue, newValue) -> {
|
||||||
mapWidth = newValue.doubleValue();
|
mapWidth = newValue.doubleValue();
|
||||||
refreshMapView();
|
mapPreview.setSize(mapWidth, mapHeight);
|
||||||
});
|
});
|
||||||
|
//
|
||||||
serverMap.heightProperty().addListener((observable, oldValue, newValue) -> {
|
serverMap.heightProperty().addListener((observable, oldValue, newValue) -> {
|
||||||
mapHeight = newValue.doubleValue();
|
mapHeight = newValue.doubleValue();
|
||||||
refreshMapView();
|
mapPreview.setSize(mapWidth, mapHeight);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -202,7 +191,7 @@ public class LobbyController implements Initializable {
|
|||||||
FXMLLoader loader = new FXMLLoader(
|
FXMLLoader loader = new FXMLLoader(
|
||||||
getClass().getResource("/views/cells/PlayerCell.fxml"));
|
getClass().getResource("/views/cells/PlayerCell.fxml"));
|
||||||
|
|
||||||
loader.setController(new PlayerCell(playerId, yacht.getBoatName(), yacht.getColour()));
|
loader.setController(new PlayerCell(playerId, yacht));
|
||||||
|
|
||||||
try {
|
try {
|
||||||
pane = loader.load();
|
pane = loader.load();
|
||||||
|
|||||||
@@ -12,8 +12,6 @@ import java.util.concurrent.TimeUnit;
|
|||||||
import javafx.animation.Timeline;
|
import javafx.animation.Timeline;
|
||||||
import javafx.application.Platform;
|
import javafx.application.Platform;
|
||||||
import javafx.beans.property.ReadOnlyBooleanProperty;
|
import javafx.beans.property.ReadOnlyBooleanProperty;
|
||||||
import javafx.beans.value.ChangeListener;
|
|
||||||
import javafx.beans.value.ObservableValue;
|
|
||||||
import javafx.collections.FXCollections;
|
import javafx.collections.FXCollections;
|
||||||
import javafx.collections.ListChangeListener;
|
import javafx.collections.ListChangeListener;
|
||||||
import javafx.collections.ObservableList;
|
import javafx.collections.ObservableList;
|
||||||
@@ -24,8 +22,6 @@ import javafx.scene.Scene;
|
|||||||
import javafx.scene.SubScene;
|
import javafx.scene.SubScene;
|
||||||
import javafx.scene.chart.LineChart;
|
import javafx.scene.chart.LineChart;
|
||||||
import javafx.scene.chart.NumberAxis;
|
import javafx.scene.chart.NumberAxis;
|
||||||
import javafx.scene.chart.XYChart;
|
|
||||||
import javafx.scene.chart.XYChart.Data;
|
|
||||||
import javafx.scene.chart.XYChart.Series;
|
import javafx.scene.chart.XYChart.Series;
|
||||||
import javafx.scene.control.Button;
|
import javafx.scene.control.Button;
|
||||||
import javafx.scene.control.CheckBox;
|
import javafx.scene.control.CheckBox;
|
||||||
@@ -87,7 +83,7 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
|||||||
@FXML
|
@FXML
|
||||||
private Label timerLabel;
|
private Label timerLabel;
|
||||||
@FXML
|
@FXML
|
||||||
private StackPane contentAnchorPane;
|
private StackPane contentStackPane;
|
||||||
|
|
||||||
private GridPane contentGridPane;
|
private GridPane contentGridPane;
|
||||||
@FXML
|
@FXML
|
||||||
@@ -134,34 +130,6 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
|||||||
Sounds.stopMusic();
|
Sounds.stopMusic();
|
||||||
Sounds.playRaceMusic();
|
Sounds.playRaceMusic();
|
||||||
|
|
||||||
finishScreenDialog = createFinishDialog();
|
|
||||||
|
|
||||||
// Load a default important annotation state
|
|
||||||
//importantAnnotations = new ImportantAnnotationsState();
|
|
||||||
|
|
||||||
//Formatting the y axis of the sparkline
|
|
||||||
// raceSparkLine.getYAxis().setRotate(180);
|
|
||||||
// raceSparkLine.getYAxis().setTickLabelRotation(180);
|
|
||||||
// raceSparkLine.getYAxis().setTranslateX(-5);
|
|
||||||
//raceSparkLine.visibleProperty().setValue(false);
|
|
||||||
//raceSparkLine.getYAxis().setAutoRanging(false);
|
|
||||||
//sparklineYAxis.setTickMarkVisible(false);
|
|
||||||
|
|
||||||
//positionVbox.getStylesheets().add(getClass().getResource("/css/master.css").toString());
|
|
||||||
// raceSparkLine.visibleProperty().setValue(false);
|
|
||||||
// raceSparkLine.getYAxis().setAutoRanging(false);
|
|
||||||
// sparklineYAxis.setTickMarkVisible(false);
|
|
||||||
// positionVbox.getStylesheets().add(getClass().getResource("/css/master.css").toString());
|
|
||||||
|
|
||||||
//selectAnnotationBtn.setOnAction(event -> loadSelectAnnotationView());
|
|
||||||
// rvAnchorPane.prefWidthProperty().bind(ViewManager.getInstance().getDecorator().widthProperty());
|
|
||||||
// rvAnchorPane.prefHeightProperty().bind(ViewManager.getInstance().getDecorator().heightProperty());
|
|
||||||
// selectAnnotationBtn.setOnAction(event -> loadSelectAnnotationView());
|
|
||||||
// windArrowHolder.getChildren().addAll(windArrow);
|
|
||||||
// windArrow.setLayoutX(windArrowHolder.getWidth() / 2);
|
|
||||||
// windArrow.setLayoutY(windArrowHolder.getHeight() / 2);
|
|
||||||
|
|
||||||
// selectAnnotationBtn.setOnAction(event -> loadSelectAnnotationView());
|
|
||||||
chatInput.lengthProperty().addListener((obs, oldLen, newLen) -> {
|
chatInput.lengthProperty().addListener((obs, oldLen, newLen) -> {
|
||||||
if (newLen.intValue() > CHAT_LIMIT) {
|
if (newLen.intValue() > CHAT_LIMIT) {
|
||||||
chatInput.setText(chatInput.getText().substring(0, CHAT_LIMIT));
|
chatInput.setText(chatInput.getText().substring(0, CHAT_LIMIT));
|
||||||
@@ -175,51 +143,44 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
|||||||
chatHistory.prefHeightProperty().bind(
|
chatHistory.prefHeightProperty().bind(
|
||||||
chatHistoryHolder.heightProperty()
|
chatHistoryHolder.heightProperty()
|
||||||
);
|
);
|
||||||
// chatHistory.setFitToWidth(true);
|
|
||||||
// chatHistory.setFitToHeight(true);
|
|
||||||
// chatHistory.textProperty().addListener((obs, oldValue, newValue) -> {
|
|
||||||
// chatHistory.setScrollTop(Double.MAX_VALUE);
|
|
||||||
// });
|
|
||||||
rvAnchorPane.setOnMouseClicked((event) ->
|
|
||||||
rvAnchorPane.requestFocus()
|
|
||||||
);
|
|
||||||
|
|
||||||
|
contentStackPane.setOnMouseClicked(event -> {
|
||||||
|
contentStackPane.requestFocus();
|
||||||
|
});
|
||||||
|
Platform.runLater(contentStackPane::requestFocus);
|
||||||
//Makes the chat history non transparent when clicked on
|
//Makes the chat history non transparent when clicked on
|
||||||
chatInput.focusedProperty().addListener(new ChangeListener<Boolean>() {
|
chatInput.focusedProperty().addListener((observable, oldValue, newValue) -> {
|
||||||
@Override
|
if (newValue) {
|
||||||
public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue,
|
chatHistory.increaseOpacity();
|
||||||
Boolean newValue) {
|
} else {
|
||||||
if (newValue) {
|
chatHistory.decreaseOpacity();
|
||||||
chatHistory.increaseOpacity();
|
|
||||||
} else {
|
|
||||||
chatHistory.decreaseOpacity();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public void showFinishDialog(ArrayList<ClientYacht> finishedBoats) {
|
public void showFinishDialog(ArrayList<ClientYacht> finishedBoats) {
|
||||||
raceState.setRaceStarted(false);
|
raceState.setRaceStarted(false);
|
||||||
finishDialogController.setFinishedBoats(finishedBoats);
|
createFinishDialog(finishedBoats);
|
||||||
finishScreenDialog.show();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private JFXDialog createFinishDialog() {
|
/**
|
||||||
|
* Create finishScreenDialog and set up finishDialogController.
|
||||||
|
*/
|
||||||
|
private void createFinishDialog(ArrayList<ClientYacht> finishedBoats) {
|
||||||
FXMLLoader dialog = new FXMLLoader(
|
FXMLLoader dialog = new FXMLLoader(
|
||||||
getClass().getResource("/views/dialogs/RaceFinishDialog.fxml"));
|
getClass().getResource("/views/dialogs/RaceFinishDialog.fxml"));
|
||||||
|
|
||||||
JFXDialog finishScreenDialog = null;
|
Platform.runLater(() -> {
|
||||||
|
try {
|
||||||
try {
|
finishScreenDialog = new JFXDialog(contentStackPane, dialog.load(),
|
||||||
finishScreenDialog = new JFXDialog(contentAnchorPane, dialog.load(),
|
JFXDialog.DialogTransition.CENTER);
|
||||||
JFXDialog.DialogTransition.CENTER);
|
finishDialogController = dialog.getController();
|
||||||
} catch (IOException e) {
|
finishDialogController.setFinishedBoats(finishedBoats);
|
||||||
e.printStackTrace();
|
finishScreenDialog.show();
|
||||||
}
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
finishDialogController = dialog.getController();
|
}
|
||||||
|
});
|
||||||
return finishScreenDialog;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void loadRace (
|
public void loadRace (
|
||||||
@@ -236,16 +197,14 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
|||||||
while (c.next()) {
|
while (c.next()) {
|
||||||
if (c.wasPermutated()) {
|
if (c.wasPermutated()) {
|
||||||
updateOrder(raceState.getPlayerPositions());
|
updateOrder(raceState.getPlayerPositions());
|
||||||
updateSparkLine();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
updateOrder(raceState.getPlayerPositions());
|
updateOrder(raceState.getPlayerPositions());
|
||||||
gameView = new GameView3D();
|
gameView = new GameView3D();
|
||||||
// gameView.setFrameRateFXText(fpsDisplay);
|
|
||||||
Platform.runLater(() -> {
|
Platform.runLater(() -> {
|
||||||
contentAnchorPane.getChildren().add(0, gameView.getAssets());
|
contentStackPane.getChildren().add(0, gameView.getAssets());
|
||||||
((SubScene) gameView.getAssets()).widthProperty()
|
((SubScene) gameView.getAssets()).widthProperty()
|
||||||
.bind(ViewManager.getInstance().getStage().widthProperty());
|
.bind(ViewManager.getInstance().getStage().widthProperty());
|
||||||
((SubScene) gameView.getAssets()).heightProperty()
|
((SubScene) gameView.getAssets()).heightProperty()
|
||||||
@@ -257,11 +216,10 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
|||||||
gameView.updateCourse(
|
gameView.updateCourse(
|
||||||
new ArrayList<>(raceData.getCompoundMarks().values()), raceData.getMarkSequence()
|
new ArrayList<>(raceData.getCompoundMarks().values()), raceData.getMarkSequence()
|
||||||
);
|
);
|
||||||
// gameView.enableZoom();
|
|
||||||
gameView.setBoatAsPlayer(player);
|
gameView.setBoatAsPlayer(player);
|
||||||
// gameView.startRace();
|
|
||||||
|
|
||||||
// raceState.addCollisionListener(gameView::drawCollision);
|
// raceState.addCollisionListener(gameView::drawCollision);
|
||||||
|
|
||||||
raceState.windDirectionProperty().addListener((obs, oldDirection, newDirection) -> {
|
raceState.windDirectionProperty().addListener((obs, oldDirection, newDirection) -> {
|
||||||
gameView.setWindDir(newDirection.doubleValue());
|
gameView.setWindDir(newDirection.doubleValue());
|
||||||
Platform.runLater(() -> updateWindDirection(newDirection.doubleValue()));
|
Platform.runLater(() -> updateWindDirection(newDirection.doubleValue()));
|
||||||
@@ -274,9 +232,7 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
|||||||
updateWindSpeed(raceState.getWindSpeed());
|
updateWindSpeed(raceState.getWindSpeed());
|
||||||
});
|
});
|
||||||
gameView.setWindDir(raceState.windDirectionProperty().doubleValue());
|
gameView.setWindDir(raceState.windDirectionProperty().doubleValue());
|
||||||
Platform.runLater(() -> {
|
Platform.runLater(this::initializeUpdateTimer);
|
||||||
initializeUpdateTimer();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -317,137 +273,6 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initialiseFPSCheckBox() {
|
|
||||||
// toggleFps.selectedProperty().addListener((obs, oldVal, newVal) ->
|
|
||||||
// gameView.setFPSVisibility(toggleFps.isSelected())
|
|
||||||
// );
|
|
||||||
}
|
|
||||||
|
|
||||||
private void initialiseAnnotationSlider() {
|
|
||||||
// annotationSlider.setLabelFormatter(new StringConverter<Double>() {
|
|
||||||
// @Override
|
|
||||||
// public String toString(Double n) {
|
|
||||||
// if (n == 0) {
|
|
||||||
// return "None";
|
|
||||||
// }
|
|
||||||
// if (n == 1) {
|
|
||||||
// return "Important";
|
|
||||||
// }
|
|
||||||
// if (n == 2) {
|
|
||||||
// return "All";
|
|
||||||
// }
|
|
||||||
// return "All";
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// @Override
|
|
||||||
// public Double fromString(String s) {
|
|
||||||
// switch (s) {
|
|
||||||
// case "None":
|
|
||||||
// return 0d;
|
|
||||||
// case "Important":
|
|
||||||
// return 1d;
|
|
||||||
// case "All":
|
|
||||||
// return 2d;
|
|
||||||
//
|
|
||||||
// default:
|
|
||||||
// return 2d;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
// annotationSlider.setValue(2);
|
|
||||||
// annotationSlider.valueProperty().addListener((obs, oldVal, newVal) ->
|
|
||||||
// setAnnotations((int) annotationSlider.getValue())
|
|
||||||
// );
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Used to add any new yachts into the race that may have started late or not have had data received yet
|
|
||||||
*/
|
|
||||||
private void updateSparkLine(){
|
|
||||||
// // TODO: 2/08/17 there is about 0 chance of this working. Once we are keeping track of boat positions it can be fixed.
|
|
||||||
// // Collect the racing yachts that aren't already in the chart
|
|
||||||
// sparkLineData.clear();
|
|
||||||
// List<ClientYacht> sparkLineCandidates = new ArrayList<>(participants.values());
|
|
||||||
// // Create a new data series for new yachts
|
|
||||||
// sparkLineCandidates
|
|
||||||
// .stream()
|
|
||||||
// .filter(yacht -> yacht.getPosition() != null)
|
|
||||||
// .forEach(yacht -> {
|
|
||||||
// Series<String, Double> yachtData = new Series<>();
|
|
||||||
// yachtData.setName(yacht.getSourceId().toString());
|
|
||||||
// yachtData.getData().add(
|
|
||||||
// new Data<>(
|
|
||||||
// Integer.toString(yacht.getLegNumber()),
|
|
||||||
// 1.0 + participants.size() - yacht.getPosition()
|
|
||||||
// )
|
|
||||||
// );
|
|
||||||
// sparkLineData.add(yachtData);
|
|
||||||
// });
|
|
||||||
//
|
|
||||||
// // Lambda function to sort the series in order of leg (later legs shown more to the right)
|
|
||||||
// sparkLineData.sort((o1, o2) -> {
|
|
||||||
// Integer leg1 = Integer.parseInt(o1.getData().get(o1.getData().size()-1).getXValue());
|
|
||||||
// Integer leg2 = Integer.parseInt(o2.getData().get(o2.getData().size()-1).getXValue());
|
|
||||||
// if (leg2 < leg1){
|
|
||||||
// return 1;
|
|
||||||
// } else {
|
|
||||||
// return -1;
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
//
|
|
||||||
// // Adds the new data series to the sparkline (and set the colour of the series)
|
|
||||||
// Platform.runLater(() -> {
|
|
||||||
// sparkLineData
|
|
||||||
// .stream()
|
|
||||||
// .filter(spark -> !raceSparkLine.getData().contains(spark))
|
|
||||||
// .forEach(spark -> {
|
|
||||||
// raceSparkLine.getData().add(spark);
|
|
||||||
// spark.getNode().lookup(".chart-series-line").setStyle("-fx-stroke:" + getBoatColorAsRGB(spark.getName()));
|
|
||||||
// });
|
|
||||||
// });
|
|
||||||
}
|
|
||||||
|
|
||||||
private void initialiseSparkLine() {
|
|
||||||
// sparklineYAxis.setUpperBound(participants.size() + 1);
|
|
||||||
// raceSparkLine.setCreateSymbols(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Updates the yachts sparkline of the desired yacht and using the new leg number
|
|
||||||
* @param yacht The yacht to be updated on the sparkline
|
|
||||||
* @param legNumber the leg number that the position will be assigned to
|
|
||||||
*/
|
|
||||||
void updateYachtPositionSparkline(ClientYacht yacht, Integer legNumber){
|
|
||||||
for (XYChart.Series<String, Double> positionData : sparkLineData) {
|
|
||||||
positionData.getData().add(
|
|
||||||
new Data<>(
|
|
||||||
Integer.toString(legNumber),
|
|
||||||
1.0 + participants.size() - yacht.getPlacing()
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* gets the rgb string of the yachts colour to use for the chart via css
|
|
||||||
* @param yachtId id of yacht passed in to get the yachts colour
|
|
||||||
* @return the colour as an rgb string
|
|
||||||
*/
|
|
||||||
private String getBoatColorAsRGB(String yachtId){
|
|
||||||
Color color = participants.get(Integer.valueOf(yachtId)).getColour();
|
|
||||||
if (color == null){
|
|
||||||
return String.format("#%02X%02X%02X",255,255,255);
|
|
||||||
}
|
|
||||||
return String.format( "#%02X%02X%02X",
|
|
||||||
(int)( color.getRed() * 255 ),
|
|
||||||
(int)( color.getGreen() * 255 ),
|
|
||||||
(int)( color.getBlue() * 255 )
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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.
|
||||||
@@ -805,7 +630,7 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
|||||||
public String readChatInput() {
|
public String readChatInput() {
|
||||||
String chat = chatInput.getText();
|
String chat = chatInput.getText();
|
||||||
chatInput.clear();
|
chatInput.clear();
|
||||||
rvAnchorPane.requestFocus();
|
contentStackPane.requestFocus();
|
||||||
return chat;
|
return chat;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -112,17 +112,25 @@ public class ServerListController implements Initializable, ServerListenerDelega
|
|||||||
serverListVBox.getChildren().add(noServersFound);
|
serverListVBox.getChildren().add(noServersFound);
|
||||||
|
|
||||||
// Set up dialog for server creation
|
// Set up dialog for server creation
|
||||||
|
serverListHostButton.setOnAction(action -> {
|
||||||
|
showServerCreationDialog();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shows Server Creation Dialog when "Host" button is clicked.
|
||||||
|
*/
|
||||||
|
private void showServerCreationDialog() {
|
||||||
Platform.runLater(() -> {
|
Platform.runLater(() -> {
|
||||||
FXMLLoader dialogContent = new FXMLLoader(getClass().getResource(
|
FXMLLoader dialogContent = new FXMLLoader(getClass().getResource(
|
||||||
"/views/dialogs/ServerCreationDialog.fxml"));
|
"/views/dialogs/ServerCreationDialog.fxml"));
|
||||||
try {
|
try {
|
||||||
JFXDialog dialog = new JFXDialog(serverListMainStackPane, dialogContent.load(),
|
JFXDialog dialog = new JFXDialog(serverListMainStackPane, dialogContent.load(),
|
||||||
DialogTransition.CENTER);
|
DialogTransition.CENTER);
|
||||||
serverListHostButton.setOnAction(action -> {
|
dialog.show();
|
||||||
dialog.show();
|
Sounds.playButtonClick();
|
||||||
Sounds.playButtonClick();
|
|
||||||
});
|
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
logger.warn("Could not create Server Creation Dialog.");
|
logger.warn("Could not create Server Creation Dialog.");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -2,6 +2,9 @@ package seng302.visualiser.controllers;
|
|||||||
|
|
||||||
import com.jfoenix.controls.JFXButton;
|
import com.jfoenix.controls.JFXButton;
|
||||||
import com.jfoenix.controls.JFXDecorator;
|
import com.jfoenix.controls.JFXDecorator;
|
||||||
|
import com.jfoenix.controls.JFXDialog;
|
||||||
|
import com.jfoenix.controls.JFXDialog.DialogTransition;
|
||||||
|
import com.jfoenix.controls.JFXSnackbar;
|
||||||
import com.jfoenix.svg.SVGGlyph;
|
import com.jfoenix.svg.SVGGlyph;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
@@ -15,6 +18,7 @@ import javafx.scene.Scene;
|
|||||||
import javafx.scene.SceneAntialiasing;
|
import javafx.scene.SceneAntialiasing;
|
||||||
import javafx.scene.image.Image;
|
import javafx.scene.image.Image;
|
||||||
import javafx.scene.layout.HBox;
|
import javafx.scene.layout.HBox;
|
||||||
|
import javafx.scene.layout.StackPane;
|
||||||
import javafx.scene.paint.Color;
|
import javafx.scene.paint.Color;
|
||||||
import javafx.stage.Stage;
|
import javafx.stage.Stage;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
@@ -23,6 +27,8 @@ import seng302.gameServer.ServerAdvertiser;
|
|||||||
import seng302.utilities.BonjourInstallChecker;
|
import seng302.utilities.BonjourInstallChecker;
|
||||||
import seng302.utilities.Sounds;
|
import seng302.utilities.Sounds;
|
||||||
import seng302.visualiser.GameClient;
|
import seng302.visualiser.GameClient;
|
||||||
|
import seng302.visualiser.controllers.dialogs.KeyBindingDialogController;
|
||||||
|
import seng302.visualiser.controllers.dialogs.PopupDialogController;
|
||||||
|
|
||||||
public class ViewManager {
|
public class ViewManager {
|
||||||
|
|
||||||
@@ -32,12 +38,9 @@ public class ViewManager {
|
|||||||
private HashMap<String, String> properties; //TODO is this the best way to do this??
|
private HashMap<String, String> properties; //TODO is this the best way to do this??
|
||||||
private ObservableList<String> playerList;
|
private ObservableList<String> playerList;
|
||||||
private Logger logger = LoggerFactory.getLogger(ViewManager.class);
|
private Logger logger = LoggerFactory.getLogger(ViewManager.class);
|
||||||
|
|
||||||
public Stage getStage() {
|
|
||||||
return stage;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Stage stage;
|
private Stage stage;
|
||||||
|
private JFXSnackbar jfxSnackbar;
|
||||||
|
private JFXDialog keyBindingDialog;
|
||||||
|
|
||||||
private ViewManager() {
|
private ViewManager() {
|
||||||
properties = new HashMap<>();
|
properties = new HashMap<>();
|
||||||
@@ -99,6 +102,8 @@ public class ViewManager {
|
|||||||
gameClient.stopGame();
|
gameClient.stopGame();
|
||||||
System.exit(0);
|
System.exit(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
jfxSnackbar = new JFXSnackbar(decorator);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -119,12 +124,31 @@ public class ViewManager {
|
|||||||
//Get the button box
|
//Get the button box
|
||||||
HBox btns = (HBox) decorator.getChildren().get(0);
|
HBox btns = (HBox) decorator.getChildren().get(0);
|
||||||
|
|
||||||
|
//Create settings button -- [WIP]
|
||||||
|
JFXButton btnKeyBinding = new JFXButton();
|
||||||
|
btnKeyBinding.setText(" Key Bindings");
|
||||||
|
btnKeyBinding.setStyle("-fx-text-fill:#fff");
|
||||||
|
btnKeyBinding.getStyleClass().add("jfx-decorator-button");
|
||||||
|
btnKeyBinding.setCursor(Cursor.HAND);
|
||||||
|
btnKeyBinding.setFocusTraversable(false);
|
||||||
|
|
||||||
|
btnKeyBinding.setOnMouseClicked(event -> Platform.runLater(() -> {
|
||||||
|
try {
|
||||||
|
if (!checkDialogOpened(decorator.getChildren())) {
|
||||||
|
showKeyBindingDialog();
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
logger.warn("Something went wrong when opening key bind dialog");
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
//Create new button
|
//Create new button
|
||||||
JFXButton btnMute = new JFXButton();
|
JFXButton btnMute = new JFXButton();
|
||||||
btnMute.setText(" Toggle Sound");
|
btnMute.setText(" Toggle Sound");
|
||||||
btnMute.setStyle("-fx-text-fill:#fff");
|
btnMute.setStyle("-fx-text-fill:#fff");
|
||||||
btnMute.getStyleClass().add("jfx-decorator-button");
|
btnMute.getStyleClass().add("jfx-decorator-button");
|
||||||
btnMute.setCursor(Cursor.HAND);
|
btnMute.setCursor(Cursor.HAND);
|
||||||
|
btnMute.setFocusTraversable(false);
|
||||||
|
|
||||||
//Create Graphics
|
//Create Graphics
|
||||||
SVGGlyph spacer = new SVGGlyph(0, "SPACER", "", Color.WHITE);
|
SVGGlyph spacer = new SVGGlyph(0, "SPACER", "", Color.WHITE);
|
||||||
@@ -134,9 +158,13 @@ public class ViewManager {
|
|||||||
SVGGlyph volumeOff = new SVGGlyph(0, "VOLUME_ON",
|
SVGGlyph volumeOff = new SVGGlyph(0, "VOLUME_ON",
|
||||||
"M13.5,9 C13.5,7.2 12.5,5.7 11,5 L11,7.2 L13.5,9.7 L13.5,9 L13.5,9 Z M16,9 C16,9.9 15.8,10.8 15.5,11.6 L17,13.1 C17.7,11.9 18,10.4 18,8.9 C18,4.6 15,1 11,0.1 L11,2.2 C13.9,3.2 16,5.8 16,9 L16,9 Z M1.3,0 L0,1.3 L4.7,6 L0,6 L0,12 L4,12 L9,17 L9,10.3 L13.3,14.6 C12.6,15.1 11.9,15.5 11,15.8 L11,17.9 C12.4,17.6 13.6,17 14.7,16.1 L16.7,18.1 L18,16.8 L9,7.8 L1.3,0 L1.3,0 Z M9,1 L6.9,3.1 L9,5.2 L9,1 L9,1 Z",
|
"M13.5,9 C13.5,7.2 12.5,5.7 11,5 L11,7.2 L13.5,9.7 L13.5,9 L13.5,9 Z M16,9 C16,9.9 15.8,10.8 15.5,11.6 L17,13.1 C17.7,11.9 18,10.4 18,8.9 C18,4.6 15,1 11,0.1 L11,2.2 C13.9,3.2 16,5.8 16,9 L16,9 Z M1.3,0 L0,1.3 L4.7,6 L0,6 L0,12 L4,12 L9,17 L9,10.3 L13.3,14.6 C12.6,15.1 11.9,15.5 11,15.8 L11,17.9 C12.4,17.6 13.6,17 14.7,16.1 L16.7,18.1 L18,16.8 L9,7.8 L1.3,0 L1.3,0 Z M9,1 L6.9,3.1 L9,5.2 L9,1 L9,1 Z",
|
||||||
Color.WHITE);
|
Color.WHITE);
|
||||||
|
SVGGlyph keyBindingGlyph = new SVGGlyph(0, "KEY_BINDING",
|
||||||
|
"M20 5H4c-1.1 0-1.99.9-1.99 2L2 17c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2zm-9 3h2v2h-2V8zm0 3h2v2h-2v-2zM8 8h2v2H8V8zm0 3h2v2H8v-2zm-1 2H5v-2h2v2zm0-3H5V8h2v2zm9 7H8v-2h8v2zm0-4h-2v-2h2v2zm0-3h-2V8h2v2zm3 3h-2v-2h2v2zm0-3h-2V8h2v2z",
|
||||||
|
Color.WHITE);
|
||||||
volumeOn.setSize(16, 16);
|
volumeOn.setSize(16, 16);
|
||||||
volumeOff.setSize(16, 16);
|
volumeOff.setSize(16, 16);
|
||||||
spacer.setSize(40, 16);
|
spacer.setSize(40, 16);
|
||||||
|
keyBindingGlyph.setSize(24, 16);
|
||||||
|
|
||||||
// Determine which graphic should go on the button
|
// Determine which graphic should go on the button
|
||||||
if (Sounds.isMusicMuted() && Sounds.isSoundEffectsMuted()) {
|
if (Sounds.isMusicMuted() && Sounds.isSoundEffectsMuted()) {
|
||||||
@@ -145,9 +173,12 @@ public class ViewManager {
|
|||||||
btnMute.setGraphic(volumeOn);
|
btnMute.setGraphic(volumeOn);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
btnKeyBinding.setGraphic(keyBindingGlyph);
|
||||||
|
|
||||||
// Add Buttons
|
// Add Buttons
|
||||||
btns.getChildren().add(0, spacer);
|
btns.getChildren().add(0, spacer);
|
||||||
btns.getChildren().add(0, btnMute);
|
btns.getChildren().add(0, btnMute);
|
||||||
|
btns.getChildren().add(0, btnKeyBinding);
|
||||||
btnMute.setOnAction((action) -> {
|
btnMute.setOnAction((action) -> {
|
||||||
Sounds.toggleAllSounds();
|
Sounds.toggleAllSounds();
|
||||||
if (btnMute.getGraphic().equals(volumeOff)) {
|
if (btnMute.getGraphic().equals(volumeOff)) {
|
||||||
@@ -159,6 +190,84 @@ public class ViewManager {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Recursively find JFXDialog given a starting node. Will traverse children of StackPane.
|
||||||
|
*
|
||||||
|
* @param nodes children nodes to be check.
|
||||||
|
* @return true if node contains JFXDialog.
|
||||||
|
*/
|
||||||
|
private Boolean checkDialogOpened(ObservableList<Node> nodes) {
|
||||||
|
boolean foundJFXDialog = false;
|
||||||
|
for (Node node : nodes) {
|
||||||
|
if (node instanceof JFXDialog) {
|
||||||
|
return true;
|
||||||
|
} else if (node instanceof StackPane) {
|
||||||
|
foundJFXDialog = checkDialogOpened(((StackPane) node).getChildren());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return foundJFXDialog;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void showKeyBindingDialog() throws IOException {
|
||||||
|
FXMLLoader dialogContent = new FXMLLoader(getClass().getResource(
|
||||||
|
"/views/dialogs/KeyBindingDialog.fxml"));
|
||||||
|
for (Node node : decorator.getChildren()) {
|
||||||
|
if (node instanceof StackPane) {
|
||||||
|
keyBindingDialog = new JFXDialog((StackPane) node,
|
||||||
|
dialogContent.load(),
|
||||||
|
DialogTransition.CENTER);
|
||||||
|
|
||||||
|
KeyBindingDialogController keyBindingDialogController = dialogContent
|
||||||
|
.getController();
|
||||||
|
keyBindingDialogController.setGameClient(this.gameClient);
|
||||||
|
keyBindingDialog.show();
|
||||||
|
decorator.requestFocus();
|
||||||
|
Sounds.playButtonClick();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void closeKeyBindingDialog() {
|
||||||
|
keyBindingDialog.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
public PopupDialogController showPopupDialog() {
|
||||||
|
FXMLLoader dialogContent = new FXMLLoader(
|
||||||
|
getClass().getResource("/views/dialogs/PopupDialog.fxml"));
|
||||||
|
for (Node node : decorator.getChildren()) {
|
||||||
|
if (node instanceof StackPane) {
|
||||||
|
try {
|
||||||
|
JFXDialog dialog = new JFXDialog((StackPane) node, dialogContent.load(),
|
||||||
|
DialogTransition.CENTER);
|
||||||
|
PopupDialogController popupDialogController = dialogContent.getController();
|
||||||
|
popupDialogController.setPopupDialog(dialog);
|
||||||
|
dialog.show();
|
||||||
|
return popupDialogController;
|
||||||
|
} catch (IOException e) {
|
||||||
|
logger.error("Cannot load Popup dialog");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show a snackbar at the bottom of the app for 1 second.
|
||||||
|
*
|
||||||
|
* @param snackbarText text to be displayed.
|
||||||
|
*/
|
||||||
|
public void showSnackbar(String snackbarText, boolean isWarning) {
|
||||||
|
if (isWarning) {
|
||||||
|
decorator.getStylesheets()
|
||||||
|
.add(getClass().getResource("/css/dialogs/Snackbar.css").toExternalForm());
|
||||||
|
} else {
|
||||||
|
if (decorator.getStylesheets().size() > 1) {
|
||||||
|
decorator.getStylesheets().remove(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
jfxSnackbar.show(snackbarText, 1500);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determines if a PC has compatibility with the bonjour protocol for server detection.
|
* Determines if a PC has compatibility with the bonjour protocol for server detection.
|
||||||
*/
|
*/
|
||||||
@@ -221,6 +330,7 @@ public class ViewManager {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Change the view to the Lobby Screen
|
* Change the view to the Lobby Screen
|
||||||
|
*
|
||||||
* @param disableReadyButton Boolean value so that clients can't try start a game.
|
* @param disableReadyButton Boolean value so that clients can't try start a game.
|
||||||
* @return A LobbyController object for the Lobby Screen.
|
* @return A LobbyController object for the Lobby Screen.
|
||||||
*/
|
*/
|
||||||
@@ -243,6 +353,7 @@ public class ViewManager {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets up the view for the race. Creating a new decorator and destroying the old one.
|
* Sets up the view for the race. Creating a new decorator and destroying the old one.
|
||||||
|
*
|
||||||
* @return A RaceViewController for the race view screen.
|
* @return A RaceViewController for the race view screen.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -267,17 +378,10 @@ public class ViewManager {
|
|||||||
scene.setOnKeyPressed(gameClient::keyPressed);
|
scene.setOnKeyPressed(gameClient::keyPressed);
|
||||||
scene.setOnKeyReleased(gameClient::keyReleased);
|
scene.setOnKeyReleased(gameClient::keyReleased);
|
||||||
|
|
||||||
// uncomment to make it full screen
|
|
||||||
// Rectangle2D visualBounds = Screen.getPrimary().getVisualBounds();
|
|
||||||
// stage.setX(visualBounds.getMinX());
|
|
||||||
// stage.setY(visualBounds.getMinY());
|
|
||||||
// stage.setWidth(visualBounds.getWidth());
|
|
||||||
// stage.setHeight(visualBounds.getHeight());
|
|
||||||
// stage.setMaximized(true);
|
|
||||||
// stage.setFullScreen(true);
|
|
||||||
|
|
||||||
stage.setMinHeight(500);
|
stage.setMinHeight(500);
|
||||||
stage.setMinWidth(800);
|
stage.setMinWidth(800);
|
||||||
|
stage.setTitle("Party Parrots At Sea");
|
||||||
|
stage.getIcons().add(new Image(getClass().getResourceAsStream("/PP.png")));
|
||||||
stage.setOnCloseRequest(e -> closeAll());
|
stage.setOnCloseRequest(e -> closeAll());
|
||||||
stage.setScene(scene);
|
stage.setScene(scene);
|
||||||
stage.show();
|
stage.show();
|
||||||
@@ -286,7 +390,7 @@ public class ViewManager {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
while (loader.getController() == null){
|
while (loader.getController() == null) {
|
||||||
try {
|
try {
|
||||||
Thread.sleep(50);
|
Thread.sleep(50);
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
@@ -296,4 +400,9 @@ public class ViewManager {
|
|||||||
|
|
||||||
return loader.getController();
|
return loader.getController();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Stage getStage() {
|
||||||
|
return stage;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import javafx.scene.control.Label;
|
|||||||
import javafx.scene.layout.GridPane;
|
import javafx.scene.layout.GridPane;
|
||||||
import javafx.scene.layout.Pane;
|
import javafx.scene.layout.Pane;
|
||||||
import javafx.scene.paint.Color;
|
import javafx.scene.paint.Color;
|
||||||
|
import seng302.model.ClientYacht;
|
||||||
import seng302.visualiser.fxObjects.assets_3D.BoatMeshType;
|
import seng302.visualiser.fxObjects.assets_3D.BoatMeshType;
|
||||||
import seng302.visualiser.fxObjects.assets_3D.BoatModel;
|
import seng302.visualiser.fxObjects.assets_3D.BoatModel;
|
||||||
import seng302.visualiser.fxObjects.assets_3D.ModelFactory;
|
import seng302.visualiser.fxObjects.assets_3D.ModelFactory;
|
||||||
@@ -24,11 +25,13 @@ public class PlayerCell {
|
|||||||
private String name;
|
private String name;
|
||||||
private Color boatColor;
|
private Color boatColor;
|
||||||
private Integer playerId;
|
private Integer playerId;
|
||||||
|
private BoatMeshType boatType;
|
||||||
|
|
||||||
public PlayerCell(Integer playerId, String playerName, Color color) {
|
public PlayerCell(Integer playerId, ClientYacht yacht) {
|
||||||
this.playerId = playerId;
|
this.playerId = playerId;
|
||||||
this.name = playerName;
|
this.name = yacht.getBoatName();
|
||||||
this.boatColor = color;
|
this.boatColor = yacht.getColour();
|
||||||
|
this.boatType = yacht.getBoatType();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void initialize() {
|
public void initialize() {
|
||||||
@@ -37,7 +40,7 @@ public class PlayerCell {
|
|||||||
// Add Rotating Boat to Player Cell with players color on it.
|
// Add Rotating Boat to Player Cell with players color on it.
|
||||||
Group group = new Group();
|
Group group = new Group();
|
||||||
boatPane.getChildren().add(group);
|
boatPane.getChildren().add(group);
|
||||||
BoatModel bo = ModelFactory.boatIconView(BoatMeshType.DINGHY, this.boatColor);
|
BoatModel bo = ModelFactory.boatIconView(boatType, boatColor);
|
||||||
group.getChildren().add(bo.getAssets());
|
group.getChildren().add(bo.getAssets());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,15 +6,25 @@ import com.jfoenix.controls.JFXTextField;
|
|||||||
import com.jfoenix.validation.RequiredFieldValidator;
|
import com.jfoenix.validation.RequiredFieldValidator;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.util.ResourceBundle;
|
import java.util.ResourceBundle;
|
||||||
import javafx.event.ActionEvent;
|
|
||||||
import javafx.fxml.FXML;
|
import javafx.fxml.FXML;
|
||||||
import javafx.fxml.Initializable;
|
import javafx.fxml.Initializable;
|
||||||
|
import javafx.geometry.Insets;
|
||||||
|
import javafx.scene.Group;
|
||||||
|
import javafx.scene.PointLight;
|
||||||
|
import javafx.scene.control.ProgressBar;
|
||||||
|
import javafx.scene.layout.Background;
|
||||||
|
import javafx.scene.layout.BackgroundFill;
|
||||||
|
import javafx.scene.layout.CornerRadii;
|
||||||
|
import javafx.scene.layout.Pane;
|
||||||
import javafx.scene.paint.Color;
|
import javafx.scene.paint.Color;
|
||||||
import seng302.gameServer.messages.CustomizeRequestType;
|
import seng302.gameServer.messages.CustomizeRequestType;
|
||||||
import seng302.utilities.Sounds;
|
import seng302.utilities.Sounds;
|
||||||
import seng302.visualiser.ClientToServerThread;
|
import seng302.visualiser.ClientToServerThread;
|
||||||
import seng302.visualiser.controllers.LobbyController;
|
import seng302.visualiser.controllers.LobbyController;
|
||||||
import seng302.visualiser.controllers.ViewManager;
|
import seng302.visualiser.controllers.ViewManager;
|
||||||
|
import seng302.visualiser.fxObjects.assets_3D.BoatMeshType;
|
||||||
|
import seng302.visualiser.fxObjects.assets_3D.BoatModel;
|
||||||
|
import seng302.visualiser.fxObjects.assets_3D.ModelFactory;
|
||||||
import seng302.visualiser.validators.FieldLengthValidator;
|
import seng302.visualiser.validators.FieldLengthValidator;
|
||||||
import seng302.visualiser.validators.ValidationTools;
|
import seng302.visualiser.validators.ValidationTools;
|
||||||
|
|
||||||
@@ -24,23 +34,35 @@ public class BoatCustomizeController implements Initializable{
|
|||||||
@FXML
|
@FXML
|
||||||
private JFXColorPicker colorPicker;
|
private JFXColorPicker colorPicker;
|
||||||
@FXML
|
@FXML
|
||||||
|
private ProgressBar speedBar;
|
||||||
|
@FXML
|
||||||
|
private ProgressBar accelBar;
|
||||||
|
@FXML
|
||||||
|
private ProgressBar handleBar;
|
||||||
|
@FXML
|
||||||
private JFXButton submitBtn;
|
private JFXButton submitBtn;
|
||||||
@FXML
|
@FXML
|
||||||
private JFXTextField boatName;
|
private JFXTextField boatName;
|
||||||
@FXML
|
@FXML
|
||||||
void colorChanged(ActionEvent event) {
|
private Pane boatPane;
|
||||||
Color color = colorPicker.getValue();
|
@FXML
|
||||||
|
void colorChanged() {
|
||||||
|
refreshBoat();
|
||||||
}
|
}
|
||||||
//---------FXML END---------//
|
//---------FXML END---------//
|
||||||
|
|
||||||
private ClientToServerThread socketThread;
|
private ClientToServerThread socketThread;
|
||||||
private LobbyController lobbyController;
|
private LobbyController lobbyController;
|
||||||
|
private BoatMeshType currentBoat;
|
||||||
|
private Double maxSpeedMultiplier = 1.0;
|
||||||
|
private Double maxTurnRateMultiplier = 1.0;
|
||||||
|
private Double maxAccelerationMultiplier = 1.0;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void initialize(URL location, ResourceBundle resources) {
|
public void initialize(URL location, ResourceBundle resources) {
|
||||||
|
|
||||||
socketThread = ViewManager.getInstance().getGameClient().getServerThread();
|
socketThread = ViewManager.getInstance().getGameClient().getServerThread();
|
||||||
|
findMaxStats();
|
||||||
RequiredFieldValidator playerNameReqValidator = new RequiredFieldValidator();
|
RequiredFieldValidator playerNameReqValidator = new RequiredFieldValidator();
|
||||||
playerNameReqValidator.setMessage("Player name required.");
|
playerNameReqValidator.setMessage("Player name required.");
|
||||||
|
|
||||||
@@ -48,6 +70,8 @@ public class BoatCustomizeController implements Initializable{
|
|||||||
playerNameLengthValidator.setMessage("Player name too long.");
|
playerNameLengthValidator.setMessage("Player name too long.");
|
||||||
|
|
||||||
boatName.setValidators(playerNameLengthValidator, playerNameReqValidator);
|
boatName.setValidators(playerNameLengthValidator, playerNameReqValidator);
|
||||||
|
boatPane.setBackground(
|
||||||
|
new Background(new BackgroundFill(Color.SKYBLUE, CornerRadii.EMPTY, Insets.EMPTY)));
|
||||||
|
|
||||||
submitBtn.setOnMouseReleased(event -> {
|
submitBtn.setOnMouseReleased(event -> {
|
||||||
Sounds.playButtonClick();
|
Sounds.playButtonClick();
|
||||||
@@ -78,7 +102,10 @@ public class BoatCustomizeController implements Initializable{
|
|||||||
colorArray[2] = (byte) blue;
|
colorArray[2] = (byte) blue;
|
||||||
|
|
||||||
socketThread.sendCustomizationRequest(CustomizeRequestType.COLOR, colorArray);
|
socketThread.sendCustomizationRequest(CustomizeRequestType.COLOR, colorArray);
|
||||||
|
socketThread.sendCustomizationRequest(CustomizeRequestType.SHAPE, currentBoat.toString().getBytes());
|
||||||
lobbyController.closeCustomizationDialog();
|
lobbyController.closeCustomizationDialog();
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -93,4 +120,61 @@ public class BoatCustomizeController implements Initializable{
|
|||||||
public void setParentController(LobbyController lobbyController){
|
public void setParentController(LobbyController lobbyController){
|
||||||
this.lobbyController = lobbyController;
|
this.lobbyController = lobbyController;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setCurrentBoat(String boatType) {
|
||||||
|
currentBoat = BoatMeshType.valueOf(boatType);
|
||||||
|
displayCurrentBoat();
|
||||||
|
refreshStatBars(currentBoat);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void nextBoat() {
|
||||||
|
currentBoat = BoatMeshType.getNextBoatType(currentBoat);
|
||||||
|
displayCurrentBoat();
|
||||||
|
refreshStatBars(currentBoat);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void prevBoat() {
|
||||||
|
currentBoat = BoatMeshType.getPrevBoatType(currentBoat);
|
||||||
|
displayCurrentBoat();
|
||||||
|
refreshStatBars(currentBoat);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void displayCurrentBoat() {
|
||||||
|
boatPane.getChildren().clear();
|
||||||
|
Group group = new Group();
|
||||||
|
boatPane.getChildren().add(group);
|
||||||
|
BoatModel bo = ModelFactory.boatCustomiseView(currentBoat, colorPicker.getValue());
|
||||||
|
group.getChildren().add(bo.getAssets());
|
||||||
|
group.getChildren().add(new PointLight());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void refreshBoat() {
|
||||||
|
boatPane.getChildren().clear();
|
||||||
|
Group group = new Group();
|
||||||
|
boatPane.getChildren().add(group);
|
||||||
|
BoatModel bo = ModelFactory.boatCustomiseView(currentBoat, colorPicker.getValue());
|
||||||
|
group.getChildren().add(bo.getAssets());
|
||||||
|
refreshStatBars(currentBoat);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void findMaxStats() {
|
||||||
|
for (BoatMeshType bmt: BoatMeshType.values()) {
|
||||||
|
if (bmt.turnStep > maxTurnRateMultiplier) {
|
||||||
|
maxTurnRateMultiplier = bmt.turnStep;
|
||||||
|
}
|
||||||
|
if (bmt.maxSpeedMultiplier > maxSpeedMultiplier) {
|
||||||
|
maxSpeedMultiplier = bmt.maxSpeedMultiplier;
|
||||||
|
}
|
||||||
|
if (bmt.accelerationMultiplier > maxAccelerationMultiplier) {
|
||||||
|
maxAccelerationMultiplier = bmt.accelerationMultiplier;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void refreshStatBars(BoatMeshType bo) {
|
||||||
|
speedBar.setProgress((bo.maxSpeedMultiplier) / maxSpeedMultiplier);
|
||||||
|
accelBar.setProgress(bo.accelerationMultiplier / maxAccelerationMultiplier);
|
||||||
|
handleBar.setProgress(bo.turnStep / maxTurnRateMultiplier);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,194 @@
|
|||||||
|
package seng302.visualiser.controllers.dialogs;
|
||||||
|
|
||||||
|
import com.jfoenix.controls.JFXButton;
|
||||||
|
import com.jfoenix.controls.JFXToggleButton;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.ResourceBundle;
|
||||||
|
import javafx.fxml.FXML;
|
||||||
|
import javafx.fxml.Initializable;
|
||||||
|
import javafx.scene.control.Button;
|
||||||
|
import javafx.scene.control.Label;
|
||||||
|
import javafx.scene.input.KeyEvent;
|
||||||
|
import seng302.model.GameKeyBind;
|
||||||
|
import seng302.model.KeyAction;
|
||||||
|
import seng302.visualiser.GameClient;
|
||||||
|
import seng302.visualiser.controllers.ViewManager;
|
||||||
|
|
||||||
|
public class KeyBindingDialogController implements Initializable {
|
||||||
|
|
||||||
|
//--------FXML BEGIN--------//
|
||||||
|
@FXML
|
||||||
|
private Label keyBindingDialogHeader;
|
||||||
|
@FXML
|
||||||
|
private Label closeLabel;
|
||||||
|
@FXML
|
||||||
|
private JFXButton zoomInbtn;
|
||||||
|
@FXML
|
||||||
|
private JFXButton zoomOutBtn;
|
||||||
|
@FXML
|
||||||
|
private JFXButton vmgBtn;
|
||||||
|
@FXML
|
||||||
|
private JFXButton sailInOutBtn;
|
||||||
|
@FXML
|
||||||
|
private JFXButton tackGybeBtn;
|
||||||
|
@FXML
|
||||||
|
private JFXButton upwindBtn;
|
||||||
|
@FXML
|
||||||
|
private JFXButton downwindBtn;
|
||||||
|
@FXML
|
||||||
|
private JFXButton resetBtn;
|
||||||
|
@FXML
|
||||||
|
private Label upwindLabel;
|
||||||
|
@FXML
|
||||||
|
private Label downwindLabel;
|
||||||
|
@FXML
|
||||||
|
private JFXToggleButton turningToggle;
|
||||||
|
@FXML
|
||||||
|
private JFXButton viewButton;
|
||||||
|
@FXML
|
||||||
|
private JFXButton rightButton;
|
||||||
|
@FXML
|
||||||
|
private JFXButton leftButton;
|
||||||
|
@FXML
|
||||||
|
private JFXButton forwardButton;
|
||||||
|
@FXML
|
||||||
|
private JFXButton backwardButton;
|
||||||
|
//---------FXML END---------//
|
||||||
|
|
||||||
|
private GameKeyBind gameKeyBind;
|
||||||
|
private List<JFXButton> buttons = new ArrayList<>();
|
||||||
|
private Map<Button, KeyAction> buttonActionMap;
|
||||||
|
private GameClient gameClient; // to send turning mode packet
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void initialize(URL location, ResourceBundle resources) {
|
||||||
|
gameKeyBind = GameKeyBind.getInstance();
|
||||||
|
buttons = new ArrayList<>();
|
||||||
|
Collections.addAll(buttons,
|
||||||
|
zoomInbtn, zoomOutBtn, vmgBtn, sailInOutBtn, tackGybeBtn, upwindBtn, downwindBtn,
|
||||||
|
viewButton, rightButton, leftButton, forwardButton, backwardButton);
|
||||||
|
bindButtonWithAction();
|
||||||
|
loadKeyBind();
|
||||||
|
|
||||||
|
buttons.forEach(button -> {
|
||||||
|
button.setOnMouseEntered(event -> mouseEnter(button));
|
||||||
|
button.setOnMousePressed(event -> buttonPressed(button));
|
||||||
|
button.setOnMouseExited(event -> mouseExit(button));
|
||||||
|
button.setOnKeyPressed(event -> keyPressed(event, button));
|
||||||
|
});
|
||||||
|
|
||||||
|
turningToggle.setOnMouseClicked(event -> toggleTurningMode());
|
||||||
|
|
||||||
|
resetBtn.setOnMouseClicked(event -> {
|
||||||
|
gameKeyBind.setToDefault();
|
||||||
|
loadKeyBind();
|
||||||
|
});
|
||||||
|
|
||||||
|
closeLabel.setOnMouseClicked(event -> ViewManager.getInstance().closeKeyBindingDialog());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set buttons' label according to GameKeyBind settings
|
||||||
|
*/
|
||||||
|
private void loadKeyBind() {
|
||||||
|
buttons.forEach(
|
||||||
|
button -> button
|
||||||
|
.setText(gameKeyBind.getKeyCode(buttonActionMap.get(button)).getName()));
|
||||||
|
turningToggle.setSelected(gameKeyBind.isContinuouslyTurning());
|
||||||
|
if (gameKeyBind.isContinuouslyTurning()) {
|
||||||
|
upwindLabel.setText("ClOCKWISE TURNING");
|
||||||
|
downwindLabel.setText("ANTICLOCKWISE TURNING");
|
||||||
|
} else {
|
||||||
|
upwindLabel.setText("UPWIND");
|
||||||
|
downwindLabel.setText("DOWNWIND");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bind buttons with specific action in a map.
|
||||||
|
*/
|
||||||
|
private void bindButtonWithAction() {
|
||||||
|
buttonActionMap = new HashMap<>();
|
||||||
|
for (int i = 0; i < 12; i++) {
|
||||||
|
buttonActionMap.put(buttons.get(i), KeyAction.getType(i + 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prompt success / failure message for reassigning key action
|
||||||
|
*/
|
||||||
|
private void showSnackBar(String message, Boolean isWarning) {
|
||||||
|
ViewManager.getInstance().showSnackbar(message, isWarning);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When a mouse enters the button, the color and font size should change to highlight
|
||||||
|
* @param button
|
||||||
|
*/
|
||||||
|
private void mouseEnter(Button button) {
|
||||||
|
button.setStyle(""
|
||||||
|
+ "-fx-background-color: -fx-pp-theme-color;"
|
||||||
|
+ "-fx-text-fill: -fx-pp-front-color;"
|
||||||
|
+ "-fx-font-size: 15;");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prompt "press key..." to inform users assign a new key bind by pressing a key
|
||||||
|
* @param button
|
||||||
|
*/
|
||||||
|
private void buttonPressed(Button button) {
|
||||||
|
button.setText("PRESS KEY...");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When mouse leaves the button, return the button to the normal state in terms of text,
|
||||||
|
* color and font size
|
||||||
|
* @param button
|
||||||
|
*/
|
||||||
|
private void mouseExit(Button button) {
|
||||||
|
button.setText(GameKeyBind.getInstance().getKeyCode(buttonActionMap.get(button)).getName());
|
||||||
|
button.setStyle(""
|
||||||
|
+ "-fx-background-color: -fx-pp-front-color; "
|
||||||
|
+ "-fx-text-fill: -fx-pp-theme-color; "
|
||||||
|
+ "-fx-font-size: 13;");
|
||||||
|
keyBindingDialogHeader.requestFocus();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When a key is pressed, check if the new binding conflicts to any existed settings, if not
|
||||||
|
* assign the selected action with the new key binding to GameKeyBind.
|
||||||
|
* @param event
|
||||||
|
* @param button
|
||||||
|
*/
|
||||||
|
private void keyPressed(KeyEvent event, Button button) {
|
||||||
|
event.consume();
|
||||||
|
KeyAction buttonAction = buttonActionMap.get(button);
|
||||||
|
if (gameKeyBind.bindKeyToAction(event.getCode(), buttonAction)) {
|
||||||
|
showSnackBar(button.getId() + " is set to " + event.getCode().getName(), false);
|
||||||
|
button.setText(gameKeyBind.getKeyCode(buttonAction).getName());
|
||||||
|
} else {
|
||||||
|
loadKeyBind();
|
||||||
|
showSnackBar(event.getCode().getName() + " is already in use", true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When the turning mode is toggled, update gameKeyBind and send out packet to notify the server
|
||||||
|
*/
|
||||||
|
private void toggleTurningMode() {
|
||||||
|
gameKeyBind.toggleTurningMode();
|
||||||
|
gameClient.sendToggleTurningModePacket();
|
||||||
|
loadKeyBind();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setGameClient(GameClient gameClient) {
|
||||||
|
this.gameClient = gameClient;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
package seng302.visualiser.controllers.dialogs;
|
||||||
|
|
||||||
|
import com.jfoenix.controls.JFXButton;
|
||||||
|
import com.jfoenix.controls.JFXDialog;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.util.ResourceBundle;
|
||||||
|
import javafx.event.EventHandler;
|
||||||
|
import javafx.fxml.FXML;
|
||||||
|
import javafx.fxml.Initializable;
|
||||||
|
import javafx.scene.control.Label;
|
||||||
|
import javafx.scene.input.MouseEvent;
|
||||||
|
|
||||||
|
public class PopupDialogController implements Initializable {
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
private Label headerLabel;
|
||||||
|
@FXML
|
||||||
|
private Label contentLabel;
|
||||||
|
@FXML
|
||||||
|
private Label closeLabel;
|
||||||
|
@FXML
|
||||||
|
private JFXButton optionButton;
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
private JFXDialog popupDialog;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void initialize(URL location, ResourceBundle resources) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setContent(String content) {
|
||||||
|
this.contentLabel.setText(content);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHeader(String header) {
|
||||||
|
this.headerLabel.setText(header);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOptionButton(JFXButton jfxButton) {
|
||||||
|
this.optionButton = jfxButton;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOptionButtonText(String text) {
|
||||||
|
this.optionButton.setText(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOptionButtonEventHandler(EventHandler<? super MouseEvent> eventHandler) {
|
||||||
|
this.optionButton.setOnMouseClicked(eventHandler);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPopupDialog(JFXDialog popupDialog) {
|
||||||
|
this.popupDialog = popupDialog;
|
||||||
|
this.closeLabel.setOnMouseClicked(event -> this.popupDialog.close());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,18 +1,19 @@
|
|||||||
package seng302.visualiser.controllers.dialogs;
|
package seng302.visualiser.controllers.dialogs;
|
||||||
|
|
||||||
import com.jfoenix.controls.JFXButton;
|
import com.jfoenix.controls.JFXButton;
|
||||||
|
import com.jfoenix.controls.JFXCheckBox;
|
||||||
import com.jfoenix.controls.JFXSlider;
|
import com.jfoenix.controls.JFXSlider;
|
||||||
import com.jfoenix.controls.JFXTextField;
|
import com.jfoenix.controls.JFXTextField;
|
||||||
import com.jfoenix.validation.RequiredFieldValidator;
|
import com.jfoenix.validation.RequiredFieldValidator;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.util.ResourceBundle;
|
import java.util.ResourceBundle;
|
||||||
import javafx.application.Platform;
|
|
||||||
import javafx.fxml.FXML;
|
import javafx.fxml.FXML;
|
||||||
import javafx.fxml.Initializable;
|
import javafx.fxml.Initializable;
|
||||||
import javafx.scene.control.Label;
|
import javafx.scene.control.Label;
|
||||||
import javafx.scene.input.MouseEvent;
|
import javafx.scene.layout.AnchorPane;
|
||||||
import seng302.gameServer.ServerDescription;
|
import seng302.gameServer.ServerDescription;
|
||||||
import seng302.utilities.Sounds;
|
import seng302.utilities.Sounds;
|
||||||
|
import seng302.visualiser.MapMaker;
|
||||||
import seng302.visualiser.controllers.ViewManager;
|
import seng302.visualiser.controllers.ViewManager;
|
||||||
import seng302.visualiser.validators.FieldLengthValidator;
|
import seng302.visualiser.validators.FieldLengthValidator;
|
||||||
import seng302.visualiser.validators.ValidationTools;
|
import seng302.visualiser.validators.ValidationTools;
|
||||||
@@ -28,13 +29,40 @@ public class ServerCreationController implements Initializable {
|
|||||||
private Label maxPlayersLabel;
|
private Label maxPlayersLabel;
|
||||||
@FXML
|
@FXML
|
||||||
private JFXButton submitBtn;
|
private JFXButton submitBtn;
|
||||||
|
@FXML
|
||||||
|
private JFXButton nextMapButton;
|
||||||
|
@FXML
|
||||||
|
private JFXButton lastMapButton;
|
||||||
|
@FXML
|
||||||
|
private Label mapNameLabel;
|
||||||
|
@FXML
|
||||||
|
private JFXSlider legsSlider;
|
||||||
|
@FXML
|
||||||
|
private Label legsSliderLabel;
|
||||||
|
@FXML
|
||||||
|
private JFXCheckBox pickupsCheckBox;
|
||||||
|
@FXML
|
||||||
|
private AnchorPane mapHolder;
|
||||||
|
|
||||||
|
private MapMaker mapMaker = MapMaker.getInstance();
|
||||||
|
|
||||||
//---------FXML END---------//
|
//---------FXML END---------//
|
||||||
|
|
||||||
public void initialize(URL location, ResourceBundle resources) {
|
public void initialize(URL location, ResourceBundle resources) {
|
||||||
|
|
||||||
|
maxPlayersSlider.valueProperty().addListener(
|
||||||
|
(observable, oldValue, newValue) -> updateMaxPlayerLabel()
|
||||||
|
);
|
||||||
|
maxPlayersSlider.setMax(mapMaker.getMaxPlayers());
|
||||||
|
maxPlayersSlider.setValue(mapMaker.getMaxPlayers());
|
||||||
|
|
||||||
|
legsSlider.valueProperty().addListener(
|
||||||
|
(obs, oldVal, newVal) -> updateLegSliderLabel()
|
||||||
|
);
|
||||||
|
legsSlider.setMax(10);
|
||||||
|
|
||||||
updateMaxPlayerLabel();
|
updateMaxPlayerLabel();
|
||||||
maxPlayersSlider.valueProperty().addListener((observable, oldValue, newValue) -> {
|
updateLegSliderLabel();
|
||||||
updateMaxPlayerLabel();
|
|
||||||
});
|
|
||||||
|
|
||||||
FieldLengthValidator fieldLengthValidator = new FieldLengthValidator(40);
|
FieldLengthValidator fieldLengthValidator = new FieldLengthValidator(40);
|
||||||
fieldLengthValidator.setMessage("Server name too long.");
|
fieldLengthValidator.setMessage("Server name too long.");
|
||||||
@@ -49,6 +77,18 @@ public class ServerCreationController implements Initializable {
|
|||||||
validateServerSettings();
|
validateServerSettings();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
nextMapButton.setOnMouseReleased(event -> {
|
||||||
|
Sounds.playButtonClick();
|
||||||
|
nextMap();
|
||||||
|
});
|
||||||
|
|
||||||
|
lastMapButton.setOnMouseReleased(event -> {
|
||||||
|
Sounds.playButtonClick();
|
||||||
|
lastMap();
|
||||||
|
});
|
||||||
|
|
||||||
|
mapHolder.getChildren().setAll(mapMaker.getCurrentGameView());
|
||||||
|
mapNameLabel.setText(mapMaker.getCurrentRegatta().getCourseName());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -69,7 +109,7 @@ public class ServerCreationController implements Initializable {
|
|||||||
private void createServer() {
|
private void createServer() {
|
||||||
ServerDescription serverDescription = ViewManager.getInstance().getGameClient()
|
ServerDescription serverDescription = ViewManager.getInstance().getGameClient()
|
||||||
.runAsHost("localhost", 4941, serverName.getText(), (int) maxPlayersSlider
|
.runAsHost("localhost", 4941, serverName.getText(), (int) maxPlayersSlider
|
||||||
.getValue());
|
.getValue(), mapMaker.getCurrentRacePath(), (int) legsSlider.getValue(), pickupsCheckBox.isSelected());
|
||||||
|
|
||||||
ViewManager.getInstance().setProperty("serverName", serverDescription.getName());
|
ViewManager.getInstance().setProperty("serverName", serverDescription.getName());
|
||||||
ViewManager.getInstance().setProperty("mapName", serverDescription.getMapName());
|
ViewManager.getInstance().setProperty("mapName", serverDescription.getMapName());
|
||||||
@@ -80,11 +120,35 @@ public class ServerCreationController implements Initializable {
|
|||||||
*/
|
*/
|
||||||
private void updateMaxPlayerLabel() {
|
private void updateMaxPlayerLabel() {
|
||||||
maxPlayersSlider.setValue(Math.floor(maxPlayersSlider.getValue()));
|
maxPlayersSlider.setValue(Math.floor(maxPlayersSlider.getValue()));
|
||||||
maxPlayersLabel.setText(String.format("YOU SELECTED: %.0f", maxPlayersSlider.getValue()));
|
maxPlayersLabel.setText(String.format("Max players: %.0f", maxPlayersSlider.getValue()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void playButtonHoverSound(MouseEvent mouseEvent) {
|
private void updateLegSliderLabel() {
|
||||||
|
legsSlider.setValue(Math.floor(legsSlider.getValue()));
|
||||||
|
legsSliderLabel.setText(
|
||||||
|
String.format("A section of the race will repeat %.0f times", legsSlider.getValue())
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void playButtonHoverSound() {
|
||||||
Sounds.playHoverSound();
|
Sounds.playHoverSound();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void nextMap() {
|
||||||
|
mapMaker.next();
|
||||||
|
updateMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void lastMap() {
|
||||||
|
mapMaker.previous();
|
||||||
|
updateMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateMap() {
|
||||||
|
mapHolder.getChildren().setAll(mapMaker.getCurrentGameView());
|
||||||
|
mapNameLabel.setText(mapMaker.getCurrentRegatta().getCourseName());
|
||||||
|
maxPlayersSlider.setMax(mapMaker.getMaxPlayers());
|
||||||
|
maxPlayersSlider.setValue(mapMaker.getMaxPlayers());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,21 +2,59 @@ package seng302.visualiser.fxObjects.assets_3D;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Enum for boat meshes. Enum values should be of the form :
|
* Enum for boat meshes. Enum values should be of the form :
|
||||||
* ENUM_VALUE (hull file, mast file, X offset of mast CoR from origin, sail file, X offset of sail CoR from origin)
|
* ENUM_VALUE (hull file, mast file, Y offset of mast CoR from origin, sail file, Y offset of sail CoR from origin, jib file, fixed sail)
|
||||||
* Files must be valid .stl files.
|
* Files must be valid .stl files.
|
||||||
*/
|
*/
|
||||||
public enum BoatMeshType {
|
public enum BoatMeshType {
|
||||||
|
|
||||||
DINGHY ("dinghy_hull.stl", "dinghy_mast.stl", -1.36653, "dinghy_sail.stl", -1.36653);
|
DINGHY("dinghy_hull.stl", "dinghy_mast.stl", 1.36653, "dinghy_sail.stl", 1.36653, null, false, 1.8, 1.0, 1.0),
|
||||||
|
CATAMARAN("catamaran_hull.stl", "catamaran_mast.stl", 0.997, "catamaran_sail.stl",
|
||||||
|
0.997, null, false, 1.0, 1.4, 2.0),
|
||||||
|
PIRATE_SHIP("pirateship_hull.stl", "pirateship_mast.stl", -0.5415, "pirateship_mainsail.stl",
|
||||||
|
-0.5415, "pirateship_frontsail.stl", true, 1.2, 1.6, 1.2);
|
||||||
|
|
||||||
final String hullFile, mastFile, sailFile;
|
final String hullFile, mastFile, sailFile, jibFile;
|
||||||
final double mastOffset, sailOffset;
|
final double mastOffset, sailOffset;
|
||||||
|
public final double maxSpeedMultiplier;
|
||||||
|
public final double accelerationMultiplier;
|
||||||
|
public final double turnStep;
|
||||||
|
final boolean fixedSail;
|
||||||
|
final static BoatMeshType[] boatTypes = new BoatMeshType[]{DINGHY, CATAMARAN, PIRATE_SHIP};
|
||||||
|
|
||||||
BoatMeshType(String hullFile, String mastFile, double mastOffset, String sailFile, double sailOffset) {
|
BoatMeshType(String hullFile, String mastFile, double mastOffset, String sailFile,
|
||||||
|
double sailOffset, String jibFile, boolean fixedSail, double maxSpeedMultiplier, double accelerationMultiplier, double turnStep) {
|
||||||
this.hullFile = hullFile;
|
this.hullFile = hullFile;
|
||||||
this.mastFile = mastFile;
|
this.mastFile = mastFile;
|
||||||
this.mastOffset = mastOffset;
|
this.mastOffset = mastOffset;
|
||||||
this.sailFile = sailFile;
|
this.sailFile = sailFile;
|
||||||
this.sailOffset = sailOffset;
|
this.sailOffset = sailOffset;
|
||||||
|
this.jibFile = jibFile;
|
||||||
|
this.fixedSail = fixedSail;
|
||||||
|
this.maxSpeedMultiplier = maxSpeedMultiplier;
|
||||||
|
this.accelerationMultiplier = accelerationMultiplier;
|
||||||
|
this.turnStep = turnStep;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static BoatMeshType getNextBoatType(BoatMeshType boatType) {
|
||||||
|
for (int i = 0; i < boatTypes.length; i++) {
|
||||||
|
if (i == boatTypes.length -1) {
|
||||||
|
return boatTypes[0];
|
||||||
|
} else if (boatType == boatTypes[i]) {
|
||||||
|
return boatTypes[i+1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return boatType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static BoatMeshType getPrevBoatType(BoatMeshType boatType) {
|
||||||
|
for (int i = 0; i < boatTypes.length; i++) {
|
||||||
|
if (i == 0 && boatType == boatTypes[i]) {
|
||||||
|
return boatTypes[boatTypes.length -1];
|
||||||
|
} else if (boatType == boatTypes[i]) {
|
||||||
|
return boatTypes[i-1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return boatType;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,14 +34,16 @@ public class BoatModel extends Model {
|
|||||||
* @param degrees The rotation of the sail in degrees
|
* @param degrees The rotation of the sail in degrees
|
||||||
*/
|
*/
|
||||||
public void rotateSail(double degrees) {
|
public void rotateSail(double degrees) {
|
||||||
MeshView mast = getMeshViewChild(MAST_INDEX);
|
if (!meshType.fixedSail) {
|
||||||
MeshView sail = getMeshViewChild(SAIL_INDEX);
|
MeshView mast = getMeshViewChild(MAST_INDEX);
|
||||||
mast.getTransforms().setAll(
|
MeshView sail = getMeshViewChild(SAIL_INDEX);
|
||||||
new Rotate(degrees, -meshType.mastOffset, 0,0, new Point3D(0, 0, 1))
|
mast.getTransforms().setAll(
|
||||||
);
|
new Rotate(degrees, 0, -meshType.mastOffset, 0, new Point3D(0, 0, 1))
|
||||||
sail.getTransforms().setAll(
|
);
|
||||||
new Rotate(degrees, -meshType.sailOffset, 0,0, new Point3D(0, 0, 1))
|
sail.getTransforms().setAll(
|
||||||
);
|
new Rotate(degrees, 0, -meshType.sailOffset,0, new Point3D(0, 0, 1))
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void hideSail() {
|
public void hideSail() {
|
||||||
@@ -69,4 +71,8 @@ public class BoatModel extends Model {
|
|||||||
private MeshView getMeshViewChild(int index) {
|
private MeshView getMeshViewChild(int index) {
|
||||||
return (MeshView) assets.getChildren().get(index);
|
return (MeshView) assets.getChildren().get(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public BoatMeshType getMeshType() {
|
||||||
|
return meshType;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -3,6 +3,7 @@ package seng302.visualiser.fxObjects.assets_3D;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import javafx.application.Platform;
|
import javafx.application.Platform;
|
||||||
|
import javafx.beans.property.ReadOnlyDoubleWrapper;
|
||||||
import javafx.geometry.Point3D;
|
import javafx.geometry.Point3D;
|
||||||
import javafx.scene.Group;
|
import javafx.scene.Group;
|
||||||
import javafx.scene.paint.Color;
|
import javafx.scene.paint.Color;
|
||||||
@@ -11,7 +12,7 @@ import javafx.scene.transform.Rotate;
|
|||||||
/**
|
/**
|
||||||
* BoatGroup is a javafx group that by default contains a graphical objects for representing a 2
|
* BoatGroup is a javafx group that by default contains a graphical objects for representing a 2
|
||||||
* dimensional boat. It contains a single polygon for the boat, a group of lines to show it's path,
|
* dimensional boat. It contains a single polygon for the boat, a group of lines to show it's path,
|
||||||
* a wake object and two text labels to annotate the boat teams name and the boats velocity. The
|
* a wake object and two text labels to annotate the boat teams name and the boatTypes velocity. The
|
||||||
* boat will update it's position onscreen everytime UpdatePosition is called unless the window is
|
* boat will update it's position onscreen everytime UpdatePosition is called unless the window is
|
||||||
* minimized in which case it attempts to store animations and apply them when the window is
|
* minimized in which case it attempts to store animations and apply them when the window is
|
||||||
* maximised.
|
* maximised.
|
||||||
@@ -28,15 +29,18 @@ public class BoatObject extends Group {
|
|||||||
private Group wake;
|
private Group wake;
|
||||||
private Color colour = Color.BLACK;
|
private Color colour = Color.BLACK;
|
||||||
private Boolean isSelected = false;
|
private Boolean isSelected = false;
|
||||||
private Rotate rotation = new Rotate(0,0,1);
|
private Rotate rotation = new Rotate(0, new Point3D(0,0,1));
|
||||||
|
|
||||||
|
private ReadOnlyDoubleWrapper rotationProperty;
|
||||||
|
|
||||||
private List<SelectedBoatListener> selectedBoatListenerListeners = new ArrayList<>();
|
private List<SelectedBoatListener> selectedBoatListenerListeners = new ArrayList<>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a BoatGroup with the default triangular boat polygon.
|
* Creates a BoatGroup with the default triangular boat polygon.
|
||||||
*/
|
*/
|
||||||
public BoatObject() {
|
public BoatObject(BoatMeshType boatMeshType) {
|
||||||
boatAssets = ModelFactory.boatGameView(BoatMeshType.DINGHY, colour);
|
rotationProperty = new ReadOnlyDoubleWrapper(0.0);
|
||||||
|
boatAssets = ModelFactory.boatGameView(boatMeshType, colour);
|
||||||
boatAssets.hideSail();
|
boatAssets.hideSail();
|
||||||
boatAssets.getAssets().getTransforms().addAll(
|
boatAssets.getAssets().getTransforms().addAll(
|
||||||
rotation
|
rotation
|
||||||
@@ -66,8 +70,6 @@ public class BoatObject extends Group {
|
|||||||
* @param windDir .
|
* @param windDir .
|
||||||
*/
|
*/
|
||||||
public void moveTo(double x, double y, double rotation, double velocity, Boolean sailIn, double windDir) {
|
public void moveTo(double x, double y, double rotation, double velocity, Boolean sailIn, double windDir) {
|
||||||
Double dx = Math.abs(boatAssets.getAssets().getLayoutX() - x);
|
|
||||||
Double dy = Math.abs(boatAssets.getAssets().getLayoutY() - y);
|
|
||||||
Platform.runLater(() -> {
|
Platform.runLater(() -> {
|
||||||
rotateTo(rotation, sailIn, windDir);
|
rotateTo(rotation, sailIn, windDir);
|
||||||
this.layoutXProperty().setValue(x);
|
this.layoutXProperty().setValue(x);
|
||||||
@@ -85,6 +87,7 @@ public class BoatObject extends Group {
|
|||||||
|
|
||||||
|
|
||||||
private void rotateTo(double heading, boolean sailsIn, double windDir) {
|
private void rotateTo(double heading, boolean sailsIn, double windDir) {
|
||||||
|
rotationProperty.set(heading);
|
||||||
rotation.setAngle(heading);
|
rotation.setAngle(heading);
|
||||||
wake.getTransforms().setAll(new Rotate(heading, new Point3D(0,0,1)));
|
wake.getTransforms().setAll(new Rotate(heading, new Point3D(0,0,1)));
|
||||||
if (sailsIn) {
|
if (sailsIn) {
|
||||||
@@ -132,4 +135,8 @@ public class BoatObject extends Group {
|
|||||||
public void addSelectedBoatListener(SelectedBoatListener sbl) {
|
public void addSelectedBoatListener(SelectedBoatListener sbl) {
|
||||||
selectedBoatListenerListeners.add(sbl);
|
selectedBoatListenerListeners.add(sbl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ReadOnlyDoubleWrapper getRotationProperty() {
|
||||||
|
return rotationProperty;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -7,6 +7,7 @@ import javafx.geometry.Point3D;
|
|||||||
import javafx.scene.AmbientLight;
|
import javafx.scene.AmbientLight;
|
||||||
import javafx.scene.CacheHint;
|
import javafx.scene.CacheHint;
|
||||||
import javafx.scene.Group;
|
import javafx.scene.Group;
|
||||||
|
import javafx.scene.PointLight;
|
||||||
import javafx.scene.paint.Color;
|
import javafx.scene.paint.Color;
|
||||||
import javafx.scene.paint.PhongMaterial;
|
import javafx.scene.paint.PhongMaterial;
|
||||||
import javafx.scene.shape.Circle;
|
import javafx.scene.shape.Circle;
|
||||||
@@ -18,7 +19,7 @@ import javafx.scene.transform.Translate;
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Factory class for creating 3D models of boats.
|
* Factory class for creating 3D models of boatTypes.
|
||||||
*/
|
*/
|
||||||
public class ModelFactory {
|
public class ModelFactory {
|
||||||
|
|
||||||
@@ -51,6 +52,35 @@ public class ModelFactory {
|
|||||||
return bo;
|
return bo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static BoatModel boatCustomiseView(BoatMeshType boatType, Color primaryColour) {
|
||||||
|
Group boatAssets = getUnmodifiedBoatModel(boatType, primaryColour);
|
||||||
|
final Rotate animationRotate = new Rotate(0, new Point3D(0,0,1));
|
||||||
|
boatAssets.getTransforms().addAll(
|
||||||
|
new Scale(8.0, 8.0, 8.0),
|
||||||
|
new Rotate(-70, new Point3D(1,0,0)),
|
||||||
|
new Translate(16,50, 1),
|
||||||
|
animationRotate
|
||||||
|
);
|
||||||
|
|
||||||
|
boatAssets.getTransforms().add(animationRotate);
|
||||||
|
BoatModel bo = new BoatModel(boatAssets, null, boatType);
|
||||||
|
bo.rotateSail(45);
|
||||||
|
|
||||||
|
bo.setAnimation(new AnimationTimer() {
|
||||||
|
double boatAngle = 0;
|
||||||
|
Rotate rotate = animationRotate;
|
||||||
|
@Override
|
||||||
|
public void handle(long now) {
|
||||||
|
boatAngle += 0.5;
|
||||||
|
rotate.setAngle(boatAngle);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
boatAssets.getChildren().addAll(
|
||||||
|
new AmbientLight()
|
||||||
|
);
|
||||||
|
return bo;
|
||||||
|
}
|
||||||
|
|
||||||
public static BoatModel boatRotatingView(BoatMeshType boatType, Color primaryColour) {
|
public static BoatModel boatRotatingView(BoatMeshType boatType, Color primaryColour) {
|
||||||
Group boatAssets = getUnmodifiedBoatModel(boatType, primaryColour);
|
Group boatAssets = getUnmodifiedBoatModel(boatType, primaryColour);
|
||||||
boatAssets.getTransforms().addAll(
|
boatAssets.getTransforms().addAll(
|
||||||
@@ -78,27 +108,35 @@ public class ModelFactory {
|
|||||||
public static BoatModel boatGameView(BoatMeshType boatType, Color primaryColour) {
|
public static BoatModel boatGameView(BoatMeshType boatType, Color primaryColour) {
|
||||||
Group boatAssets = getUnmodifiedBoatModel(boatType, primaryColour);
|
Group boatAssets = getUnmodifiedBoatModel(boatType, primaryColour);
|
||||||
boatAssets.getTransforms().setAll(
|
boatAssets.getTransforms().setAll(
|
||||||
new Rotate(-90, new Point3D(0,0,1)),
|
|
||||||
new Scale(0.3, 0.3, 0.3)
|
new Scale(0.3, 0.3, 0.3)
|
||||||
);
|
);
|
||||||
return new BoatModel(boatAssets, null, boatType);
|
return new BoatModel(boatAssets, null, boatType);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Group getUnmodifiedBoatModel(BoatMeshType boatType, Color primaryColour) {
|
private static Group getUnmodifiedBoatModel(BoatMeshType boatType, Color primaryColour) {
|
||||||
|
|
||||||
Group boatAssets = new Group();
|
Group boatAssets = new Group();
|
||||||
MeshView hull = importFile(boatType.hullFile);
|
MeshView hull = importSTL(boatType.hullFile);
|
||||||
hull.setMaterial(new PhongMaterial(primaryColour));
|
hull.setMaterial(new PhongMaterial(primaryColour));
|
||||||
MeshView mast = importFile(boatType.mastFile);
|
MeshView mast = importSTL(boatType.mastFile);
|
||||||
mast.setMaterial(new PhongMaterial(primaryColour));
|
mast.setMaterial(new PhongMaterial(primaryColour));
|
||||||
MeshView sail = importFile(boatType.sailFile);
|
MeshView sail = importSTL(boatType.sailFile);
|
||||||
sail.setMaterial(new PhongMaterial(Color.WHITE));
|
sail.setMaterial(new PhongMaterial(Color.WHITE));
|
||||||
boatAssets.getChildren().addAll(hull, mast, sail);
|
|
||||||
|
if (boatType.jibFile != null) {
|
||||||
|
MeshView jib = importSTL(boatType.jibFile);
|
||||||
|
sail.setMaterial(new PhongMaterial(Color.WHITE));
|
||||||
|
boatAssets.getChildren().addAll(hull, mast, sail, jib);
|
||||||
|
} else {
|
||||||
|
boatAssets.getChildren().addAll(hull, mast, sail);
|
||||||
|
}
|
||||||
|
|
||||||
return boatAssets;
|
return boatAssets;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static MeshView importFile(String fileName) {
|
private static MeshView importSTL(String fileName) {
|
||||||
StlMeshImporter importer = new StlMeshImporter();
|
StlMeshImporter importer = new StlMeshImporter();
|
||||||
importer.read(ModelFactory.class.getResource("/meshes/" + fileName));
|
importer.read(ModelFactory.class.getResource("/meshes/boatSTLs/" + fileName));
|
||||||
MeshView importedFile = new MeshView(importer.getImport());
|
MeshView importedFile = new MeshView(importer.getImport());
|
||||||
importedFile.setCache(true);
|
importedFile.setCache(true);
|
||||||
importedFile.setCacheHint(CacheHint.SCALE_AND_ROTATE);
|
importedFile.setCacheHint(CacheHint.SCALE_AND_ROTATE);
|
||||||
|
|||||||
@@ -1,108 +0,0 @@
|
|||||||
package seng302.visualiser;
|
|
||||||
|
|
||||||
import com.interactivemesh.jfx.importer.stl.StlMeshImporter;
|
|
||||||
import javafx.animation.AnimationTimer;
|
|
||||||
import javafx.application.Application;
|
|
||||||
import javafx.geometry.Point3D;
|
|
||||||
import javafx.scene.Camera;
|
|
||||||
import javafx.scene.Group;
|
|
||||||
import javafx.scene.PerspectiveCamera;
|
|
||||||
import javafx.scene.Scene;
|
|
||||||
import javafx.scene.SceneAntialiasing;
|
|
||||||
import javafx.scene.paint.Color;
|
|
||||||
import javafx.scene.paint.PhongMaterial;
|
|
||||||
import javafx.scene.shape.MeshView;
|
|
||||||
import javafx.scene.transform.Rotate;
|
|
||||||
import javafx.scene.transform.Scale;
|
|
||||||
import javafx.scene.transform.Translate;
|
|
||||||
import javafx.stage.Stage;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Created by cir27 on 7/09/17.
|
|
||||||
*/
|
|
||||||
public class test3d extends Application {
|
|
||||||
|
|
||||||
Group root = new Group();
|
|
||||||
Scene scene;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void start(Stage primaryStage) throws Exception {
|
|
||||||
// camera = new PerspectiveCamera();
|
|
||||||
// gameObjects = new Group();
|
|
||||||
// root3D = new Group(camera, gameObjects);
|
|
||||||
scene = new Scene(
|
|
||||||
root, 1000, 1000, true, SceneAntialiasing.BALANCED
|
|
||||||
);
|
|
||||||
gameView3DTest();
|
|
||||||
primaryStage.setScene(scene);
|
|
||||||
primaryStage.show();
|
|
||||||
// scene.setCamera(camera);
|
|
||||||
// primaryStage.setScene(scene);
|
|
||||||
// primaryStage.show();
|
|
||||||
//
|
|
||||||
// StlMeshImporter importer = new StlMeshImporter();
|
|
||||||
// importer.read(test3d.class.getResource("/meshes/dinghy_hull.stl").toString());
|
|
||||||
// MeshView boat = new MeshView(importer.getImport());
|
|
||||||
// boat.setMaterial(new PhongMaterial(Color.GREENYELLOW));
|
|
||||||
//
|
|
||||||
// importer = new StlMeshImporter();
|
|
||||||
// importer.read(getClass().getResource("/meshes/dinghy_mast.stl").toString());
|
|
||||||
// MeshView mast = new MeshView(importer.getImport());
|
|
||||||
// mast.setMaterial(new PhongMaterial(Color.GREENYELLOW));
|
|
||||||
//
|
|
||||||
// importer = new StlMeshImporter();
|
|
||||||
// importer.read(getClass().getResource("/meshes/dinghy_sail.stl").toString());
|
|
||||||
// MeshView sail = new MeshView(importer.getImport());
|
|
||||||
// sail.setMaterial(new PhongMaterial(Color.LIGHTGREY));
|
|
||||||
//
|
|
||||||
// gameObjects.getChildren().addAll(boat, mast, sail);
|
|
||||||
//
|
|
||||||
// gameObjects.getTransforms().add(new Scale(25, 25,25));
|
|
||||||
// gameObjects.getTransforms().add(new Translate(15, 20,0));
|
|
||||||
// gameObjects.getTransforms().addAll(
|
|
||||||
// new Rotate(90, new Point3D(0,0,1)),
|
|
||||||
// new Rotate(90, new Point3D(0, 1, 0))
|
|
||||||
// );
|
|
||||||
//
|
|
||||||
//// PointLight light = new PointLight();
|
|
||||||
//// light.setLightOn(true);
|
|
||||||
//// light.getTransforms().add(new Translate(15, 20, 0));
|
|
||||||
////
|
|
||||||
//// PointLight light2 = new PointLight();
|
|
||||||
//// light2.setLightOn(true);
|
|
||||||
//// light2.getTransforms().add(new Translate(30, 40, 0));
|
|
||||||
//
|
|
||||||
//// root3D.getChildren().addAll(light);
|
|
||||||
//
|
|
||||||
// scene.setOnKeyPressed(event -> {
|
|
||||||
// switch (event.getCode()) {
|
|
||||||
// case UP:
|
|
||||||
// gameObjects.getTransforms().add(new Rotate(5, new Point3D(0,0,1)));
|
|
||||||
// break;
|
|
||||||
// case DOWN:
|
|
||||||
// gameObjects.getTransforms().add(new Rotate(-5, new Point3D(0,0,1)));
|
|
||||||
// break;
|
|
||||||
// case LEFT:
|
|
||||||
// gameObjects.getTransforms().add(new Rotate(-5, new Point3D(0,1,0)));
|
|
||||||
// break;
|
|
||||||
// case RIGHT:
|
|
||||||
// gameObjects.getTransforms().add(new Rotate(5, new Point3D(0,1,0)));
|
|
||||||
// break;
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
//
|
|
||||||
// AnimationTimer animationTimer = new AnimationTimer() {
|
|
||||||
// @Override
|
|
||||||
// public void handle(long now) {
|
|
||||||
// sail.getTransforms().add(new Rotate(0.5, 0, -1.36653, 0, new Point3D(0, 0, 1)));
|
|
||||||
// }
|
|
||||||
// };
|
|
||||||
//
|
|
||||||
//// animationTimer.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void gameView3DTest() {
|
|
||||||
GameView3D gameView3D = new GameView3D();
|
|
||||||
root.getChildren().add(gameView3D.getAssets());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
Before Width: | Height: | Size: 2.8 KiB After Width: | Height: | Size: 92 KiB |
@@ -1,9 +0,0 @@
|
|||||||
<?xml version="1.0" ?>
|
|
||||||
|
|
||||||
<configurations>
|
|
||||||
<race-name>AC35</race-name>
|
|
||||||
<race-size>6</race-size>
|
|
||||||
<time-scale>10.0</time-scale>
|
|
||||||
<windDir-direction>135</windDir-direction>
|
|
||||||
</configurations>
|
|
||||||
|
|
||||||
@@ -1,80 +0,0 @@
|
|||||||
<?xml version="1.0" ?>
|
|
||||||
|
|
||||||
<markers>
|
|
||||||
<marks>
|
|
||||||
<gate>
|
|
||||||
<name type="start-line">Start</name>
|
|
||||||
<mark>
|
|
||||||
<name>Start1</name>
|
|
||||||
<latitude>57.6703330</latitude>
|
|
||||||
<longitude>11.8278330</longitude>
|
|
||||||
<id>122</id>
|
|
||||||
</mark>
|
|
||||||
<mark>
|
|
||||||
<name>Start2</name>
|
|
||||||
<latitude>57.6703330</latitude>
|
|
||||||
<longitude>11.8271333</longitude>
|
|
||||||
<id>123</id>
|
|
||||||
</mark>
|
|
||||||
</gate>
|
|
||||||
<mark>
|
|
||||||
<name>Mid Mark</name>
|
|
||||||
<latitude>57.6675700</latitude>
|
|
||||||
<longitude>11.8359880</longitude>
|
|
||||||
<id>131</id>
|
|
||||||
</mark>
|
|
||||||
<gate>
|
|
||||||
<name>Leeward Gate</name>
|
|
||||||
<mark>
|
|
||||||
<name>Leeward Gate1</name>
|
|
||||||
<latitude>57.6708220</latitude>
|
|
||||||
<longitude>11.8433900</longitude>
|
|
||||||
<id>124</id>
|
|
||||||
</mark>
|
|
||||||
<mark>
|
|
||||||
<name>Leeward Gate2</name>
|
|
||||||
<latitude>57.6711220</latitude>
|
|
||||||
<longitude>11.8436900</longitude>
|
|
||||||
<id>125</id>
|
|
||||||
</mark>
|
|
||||||
</gate>
|
|
||||||
<gate>
|
|
||||||
<name>Windward Gate</name>
|
|
||||||
<mark>
|
|
||||||
<name>Windward Gate1</name>
|
|
||||||
<latitude>57.6650170</latitude>
|
|
||||||
<longitude>11.8279170</longitude>
|
|
||||||
<id>126</id>
|
|
||||||
</mark>
|
|
||||||
<mark>
|
|
||||||
<name>Windward Gate2</name>
|
|
||||||
<latitude>57.6653170</latitude>
|
|
||||||
<longitude>11.8282170</longitude>
|
|
||||||
<id>127</id>
|
|
||||||
</mark>
|
|
||||||
</gate>
|
|
||||||
<gate type="finish-line">
|
|
||||||
<name>Finish</name>
|
|
||||||
<mark>
|
|
||||||
<name>Finish1</name>
|
|
||||||
<latitude>57.6715240</latitude>
|
|
||||||
<longitude>11.8444950</longitude>
|
|
||||||
<id>128</id>
|
|
||||||
</mark>
|
|
||||||
<mark>
|
|
||||||
<name>Finish2</name>
|
|
||||||
<latitude>57.6718240</latitude>
|
|
||||||
<longitude>11.8447950</longitude>
|
|
||||||
<id>129</id>
|
|
||||||
</mark>
|
|
||||||
</gate>
|
|
||||||
</marks>
|
|
||||||
<order>
|
|
||||||
<one>Start</one>
|
|
||||||
<two>Mid Mark</two>
|
|
||||||
<three>Leeward Gate</three>
|
|
||||||
<four>Windward Gate</four>
|
|
||||||
<five>Leeward Gate</five>
|
|
||||||
<six>Finish</six>
|
|
||||||
</order>
|
|
||||||
</markers>
|
|
||||||
@@ -1,72 +0,0 @@
|
|||||||
<?xml version="1.0" ?>
|
|
||||||
|
|
||||||
<course>
|
|
||||||
<marks>
|
|
||||||
<gate>
|
|
||||||
<name type="start-line">Start</name>
|
|
||||||
<mark>
|
|
||||||
<name>Start1</name>
|
|
||||||
<latitude>32.296577</latitude>
|
|
||||||
<longitude>-64.854304</longitude>
|
|
||||||
</mark>
|
|
||||||
<mark>
|
|
||||||
<name>Start2</name>
|
|
||||||
<latitude>32.293771</latitude>
|
|
||||||
<longitude>-64.855242</longitude>
|
|
||||||
</mark>
|
|
||||||
</gate>
|
|
||||||
<mark>
|
|
||||||
<name>Mid Mark</name>
|
|
||||||
<latitude>32.293039</latitude>
|
|
||||||
<longitude>-64.843983</longitude>
|
|
||||||
</mark>
|
|
||||||
<gate>
|
|
||||||
<name>Leeward Gate</name>
|
|
||||||
<mark>
|
|
||||||
<name>Leeward Gate1</name>
|
|
||||||
<latitude>32.284680</latitude>
|
|
||||||
<longitude>-64.850045</longitude>
|
|
||||||
</mark>
|
|
||||||
<mark>
|
|
||||||
<name>Leeward Gate2</name>
|
|
||||||
<latitude>32.280164</latitude>
|
|
||||||
<longitude>-64.847591</longitude>
|
|
||||||
</mark>
|
|
||||||
</gate>
|
|
||||||
<gate>
|
|
||||||
<name>Windward Gate</name>
|
|
||||||
<mark>
|
|
||||||
<name>Windward Gate1</name>
|
|
||||||
<latitude>32.309693</latitude>
|
|
||||||
<longitude>-64.835249</longitude>
|
|
||||||
</mark>
|
|
||||||
<mark>
|
|
||||||
<name>Windward Gate2</name>
|
|
||||||
<latitude>32.308046</latitude>
|
|
||||||
<longitude>-64.831785</longitude>
|
|
||||||
</mark>
|
|
||||||
</gate>
|
|
||||||
<gate type="finish-line">
|
|
||||||
<name>Finish</name>
|
|
||||||
<mark>
|
|
||||||
<name>Finish1</name>
|
|
||||||
<latitude>32.317379</latitude>
|
|
||||||
<longitude>-64.839291</longitude>
|
|
||||||
</mark>
|
|
||||||
<mark>
|
|
||||||
<name>Finish2</name>
|
|
||||||
<latitude>32.317257</latitude>
|
|
||||||
<longitude>-64.836260</longitude>
|
|
||||||
</mark>
|
|
||||||
</gate>
|
|
||||||
</marks>
|
|
||||||
<order>
|
|
||||||
<one>Start</one>
|
|
||||||
<two>Mid Mark</two>
|
|
||||||
<three>Leeward Gate</three>
|
|
||||||
<four>Windward Gate</four>
|
|
||||||
<five>Leeward Gate</five>
|
|
||||||
<six>Finish</six>
|
|
||||||
</order>
|
|
||||||
</course>
|
|
||||||
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
<?xml version="1.0" ?>
|
|
||||||
|
|
||||||
<teams>
|
|
||||||
<team>
|
|
||||||
<name>Oracle Team USA</name>
|
|
||||||
<alias>USA</alias>
|
|
||||||
<currentVelocity>0.0</currentVelocity>
|
|
||||||
<id>102</id>
|
|
||||||
</team>
|
|
||||||
<team>
|
|
||||||
<name>Artemis Racing</name>
|
|
||||||
<alias>ART</alias>
|
|
||||||
<currentVelocity>0.0</currentVelocity>
|
|
||||||
<id>101</id>
|
|
||||||
</team>
|
|
||||||
<team>
|
|
||||||
<name>Emirates Team New Zealand</name>
|
|
||||||
<alias>NZL</alias>
|
|
||||||
<currentVelocity>0.0</currentVelocity>
|
|
||||||
<id>103</id>
|
|
||||||
</team>
|
|
||||||
<team>
|
|
||||||
<name>Land Rover BAR</name>
|
|
||||||
<alias>BAR</alias>
|
|
||||||
<currentVelocity>0.0</currentVelocity>
|
|
||||||
<id>104</id>
|
|
||||||
</team>
|
|
||||||
<team>
|
|
||||||
<name>SoftBank Team Japan</name>
|
|
||||||
<alias>JAP</alias>
|
|
||||||
<currentVelocity>0.0</currentVelocity>
|
|
||||||
<id>105</id>
|
|
||||||
</team>
|
|
||||||
<team>
|
|
||||||
<name>Groupama Team France</name>
|
|
||||||
<alias>FRC</alias>
|
|
||||||
<currentVelocity>0.0</currentVelocity>
|
|
||||||
<id>106</id>
|
|
||||||
</team>
|
|
||||||
</teams>
|
|
||||||
@@ -44,8 +44,18 @@
|
|||||||
-fx-border-color: -fx-decorator-color;
|
-fx-border-color: -fx-decorator-color;
|
||||||
-fx-border-width: 0 4 4 4;
|
-fx-border-width: 0 4 4 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.jfx-decorator-button {
|
||||||
|
-fx-focus-traversable: false; /* so decorator button will not be focused */
|
||||||
|
}
|
||||||
|
|
||||||
/********* customised scroll bar for scroll pane ***********/
|
/********* customised scroll bar for scroll pane ***********/
|
||||||
|
|
||||||
|
.scroll-pane {
|
||||||
|
-fx-focus-traversable: false;
|
||||||
|
-fx-border-style: none;
|
||||||
|
}
|
||||||
|
|
||||||
/* The main scrollbar **track** CSS class */
|
/* The main scrollbar **track** CSS class */
|
||||||
.scroll-bar:horizontal .track,
|
.scroll-bar:horizontal .track,
|
||||||
.scroll-bar:vertical .track {
|
.scroll-bar:vertical .track {
|
||||||
@@ -99,4 +109,16 @@
|
|||||||
|
|
||||||
.slider .track {
|
.slider .track {
|
||||||
-fx-background-color: -fx-pp-dark-text-color;
|
-fx-background-color: -fx-pp-dark-text-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
.jfx-snackbar-content {
|
||||||
|
-fx-background-color: -fx-pp-front-color;
|
||||||
|
-fx-padding: 0 5 0 5;
|
||||||
|
-fx-spacing: 0 5 0 5;
|
||||||
|
-fx-font-size: 15;
|
||||||
|
}
|
||||||
|
|
||||||
|
.jfx-snackbar-toast {
|
||||||
|
-fx-text-fill: -fx-pp-theme-color;
|
||||||
|
-fx-font-size: 15;
|
||||||
}
|
}
|
||||||
@@ -48,6 +48,7 @@ GridPane .timer * {
|
|||||||
-fx-text-fill: -fx-pp-theme-color;
|
-fx-text-fill: -fx-pp-theme-color;
|
||||||
-fx-font-size: 13px;
|
-fx-font-size: 13px;
|
||||||
-fx-pref-height: 35px;
|
-fx-pref-height: 35px;
|
||||||
|
-fx-focus-traversable: false;
|
||||||
}
|
}
|
||||||
|
|
||||||
#chatSend:hover {
|
#chatSend:hover {
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
-fx-font-size: 20px;
|
-fx-font-size: 20px;
|
||||||
-fx-text-fill: -fx-pp-light-text-color;
|
-fx-text-fill: -fx-pp-light-text-color;
|
||||||
-fx-background-color: -fx-pp-theme-color;
|
-fx-background-color: -fx-pp-theme-color;
|
||||||
|
-fx-focus-traversable: false;
|
||||||
}
|
}
|
||||||
|
|
||||||
.jfx-rippler {
|
.jfx-rippler {
|
||||||
|
|||||||
@@ -0,0 +1,59 @@
|
|||||||
|
#keyBindingDialogHeader {
|
||||||
|
-fx-font-size: 27px;
|
||||||
|
-fx-text-fill: -fx-pp-dark-text-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
#closeLabel {
|
||||||
|
-fx-font-size: 30;
|
||||||
|
-fx-text-fill: -fx-pp-dark-text-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
#closeLabel:hover {
|
||||||
|
-fx-text-fill: red;
|
||||||
|
-fx-font-size: 33px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sectionLabel {
|
||||||
|
-fx-text-fill: -fx-pp-dark-text-color;
|
||||||
|
-fx-font-size: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
JFXButton {
|
||||||
|
-fx-background-color: -fx-pp-light-text-color;
|
||||||
|
-fx-text-fill: -fx-pp-theme-color;
|
||||||
|
-fx-font-size: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
Label {
|
||||||
|
-fx-font-size: 15px;
|
||||||
|
-fx-text-fill: -fx-pp-theme-color;
|
||||||
|
-fx-effect: -fx-pp-dropshadow-light;
|
||||||
|
}
|
||||||
|
|
||||||
|
JFXToggleButton {
|
||||||
|
-jfx-toggle-color: -fx-pp-theme-color;
|
||||||
|
-fx-text-fill: -fx-pp-theme-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
#resetBtn {
|
||||||
|
-fx-background-color: -fx-pp-theme-color;
|
||||||
|
-fx-text-fill: -fx-pp-front-color;
|
||||||
|
-fx-effect: -fx-pp-dropshadow-light;
|
||||||
|
-fx-font-size: 18;
|
||||||
|
}
|
||||||
|
|
||||||
|
#resetBtn:hover {
|
||||||
|
-fx-font-size: 20;
|
||||||
|
}
|
||||||
|
|
||||||
|
.jfx-snackbar-content {
|
||||||
|
-fx-background-color: #323232;
|
||||||
|
}
|
||||||
|
|
||||||
|
.jfx-snackbar-toast {
|
||||||
|
-fx-text-fill: WHITE;
|
||||||
|
}
|
||||||
|
|
||||||
|
.jfx-snackbar-action {
|
||||||
|
-fx-text-fill: #ff4081;
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
#headerLabel {
|
||||||
|
-fx-font-size: 20px;
|
||||||
|
-fx-text-fill: -fx-pp-dark-text-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
#closeLabel {
|
||||||
|
-fx-font-size: 22px;
|
||||||
|
-fx-text-fill: -fx-pp-dark-text-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
#closeLabel:hover {
|
||||||
|
-fx-font-size: 24px;
|
||||||
|
-fx-text-fill: red;
|
||||||
|
}
|
||||||
|
|
||||||
|
#contentLabel {
|
||||||
|
-fx-font-size: 22px;
|
||||||
|
-fx-text-fill: -fx-pp-dark-text-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
#optionButton {
|
||||||
|
-fx-background-color: -fx-pp-theme-color;
|
||||||
|
-fx-text-fill: -fx-pp-light-text-color;
|
||||||
|
-fx-font-size: 18px;
|
||||||
|
-fx-effect: -fx-pp-dropshadow-light;
|
||||||
|
-fx-max-height: 55;
|
||||||
|
-fx-focus-traversable: false;
|
||||||
|
}
|
||||||
|
|
||||||
|
#optionButton:hover {
|
||||||
|
-fx-font-size: 20px !important;
|
||||||
|
-fx-background-color: -fx-pp-light-theme-color;
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
/* a separate file to dynamically change snackbar's color */
|
||||||
|
.jfx-snackbar-toast {
|
||||||
|
-fx-text-fill: red !important;
|
||||||
|
}
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<RaceDefinition>
|
||||||
|
|
||||||
|
<CourseName> El Classico </CourseName>
|
||||||
|
|
||||||
|
<CentralLat> 57.6679590 </CentralLat>
|
||||||
|
<CentralLng> 11.8503233 </CentralLng>
|
||||||
|
|
||||||
|
<MaxPlayers> 10 </MaxPlayers>
|
||||||
|
|
||||||
|
<Marks>
|
||||||
|
<CompoundMark CompoundMarkID="1">
|
||||||
|
<Mark Lat="57.670603" Lng="11.828262"/>
|
||||||
|
<Mark Lat="57.669445" Lng="11.826413"/>
|
||||||
|
</CompoundMark>
|
||||||
|
<CompoundMark CompoundMarkID="2">
|
||||||
|
<Mark Lat="57.6675700" Lng="11.8359880"/>
|
||||||
|
</CompoundMark>
|
||||||
|
<CompoundMark CompoundMarkID="3">
|
||||||
|
<Mark Lat="57.6708220" Lng="11.8433900"/>
|
||||||
|
<Mark Lat="57.671629" Lng="11.840951"/>
|
||||||
|
</CompoundMark>
|
||||||
|
<CompoundMark CompoundMarkID="4">
|
||||||
|
<Mark Lat="57.664190" Lng="11.829576"/>
|
||||||
|
<Mark Lat="57.665316" Lng="11.827184"/>
|
||||||
|
</CompoundMark>
|
||||||
|
<CompoundMark CompoundMarkID="5">
|
||||||
|
<Mark Lat="57.672350" Lng="11.842535"/>
|
||||||
|
<Mark Lat="57.6715240" Lng="11.8444950"/>
|
||||||
|
</CompoundMark>
|
||||||
|
</Marks>
|
||||||
|
|
||||||
|
<Course>
|
||||||
|
<OpeningSegment>
|
||||||
|
<Corner CompoundMarkID="1" Rounding="PS"/>
|
||||||
|
<Corner CompoundMarkID="2" Rounding="P"/>
|
||||||
|
</OpeningSegment>
|
||||||
|
|
||||||
|
<RepeatingSegment>
|
||||||
|
<Corner CompoundMarkID="3" Rounding="SP"/>
|
||||||
|
<Corner CompoundMarkID="4" Rounding="PS"/>
|
||||||
|
</RepeatingSegment>
|
||||||
|
|
||||||
|
<ClosingSegment>
|
||||||
|
<Corner CompoundMarkID="5" Rounding="PS"/>
|
||||||
|
</ClosingSegment>
|
||||||
|
</Course>
|
||||||
|
|
||||||
|
<CourseLimit>
|
||||||
|
<Limit Lat="57.6739450" Lng="11.8417100" />
|
||||||
|
<Limit Lat="57.6709520" Lng="11.8485010" />
|
||||||
|
<Limit Lat="57.6690260" Lng="11.8472790" />
|
||||||
|
<Limit Lat="57.6693140" Lng="11.8457610" />
|
||||||
|
<Limit Lat="57.6665370" Lng="11.8432910" />
|
||||||
|
<Limit Lat="57.6641400" Lng="11.8385840" />
|
||||||
|
<Limit Lat="57.6629430" Lng="11.8332030" />
|
||||||
|
<Limit Lat="57.6629480" Lng="11.8249660" />
|
||||||
|
<Limit Lat="57.6686890" Lng="11.8250920" />
|
||||||
|
<Limit Lat="57.6692230" Lng="11.8231430" />
|
||||||
|
<Limit Lat="57.6725370" Lng="11.8272480" />
|
||||||
|
<Limit Lat="57.6708220" Lng="11.8321340" />
|
||||||
|
</CourseLimit>
|
||||||
|
|
||||||
|
</RaceDefinition>
|
||||||
@@ -0,0 +1,79 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<RaceDefinition>
|
||||||
|
|
||||||
|
<CourseName> HorseShoe </CourseName>
|
||||||
|
|
||||||
|
<CentralLat> -14.6457 </CentralLat>
|
||||||
|
<CentralLng> 47.612855 </CentralLng>
|
||||||
|
|
||||||
|
<MaxPlayers> 5 </MaxPlayers>
|
||||||
|
|
||||||
|
<Marks>
|
||||||
|
<CompoundMark CompoundMarkID="1">
|
||||||
|
<Mark Lat="-14.071412" Lng="47.05756"/>
|
||||||
|
<Mark Lat="-14.069914" Lng="47.058541"/>
|
||||||
|
</CompoundMark>
|
||||||
|
<CompoundMark CompoundMarkID="2">
|
||||||
|
<Mark Lat="-14.067194" Lng="47.053818" />
|
||||||
|
</CompoundMark>
|
||||||
|
<CompoundMark CompoundMarkID="3">
|
||||||
|
<Mark Lat="-14.061248" Lng="47.058556" />
|
||||||
|
</CompoundMark>
|
||||||
|
<CompoundMark CompoundMarkID="4">
|
||||||
|
<Mark Lat="-14.060584" Lng="47.063088"/>
|
||||||
|
<Mark Lat="-14.060617" Lng="47.06374" />
|
||||||
|
</CompoundMark>
|
||||||
|
<CompoundMark CompoundMarkID="5">
|
||||||
|
<Mark Lat="-14.064637" Lng="47.060307"/>
|
||||||
|
<Mark Lat="-14.06477" Lng="47.061165"/>
|
||||||
|
</CompoundMark>
|
||||||
|
<CompoundMark CompoundMarkID="6">
|
||||||
|
<Mark Lat="-14.063839" Lng="47.06762"/>
|
||||||
|
</CompoundMark>
|
||||||
|
<CompoundMark CompoundMarkID="7">
|
||||||
|
<Mark Lat="-14.068954" Lng="47.066349"/>
|
||||||
|
</CompoundMark>
|
||||||
|
<CompoundMark CompoundMarkID="8">
|
||||||
|
<Mark Lat="-14.07025" Lng="47.060238"/>
|
||||||
|
<Mark Lat="-14.071047" Lng="47.060307"/>
|
||||||
|
</CompoundMark>
|
||||||
|
</Marks>
|
||||||
|
|
||||||
|
<Course>
|
||||||
|
|
||||||
|
<OpeningSegment>
|
||||||
|
<Corner CompoundMarkID="1" Rounding="PS"/>
|
||||||
|
<Corner CompoundMarkID="2" Rounding="S"/>
|
||||||
|
<Corner CompoundMarkID="3" Rounding="S"/>
|
||||||
|
<Corner CompoundMarkID="4" Rounding="SP"/>
|
||||||
|
</OpeningSegment>
|
||||||
|
|
||||||
|
<RepeatingSegment>
|
||||||
|
<Corner CompoundMarkID="5" Rounding="SP"/>
|
||||||
|
<Corner CompoundMarkID="4" Rounding="PS"/>
|
||||||
|
</RepeatingSegment>
|
||||||
|
|
||||||
|
<ClosingSegment>
|
||||||
|
<Corner CompoundMarkID="6" Rounding="S"/>
|
||||||
|
<Corner CompoundMarkID="7" Rounding="S"/>
|
||||||
|
<Corner CompoundMarkID="8" Rounding="SP" />
|
||||||
|
</ClosingSegment>
|
||||||
|
|
||||||
|
</Course>
|
||||||
|
|
||||||
|
<CourseLimit>
|
||||||
|
<Limit Lat="-14.073371" Lng="47.058213" />
|
||||||
|
<Limit Lat="-14.06453" Lng="47.050003" />
|
||||||
|
<Limit Lat="-14.059022" Lng="47.057286" />
|
||||||
|
<Limit Lat="-14.058723" Lng="47.064358" />
|
||||||
|
<Limit Lat="-14.06261" Lng="47.071293" />
|
||||||
|
<Limit Lat="-14.070814" Lng="47.06762" />
|
||||||
|
<Limit Lat="-14.072773" Lng="47.059689" />
|
||||||
|
<Limit Lat="-14.068323" Lng="47.059449" />
|
||||||
|
<Limit Lat="-14.064969" Lng="47.065113" />
|
||||||
|
<Limit Lat="-14.066131" Lng="47.05986" />
|
||||||
|
<Limit Lat="-14.063441" Lng="47.058419" />
|
||||||
|
<Limit Lat="-14.068091" Lng="47.059174" />
|
||||||
|
</CourseLimit>
|
||||||
|
|
||||||
|
</RaceDefinition>
|
||||||
@@ -5,8 +5,8 @@
|
|||||||
<author>Blender User</author>
|
<author>Blender User</author>
|
||||||
<authoring_tool>Blender 2.78.0 commit date:2016-09-26, commit time:12:42, hash:4bb1e22</authoring_tool>
|
<authoring_tool>Blender 2.78.0 commit date:2016-09-26, commit time:12:42, hash:4bb1e22</authoring_tool>
|
||||||
</contributor>
|
</contributor>
|
||||||
<created>2017-09-11T16:51:03</created>
|
<created>2017-09-26T01:05:25</created>
|
||||||
<modified>2017-09-11T16:51:03</modified>
|
<modified>2017-09-26T01:05:25</modified>
|
||||||
<unit name="meter" meter="1"/>
|
<unit name="meter" meter="1"/>
|
||||||
<up_axis>Z_UP</up_axis>
|
<up_axis>Z_UP</up_axis>
|
||||||
</asset>
|
</asset>
|
||||||
@@ -48,7 +48,7 @@
|
|||||||
<geometry id="Plane_004-mesh" name="Plane.004">
|
<geometry id="Plane_004-mesh" name="Plane.004">
|
||||||
<mesh>
|
<mesh>
|
||||||
<source id="Plane_004-mesh-positions">
|
<source id="Plane_004-mesh-positions">
|
||||||
<float_array id="Plane_004-mesh-positions-array" count="240">-1 -0.09999954 0.01554524 1 -0.09999954 0.01554524 -1 0.1000005 0.01554524 1 0.1000005 0.01554524 1 0.1000005 0.01554524 1 -0.09999954 0.01554524 1.019509 -0.09807801 0.01554524 1.038269 -0.09238743 0.01554524 1.055557 -0.08314645 0.01554524 1.070711 -0.07071018 0.01554524 1.083147 -0.05555653 0.01554524 1.092388 -0.03826785 0.01554524 1.098079 -0.01950848 0.01554524 1.1 5.96046e-7 0.01554524 1.098079 0.01950955 0.01554524 1.092388 0.03826892 0.01554524 1.083147 0.0555576 0.01554524 1.070711 0.07071125 0.01554524 1.055557 0.08314752 0.01554524 1.038269 0.09238851 0.01554524 1.019509 0.09807896 0.01554524 -1 0.1000005 0.01554524 -1.019509 0.0980789 0.01554524 -1.038268 0.09238833 0.01554524 -1.055557 0.08314734 0.01554524 -1.070711 0.07071107 0.01554524 -1.083147 0.05555742 0.01554524 -1.092388 0.03826874 0.01554524 -1.098078 0.01950937 0.01554524 -1.1 4.56348e-7 0.01554524 -1.098078 -0.0195086 0.01554524 -1.092388 -0.03826785 0.01554524 -1.083147 -0.05555653 0.01554524 -1.070711 -0.07071018 0.01554524 -1.055557 -0.08314645 0.01554524 -1.038268 -0.09238755 0.01554524 -1.019509 -0.09807813 0.01554524 -0.9999997 -0.09999954 0.01554524 1 4.76837e-7 0.01554524 -1 4.76837e-7 0.01554524 -1 4.76837e-7 0.04452204 -1 0.1000005 0.04452204 -1 -0.09999954 0.04452204 1 -0.09999954 0.04452204 1 0.1000005 0.04452204 1.019509 -0.09807801 0.04452204 1 -0.09999954 0.04452204 1.038269 -0.09238743 0.04452204 1.055557 -0.08314645 0.04452204 1.070711 -0.07071018 0.04452204 1.083147 -0.05555653 0.04452204 1.092388 -0.03826785 0.04452204 1.098079 -0.01950848 0.04452204 1.1 5.96046e-7 0.04452204 1.098079 0.01950955 0.04452204 1.092388 0.03826892 0.04452204 1.083147 0.0555576 0.04452204 1.070711 0.07071125 0.04452204 1.055557 0.08314752 0.04452204 1.038269 0.09238851 0.04452204 1.019509 0.09807896 0.04452204 1 0.1000005 0.04452204 -1.019509 0.0980789 0.04452204 -1 0.1000005 0.04452204 -1.038268 0.09238833 0.04452204 -1.055557 0.08314734 0.04452204 -1.070711 0.07071107 0.04452204 -1.083147 0.05555742 0.04452204 -1.092388 0.03826874 0.04452204 -1.098078 0.01950937 0.04452204 -1.1 4.56348e-7 0.04452204 -1.098078 -0.0195086 0.04452204 -1.092388 -0.03826785 0.04452204 -1.083147 -0.05555653 0.04452204 -1.070711 -0.07071018 0.04452204 -1.055557 -0.08314645 0.04452204 -1.038268 -0.09238755 0.04452204 -1.019509 -0.09807813 0.04452204 -0.9999997 -0.09999954 0.04452204 1 4.76837e-7 0.04452204</float_array>
|
<float_array id="Plane_004-mesh-positions-array" count="240">-1 -0.09999954 0.01554518 1 -0.09999954 0.01554518 -1 0.1000005 0.01554518 1 0.1000005 0.01554518 1 0.1000005 0.01554518 1 -0.09999954 0.01554518 1.019509 -0.09807801 0.01554518 1.038269 -0.09238743 0.01554518 1.055557 -0.08314645 0.01554518 1.070711 -0.07071018 0.01554518 1.083147 -0.05555647 0.01554518 1.092388 -0.03826785 0.01554518 1.098079 -0.01950848 0.01554518 1.1 5.96046e-7 0.01554518 1.098079 0.01950955 0.01554518 1.092388 0.03826892 0.01554518 1.083147 0.05555754 0.01554518 1.070711 0.07071125 0.01554518 1.055557 0.08314752 0.01554518 1.038269 0.09238851 0.01554518 1.019509 0.09807896 0.01554518 -1 0.1000005 0.01554518 -1.019509 0.0980789 0.01554518 -1.038268 0.09238833 0.01554518 -1.055557 0.08314734 0.01554518 -1.070711 0.07071107 0.01554518 -1.083147 0.05555737 0.01554518 -1.092388 0.03826874 0.01554518 -1.098078 0.01950937 0.01554518 -1.1 4.56348e-7 0.01554518 -1.098078 -0.0195086 0.01554518 -1.092388 -0.03826785 0.01554518 -1.083147 -0.05555647 0.01554518 -1.070711 -0.07071018 0.01554518 -1.055557 -0.08314645 0.01554518 -1.038268 -0.09238755 0.01554518 -1.019509 -0.09807813 0.01554518 -0.9999997 -0.09999954 0.01554518 1 4.76837e-7 0.01554518 -1 4.76837e-7 0.01554518 -1 4.76837e-7 0.04452198 -1 0.1000005 0.04452198 -1 -0.09999954 0.04452198 1 -0.09999954 0.04452198 1 0.1000005 0.04452198 1.019509 -0.09807801 0.04452198 1 -0.09999954 0.04452198 1.038269 -0.09238743 0.04452198 1.055557 -0.08314645 0.04452198 1.070711 -0.07071018 0.04452198 1.083147 -0.05555647 0.04452198 1.092388 -0.03826785 0.04452198 1.098079 -0.01950848 0.04452198 1.1 5.96046e-7 0.04452198 1.098079 0.01950955 0.04452198 1.092388 0.03826892 0.04452198 1.083147 0.05555754 0.04452198 1.070711 0.07071125 0.04452198 1.055557 0.08314752 0.04452198 1.038269 0.09238851 0.04452198 1.019509 0.09807896 0.04452198 1 0.1000005 0.04452198 -1.019509 0.0980789 0.04452198 -1 0.1000005 0.04452198 -1.038268 0.09238833 0.04452198 -1.055557 0.08314734 0.04452198 -1.070711 0.07071107 0.04452198 -1.083147 0.05555737 0.04452198 -1.092388 0.03826874 0.04452198 -1.098078 0.01950937 0.04452198 -1.1 4.56348e-7 0.04452198 -1.098078 -0.0195086 0.04452198 -1.092388 -0.03826785 0.04452198 -1.083147 -0.05555647 0.04452198 -1.070711 -0.07071018 0.04452198 -1.055557 -0.08314645 0.04452198 -1.038268 -0.09238755 0.04452198 -1.019509 -0.09807813 0.04452198 -0.9999997 -0.09999954 0.04452198 1 4.76837e-7 0.04452198</float_array>
|
||||||
<technique_common>
|
<technique_common>
|
||||||
<accessor source="#Plane_004-mesh-positions-array" count="80" stride="3">
|
<accessor source="#Plane_004-mesh-positions-array" count="80" stride="3">
|
||||||
<param name="X" type="float"/>
|
<param name="X" type="float"/>
|
||||||
@@ -58,9 +58,9 @@
|
|||||||
</technique_common>
|
</technique_common>
|
||||||
</source>
|
</source>
|
||||||
<source id="Plane_004-mesh-normals">
|
<source id="Plane_004-mesh-normals">
|
||||||
<float_array id="Plane_004-mesh-normals-array" count="342">0 0 -1 0 0 -1 0 0 -1 0 0 -1 1.19345e-7 0 -1 0 0 -1 0 0 -1 0 0 -1 0 0 -1 0 0 -1 0 0 -1 0 0 -1 0 0 -1 0 0 -1 0 0 -1 0 0 -1 0 0 -1 0 0 -1 0 0 -1 0 0 -1 -1.19344e-7 0 -1 0 0 1 -1.19345e-7 0 1 0 0 1 1.19344e-7 0 1 -4.77372e-7 0 1 0 0 1 0 0 1 0 0 1 -2.38688e-7 0 1 0 0 1 2.3869e-7 0 1 1.19345e-7 0 1 0 0 1 0 0 1 0 0 1 0 0 1 0 0 1 0 0 1 -2.3869e-7 0 1 0 0 1 -0.6343874 0.7730153 0 -1 0 0 0.9569399 -0.2902863 0 1 0 0 -0.7730182 0.6343839 0 0.9951848 -0.09801703 0 -0.8819218 0.4713957 0 0.9951835 0.09803056 0 -1 -5.14244e-6 0 -0.9569436 0.2902743 0 0.9569399 0.2902863 0 -0.9951834 0.09803056 0 0.8819165 0.4714059 0 0.9238785 0.3826861 0 -0.9951835 -0.09802997 0 0.7730053 0.6343997 0 0.3826843 -0.9238792 0 0 -1 0 -0.9569393 -0.2902879 0 0.6344003 0.7730048 0 0 1 0 -0.8819164 -0.4714059 0 0.4713947 0.8819224 0 0.09802103 -0.9951844 0 -0.7730182 -0.6343839 0 1 3.85683e-6 0 0.2902728 0.9569441 0 -0.2902856 0.9569401 0 -0.6343874 -0.7730153 0 0.09802168 0.9951844 0 -0.4713947 0.8819224 0 -0.4713994 -0.8819198 0 -0.09802168 0.9951844 0 0.6344003 -0.7730048 0 -0.2902857 -0.9569401 0 1 2.57122e-6 0 -0.2902857 0.9569401 0 0.7730085 -0.6343957 0 -0.0980131 -0.9951851 0 -0.4713975 0.881921 0 0.8819219 -0.4713957 0 0.9569398 -0.2902863 0 -0.7730182 0.634384 0 0.9951835 -0.09802997 0 -0.8819165 0.4714059 0 0.9951847 0.09801757 0 -1 -3.85683e-6 0 -0.9569399 0.2902863 0 0.9569398 0.2902863 0 -0.9951834 0.09803056 0 0.8819218 0.4713957 0 0.9238789 0.3826851 0 0.7730085 0.6343957 0 0.3826831 -0.9238798 0 -0.956943 -0.2902759 0 0.6344001 0.7730049 0 -0.8819219 -0.4713957 0 0.4713975 0.881921 0 0.09802103 -0.9951844 0 -0.7730182 -0.634384 0 1 3.85683e-6 0 -0.2902855 0.9569401 0 0.09802103 0.9951844 0 -0.4714021 -0.8819184 0 -0.09802103 0.9951844 0 0.6344001 -0.7730049 0 -0.2902856 -0.9569401 0 1 2.57122e-6 0 -0.2902856 0.9569401 0 0.7730054 -0.6343996 0 -0.09801179 -0.9951853 0 -0.4713947 0.8819224 0 0.8819164 -0.471406 0</float_array>
|
<float_array id="Plane_004-mesh-normals-array" count="270">0 0 -1 1.19345e-7 0 -1 0 0 -1 0 0 -1 -1.19344e-7 0 -1 -1.19343e-7 0 -1 0 0 -1 0 0 -1 -1.19343e-7 0 -1 0 0 1 1.19345e-7 0 1 0 0 1 -4.77394e-7 0 1 -1.19344e-7 0 1 -4.77375e-7 0 1 4.77387e-7 0 1 0 0 1 -1.19345e-7 0 1 2.38692e-7 0 1 2.38687e-7 0 1 -2.38687e-7 0 1 -0.6343871 0.7730156 0 -1 0 0 0.9569398 -0.2902864 0 1 0 0 -0.7730116 0.6343919 0 0.9951861 -0.09800404 0 -0.8819217 0.4713962 0 0.9951872 0.09799164 0 -0.9569509 0.2902504 0 0.9569326 0.2903105 0 -0.9951821 0.09804385 0 0.8819217 0.471396 0 0.923877 0.3826896 0 -0.9951823 -0.09804314 0 0.773018 0.6343841 0 0.3826818 -0.9238802 0 0 -1 0 -0.9569467 -0.2902641 0 0.6343807 0.7730209 0 0 1 0 -0.8819217 -0.4713962 0 0.4714139 0.8819121 0 0.09802061 -0.9951844 0 -0.7730181 -0.6343839 0 1 3.85683e-6 0 0.2902668 0.9569458 0 -0.2902731 0.9569439 0 -0.6343807 -0.7730209 0 0.09802073 0.9951844 0 -0.4714134 0.8819125 0 -0.4713908 -0.8819245 0 -0.09802436 0.995184 0 0.6343871 -0.7730156 0 -0.2902895 -0.956939 0 -0.2902888 0.9569392 0 0.7730117 -0.6343918 0 -0.09801268 -0.9951853 0 -0.4713921 0.8819237 0 0.8819217 -0.4713962 0 -0.6343807 0.7730209 0 0.9569326 -0.2903105 0 -0.7730181 0.634384 0 0.9951873 -0.0979911 0 0.995186 0.09800463 0 -0.9569472 0.2902624 0 0.9569398 0.2902864 0 -0.9951821 0.09804385 0 0.923877 0.3826897 0 0.7730115 0.634392 0 0.3826841 -0.9238793 0 -0.9569503 -0.2902522 0 0.6343871 0.7730156 0 0.4714112 0.8819137 0 0.09801995 -0.9951846 0 -0.7730117 -0.6343919 0 1 2.57122e-6 0 0.2902686 0.9569453 0 -0.2902749 0.9569434 0 -0.6343871 -0.7730156 0 0.09802132 0.9951844 0 -0.4714105 0.8819139 0 -0.4713962 -0.8819217 0 -0.09802371 0.9951841 0 0.6343807 -0.7730209 0 -0.2902895 -0.956939 0 -0.2902888 0.9569392 0 0.7730181 -0.634384 0 -0.09801262 -0.9951853 0 -0.4713866 0.8819267 0</float_array>
|
||||||
<technique_common>
|
<technique_common>
|
||||||
<accessor source="#Plane_004-mesh-normals-array" count="114" stride="3">
|
<accessor source="#Plane_004-mesh-normals-array" count="90" stride="3">
|
||||||
<param name="X" type="float"/>
|
<param name="X" type="float"/>
|
||||||
<param name="Y" type="float"/>
|
<param name="Y" type="float"/>
|
||||||
<param name="Z" type="float"/>
|
<param name="Z" type="float"/>
|
||||||
@@ -74,7 +74,7 @@
|
|||||||
<input semantic="VERTEX" source="#Plane_004-mesh-vertices" offset="0"/>
|
<input semantic="VERTEX" source="#Plane_004-mesh-vertices" offset="0"/>
|
||||||
<input semantic="NORMAL" source="#Plane_004-mesh-normals" offset="1"/>
|
<input semantic="NORMAL" source="#Plane_004-mesh-normals" offset="1"/>
|
||||||
<vcount>3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 </vcount>
|
<vcount>3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 </vcount>
|
||||||
<p>38 0 0 0 39 0 6 0 5 0 38 0 8 1 6 1 38 1 9 2 38 2 10 2 8 0 38 0 9 0 10 0 38 0 11 0 11 0 38 0 12 0 12 3 38 3 13 3 4 0 20 0 38 0 19 0 38 0 20 0 18 4 38 4 19 4 17 0 38 0 18 0 16 0 38 0 17 0 15 0 38 0 16 0 14 0 38 0 15 0 13 0 38 0 14 0 37 5 36 5 39 5 35 6 39 6 36 6 21 7 39 7 22 7 34 8 39 8 35 8 33 9 39 9 34 9 32 10 39 10 33 10 31 11 39 11 32 11 30 12 39 12 31 12 29 13 39 13 30 13 28 14 39 14 29 14 27 15 39 15 28 15 26 16 39 16 27 16 25 17 39 17 26 17 22 18 39 18 23 18 23 19 39 19 24 19 24 20 39 20 25 20 40 21 43 21 79 21 45 21 79 21 46 21 48 21 79 21 45 21 49 21 50 21 79 21 48 21 49 21 79 21 50 22 51 22 79 22 51 21 52 21 79 21 52 23 53 23 79 23 61 21 79 21 60 21 59 21 60 21 79 21 58 21 59 21 79 21 57 21 58 21 79 21 56 21 57 21 79 21 55 21 56 21 79 21 54 24 55 24 79 24 53 21 54 21 79 21 78 25 40 25 77 25 76 26 77 26 40 26 63 27 62 27 40 27 75 28 76 28 40 28 74 29 75 29 40 29 73 30 74 30 40 30 72 31 73 31 40 31 71 32 72 32 40 32 70 33 71 33 40 33 69 34 70 34 40 34 68 35 69 35 40 35 67 36 68 36 40 36 66 37 67 37 40 37 62 38 64 38 40 38 64 39 65 39 40 39 65 40 66 40 40 40 25 41 65 41 24 41 38 42 61 42 4 42 12 43 51 43 11 43 38 44 43 44 1 44 26 45 66 45 25 45 13 46 52 46 12 46 0 42 40 42 39 42 27 47 67 47 26 47 14 48 53 48 13 48 5 49 79 49 38 49 28 50 68 50 27 50 15 51 54 51 14 51 29 52 69 52 28 52 16 53 55 53 15 53 38 54 47 54 7 54 39 42 41 42 2 42 30 55 70 55 29 55 17 56 56 56 16 56 8 57 45 57 6 57 1 58 42 58 0 58 31 59 71 59 30 59 18 60 57 60 17 60 2 61 44 61 3 61 32 62 72 62 31 62 19 63 58 63 18 63 6 64 46 64 5 64 33 65 73 65 32 65 37 66 40 66 78 66 20 67 59 67 19 67 6 68 47 68 7 68 34 69 74 69 33 69 4 70 60 70 20 70 7 71 48 71 8 71 35 72 75 72 34 72 22 73 63 73 21 73 9 74 48 74 8 74 36 75 76 75 35 75 21 76 40 76 39 76 23 77 62 77 22 77 10 78 49 78 9 78 37 79 77 79 36 79 24 80 64 80 23 80 11 81 50 81 10 81 3 44 79 44 38 44 39 0 2 0 3 0 38 0 1 0 0 0 39 0 3 0 38 0 44 21 41 21 40 21 40 21 42 21 43 21 79 21 44 21 40 21 25 41 66 41 65 41 38 42 79 42 61 42 12 82 52 82 51 82 38 44 79 44 43 44 26 83 67 83 66 83 13 84 53 84 52 84 0 42 42 42 40 42 27 85 68 85 67 85 14 86 54 86 53 86 5 87 46 87 79 87 28 88 69 88 68 88 15 89 55 89 54 89 29 90 70 90 69 90 16 91 56 91 55 91 38 92 79 92 47 92 39 42 40 42 41 42 30 55 71 55 70 55 17 93 57 93 56 93 8 94 48 94 45 94 1 58 43 58 42 58 31 95 72 95 71 95 18 96 58 96 57 96 2 61 41 61 44 61 32 97 73 97 72 97 19 98 59 98 58 98 6 99 45 99 46 99 33 100 74 100 73 100 37 101 39 101 40 101 20 67 60 67 59 67 6 102 45 102 47 102 34 69 75 69 74 69 4 103 61 103 60 103 7 80 47 80 48 80 35 104 76 104 75 104 22 105 62 105 63 105 9 106 49 106 48 106 36 107 77 107 76 107 21 108 63 108 40 108 23 109 64 109 62 109 10 110 50 110 49 110 37 111 78 111 77 111 24 112 65 112 64 112 11 113 51 113 50 113 3 44 44 44 79 44</p>
|
<p>38 0 0 0 39 0 6 1 5 1 38 1 8 0 6 0 38 0 9 2 38 2 10 2 8 0 38 0 9 0 10 0 38 0 11 0 11 0 38 0 12 0 12 3 38 3 13 3 4 0 20 0 38 0 19 0 38 0 20 0 18 0 38 0 19 0 17 0 38 0 18 0 16 0 38 0 17 0 15 0 38 0 16 0 14 0 38 0 15 0 13 0 38 0 14 0 37 4 36 4 39 4 35 0 39 0 36 0 21 0 39 0 22 0 34 0 39 0 35 0 33 5 39 5 34 5 32 0 39 0 33 0 31 0 39 0 32 0 30 0 39 0 31 0 29 0 39 0 30 0 28 6 39 6 29 6 27 0 39 0 28 0 26 0 39 0 27 0 25 7 39 7 26 7 22 0 39 0 23 0 23 0 39 0 24 0 24 8 39 8 25 8 40 9 43 9 79 9 45 9 79 9 46 9 48 9 79 9 45 9 49 9 50 9 79 9 48 9 49 9 79 9 50 10 51 10 79 10 51 9 52 9 79 9 52 11 53 11 79 11 61 9 79 9 60 9 59 9 60 9 79 9 58 12 59 12 79 12 57 9 58 9 79 9 56 9 57 9 79 9 55 9 56 9 79 9 54 13 55 13 79 13 53 9 54 9 79 9 78 14 40 14 77 14 76 15 77 15 40 15 63 9 62 9 40 9 75 9 76 9 40 9 74 9 75 9 40 9 73 9 74 9 40 9 72 9 73 9 40 9 71 9 72 9 40 9 70 9 71 9 40 9 69 16 70 16 40 16 68 9 69 9 40 9 67 17 68 17 40 17 66 18 67 18 40 18 62 9 64 9 40 9 64 19 65 19 40 19 65 20 66 20 40 20 25 21 65 21 24 21 38 22 61 22 4 22 12 23 51 23 11 23 38 24 43 24 1 24 26 25 66 25 25 25 13 26 52 26 12 26 0 22 40 22 39 22 27 27 67 27 26 27 14 28 53 28 13 28 5 22 79 22 38 22 28 29 68 29 27 29 15 30 54 30 14 30 29 31 69 31 28 31 16 32 55 32 15 32 38 33 47 33 7 33 39 22 41 22 2 22 30 34 70 34 29 34 17 35 56 35 16 35 8 36 45 36 6 36 1 37 42 37 0 37 31 38 71 38 30 38 18 39 57 39 17 39 2 40 44 40 3 40 32 41 72 41 31 41 19 42 58 42 18 42 6 43 46 43 5 43 33 44 73 44 32 44 37 45 40 45 78 45 20 46 59 46 19 46 6 47 47 47 7 47 34 48 74 48 33 48 4 49 60 49 20 49 7 50 48 50 8 50 35 51 75 51 34 51 22 52 63 52 21 52 9 53 48 53 8 53 36 54 76 54 35 54 21 24 40 24 39 24 23 55 62 55 22 55 10 56 49 56 9 56 37 57 77 57 36 57 24 58 64 58 23 58 11 59 50 59 10 59 3 24 79 24 38 24 39 0 2 0 3 0 38 0 1 0 0 0 39 0 3 0 38 0 44 9 41 9 40 9 40 9 42 9 43 9 79 9 44 9 40 9 25 60 66 60 65 60 38 22 79 22 61 22 12 61 52 61 51 61 38 24 79 24 43 24 26 62 67 62 66 62 13 63 53 63 52 63 0 22 42 22 40 22 27 27 68 27 67 27 14 64 54 64 53 64 5 22 46 22 79 22 28 65 69 65 68 65 15 66 55 66 54 66 29 67 70 67 69 67 16 32 56 32 55 32 38 68 79 68 47 68 39 22 40 22 41 22 30 34 71 34 70 34 17 69 57 69 56 69 8 70 48 70 45 70 1 37 43 37 42 37 31 71 72 71 71 71 18 72 58 72 57 72 2 40 41 40 44 40 32 41 73 41 72 41 19 73 59 73 58 73 6 74 45 74 46 74 33 75 74 75 73 75 37 76 39 76 40 76 20 77 60 77 59 77 6 78 45 78 47 78 34 79 75 79 74 79 4 80 61 80 60 80 7 81 47 81 48 81 35 82 76 82 75 82 22 83 62 83 63 83 9 84 49 84 48 84 36 85 77 85 76 85 21 24 63 24 40 24 23 86 64 86 62 86 10 87 50 87 49 87 37 88 78 88 77 88 24 89 65 89 64 89 11 59 51 59 50 59 3 24 44 24 79 24</p>
|
||||||
</polylist>
|
</polylist>
|
||||||
</mesh>
|
</mesh>
|
||||||
</geometry>
|
</geometry>
|
||||||
@@ -83,7 +83,7 @@
|
|||||||
<library_visual_scenes>
|
<library_visual_scenes>
|
||||||
<visual_scene id="Scene" name="Scene">
|
<visual_scene id="Scene" name="Scene">
|
||||||
<node id="Plane" name="Plane" type="NODE">
|
<node id="Plane" name="Plane" type="NODE">
|
||||||
<matrix sid="transform">1 0 0 0 0 1 0 -4.76837e-7 0 0 1 0 0 0 0 1</matrix>
|
<matrix sid="transform">0.4856636 0 0 0 0 0.6802911 0 -4.76837e-7 0 0 1 0 0 0 0 1</matrix>
|
||||||
<instance_geometry url="#Plane_004-mesh" name="Plane">
|
<instance_geometry url="#Plane_004-mesh" name="Plane">
|
||||||
<bind_material>
|
<bind_material>
|
||||||
<technique_common>
|
<technique_common>
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 50 KiB |
|
Before Width: | Height: | Size: 44 KiB |
|
Before Width: | Height: | Size: 37 KiB |
|
Before Width: | Height: | Size: 52 KiB |
|
Before Width: | Height: | Size: 46 KiB |
|
Before Width: | Height: | Size: 51 KiB |
|
Before Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 54 KiB |
|
Before Width: | Height: | Size: 49 KiB |
|
Before Width: | Height: | Size: 8.9 KiB |
|
Before Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 202 KiB |
|
Before Width: | Height: | Size: 59 KiB |
@@ -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="101" 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="102" 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="103" 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="104" 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="105" 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="106" 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,105 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<Race>
|
|
||||||
<CreationTimeDate>2015-08-29T13:12:40+02:00</CreationTimeDate>
|
|
||||||
<RaceStartTime Start="2015-08-29T13:10:00+02:00" Postpone="False"/>
|
|
||||||
<RaceID>15082901</RaceID>
|
|
||||||
<RaceType>Fleet</RaceType>
|
|
||||||
<Participants>
|
|
||||||
<Yacht SourceID="101"/>
|
|
||||||
<Yacht SourceID="102"/>
|
|
||||||
<Yacht SourceID="103"/>
|
|
||||||
<Yacht SourceID="104"/>
|
|
||||||
<Yacht SourceID="105"/>
|
|
||||||
<Yacht SourceID="106"/>
|
|
||||||
</Participants>
|
|
||||||
<Course>
|
|
||||||
<CompoundMark CompoundMarkID="1" Name="Mark0">
|
|
||||||
<Mark SeqID="1" Name="Start Line 1" TargetLat="57.6703330" TargetLng="11.8278330"
|
|
||||||
SourceID="122"/>
|
|
||||||
<Mark SeqID="2" Name="Start Line 2" TargetLat="57.6703330" TargetLng="11.8278330"
|
|
||||||
SourceID="123"/>
|
|
||||||
</CompoundMark>
|
|
||||||
<CompoundMark CompoundMarkID="2" Name="Mark1">
|
|
||||||
<Mark SeqID="1" Name="Mark1" TargetLat="57.6675700" TargetLng="11.8359880" SourceID="131"/>
|
|
||||||
</CompoundMark>
|
|
||||||
<CompoundMark CompoundMarkID="3" Name="Mark2">
|
|
||||||
<Mark SeqID="1" Name="Lee Gate 1" TargetLat="57.6708220" TargetLng="11.8433900"
|
|
||||||
SourceID="124"/>
|
|
||||||
<Mark SeqID="2" Name="Lee Gate 2" TargetLat="57.6708220" TargetLng="11.8433900"
|
|
||||||
SourceID="125"/>
|
|
||||||
</CompoundMark>
|
|
||||||
<CompoundMark CompoundMarkID="4" Name="Mark3">
|
|
||||||
<Mark SeqID="1" Name="Wind Gate 1" TargetLat="57.6650170" TargetLng="11.8279170"
|
|
||||||
SourceID="126"/>
|
|
||||||
<Mark SeqID="2" Name="Wind Gate 2" TargetLat="57.6650170" TargetLng="11.8279170"
|
|
||||||
SourceID="127"/>
|
|
||||||
</CompoundMark>
|
|
||||||
<CompoundMark CompoundMarkID="5" Name="Mark2">
|
|
||||||
<Mark SeqID="1" Name="Lee Gate 1" TargetLat="57.6708220" TargetLng="11.8433900"
|
|
||||||
SourceID="124"/>
|
|
||||||
<Mark SeqID="2" Name="Lee Gate 2" TargetLat="57.6708220" TargetLng="11.8433900"
|
|
||||||
SourceID="125"/>
|
|
||||||
</CompoundMark>
|
|
||||||
<CompoundMark CompoundMarkID="6" Name="Mark3">
|
|
||||||
<Mark SeqID="1" Name="Wind Gate 1" TargetLat="57.6650170" TargetLng="11.8279170"
|
|
||||||
SourceID="126"/>
|
|
||||||
<Mark SeqID="2" Name="Wind Gate 2" TargetLat="57.6650170" TargetLng="11.8279170"
|
|
||||||
SourceID="127"/>
|
|
||||||
</CompoundMark>
|
|
||||||
<CompoundMark CompoundMarkID="7" Name="Mark2">
|
|
||||||
<Mark SeqID="1" Name="Lee Gate 1" TargetLat="57.6708220" TargetLng="11.8433900"
|
|
||||||
SourceID="124"/>
|
|
||||||
<Mark SeqID="2" Name="Lee Gate 2" TargetLat="57.6708220" TargetLng="11.8433900"
|
|
||||||
SourceID="125"/>
|
|
||||||
</CompoundMark>
|
|
||||||
<CompoundMark CompoundMarkID="8" Name="Mark3">
|
|
||||||
<Mark SeqID="1" Name="Wind Gate 1" TargetLat="57.6650170" TargetLng="11.8279170"
|
|
||||||
SourceID="126"/>
|
|
||||||
<Mark SeqID="2" Name="Wind Gate 2" TargetLat="57.6650170" TargetLng="11.8279170"
|
|
||||||
SourceID="127"/>
|
|
||||||
</CompoundMark>
|
|
||||||
<CompoundMark CompoundMarkID="9" Name="Mark2">
|
|
||||||
<Mark SeqID="1" Name="Lee Gate 1" TargetLat="57.6708220" TargetLng="11.8433900"
|
|
||||||
SourceID="124"/>
|
|
||||||
<Mark SeqID="2" Name="Lee Gate 2" TargetLat="57.6708220" TargetLng="11.8433900"
|
|
||||||
SourceID="125"/>
|
|
||||||
</CompoundMark>
|
|
||||||
<CompoundMark CompoundMarkID="10" Name="Mark3">
|
|
||||||
<Mark SeqID="1" Name="Wind Gate 1" TargetLat="57.6650170" TargetLng="11.8279170"
|
|
||||||
SourceID="126"/>
|
|
||||||
<Mark SeqID="2" Name="Wind Gate 2" TargetLat="57.6650170" TargetLng="11.8279170"
|
|
||||||
SourceID="127"/>
|
|
||||||
</CompoundMark>
|
|
||||||
<CompoundMark CompoundMarkID="11" Name="Mark4">
|
|
||||||
<Mark SeqID="1" Name="Finish Line 1" TargetLat="57.6715240" TargetLng="11.8444950"
|
|
||||||
SourceID="128"/>
|
|
||||||
<Mark SeqID="2" Name="Finish Line 2" TargetLat="57.6715240" TargetLng="11.8444950"
|
|
||||||
SourceID="129"/>
|
|
||||||
</CompoundMark>
|
|
||||||
</Course>
|
|
||||||
<CompoundMarkSequence>
|
|
||||||
<Corner SeqID="1" CompoundMarkID="1" Rounding="PS" ZoneSize="3"/>
|
|
||||||
<Corner SeqID="2" CompoundMarkID="2" Rounding="Port" ZoneSize="3"/>
|
|
||||||
<Corner SeqID="3" CompoundMarkID="3" Rounding="SP" ZoneSize="3"/>
|
|
||||||
<Corner SeqID="4" CompoundMarkID="4" Rounding="PS" ZoneSize="3"/>
|
|
||||||
<Corner SeqID="5" CompoundMarkID="5" Rounding="SP" ZoneSize="3"/>
|
|
||||||
<Corner SeqID="6" CompoundMarkID="6" Rounding="PS" ZoneSize="3"/>
|
|
||||||
<Corner SeqID="7" CompoundMarkID="7" Rounding="SP" ZoneSize="3"/>
|
|
||||||
<Corner SeqID="8" CompoundMarkID="8" Rounding="PS" ZoneSize="3"/>
|
|
||||||
<Corner SeqID="9" CompoundMarkID="9" Rounding="SP" ZoneSize="3"/>
|
|
||||||
<Corner SeqID="10" CompoundMarkID="10" Rounding="PS" ZoneSize="3"/>
|
|
||||||
<Corner SeqID="11" CompoundMarkID="11" Rounding="PS" ZoneSize="3"/>
|
|
||||||
</CompoundMarkSequence>
|
|
||||||
<CourseLimit>
|
|
||||||
<Limit SeqID="1" Lat="57.6739450" Lon="11.8417100"/>
|
|
||||||
<Limit SeqID="2" Lat="57.6709520" Lon="11.8485010"/>
|
|
||||||
<Limit SeqID="3" Lat="57.6690260" Lon="11.8472790"/>
|
|
||||||
<Limit SeqID="4" Lat="57.6693140" Lon="11.8457610"/>
|
|
||||||
<Limit SeqID="5" Lat="57.6665370" Lon="11.8432910"/>
|
|
||||||
<Limit SeqID="6" Lat="57.6641400" Lon="11.8385840"/>
|
|
||||||
<Limit SeqID="7" Lat="57.6629430" Lon="11.8332030"/>
|
|
||||||
<Limit SeqID="8" Lat="57.6629480" Lon="11.8249660"/>
|
|
||||||
<Limit SeqID="9" Lat="57.6686890" Lon="11.8250920"/>
|
|
||||||
<Limit SeqID="10" Lat="57.6708220" Lon="11.8321340"/>
|
|
||||||
</CourseLimit>
|
|
||||||
</Race>
|
|
||||||
@@ -12,7 +12,7 @@
|
|||||||
</BoatShapes>
|
</BoatShapes>
|
||||||
<Boats>
|
<Boats>
|
||||||
<#list boats as boat>
|
<#list boats as boat>
|
||||||
<Boat Type="Yacht" SourceID="${boat.sourceId}" ShapeID="4" HullNum="${boat.hullID}" StoweName="${boat.shortName}" ShortName="${boat.shortName}"
|
<Boat Type="${boat.boatType}" SourceID="${boat.sourceId}" ShapeID="4" HullNum="${boat.hullID}" StoweName="${boat.shortName}" ShortName="${boat.shortName}"
|
||||||
BoatName="${boat.boatName}" Country="${boat.country}" Color="${boat.boatColor}">
|
BoatName="${boat.boatName}" Country="${boat.country}" Color="${boat.boatColor}">
|
||||||
<GPSposition Z="0" Y="3.7" X="0" />
|
<GPSposition Z="0" Y="3.7" X="0" />
|
||||||
<MastTop Z="0" Y="6.2" X="0" />
|
<MastTop Z="0" Y="6.2" X="0" />
|
||||||
|
|||||||
@@ -4,62 +4,39 @@
|
|||||||
<RaceStartTime Start="${raceStartTime}" Postpone="False" />
|
<RaceStartTime Start="${raceStartTime}" Postpone="False" />
|
||||||
<RaceID>15082901</RaceID>
|
<RaceID>15082901</RaceID>
|
||||||
<RaceType>Fleet</RaceType>
|
<RaceType>Fleet</RaceType>
|
||||||
<Participants>
|
|
||||||
|
<Participants MaxPlayers="${maxPlayers}">
|
||||||
<#list boats as boat>
|
<#list boats as boat>
|
||||||
<Yacht SourceID="${boat.sourceId}"/>
|
<Yacht SourceID="${boat.sourceId}"/>
|
||||||
</#list>
|
</#list>
|
||||||
</Participants>
|
</Participants>
|
||||||
<Tokens>
|
|
||||||
|
<Tokens Enabled="${tokensEnabled}">
|
||||||
<#list tokens as token>
|
<#list tokens as token>
|
||||||
<Token TokenType="${token.tokenType}" TargetLat="${token.lat?c}" TargetLng="${token.lng?c}"/>
|
<Token TokenType="${token.tokenType}" TargetLat="${token.lat?c}" TargetLng="${token.lng?c}"/>
|
||||||
</#list>
|
</#list>
|
||||||
</Tokens>
|
</Tokens>
|
||||||
|
|
||||||
<Course>
|
<Course>
|
||||||
<CompoundMark CompoundMarkID="1" Name="Mark0">
|
<#list compoundMarks as compoundMark>
|
||||||
<Mark SeqID="1" Name="Start Line 1" TargetLat="57.670603" TargetLng="11.828262" SourceID="122" />
|
<CompoundMark CompoundMarkID="${compoundMark.id?c}" Name="${compoundMark.name}">
|
||||||
<Mark SeqID="2" Name="Start Line 2" TargetLat="57.669445" TargetLng="11.826413" SourceID="123" />
|
<#list compoundMark.marks as mark>
|
||||||
</CompoundMark>
|
<Mark SeqID="${mark.seqID?c}" Name="${mark.name}" TargetLat="${mark.lat?c}" TargetLng="${mark.lng?c}" SourceID="${mark.sourceID?c}" />
|
||||||
<CompoundMark CompoundMarkID="2" Name="Mark1">
|
</#list>
|
||||||
<Mark SeqID="1" Name="Mark1" TargetLat="57.6675700" TargetLng="11.8359880" SourceID="131" />
|
</CompoundMark>
|
||||||
</CompoundMark>
|
</#list>
|
||||||
<CompoundMark CompoundMarkID="3" Name="Mark2">
|
|
||||||
<Mark SeqID="1" Name="Lee Gate 1" TargetLat="57.6708220" TargetLng="11.8433900" SourceID="124" />
|
|
||||||
<Mark SeqID="2" Name="Lee Gate 2" TargetLat="57.671629" TargetLng="11.840951" SourceID="125" />
|
|
||||||
</CompoundMark>
|
|
||||||
<CompoundMark CompoundMarkID="4" Name="Mark3">
|
|
||||||
<Mark SeqID="1" Name="Wind Gate 1" TargetLat="57.664190" TargetLng="11.829576" SourceID="126" />
|
|
||||||
<Mark SeqID="2" Name="Wind Gate 2" TargetLat="57.665316" TargetLng="11.827184" SourceID="127" />
|
|
||||||
</CompoundMark>
|
|
||||||
<CompoundMark CompoundMarkID="5" Name="Mark4">
|
|
||||||
<Mark SeqID="1" Name="Finish Line 1" TargetLat="57.672350" TargetLng="11.842535" SourceID="128" />
|
|
||||||
<Mark SeqID="2" Name="Finish Line 2" TargetLat="57.6715240" TargetLng="11.8444950" SourceID="129" />
|
|
||||||
</CompoundMark>
|
|
||||||
</Course>
|
</Course>
|
||||||
|
|
||||||
<CompoundMarkSequence>
|
<CompoundMarkSequence>
|
||||||
<Corner SeqID="1" CompoundMarkID="1" Rounding="PS" ZoneSize="3" />
|
<#list roundings as corner>
|
||||||
<Corner SeqID="2" CompoundMarkID="2" Rounding="Port" ZoneSize="3" />
|
<Corner SeqID="${corner.seqID?c}" CompoundMarkID="${corner.compoundMarkID?c}" Rounding="${corner.rounding}" ZoneSize="${corner.zoneSize?c}" />
|
||||||
<Corner SeqID="3" CompoundMarkID="3" Rounding="SP" ZoneSize="3" />
|
</#list>
|
||||||
<Corner SeqID="4" CompoundMarkID="4" Rounding="PS" ZoneSize="3" />
|
|
||||||
<Corner SeqID="5" CompoundMarkID="3" Rounding="SP" ZoneSize="3" />
|
|
||||||
<Corner SeqID="6" CompoundMarkID="4" Rounding="PS" ZoneSize="3" />
|
|
||||||
<Corner SeqID="7" CompoundMarkID="3" Rounding="SP" ZoneSize="3" />
|
|
||||||
<Corner SeqID="8" CompoundMarkID="4" Rounding="PS" ZoneSize="3" />
|
|
||||||
<Corner SeqID="9" CompoundMarkID="3" Rounding="SP" ZoneSize="3" />
|
|
||||||
<Corner SeqID="10" CompoundMarkID="4" Rounding="PS" ZoneSize="3" />
|
|
||||||
<Corner SeqID="11" CompoundMarkID="5" Rounding="PS" ZoneSize="3" />
|
|
||||||
</CompoundMarkSequence>
|
</CompoundMarkSequence>
|
||||||
|
|
||||||
<CourseLimit>
|
<CourseLimit>
|
||||||
<Limit SeqID="1" Lat="57.6739450" Lon="11.8417100" />
|
<#list courseLimit as limit>
|
||||||
<Limit SeqID="2" Lat="57.6709520" Lon="11.8485010" />
|
<Limit SeqID="${limit.seqID?c}" Lat="${limit.lat?c}" Lon="${limit.lng?c}" />
|
||||||
<Limit SeqID="3" Lat="57.6690260" Lon="11.8472790" />
|
</#list>
|
||||||
<Limit SeqID="4" Lat="57.6693140" Lon="11.8457610" />
|
|
||||||
<Limit SeqID="5" Lat="57.6665370" Lon="11.8432910" />
|
|
||||||
<Limit SeqID="6" Lat="57.6641400" Lon="11.8385840" />
|
|
||||||
<Limit SeqID="7" Lat="57.6629430" Lon="11.8332030" />
|
|
||||||
<Limit SeqID="8" Lat="57.6629480" Lon="11.8249660" />
|
|
||||||
<Limit SeqID="9" Lat="57.6686890" Lon="11.8250920" />
|
|
||||||
<Limit SeqID="10" Lat="57.6692230" Lon="11.8231430" />
|
|
||||||
<Limit SeqID="11" Lat="57.6725370" Lon="11.8272480" />
|
|
||||||
<Limit SeqID="12" Lat="57.6708220" Lon="11.8321340" />
|
|
||||||
</CourseLimit>
|
</CourseLimit>
|
||||||
|
|
||||||
</Race>
|
</Race>
|
||||||
@@ -5,14 +5,15 @@
|
|||||||
<?import javafx.geometry.Insets?>
|
<?import javafx.geometry.Insets?>
|
||||||
<?import javafx.scene.control.Label?>
|
<?import javafx.scene.control.Label?>
|
||||||
<?import javafx.scene.control.ScrollPane?>
|
<?import javafx.scene.control.ScrollPane?>
|
||||||
|
<?import javafx.scene.layout.AnchorPane?>
|
||||||
<?import javafx.scene.layout.ColumnConstraints?>
|
<?import javafx.scene.layout.ColumnConstraints?>
|
||||||
<?import javafx.scene.layout.GridPane?>
|
<?import javafx.scene.layout.GridPane?>
|
||||||
<?import javafx.scene.layout.Pane?>
|
|
||||||
<?import javafx.scene.layout.RowConstraints?>
|
<?import javafx.scene.layout.RowConstraints?>
|
||||||
<?import javafx.scene.layout.StackPane?>
|
<?import javafx.scene.layout.StackPane?>
|
||||||
<?import javafx.scene.layout.VBox?>
|
<?import javafx.scene.layout.VBox?>
|
||||||
<?import javafx.scene.text.Font?>
|
<?import javafx.scene.text.Font?>
|
||||||
<StackPane fx:id="serverListMainStackPane" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" minHeight="-Infinity" minWidth="-Infinity" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="seng302.visualiser.controllers.LobbyController">
|
|
||||||
|
<StackPane fx:id="serverListMainStackPane" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" minHeight="-Infinity" minWidth="-Infinity" xmlns="http://javafx.com/javafx/8.0.112" xmlns:fx="http://javafx.com/fxml/1" fx:controller="seng302.visualiser.controllers.LobbyController">
|
||||||
<children>
|
<children>
|
||||||
<GridPane fx:id="serverListMainGridPane" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308">
|
<GridPane fx:id="serverListMainGridPane" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308">
|
||||||
<children>
|
<children>
|
||||||
@@ -37,8 +38,7 @@
|
|||||||
</GridPane>
|
</GridPane>
|
||||||
<GridPane>
|
<GridPane>
|
||||||
<children>
|
<children>
|
||||||
<Label fx:id="serverName" text="Party Parrots In Space"
|
<Label fx:id="serverName" text="Party Parrots In Space" GridPane.valignment="CENTER">
|
||||||
GridPane.valignment="CENTER">
|
|
||||||
<font>
|
<font>
|
||||||
<Font size="31.0" />
|
<Font size="31.0" />
|
||||||
</font>
|
</font>
|
||||||
@@ -46,8 +46,7 @@
|
|||||||
<Insets left="35.0" top="10.0" />
|
<Insets left="35.0" top="10.0" />
|
||||||
</padding>
|
</padding>
|
||||||
</Label>
|
</Label>
|
||||||
<Label fx:id="mapName" text="This is a map, it's called Haoming"
|
<Label fx:id="mapName" text="This is a map, it's called Haoming" GridPane.rowIndex="1">
|
||||||
GridPane.rowIndex="1">
|
|
||||||
<padding>
|
<padding>
|
||||||
<Insets left="35.0" top="-15.0" />
|
<Insets left="35.0" top="-15.0" />
|
||||||
</padding>
|
</padding>
|
||||||
@@ -73,17 +72,20 @@
|
|||||||
<children>
|
<children>
|
||||||
<ScrollPane fx:id="playerListScrollPane" hbarPolicy="NEVER" GridPane.columnIndex="1" GridPane.halignment="CENTER" GridPane.valignment="CENTER">
|
<ScrollPane fx:id="playerListScrollPane" hbarPolicy="NEVER" GridPane.columnIndex="1" GridPane.halignment="CENTER" GridPane.valignment="CENTER">
|
||||||
<content>
|
<content>
|
||||||
<VBox fx:id="playerListVBox" prefHeight="200.0" prefWidth="100.0"/>
|
<VBox fx:id="playerListVBox" prefHeight="200.0" prefWidth="100.0" />
|
||||||
</content>
|
</content>
|
||||||
<GridPane.margin>
|
<GridPane.margin>
|
||||||
<Insets bottom="15.0" left="7.0" right="15.0" top="15.0" />
|
<Insets bottom="15.0" left="7.0" right="15.0" top="15.0" />
|
||||||
</GridPane.margin>
|
</GridPane.margin>
|
||||||
</ScrollPane>
|
</ScrollPane>
|
||||||
<Pane fx:id="serverMap" style="-fx-background-color: skyblue;">
|
<AnchorPane fx:id="serverMap" style="-fx-background-color: skyblue;">
|
||||||
<GridPane.margin>
|
<opaqueInsets>
|
||||||
<Insets bottom="15.0" left="15.0" right="7.0" top="15.0" />
|
<Insets />
|
||||||
</GridPane.margin>
|
</opaqueInsets>
|
||||||
</Pane>
|
<GridPane.margin>
|
||||||
|
<Insets bottom="15.0" left="15.0" right="7.0" top="15.0" />
|
||||||
|
</GridPane.margin>
|
||||||
|
</AnchorPane>
|
||||||
</children>
|
</children>
|
||||||
</GridPane>
|
</GridPane>
|
||||||
</children>
|
</children>
|
||||||
@@ -96,7 +98,7 @@
|
|||||||
<RowConstraints maxHeight="80.0" minHeight="80.0" prefHeight="80.0" vgrow="SOMETIMES" />
|
<RowConstraints maxHeight="80.0" minHeight="80.0" prefHeight="80.0" vgrow="SOMETIMES" />
|
||||||
</rowConstraints>
|
</rowConstraints>
|
||||||
<stylesheets>
|
<stylesheets>
|
||||||
<String fx:value="/css/Master.css"/>
|
<String fx:value="/css/Master.css" />
|
||||||
<String fx:value="/css/LobbyView.css" />
|
<String fx:value="/css/LobbyView.css" />
|
||||||
</stylesheets>
|
</stylesheets>
|
||||||
</GridPane>
|
</GridPane>
|
||||||
|
|||||||
@@ -7,241 +7,228 @@
|
|||||||
<?import javafx.scene.control.Label?>
|
<?import javafx.scene.control.Label?>
|
||||||
<?import javafx.scene.image.Image?>
|
<?import javafx.scene.image.Image?>
|
||||||
<?import javafx.scene.image.ImageView?>
|
<?import javafx.scene.image.ImageView?>
|
||||||
<?import javafx.scene.layout.AnchorPane?>
|
|
||||||
<?import javafx.scene.layout.ColumnConstraints?>
|
<?import javafx.scene.layout.ColumnConstraints?>
|
||||||
<?import javafx.scene.layout.GridPane?>
|
<?import javafx.scene.layout.GridPane?>
|
||||||
<?import javafx.scene.layout.Pane?>
|
<?import javafx.scene.layout.Pane?>
|
||||||
<?import javafx.scene.layout.RowConstraints?>
|
<?import javafx.scene.layout.RowConstraints?>
|
||||||
<?import javafx.scene.layout.StackPane?>
|
<?import javafx.scene.layout.StackPane?>
|
||||||
<?import javafx.scene.text.Font?>
|
<?import javafx.scene.text.Font?>
|
||||||
<AnchorPane fx:id="rvAnchorPane" maxHeight="1.7976931348623157E308"
|
|
||||||
|
<StackPane fx:id="contentStackPane" maxHeight="1.7976931348623157E308"
|
||||||
maxWidth="1.7976931348623157E308" minHeight="-Infinity" minWidth="-Infinity" prefHeight="800.0"
|
maxWidth="1.7976931348623157E308" minHeight="-Infinity" minWidth="-Infinity" prefHeight="800.0"
|
||||||
prefWidth="1200.0" style="-fx-background-color: skyblue;" xmlns="http://javafx.com/javafx/8"
|
prefWidth="1200.0" style="-fx-background-color: skyblue;" xmlns="http://javafx.com/javafx/8.0.111"
|
||||||
xmlns:fx="http://javafx.com/fxml/1"
|
xmlns:fx="http://javafx.com/fxml/1"
|
||||||
fx:controller="seng302.visualiser.controllers.RaceViewController">
|
fx:controller="seng302.visualiser.controllers.RaceViewController">
|
||||||
<children>
|
<children>
|
||||||
<StackPane fx:id="contentAnchorPane" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" prefHeight="800.0" prefWidth="1200.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
<GridPane maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308"
|
||||||
<children>
|
prefHeight="800.0" prefWidth="1200.0">
|
||||||
<GridPane maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308"
|
<columnConstraints>
|
||||||
prefHeight="800.0" prefWidth="1200.0">
|
<ColumnConstraints hgrow="SOMETIMES" maxWidth="250.0" minWidth="250.0"
|
||||||
<columnConstraints>
|
prefWidth="250.0"/>
|
||||||
<ColumnConstraints hgrow="SOMETIMES" maxWidth="250.0" minWidth="250.0"
|
<ColumnConstraints hgrow="SOMETIMES" maxWidth="1.7976931348623157E308"/>
|
||||||
prefWidth="250.0"/>
|
<ColumnConstraints hgrow="SOMETIMES" maxWidth="-Infinity" minWidth="400.0"
|
||||||
<ColumnConstraints hgrow="SOMETIMES" maxWidth="1.7976931348623157E308"/>
|
prefWidth="400.0"/>
|
||||||
<ColumnConstraints hgrow="SOMETIMES" maxWidth="-Infinity" minWidth="400.0"
|
</columnConstraints>
|
||||||
prefWidth="400.0"/>
|
<rowConstraints>
|
||||||
</columnConstraints>
|
<RowConstraints maxHeight="70.0" minHeight="70.0" prefHeight="70.0"
|
||||||
<rowConstraints>
|
vgrow="SOMETIMES"/>
|
||||||
<RowConstraints maxHeight="70.0" minHeight="70.0" prefHeight="70.0"
|
<RowConstraints maxHeight="1.7976931348623157E308" vgrow="SOMETIMES"/>
|
||||||
vgrow="SOMETIMES"/>
|
<RowConstraints maxHeight="250.0" minHeight="250.0" prefHeight="250.0"
|
||||||
<RowConstraints maxHeight="1.7976931348623157E308" vgrow="SOMETIMES"/>
|
valignment="BOTTOM" vgrow="SOMETIMES"/>
|
||||||
<RowConstraints maxHeight="250.0" minHeight="250.0" prefHeight="250.0"
|
</rowConstraints>
|
||||||
valignment="BOTTOM" vgrow="SOMETIMES"/>
|
<children>
|
||||||
</rowConstraints>
|
<GridPane id="timerGrid" fx:id="timerGrid" prefWidth="192.0" styleClass="timer">
|
||||||
<children>
|
<columnConstraints>
|
||||||
<GridPane id="timerGrid" fx:id="timerGrid" prefWidth="192.0"
|
<ColumnConstraints hgrow="SOMETIMES" maxWidth="50.0" minWidth="50.0"
|
||||||
styleClass="timer">
|
prefWidth="50.0"/>
|
||||||
<columnConstraints>
|
<ColumnConstraints hgrow="SOMETIMES" maxWidth="135.0" minWidth="135.0"
|
||||||
<ColumnConstraints hgrow="SOMETIMES" maxWidth="50.0" minWidth="50.0"
|
prefWidth="135.0"/>
|
||||||
prefWidth="50.0"/>
|
</columnConstraints>
|
||||||
<ColumnConstraints hgrow="SOMETIMES" maxWidth="135.0"
|
<rowConstraints>
|
||||||
minWidth="135.0" prefWidth="135.0"/>
|
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES"/>
|
||||||
</columnConstraints>
|
</rowConstraints>
|
||||||
<rowConstraints>
|
<opaqueInsets>
|
||||||
<RowConstraints minHeight="10.0" prefHeight="30.0"
|
<Insets/>
|
||||||
vgrow="SOMETIMES"/>
|
</opaqueInsets>
|
||||||
</rowConstraints>
|
<GridPane.margin>
|
||||||
<opaqueInsets>
|
<Insets left="10.0" right="200.0" top="10.0"/>
|
||||||
<Insets/>
|
</GridPane.margin>
|
||||||
</opaqueInsets>
|
<children>
|
||||||
<GridPane.margin>
|
<ImageView fitHeight="40.0" fitWidth="40.0" pickOnBounds="true"
|
||||||
<Insets left="10.0" right="200.0" top="10.0"/>
|
preserveRatio="true" GridPane.halignment="CENTER"
|
||||||
</GridPane.margin>
|
GridPane.valignment="CENTER">
|
||||||
<children>
|
<image>
|
||||||
<ImageView fitHeight="40.0" fitWidth="40.0" pickOnBounds="true"
|
<Image url="@../images/timer.png"/>
|
||||||
preserveRatio="true" GridPane.halignment="CENTER"
|
</image>
|
||||||
GridPane.valignment="CENTER">
|
<GridPane.margin>
|
||||||
<image>
|
<Insets/>
|
||||||
<Image url="@../images/timer.png"/>
|
</GridPane.margin>
|
||||||
</image>
|
</ImageView>
|
||||||
<GridPane.margin>
|
<Label fx:id="timerLabel" text="00:03:34" GridPane.columnIndex="1"
|
||||||
<Insets/>
|
GridPane.halignment="CENTER" GridPane.valignment="CENTER">
|
||||||
</GridPane.margin>
|
<font>
|
||||||
</ImageView>
|
<Font size="21.0"/>
|
||||||
<Label fx:id="timerLabel" text="00:03:34" GridPane.columnIndex="1"
|
</font>
|
||||||
GridPane.halignment="CENTER" GridPane.valignment="CENTER">
|
<GridPane.margin>
|
||||||
<font>
|
<Insets/>
|
||||||
<Font size="21.0"/>
|
</GridPane.margin>
|
||||||
</font>
|
</Label>
|
||||||
<GridPane.margin>
|
</children>
|
||||||
<Insets/>
|
</GridPane>
|
||||||
</GridPane.margin>
|
<GridPane GridPane.columnIndex="2">
|
||||||
</Label>
|
<columnConstraints>
|
||||||
</children>
|
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0"/>
|
||||||
</GridPane>
|
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0"/>
|
||||||
<GridPane GridPane.columnIndex="2">
|
</columnConstraints>
|
||||||
<columnConstraints>
|
<rowConstraints>
|
||||||
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0"
|
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES"/>
|
||||||
prefWidth="100.0"/>
|
</rowConstraints>
|
||||||
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0"
|
</GridPane>
|
||||||
prefWidth="100.0"/>
|
<GridPane fx:id="chatGridPane" GridPane.columnIndex="2" GridPane.rowIndex="2">
|
||||||
</columnConstraints>
|
<columnConstraints>
|
||||||
<rowConstraints>
|
<ColumnConstraints hgrow="SOMETIMES" maxWidth="390.0" minWidth="390.0"
|
||||||
<RowConstraints minHeight="10.0" prefHeight="30.0"
|
prefWidth="390.0"/>
|
||||||
vgrow="SOMETIMES"/>
|
</columnConstraints>
|
||||||
</rowConstraints>
|
<rowConstraints>
|
||||||
</GridPane>
|
<RowConstraints maxHeight="1.7976931348623157E308" vgrow="SOMETIMES"/>
|
||||||
<GridPane fx:id="chatGridPane" GridPane.columnIndex="2"
|
<RowConstraints maxHeight="60.0" minHeight="60.0" prefHeight="60.0"
|
||||||
GridPane.rowIndex="2">
|
vgrow="SOMETIMES"/>
|
||||||
<columnConstraints>
|
</rowConstraints>
|
||||||
<ColumnConstraints hgrow="SOMETIMES" maxWidth="390.0"
|
<children>
|
||||||
minWidth="390.0" prefWidth="390.0"/>
|
<Pane fx:id="chatHistoryHolder" prefHeight="200.0" prefWidth="200.0"
|
||||||
</columnConstraints>
|
GridPane.hgrow="ALWAYS" GridPane.valignment="BOTTOM"
|
||||||
<rowConstraints>
|
GridPane.vgrow="ALWAYS">
|
||||||
<RowConstraints maxHeight="1.7976931348623157E308"
|
<GridPane.margin>
|
||||||
vgrow="SOMETIMES"/>
|
<Insets/>
|
||||||
<RowConstraints maxHeight="60.0" minHeight="60.0" prefHeight="60.0"
|
</GridPane.margin>
|
||||||
vgrow="SOMETIMES"/>
|
<padding>
|
||||||
</rowConstraints>
|
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0"/>
|
||||||
<children>
|
</padding>
|
||||||
<Pane fx:id="chatHistoryHolder" prefHeight="200.0" prefWidth="200.0"
|
</Pane>
|
||||||
GridPane.hgrow="ALWAYS" GridPane.valignment="BOTTOM"
|
<GridPane fx:id="chatInputHolder" GridPane.rowIndex="1">
|
||||||
GridPane.vgrow="ALWAYS">
|
<columnConstraints>
|
||||||
<GridPane.margin>
|
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0"
|
||||||
<Insets/>
|
prefWidth="100.0"/>
|
||||||
</GridPane.margin>
|
<ColumnConstraints hgrow="SOMETIMES" maxWidth="-Infinity"
|
||||||
<padding>
|
minWidth="90.0" prefWidth="90.0"/>
|
||||||
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0"/>
|
</columnConstraints>
|
||||||
</padding>
|
<rowConstraints>
|
||||||
</Pane>
|
<RowConstraints maxHeight="50.0" minHeight="50.0" prefHeight="50.0"
|
||||||
<GridPane fx:id="chatInputHolder" GridPane.rowIndex="1">
|
valignment="CENTER" vgrow="SOMETIMES"/>
|
||||||
<columnConstraints>
|
</rowConstraints>
|
||||||
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0"
|
<children>
|
||||||
prefWidth="100.0"/>
|
<JFXButton fx:id="chatSend" alignment="CENTER" buttonType="RAISED"
|
||||||
<ColumnConstraints hgrow="SOMETIMES" maxWidth="-Infinity"
|
focusTraversable="false" maxHeight="-Infinity"
|
||||||
minWidth="90.0" prefWidth="90.0"/>
|
maxWidth="1.7976931348623157E308" minHeight="-Infinity"
|
||||||
</columnConstraints>
|
minWidth="-Infinity" prefHeight="35.0" text="SEND"
|
||||||
<rowConstraints>
|
GridPane.columnIndex="1">
|
||||||
<RowConstraints maxHeight="50.0" minHeight="50.0"
|
<GridPane.margin>
|
||||||
prefHeight="50.0" valignment="CENTER" vgrow="SOMETIMES"/>
|
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0"/>
|
||||||
</rowConstraints>
|
</GridPane.margin>
|
||||||
<children>
|
</JFXButton>
|
||||||
<JFXButton fx:id="chatSend" alignment="CENTER"
|
<JFXTextField fx:id="chatInput" focusTraversable="false"
|
||||||
buttonType="RAISED" maxHeight="-Infinity"
|
maxHeight="35.0" minHeight="-Infinity" prefHeight="35.0">
|
||||||
maxWidth="1.7976931348623157E308" minHeight="-Infinity"
|
<GridPane.margin>
|
||||||
minWidth="-Infinity" prefHeight="35.0" text="SEND"
|
<Insets bottom="10.0" left="20.0" right="10.0"/>
|
||||||
GridPane.columnIndex="1">
|
</GridPane.margin>
|
||||||
<GridPane.margin>
|
<padding>
|
||||||
<Insets bottom="10.0" left="10.0" right="10.0"
|
<Insets right="15.0"/>
|
||||||
top="10.0"/>
|
</padding>
|
||||||
</GridPane.margin>
|
</JFXTextField>
|
||||||
</JFXButton>
|
</children>
|
||||||
<JFXTextField fx:id="chatInput" maxHeight="35.0"
|
<GridPane.margin>
|
||||||
minHeight="-Infinity" prefHeight="35.0">
|
<Insets top="10.0"/>
|
||||||
<GridPane.margin>
|
</GridPane.margin>
|
||||||
<Insets bottom="10.0" left="20.0" right="10.0"/>
|
</GridPane>
|
||||||
</GridPane.margin>
|
</children>
|
||||||
<padding>
|
<GridPane.margin>
|
||||||
<Insets right="15.0"/>
|
<Insets bottom="10.0" right="10.0"/>
|
||||||
</padding>
|
</GridPane.margin>
|
||||||
</JFXTextField>
|
</GridPane>
|
||||||
</children>
|
<GridPane fx:id="windGridPane" maxHeight="-Infinity" maxWidth="-Infinity"
|
||||||
<GridPane.margin>
|
prefHeight="150.0" prefWidth="240.0" GridPane.halignment="CENTER"
|
||||||
<Insets top="10.0"/>
|
GridPane.rowIndex="2" GridPane.valignment="BOTTOM">
|
||||||
</GridPane.margin>
|
<columnConstraints>
|
||||||
</GridPane>
|
<ColumnConstraints hgrow="SOMETIMES" maxWidth="110.0" minWidth="110.0"
|
||||||
</children>
|
prefWidth="110.0"/>
|
||||||
<GridPane.margin>
|
<ColumnConstraints hgrow="SOMETIMES" maxWidth="132.0" minWidth="10.0"
|
||||||
<Insets bottom="10.0" right="10.0"/>
|
prefWidth="132.0"/>
|
||||||
</GridPane.margin>
|
</columnConstraints>
|
||||||
</GridPane>
|
<rowConstraints>
|
||||||
<GridPane fx:id="windGridPane" maxHeight="-Infinity" maxWidth="-Infinity"
|
<RowConstraints maxHeight="120.0" minHeight="120.0" prefHeight="120.0"
|
||||||
prefHeight="150.0" prefWidth="240.0" GridPane.halignment="CENTER"
|
vgrow="SOMETIMES"/>
|
||||||
GridPane.rowIndex="2" GridPane.valignment="BOTTOM">
|
<RowConstraints maxHeight="30.0" minHeight="30.0" prefHeight="30.0"
|
||||||
<columnConstraints>
|
vgrow="SOMETIMES"/>
|
||||||
<ColumnConstraints hgrow="SOMETIMES" maxWidth="110.0"
|
</rowConstraints>
|
||||||
minWidth="110.0" prefWidth="110.0"/>
|
<children>
|
||||||
<ColumnConstraints hgrow="SOMETIMES" maxWidth="132.0" minWidth="10.0"
|
<Label fx:id="positionLabel" text="Position:" GridPane.columnIndex="1"
|
||||||
prefWidth="132.0"/>
|
GridPane.halignment="LEFT" GridPane.rowSpan="2" GridPane.valignment="TOP">
|
||||||
</columnConstraints>
|
<padding>
|
||||||
<rowConstraints>
|
<Insets bottom="5.0" left="10.0" right="5.0" top="5.0"/>
|
||||||
<RowConstraints maxHeight="120.0" minHeight="120.0"
|
</padding>
|
||||||
prefHeight="120.0" vgrow="SOMETIMES"/>
|
</Label>
|
||||||
<RowConstraints maxHeight="30.0" minHeight="30.0" prefHeight="30.0"
|
<Label fx:id="boatSpeedLabel" text="Boat Speed:" GridPane.columnIndex="1"
|
||||||
vgrow="SOMETIMES"/>
|
GridPane.halignment="LEFT" GridPane.rowSpan="2"
|
||||||
</rowConstraints>
|
GridPane.valignment="CENTER">
|
||||||
<children>
|
<opaqueInsets>
|
||||||
<Label fx:id="positionLabel" text="Position:"
|
<Insets/>
|
||||||
GridPane.columnIndex="1" GridPane.halignment="LEFT"
|
</opaqueInsets>
|
||||||
GridPane.rowSpan="2" GridPane.valignment="TOP">
|
<padding>
|
||||||
<padding>
|
<Insets bottom="5.0" left="10.0" right="5.0" top="5.0"/>
|
||||||
<Insets bottom="5.0" left="10.0" right="5.0" top="5.0"/>
|
</padding>
|
||||||
</padding>
|
</Label>
|
||||||
</Label>
|
<Label fx:id="boatHeadingLabel" text="Boat Heading:"
|
||||||
<Label fx:id="boatSpeedLabel" text="Boat Speed:"
|
GridPane.columnIndex="1" GridPane.halignment="LEFT" GridPane.rowSpan="2"
|
||||||
GridPane.columnIndex="1" GridPane.halignment="LEFT"
|
GridPane.valignment="BOTTOM">
|
||||||
GridPane.rowSpan="2" GridPane.valignment="CENTER">
|
<padding>
|
||||||
<opaqueInsets>
|
<Insets bottom="5.0" left="10.0" right="5.0" top="5.0"/>
|
||||||
<Insets/>
|
</padding>
|
||||||
</opaqueInsets>
|
</Label>
|
||||||
<padding>
|
<GridPane fx:id="windHolder" GridPane.rowSpan="2">
|
||||||
<Insets bottom="5.0" left="10.0" right="5.0" top="5.0"/>
|
<columnConstraints>
|
||||||
</padding>
|
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0"
|
||||||
</Label>
|
prefWidth="100.0"/>
|
||||||
<Label fx:id="boatHeadingLabel" text="Boat Heading:"
|
</columnConstraints>
|
||||||
GridPane.columnIndex="1" GridPane.halignment="LEFT"
|
<rowConstraints>
|
||||||
GridPane.rowSpan="2" GridPane.valignment="BOTTOM">
|
<RowConstraints maxHeight="120.0" minHeight="120.0"
|
||||||
<padding>
|
prefHeight="120.0" vgrow="SOMETIMES"/>
|
||||||
<Insets bottom="5.0" left="10.0" right="5.0" top="5.0"/>
|
<RowConstraints maxHeight="30.0" minHeight="30.0" prefHeight="30.0"
|
||||||
</padding>
|
vgrow="SOMETIMES"/>
|
||||||
</Label>
|
</rowConstraints>
|
||||||
<GridPane fx:id="windHolder" GridPane.rowSpan="2">
|
<children>
|
||||||
<columnConstraints>
|
<ImageView fx:id="windImageView" fitHeight="92.0" fitWidth="109.0"
|
||||||
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0"
|
pickOnBounds="true" preserveRatio="true"
|
||||||
prefWidth="100.0"/>
|
GridPane.halignment="CENTER" GridPane.rowSpan="2"
|
||||||
</columnConstraints>
|
GridPane.valignment="CENTER"/>
|
||||||
<rowConstraints>
|
<Label fx:id="windSpeedLabel" text="0.0 Knots"
|
||||||
<RowConstraints maxHeight="120.0" minHeight="120.0"
|
GridPane.halignment="RIGHT" GridPane.rowIndex="1"
|
||||||
prefHeight="120.0" vgrow="SOMETIMES"/>
|
GridPane.valignment="CENTER">
|
||||||
<RowConstraints maxHeight="30.0" minHeight="30.0"
|
<GridPane.margin>
|
||||||
prefHeight="30.0" vgrow="SOMETIMES"/>
|
<Insets right="5.0"/>
|
||||||
</rowConstraints>
|
</GridPane.margin>
|
||||||
<children>
|
</Label>
|
||||||
<ImageView fx:id="windImageView" fitHeight="92.0"
|
<Label fx:id="windDirectionLabel" text="180.0°"
|
||||||
fitWidth="109.0" pickOnBounds="true" preserveRatio="true"
|
GridPane.halignment="LEFT" GridPane.rowIndex="1"
|
||||||
GridPane.halignment="CENTER" GridPane.rowSpan="2"
|
GridPane.valignment="CENTER">
|
||||||
GridPane.valignment="CENTER"/>
|
<GridPane.margin>
|
||||||
<Label fx:id="windSpeedLabel" text="0.0 Knots"
|
<Insets left="5.0"/>
|
||||||
GridPane.halignment="RIGHT" GridPane.rowIndex="1"
|
</GridPane.margin>
|
||||||
GridPane.valignment="CENTER">
|
</Label>
|
||||||
<GridPane.margin>
|
</children>
|
||||||
<Insets right="5.0"/>
|
</GridPane>
|
||||||
</GridPane.margin>
|
</children>
|
||||||
</Label>
|
<opaqueInsets>
|
||||||
<Label fx:id="windDirectionLabel" text="180.0°"
|
<Insets/>
|
||||||
GridPane.halignment="LEFT" GridPane.rowIndex="1"
|
</opaqueInsets>
|
||||||
GridPane.valignment="CENTER">
|
<GridPane.margin>
|
||||||
<GridPane.margin>
|
<Insets bottom="10.0" left="10.0" top="40.0"/>
|
||||||
<Insets left="5.0"/>
|
</GridPane.margin>
|
||||||
</GridPane.margin>
|
</GridPane>
|
||||||
</Label>
|
</children>
|
||||||
</children>
|
</GridPane>
|
||||||
</GridPane>
|
</children>
|
||||||
</children>
|
|
||||||
<opaqueInsets>
|
|
||||||
<Insets/>
|
|
||||||
</opaqueInsets>
|
|
||||||
<GridPane.margin>
|
|
||||||
<Insets bottom="10.0" left="10.0" top="40.0"/>
|
|
||||||
</GridPane.margin>
|
|
||||||
</GridPane>
|
|
||||||
</children>
|
|
||||||
</GridPane>
|
|
||||||
</children>
|
|
||||||
</StackPane>
|
|
||||||
</children>
|
|
||||||
<stylesheets>
|
<stylesheets>
|
||||||
<String fx:value="/css/Master.css" />
|
<String fx:value="/css/Master.css"/>
|
||||||
<String fx:value="/css/RaceView.css" />
|
<String fx:value="/css/RaceView.css"/>
|
||||||
</stylesheets>
|
</stylesheets>
|
||||||
</AnchorPane>
|
</StackPane>
|
||||||
|
|||||||
@@ -1,5 +1,11 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
|
<?import javafx.scene.text.*?>
|
||||||
|
<?import com.jfoenix.controls.*?>
|
||||||
|
<?import java.lang.*?>
|
||||||
|
<?import javafx.geometry.*?>
|
||||||
|
<?import javafx.scene.control.*?>
|
||||||
|
<?import javafx.scene.layout.*?>
|
||||||
<?import com.jfoenix.controls.JFXButton?>
|
<?import com.jfoenix.controls.JFXButton?>
|
||||||
<?import com.jfoenix.controls.JFXColorPicker?>
|
<?import com.jfoenix.controls.JFXColorPicker?>
|
||||||
<?import com.jfoenix.controls.JFXDialogLayout?>
|
<?import com.jfoenix.controls.JFXDialogLayout?>
|
||||||
@@ -10,54 +16,45 @@
|
|||||||
<?import javafx.scene.layout.ColumnConstraints?>
|
<?import javafx.scene.layout.ColumnConstraints?>
|
||||||
<?import javafx.scene.layout.GridPane?>
|
<?import javafx.scene.layout.GridPane?>
|
||||||
<?import javafx.scene.layout.RowConstraints?>
|
<?import javafx.scene.layout.RowConstraints?>
|
||||||
<JFXDialogLayout maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity"
|
|
||||||
minWidth="-Infinity" prefWidth="400.0" xmlns="http://javafx.com/javafx/8"
|
<JFXDialogLayout maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefWidth="400.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="seng302.visualiser.controllers.dialogs.BoatCustomizeController">
|
||||||
xmlns:fx="http://javafx.com/fxml/1"
|
|
||||||
fx:controller="seng302.visualiser.controllers.dialogs.BoatCustomizeController">
|
|
||||||
<children>
|
<children>
|
||||||
<GridPane>
|
<GridPane>
|
||||||
<columnConstraints>
|
<columnConstraints>
|
||||||
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
|
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
|
||||||
</columnConstraints>
|
</columnConstraints>
|
||||||
<rowConstraints>
|
<rowConstraints>
|
||||||
<RowConstraints maxHeight="90.0" minHeight="90.0" prefHeight="90.0" vgrow="SOMETIMES" />
|
<RowConstraints maxHeight="90.0" minHeight="48.0" prefHeight="48.0" vgrow="SOMETIMES" />
|
||||||
<RowConstraints maxHeight="100.0" minHeight="100.0" prefHeight="100.0" vgrow="SOMETIMES" />
|
<RowConstraints maxHeight="207.0" minHeight="93.0" prefHeight="181.0" vgrow="SOMETIMES" />
|
||||||
<RowConstraints maxHeight="125.0" minHeight="61.0" prefHeight="99.0"
|
<RowConstraints maxHeight="207.0" minHeight="93.0" prefHeight="181.0" vgrow="SOMETIMES" />
|
||||||
vgrow="SOMETIMES"/>
|
<RowConstraints maxHeight="145.0" minHeight="66.0" prefHeight="109.0" vgrow="SOMETIMES" />
|
||||||
<RowConstraints maxHeight="164.0" minHeight="100.0" prefHeight="126.0"
|
<RowConstraints maxHeight="125.0" minHeight="24.0" prefHeight="72.0" vgrow="SOMETIMES" />
|
||||||
vgrow="SOMETIMES"/>
|
<RowConstraints maxHeight="164.0" minHeight="100.0" prefHeight="105.0" vgrow="SOMETIMES" />
|
||||||
</rowConstraints>
|
</rowConstraints>
|
||||||
<children>
|
<children>
|
||||||
<Label fx:id="hostDialogHeader" text="Customize Boat" GridPane.halignment="CENTER"
|
<Label fx:id="hostDialogHeader" text="Customize Boat" GridPane.halignment="CENTER" GridPane.valignment="CENTER" />
|
||||||
GridPane.valignment="CENTER"/>
|
<JFXButton fx:id="submitBtn" prefHeight="45.0" prefWidth="220.0" text="Customize Boat" GridPane.halignment="CENTER" GridPane.rowIndex="5" GridPane.valignment="CENTER" />
|
||||||
<JFXButton fx:id="submitBtn" prefHeight="45.0" prefWidth="220.0" text="Customize Boat" GridPane.halignment="CENTER" GridPane.rowIndex="3" GridPane.valignment="CENTER" />
|
<JFXTextField fx:id="boatName" focusColor="#6c6c6c" promptText="Boat Name" unFocusColor="#6b6b6b" GridPane.rowIndex="3">
|
||||||
<JFXTextField fx:id="boatName" focusColor="#6c6c6c" promptText="Boat Name"
|
|
||||||
unFocusColor="#6b6b6b" GridPane.rowIndex="1">
|
|
||||||
<GridPane.margin>
|
<GridPane.margin>
|
||||||
<Insets left="30.0" right="30.0" />
|
<Insets left="30.0" right="30.0" />
|
||||||
</GridPane.margin></JFXTextField>
|
</GridPane.margin></JFXTextField>
|
||||||
<GridPane GridPane.halignment="CENTER" GridPane.rowIndex="2"
|
<GridPane GridPane.halignment="CENTER" GridPane.rowIndex="4" GridPane.valignment="CENTER">
|
||||||
GridPane.valignment="CENTER">
|
|
||||||
<columnConstraints>
|
<columnConstraints>
|
||||||
<ColumnConstraints hgrow="SOMETIMES" maxWidth="139.0" minWidth="10.0"
|
<ColumnConstraints hgrow="SOMETIMES" maxWidth="139.0" minWidth="10.0" prefWidth="94.0" />
|
||||||
prefWidth="94.0"/>
|
<ColumnConstraints hgrow="SOMETIMES" maxWidth="203.0" minWidth="10.0" prefWidth="198.0" />
|
||||||
<ColumnConstraints hgrow="SOMETIMES" maxWidth="203.0" minWidth="10.0"
|
|
||||||
prefWidth="198.0"/>
|
|
||||||
</columnConstraints>
|
</columnConstraints>
|
||||||
<rowConstraints>
|
<rowConstraints>
|
||||||
<RowConstraints percentHeight="100.0" valignment="CENTER" vgrow="SOMETIMES"/>
|
<RowConstraints percentHeight="100.0" valignment="CENTER" vgrow="SOMETIMES" />
|
||||||
</rowConstraints>
|
</rowConstraints>
|
||||||
<children>
|
<children>
|
||||||
<Label fx:id="boatColorLabel" prefHeight="25.0" prefWidth="96.0"
|
<Label fx:id="boatColorLabel" prefHeight="25.0" prefWidth="96.0" text="Boat Color" GridPane.valignment="CENTER">
|
||||||
text="Boat Color" GridPane.valignment="CENTER">
|
|
||||||
<GridPane.margin>
|
<GridPane.margin>
|
||||||
<Insets top="-10.0" />
|
<Insets top="-10.0" />
|
||||||
</GridPane.margin>
|
</GridPane.margin>
|
||||||
</Label>
|
</Label>
|
||||||
<JFXColorPicker fx:id="colorPicker" onAction="#colorChanged"
|
<JFXColorPicker fx:id="colorPicker" onAction="#colorChanged" GridPane.columnIndex="1" GridPane.valignment="CENTER">
|
||||||
GridPane.columnIndex="1" GridPane.valignment="CENTER">
|
|
||||||
<GridPane.margin>
|
<GridPane.margin>
|
||||||
<Insets left="30.0" top="-10.0"/>
|
<Insets left="30.0" top="-10.0" />
|
||||||
</GridPane.margin>
|
</GridPane.margin>
|
||||||
</JFXColorPicker>
|
</JFXColorPicker>
|
||||||
</children>
|
</children>
|
||||||
@@ -65,11 +62,45 @@
|
|||||||
<Insets left="30.0" right="30.0" />
|
<Insets left="30.0" right="30.0" />
|
||||||
</GridPane.margin>
|
</GridPane.margin>
|
||||||
</GridPane>
|
</GridPane>
|
||||||
|
<GridPane GridPane.rowIndex="1">
|
||||||
|
<columnConstraints>
|
||||||
|
<ColumnConstraints hgrow="SOMETIMES" maxWidth="-Infinity" minWidth="-Infinity" prefWidth="50.0" />
|
||||||
|
<ColumnConstraints hgrow="SOMETIMES" maxWidth="256.0" minWidth="10.0" />
|
||||||
|
<ColumnConstraints hgrow="SOMETIMES" maxWidth="-Infinity" minWidth="-Infinity" prefWidth="50.0" />
|
||||||
|
</columnConstraints>
|
||||||
|
<rowConstraints>
|
||||||
|
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
|
||||||
|
</rowConstraints>
|
||||||
|
<children>
|
||||||
|
<Pane fx:id="boatPane" prefHeight="200.0" prefWidth="200.0" GridPane.columnIndex="1" />
|
||||||
|
<JFXButton buttonType="RAISED" onAction="#prevBoat" prefHeight="200.0" prefWidth="50.0" text="<" />
|
||||||
|
<JFXButton buttonType="RAISED" onAction="#nextBoat" prefHeight="200.0" prefWidth="50.0" text=">" GridPane.columnIndex="2" />
|
||||||
|
</children>
|
||||||
|
</GridPane>
|
||||||
|
<GridPane GridPane.rowIndex="2">
|
||||||
|
<columnConstraints>
|
||||||
|
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
|
||||||
|
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
|
||||||
|
</columnConstraints>
|
||||||
|
<rowConstraints>
|
||||||
|
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
|
||||||
|
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
|
||||||
|
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
|
||||||
|
</rowConstraints>
|
||||||
|
<children>
|
||||||
|
<Text strokeType="OUTSIDE" strokeWidth="0.0" text="Max Speed:" GridPane.halignment="CENTER" GridPane.valignment="CENTER" />
|
||||||
|
<Text strokeType="OUTSIDE" strokeWidth="0.0" text="Acceleration:" GridPane.halignment="CENTER" GridPane.rowIndex="1" GridPane.valignment="CENTER" />
|
||||||
|
<Text strokeType="OUTSIDE" strokeWidth="0.0" text="Handling:" GridPane.halignment="CENTER" GridPane.rowIndex="2" GridPane.valignment="CENTER" />
|
||||||
|
<ProgressBar fx:id="speedBar" focusTraversable="false" prefWidth="200.0" progress="0.0" GridPane.columnIndex="1" />
|
||||||
|
<ProgressBar fx:id="accelBar" prefWidth="200.0" progress="0.0" GridPane.columnIndex="1" GridPane.rowIndex="1" />
|
||||||
|
<ProgressBar fx:id="handleBar" prefWidth="200.0" progress="0.0" GridPane.columnIndex="1" GridPane.rowIndex="2" />
|
||||||
|
</children>
|
||||||
|
</GridPane>
|
||||||
</children>
|
</children>
|
||||||
</GridPane>
|
</GridPane>
|
||||||
</children>
|
</children>
|
||||||
<stylesheets>
|
<stylesheets>
|
||||||
<String fx:value="/css/dialogs/BoatCustomize.css"/>
|
<String fx:value="/css/dialogs/BoatCustomize.css" />
|
||||||
<String fx:value="/css/Master.css"/>
|
<String fx:value="/css/Master.css" />
|
||||||
</stylesheets>
|
</stylesheets>
|
||||||
</JFXDialogLayout>
|
</JFXDialogLayout>
|
||||||
|
|||||||
@@ -0,0 +1,231 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
|
<?import com.jfoenix.controls.JFXButton?>
|
||||||
|
<?import com.jfoenix.controls.JFXDialogLayout?>
|
||||||
|
<?import com.jfoenix.controls.JFXToggleButton?>
|
||||||
|
<?import java.net.URL?>
|
||||||
|
<?import javafx.geometry.Insets?>
|
||||||
|
<?import javafx.scene.control.Label?>
|
||||||
|
<?import javafx.scene.control.ScrollPane?>
|
||||||
|
<?import javafx.scene.layout.ColumnConstraints?>
|
||||||
|
<?import javafx.scene.layout.GridPane?>
|
||||||
|
<?import javafx.scene.layout.RowConstraints?>
|
||||||
|
<?import javafx.scene.layout.StackPane?>
|
||||||
|
<JFXDialogLayout fx:id="keyBindDialog" maxHeight="-Infinity" maxWidth="-Infinity"
|
||||||
|
minHeight="-Infinity" minWidth="-Infinity" prefHeight="580.0" prefWidth="500.0"
|
||||||
|
xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1"
|
||||||
|
fx:controller="seng302.visualiser.controllers.dialogs.KeyBindingDialogController">
|
||||||
|
<stylesheets>
|
||||||
|
<URL value="@../../css/dialogs/KeyBindingDialog.css"/>
|
||||||
|
<URL value="@../../css/Master.css"/>
|
||||||
|
</stylesheets>
|
||||||
|
<children>
|
||||||
|
<GridPane>
|
||||||
|
<columnConstraints>
|
||||||
|
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0"/>
|
||||||
|
</columnConstraints>
|
||||||
|
<rowConstraints>
|
||||||
|
<RowConstraints maxHeight="-Infinity" minHeight="-Infinity" prefHeight="60.0"
|
||||||
|
vgrow="SOMETIMES"/>
|
||||||
|
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES"/>
|
||||||
|
<RowConstraints maxHeight="-Infinity" minHeight="-Infinity" prefHeight="60.0"
|
||||||
|
vgrow="SOMETIMES"/>
|
||||||
|
</rowConstraints>
|
||||||
|
<children>
|
||||||
|
<ScrollPane prefHeight="200.0" prefWidth="200.0" GridPane.rowIndex="1">
|
||||||
|
<content>
|
||||||
|
<StackPane prefHeight="150.0" prefWidth="200.0">
|
||||||
|
<children>
|
||||||
|
<GridPane>
|
||||||
|
<children>
|
||||||
|
<JFXButton fx:id="viewButton" buttonType="RAISED"
|
||||||
|
minHeight="35.0" prefWidth="120.0" text="F1"
|
||||||
|
GridPane.columnIndex="1" GridPane.halignment="CENTER"
|
||||||
|
GridPane.rowIndex="14" GridPane.valignment="CENTER"/>
|
||||||
|
<Label text="VIEW ASPECT" GridPane.halignment="CENTER"
|
||||||
|
GridPane.rowIndex="14" GridPane.valignment="CENTER"/>
|
||||||
|
<JFXButton fx:id="rightButton" buttonType="RAISED"
|
||||||
|
minHeight="35.0" prefWidth="120.0" text="D"
|
||||||
|
GridPane.columnIndex="1" GridPane.halignment="CENTER"
|
||||||
|
GridPane.rowIndex="13" GridPane.valignment="CENTER"/>
|
||||||
|
<Label text="RIGHT" GridPane.halignment="CENTER"
|
||||||
|
GridPane.rowIndex="13" GridPane.valignment="CENTER"/>
|
||||||
|
<JFXButton fx:id="leftButton" buttonType="RAISED"
|
||||||
|
minHeight="35.0" prefWidth="120.0" text="A"
|
||||||
|
GridPane.columnIndex="1" GridPane.halignment="CENTER"
|
||||||
|
GridPane.rowIndex="12" GridPane.valignment="CENTER"/>
|
||||||
|
<Label text="LEFT" GridPane.halignment="CENTER"
|
||||||
|
GridPane.rowIndex="12" GridPane.valignment="CENTER"/>
|
||||||
|
<JFXButton fx:id="forwardButton" buttonType="RAISED"
|
||||||
|
minHeight="35.0" prefWidth="120.0" text="W"
|
||||||
|
GridPane.columnIndex="1" GridPane.halignment="CENTER"
|
||||||
|
GridPane.rowIndex="10" GridPane.valignment="CENTER"/>
|
||||||
|
<Label text="FORWARD" GridPane.halignment="CENTER"
|
||||||
|
GridPane.rowIndex="10" GridPane.valignment="CENTER"/>
|
||||||
|
<JFXButton fx:id="backwardButton" buttonType="RAISED"
|
||||||
|
minHeight="35.0" prefWidth="120.0" text="S"
|
||||||
|
GridPane.columnIndex="1" GridPane.halignment="CENTER"
|
||||||
|
GridPane.rowIndex="11" GridPane.valignment="CENTER"/>
|
||||||
|
<Label text="BACKWARD" GridPane.halignment="CENTER"
|
||||||
|
GridPane.rowIndex="11" GridPane.valignment="CENTER"/>
|
||||||
|
<Label text="ZOOM IN" GridPane.halignment="CENTER"
|
||||||
|
GridPane.rowIndex="1" GridPane.valignment="CENTER">
|
||||||
|
<GridPane.margin>
|
||||||
|
<Insets/>
|
||||||
|
</GridPane.margin>
|
||||||
|
</Label>
|
||||||
|
<Label text="ZOOM OUT" GridPane.halignment="CENTER"
|
||||||
|
GridPane.rowIndex="2" GridPane.valignment="CENTER">
|
||||||
|
<GridPane.margin>
|
||||||
|
<Insets/>
|
||||||
|
</GridPane.margin>
|
||||||
|
</Label>
|
||||||
|
<Label text="VMG" GridPane.halignment="CENTER"
|
||||||
|
GridPane.rowIndex="3" GridPane.valignment="CENTER">
|
||||||
|
<GridPane.margin>
|
||||||
|
<Insets/>
|
||||||
|
</GridPane.margin>
|
||||||
|
</Label>
|
||||||
|
<Label text="SAILS IN/OUT" GridPane.halignment="CENTER"
|
||||||
|
GridPane.rowIndex="4" GridPane.valignment="CENTER">
|
||||||
|
<GridPane.margin>
|
||||||
|
<Insets/>
|
||||||
|
</GridPane.margin>
|
||||||
|
</Label>
|
||||||
|
<Label text="TACK/GYBE" GridPane.halignment="CENTER"
|
||||||
|
GridPane.rowIndex="5" GridPane.valignment="CENTER">
|
||||||
|
<GridPane.margin>
|
||||||
|
<Insets/>
|
||||||
|
</GridPane.margin>
|
||||||
|
</Label>
|
||||||
|
<Label fx:id="upwindLabel" text="UPWIND"
|
||||||
|
GridPane.halignment="CENTER" GridPane.rowIndex="6"
|
||||||
|
GridPane.valignment="CENTER">
|
||||||
|
<GridPane.margin>
|
||||||
|
<Insets/>
|
||||||
|
</GridPane.margin>
|
||||||
|
</Label>
|
||||||
|
<Label fx:id="downwindLabel" text="DOWNWIND"
|
||||||
|
GridPane.halignment="CENTER" GridPane.rowIndex="7"
|
||||||
|
GridPane.valignment="CENTER">
|
||||||
|
<GridPane.margin>
|
||||||
|
<Insets/>
|
||||||
|
</GridPane.margin>
|
||||||
|
</Label>
|
||||||
|
<JFXButton id="ZOOM IN" fx:id="zoomInbtn" buttonType="RAISED"
|
||||||
|
maxHeight="-Infinity" maxWidth="-Infinity" minHeight="35.0"
|
||||||
|
minWidth="-Infinity" prefWidth="120.0" text="Z"
|
||||||
|
GridPane.columnIndex="1" GridPane.halignment="CENTER"
|
||||||
|
GridPane.rowIndex="1" GridPane.valignment="CENTER"/>
|
||||||
|
<JFXButton id="ZOOM OUT" fx:id="zoomOutBtn" buttonType="RAISED"
|
||||||
|
maxHeight="-Infinity" maxWidth="-Infinity" minHeight="35.0"
|
||||||
|
minWidth="-Infinity" prefWidth="120.0" text="X"
|
||||||
|
GridPane.columnIndex="1" GridPane.halignment="CENTER"
|
||||||
|
GridPane.rowIndex="2" GridPane.valignment="CENTER"/>
|
||||||
|
<JFXButton id="VMG" fx:id="vmgBtn" buttonType="RAISED"
|
||||||
|
maxHeight="-Infinity" maxWidth="-Infinity" minHeight="35.0"
|
||||||
|
minWidth="-Infinity" prefWidth="120.0" text="SPACE"
|
||||||
|
GridPane.columnIndex="1" GridPane.halignment="CENTER"
|
||||||
|
GridPane.rowIndex="3" GridPane.valignment="CENTER"/>
|
||||||
|
<JFXButton id="SAILS IN/OUT" fx:id="sailInOutBtn"
|
||||||
|
buttonType="RAISED" maxHeight="-Infinity"
|
||||||
|
maxWidth="-Infinity" minHeight="35.0" minWidth="-Infinity"
|
||||||
|
prefWidth="120.0" text="SHIFT" GridPane.columnIndex="1"
|
||||||
|
GridPane.halignment="CENTER" GridPane.rowIndex="4"
|
||||||
|
GridPane.valignment="CENTER"/>
|
||||||
|
<JFXButton id="TACK/GYBE" fx:id="tackGybeBtn"
|
||||||
|
buttonType="RAISED" maxHeight="-Infinity"
|
||||||
|
maxWidth="-Infinity" minHeight="35.0" minWidth="-Infinity"
|
||||||
|
prefWidth="120.0" text="ENTER" GridPane.columnIndex="1"
|
||||||
|
GridPane.halignment="CENTER" GridPane.rowIndex="5"
|
||||||
|
GridPane.valignment="CENTER"/>
|
||||||
|
<JFXButton id="UPWIND" fx:id="upwindBtn" buttonType="RAISED"
|
||||||
|
maxHeight="-Infinity" maxWidth="-Infinity" minHeight="35.0"
|
||||||
|
minWidth="-Infinity" prefWidth="120.0" text="PAGE_UP"
|
||||||
|
GridPane.columnIndex="1" GridPane.halignment="CENTER"
|
||||||
|
GridPane.rowIndex="6" GridPane.valignment="CENTER"/>
|
||||||
|
<JFXButton id="DOWNWIND" fx:id="downwindBtn"
|
||||||
|
buttonType="RAISED" maxHeight="-Infinity"
|
||||||
|
maxWidth="-Infinity" minHeight="35.0" minWidth="-Infinity"
|
||||||
|
prefWidth="120.0" text="PAGE_DOWN" GridPane.columnIndex="1"
|
||||||
|
GridPane.halignment="CENTER" GridPane.rowIndex="7"
|
||||||
|
GridPane.valignment="CENTER"/>
|
||||||
|
<JFXToggleButton fx:id="turningToggle" minHeight="-Infinity"
|
||||||
|
prefHeight="35.0" text="OFF / ON" GridPane.columnIndex="1"
|
||||||
|
GridPane.halignment="CENTER" GridPane.rowIndex="8"/>
|
||||||
|
<Label text="CONTINUOUSLY TURNING" GridPane.halignment="CENTER"
|
||||||
|
GridPane.rowIndex="8" GridPane.valignment="CENTER">
|
||||||
|
<GridPane.margin>
|
||||||
|
<Insets/>
|
||||||
|
</GridPane.margin>
|
||||||
|
</Label>
|
||||||
|
<Label styleClass="sectionLabel" text="BOAT ACTIONS"
|
||||||
|
GridPane.columnSpan="2" GridPane.halignment="CENTER"
|
||||||
|
GridPane.valignment="CENTER">
|
||||||
|
<GridPane.margin>
|
||||||
|
<Insets left="50.0"/>
|
||||||
|
</GridPane.margin>
|
||||||
|
</Label>
|
||||||
|
<Label styleClass="sectionLabel" text="CAMERA SETTINGS"
|
||||||
|
GridPane.columnSpan="2" GridPane.halignment="CENTER"
|
||||||
|
GridPane.rowIndex="9" GridPane.valignment="CENTER">
|
||||||
|
<GridPane.margin>
|
||||||
|
<Insets left="50.0"/>
|
||||||
|
</GridPane.margin>
|
||||||
|
</Label>
|
||||||
|
</children>
|
||||||
|
<columnConstraints>
|
||||||
|
<ColumnConstraints hgrow="SOMETIMES" maxWidth="-Infinity"
|
||||||
|
minWidth="-Infinity" prefWidth="250.0"/>
|
||||||
|
<ColumnConstraints hgrow="SOMETIMES" maxWidth="-Infinity"
|
||||||
|
minWidth="-Infinity" prefWidth="150.0"/>
|
||||||
|
</columnConstraints>
|
||||||
|
<rowConstraints>
|
||||||
|
<RowConstraints maxHeight="50.0" minHeight="50.0"
|
||||||
|
prefHeight="50.0" vgrow="SOMETIMES"/>
|
||||||
|
<RowConstraints maxHeight="50.0" minHeight="50.0"
|
||||||
|
prefHeight="50.0" vgrow="SOMETIMES"/>
|
||||||
|
<RowConstraints maxHeight="50.0" minHeight="50.0"
|
||||||
|
prefHeight="50.0" vgrow="SOMETIMES"/>
|
||||||
|
<RowConstraints maxHeight="50.0" minHeight="50.0"
|
||||||
|
prefHeight="50.0" vgrow="SOMETIMES"/>
|
||||||
|
<RowConstraints maxHeight="50.0" minHeight="50.0"
|
||||||
|
prefHeight="50.0" vgrow="SOMETIMES"/>
|
||||||
|
<RowConstraints maxHeight="50.0" minHeight="50.0"
|
||||||
|
prefHeight="50.0" vgrow="SOMETIMES"/>
|
||||||
|
<RowConstraints maxHeight="50.0" minHeight="50.0"
|
||||||
|
prefHeight="50.0" vgrow="SOMETIMES"/>
|
||||||
|
<RowConstraints maxHeight="50.0" minHeight="50.0"
|
||||||
|
prefHeight="50.0" vgrow="SOMETIMES"/>
|
||||||
|
<RowConstraints maxHeight="50.0" minHeight="50.0"
|
||||||
|
prefHeight="50.0" vgrow="SOMETIMES"/>
|
||||||
|
<RowConstraints maxHeight="50.0" minHeight="50.0"
|
||||||
|
prefHeight="50.0" vgrow="SOMETIMES"/>
|
||||||
|
<RowConstraints maxHeight="50.0" minHeight="50.0"
|
||||||
|
prefHeight="50.0" vgrow="SOMETIMES"/>
|
||||||
|
<RowConstraints maxHeight="50.0" minHeight="50.0"
|
||||||
|
prefHeight="50.0" vgrow="SOMETIMES"/>
|
||||||
|
<RowConstraints maxHeight="50.0" minHeight="50.0"
|
||||||
|
prefHeight="50.0" vgrow="SOMETIMES"/>
|
||||||
|
<RowConstraints maxHeight="50.0" minHeight="50.0"
|
||||||
|
prefHeight="50.0" vgrow="SOMETIMES"/>
|
||||||
|
<RowConstraints maxHeight="50.0" minHeight="50.0"
|
||||||
|
prefHeight="50.0" vgrow="SOMETIMES"/>
|
||||||
|
</rowConstraints>
|
||||||
|
</GridPane>
|
||||||
|
</children>
|
||||||
|
</StackPane>
|
||||||
|
</content>
|
||||||
|
</ScrollPane>
|
||||||
|
<Label fx:id="keyBindingDialogHeader" text="CUSTOM KEYBINDING" GridPane.columnSpan="2"
|
||||||
|
GridPane.halignment="CENTER" GridPane.valignment="CENTER"/>
|
||||||
|
<Label fx:id="closeLabel" text="✖" GridPane.halignment="RIGHT"
|
||||||
|
GridPane.valignment="TOP"/>
|
||||||
|
<JFXButton fx:id="resetBtn" buttonType="RAISED" maxHeight="-Infinity"
|
||||||
|
maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="45.0"
|
||||||
|
prefWidth="150.0" text="RESET" GridPane.columnSpan="2" GridPane.halignment="CENTER"
|
||||||
|
GridPane.rowIndex="2" GridPane.valignment="CENTER"/>
|
||||||
|
</children>
|
||||||
|
</GridPane>
|
||||||
|
</children>
|
||||||
|
</JFXDialogLayout>
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
|
|
||||||
|
<?import com.jfoenix.controls.JFXButton?>
|
||||||
|
<?import com.jfoenix.controls.JFXDialogLayout?>
|
||||||
|
<?import java.net.URL?>
|
||||||
|
<?import javafx.geometry.Insets?>
|
||||||
|
<?import javafx.scene.control.Label?>
|
||||||
|
<?import javafx.scene.layout.ColumnConstraints?>
|
||||||
|
<?import javafx.scene.layout.GridPane?>
|
||||||
|
<?import javafx.scene.layout.RowConstraints?>
|
||||||
|
<JFXDialogLayout maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity"
|
||||||
|
minWidth="-Infinity" prefWidth="550.0" xmlns="http://javafx.com/javafx/8"
|
||||||
|
xmlns:fx="http://javafx.com/fxml/1"
|
||||||
|
fx:controller="seng302.visualiser.controllers.dialogs.PopupDialogController">
|
||||||
|
<children>
|
||||||
|
<GridPane>
|
||||||
|
<columnConstraints>
|
||||||
|
<ColumnConstraints hgrow="SOMETIMES" maxWidth="1.7976931348623157E308"/>
|
||||||
|
</columnConstraints>
|
||||||
|
<rowConstraints>
|
||||||
|
<RowConstraints maxHeight="-Infinity" minHeight="30.0" prefHeight="30.0"
|
||||||
|
vgrow="SOMETIMES"/>
|
||||||
|
<RowConstraints maxHeight="1.7976931348623157E308" minHeight="80.0"
|
||||||
|
prefHeight="80.0" vgrow="SOMETIMES"/>
|
||||||
|
<RowConstraints minHeight="50.0" prefHeight="50.0" vgrow="SOMETIMES"/>
|
||||||
|
</rowConstraints>
|
||||||
|
<children>
|
||||||
|
<JFXButton fx:id="optionButton" buttonType="RAISED" prefHeight="55.0"
|
||||||
|
prefWidth="150.0" GridPane.halignment="RIGHT" GridPane.rowIndex="2"
|
||||||
|
GridPane.valignment="CENTER">
|
||||||
|
<GridPane.margin>
|
||||||
|
<Insets/>
|
||||||
|
</GridPane.margin>
|
||||||
|
</JFXButton>
|
||||||
|
<Label fx:id="contentLabel" text="Popup content goes here ..."
|
||||||
|
GridPane.rowIndex="1"/>
|
||||||
|
<Label fx:id="headerLabel" text="Popup header"/>
|
||||||
|
<Label fx:id="closeLabel" text="✖" translateY="-10.0" GridPane.halignment="RIGHT"/>
|
||||||
|
</children>
|
||||||
|
</GridPane>
|
||||||
|
</children>
|
||||||
|
<stylesheets>
|
||||||
|
<URL value="@../../css/dialogs/Popup.css"/>
|
||||||
|
<URL value="@../../css/Master.css"/>
|
||||||
|
</stylesheets>
|
||||||
|
</JFXDialogLayout>
|
||||||
@@ -1,69 +1,178 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
<?import com.jfoenix.controls.JFXButton?>
|
<?import com.jfoenix.controls.JFXButton?>
|
||||||
|
<?import com.jfoenix.controls.JFXCheckBox?>
|
||||||
<?import com.jfoenix.controls.JFXDialogLayout?>
|
<?import com.jfoenix.controls.JFXDialogLayout?>
|
||||||
<?import com.jfoenix.controls.JFXSlider?>
|
<?import com.jfoenix.controls.JFXSlider?>
|
||||||
<?import com.jfoenix.controls.JFXTextField?>
|
<?import com.jfoenix.controls.JFXTextField?>
|
||||||
<?import java.lang.String?>
|
|
||||||
<?import javafx.geometry.Insets?>
|
<?import javafx.geometry.Insets?>
|
||||||
<?import javafx.scene.control.Label?>
|
<?import javafx.scene.control.Label?>
|
||||||
|
<?import javafx.scene.layout.AnchorPane?>
|
||||||
<?import javafx.scene.layout.ColumnConstraints?>
|
<?import javafx.scene.layout.ColumnConstraints?>
|
||||||
<?import javafx.scene.layout.GridPane?>
|
<?import javafx.scene.layout.GridPane?>
|
||||||
<?import javafx.scene.layout.RowConstraints?>
|
<?import javafx.scene.layout.RowConstraints?>
|
||||||
<?import javafx.scene.layout.VBox?>
|
<?import javafx.scene.layout.VBox?>
|
||||||
<JFXDialogLayout maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefWidth="550.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="seng302.visualiser.controllers.dialogs.ServerCreationController">
|
<?import javafx.scene.text.Font?>
|
||||||
<children>
|
|
||||||
<GridPane>
|
<JFXDialogLayout maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="600.0" prefWidth="1000.0" xmlns="http://javafx.com/javafx/8.0.112" xmlns:fx="http://javafx.com/fxml/1" fx:controller="seng302.visualiser.controllers.dialogs.ServerCreationController">
|
||||||
<columnConstraints>
|
<children>
|
||||||
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
|
<GridPane>
|
||||||
</columnConstraints>
|
<children>
|
||||||
<rowConstraints>
|
<JFXButton fx:id="submitBtn" onMouseEntered="#playButtonHoverSound" prefHeight="55.0" prefWidth="250.0" text="SUBMIT" GridPane.halignment="CENTER" GridPane.rowIndex="2" GridPane.valignment="CENTER">
|
||||||
<RowConstraints maxHeight="90.0" minHeight="90.0" prefHeight="90.0" vgrow="SOMETIMES" />
|
<font>
|
||||||
<RowConstraints maxHeight="100.0" minHeight="100.0" prefHeight="100.0" vgrow="SOMETIMES" />
|
<Font name="System Bold" size="13.0" />
|
||||||
<RowConstraints maxHeight="100.0" minHeight="100.0" prefHeight="100.0" vgrow="SOMETIMES" />
|
</font></JFXButton>
|
||||||
<RowConstraints maxHeight="100.0" minHeight="100.0" prefHeight="100.0" vgrow="SOMETIMES" />
|
<GridPane GridPane.rowIndex="1">
|
||||||
</rowConstraints>
|
|
||||||
<children>
|
|
||||||
<Label fx:id="hostDialogHeader" text="HOST A GAME SERVER" GridPane.halignment="CENTER" GridPane.valignment="CENTER" />
|
|
||||||
<JFXButton fx:id="submitBtn" onMouseEntered="#playButtonHoverSound" prefHeight="55.0" prefWidth="250.0" text="SUBMIT" GridPane.halignment="CENTER" GridPane.rowIndex="3" GridPane.valignment="CENTER" />
|
|
||||||
<JFXTextField fx:id="serverName" promptText="SERVER NAME" GridPane.rowIndex="1">
|
|
||||||
<GridPane.margin>
|
|
||||||
<Insets left="30.0" right="30.0" />
|
|
||||||
</GridPane.margin></JFXTextField>
|
|
||||||
<GridPane fx:id="maxPlayersGridPane" GridPane.rowIndex="2">
|
|
||||||
<columnConstraints>
|
<columnConstraints>
|
||||||
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" percentWidth="30.0" prefWidth="100.0" />
|
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
|
||||||
<ColumnConstraints hgrow="SOMETIMES" minWidth="100.0" prefWidth="100.0" />
|
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
|
||||||
</columnConstraints>
|
</columnConstraints>
|
||||||
<rowConstraints>
|
<rowConstraints>
|
||||||
<RowConstraints minHeight="10.0" percentHeight="60.0" prefHeight="10.0" vgrow="SOMETIMES" />
|
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
|
||||||
<RowConstraints minHeight="10.0" percentHeight="40.0" prefHeight="30.0" vgrow="SOMETIMES" />
|
|
||||||
</rowConstraints>
|
</rowConstraints>
|
||||||
<children>
|
<children>
|
||||||
<Label fx:id="maxPlayersLabel" text="20" GridPane.columnIndex="1" GridPane.halignment="CENTER" GridPane.rowIndex="1" GridPane.valignment="TOP">
|
<GridPane>
|
||||||
<GridPane.margin>
|
<columnConstraints>
|
||||||
<Insets right="30.0" />
|
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
|
||||||
</GridPane.margin></Label>
|
</columnConstraints>
|
||||||
<Label fx:id="maxPlayerPromptLabel" text="MAX PLAYERS" GridPane.halignment="LEFT" GridPane.valignment="BOTTOM">
|
<rowConstraints>
|
||||||
<GridPane.margin>
|
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
|
||||||
<Insets left="30.0" top="20.0" />
|
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
|
||||||
</GridPane.margin>
|
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
|
||||||
</Label>
|
</rowConstraints>
|
||||||
<VBox alignment="BOTTOM_CENTER" prefHeight="200.0" prefWidth="100.0" GridPane.columnIndex="1" GridPane.halignment="CENTER" GridPane.valignment="CENTER">
|
<children>
|
||||||
<children>
|
<JFXTextField fx:id="serverName" promptText="SERVER NAME">
|
||||||
<JFXSlider fx:id="maxPlayersSlider" blockIncrement="1.0" majorTickUnit="2.0" max="20.0" min="1.0" minorTickCount="1" snapToTicks="true" styleClass="maxPlayers" value="11.0" />
|
<padding>
|
||||||
</children>
|
<Insets left="15.0" right="15.0" />
|
||||||
<GridPane.margin>
|
</padding>
|
||||||
<Insets bottom="10.0" right="30.0" />
|
<GridPane.margin>
|
||||||
</GridPane.margin>
|
<Insets left="35.0" right="35.0" />
|
||||||
</VBox>
|
</GridPane.margin>
|
||||||
|
</JFXTextField>
|
||||||
|
<GridPane fx:id="maxPlayersGridPane" GridPane.rowIndex="1">
|
||||||
|
<children>
|
||||||
|
<Label fx:id="maxPlayersLabel" text="20" GridPane.columnIndex="1" GridPane.halignment="CENTER" GridPane.rowIndex="1" GridPane.valignment="TOP">
|
||||||
|
<GridPane.margin>
|
||||||
|
<Insets right="30.0" />
|
||||||
|
</GridPane.margin>
|
||||||
|
</Label>
|
||||||
|
<Label fx:id="maxPlayerPromptLabel" text="MAX PLAYERS" GridPane.halignment="LEFT" GridPane.valignment="BOTTOM">
|
||||||
|
<GridPane.margin>
|
||||||
|
<Insets left="30.0" top="20.0" />
|
||||||
|
</GridPane.margin>
|
||||||
|
</Label>
|
||||||
|
<VBox alignment="BOTTOM_CENTER" prefHeight="200.0" prefWidth="100.0" GridPane.columnIndex="1" GridPane.halignment="CENTER" GridPane.valignment="CENTER">
|
||||||
|
<children>
|
||||||
|
<JFXSlider fx:id="maxPlayersSlider" blockIncrement="1.0" majorTickUnit="2.0" max="20.0" min="1.0" minorTickCount="1" snapToTicks="true" styleClass="maxPlayers" value="11.0" />
|
||||||
|
</children>
|
||||||
|
<GridPane.margin>
|
||||||
|
<Insets bottom="10.0" right="30.0" />
|
||||||
|
</GridPane.margin>
|
||||||
|
</VBox>
|
||||||
|
</children>
|
||||||
|
<columnConstraints>
|
||||||
|
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" percentWidth="30.0" prefWidth="100.0" />
|
||||||
|
<ColumnConstraints hgrow="SOMETIMES" minWidth="100.0" prefWidth="100.0" />
|
||||||
|
</columnConstraints>
|
||||||
|
<rowConstraints>
|
||||||
|
<RowConstraints minHeight="10.0" percentHeight="60.0" prefHeight="10.0" vgrow="SOMETIMES" />
|
||||||
|
<RowConstraints minHeight="10.0" percentHeight="40.0" prefHeight="30.0" vgrow="SOMETIMES" />
|
||||||
|
</rowConstraints>
|
||||||
|
</GridPane>
|
||||||
|
<GridPane fx:id="maxPlayersGridPane1" GridPane.rowIndex="2">
|
||||||
|
<children>
|
||||||
|
<Label fx:id="legsSliderLabel" text="20" GridPane.columnIndex="1" GridPane.halignment="CENTER" GridPane.rowIndex="1" GridPane.valignment="TOP">
|
||||||
|
<GridPane.margin>
|
||||||
|
<Insets right="30.0" />
|
||||||
|
</GridPane.margin>
|
||||||
|
</Label>
|
||||||
|
<VBox alignment="BOTTOM_CENTER" prefHeight="200.0" prefWidth="100.0" GridPane.columnIndex="1" GridPane.halignment="CENTER" GridPane.valignment="CENTER">
|
||||||
|
<children>
|
||||||
|
<JFXSlider fx:id="legsSlider" blockIncrement="1.0" majorTickUnit="2.0" max="20.0" min="1.0" minorTickCount="1" snapToTicks="true" styleClass="maxPlayers" value="11.0" />
|
||||||
|
</children>
|
||||||
|
<GridPane.margin>
|
||||||
|
<Insets bottom="10.0" right="30.0" />
|
||||||
|
</GridPane.margin>
|
||||||
|
</VBox>
|
||||||
|
<GridPane>
|
||||||
|
<children>
|
||||||
|
<Label alignment="CENTER" text="NUMBER OF" GridPane.halignment="CENTER" />
|
||||||
|
<Label alignment="CENTER" text="REPEATING LEGS" GridPane.halignment="CENTER" GridPane.rowIndex="1" />
|
||||||
|
</children>
|
||||||
|
<columnConstraints>
|
||||||
|
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
|
||||||
|
</columnConstraints>
|
||||||
|
<rowConstraints>
|
||||||
|
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
|
||||||
|
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
|
||||||
|
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
|
||||||
|
</rowConstraints>
|
||||||
|
</GridPane>
|
||||||
|
<JFXCheckBox fx:id="pickupsCheckBox" text="Enable Pickups" GridPane.rowIndex="1">
|
||||||
|
<GridPane.margin>
|
||||||
|
<Insets left="5.0" />
|
||||||
|
</GridPane.margin>
|
||||||
|
</JFXCheckBox>
|
||||||
|
</children>
|
||||||
|
<columnConstraints>
|
||||||
|
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" percentWidth="30.0" prefWidth="100.0" />
|
||||||
|
<ColumnConstraints hgrow="SOMETIMES" minWidth="100.0" prefWidth="100.0" />
|
||||||
|
</columnConstraints>
|
||||||
|
<rowConstraints>
|
||||||
|
<RowConstraints minHeight="10.0" percentHeight="60.0" prefHeight="10.0" vgrow="SOMETIMES" />
|
||||||
|
<RowConstraints minHeight="10.0" percentHeight="40.0" prefHeight="30.0" vgrow="SOMETIMES" />
|
||||||
|
</rowConstraints>
|
||||||
|
</GridPane>
|
||||||
|
</children>
|
||||||
|
</GridPane>
|
||||||
|
<GridPane GridPane.columnIndex="1">
|
||||||
|
<columnConstraints>
|
||||||
|
<ColumnConstraints hgrow="SOMETIMES" maxWidth="35.0" prefWidth="35.0" />
|
||||||
|
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
|
||||||
|
<ColumnConstraints hgrow="SOMETIMES" maxWidth="35.0" minWidth="35.0" prefWidth="35.0" />
|
||||||
|
</columnConstraints>
|
||||||
|
<rowConstraints>
|
||||||
|
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
|
||||||
|
</rowConstraints>
|
||||||
|
<children>
|
||||||
|
<JFXButton fx:id="lastMapButton" maxHeight="300.0" minHeight="300.0" prefHeight="300.0" prefWidth="35.0" style="-fx-border-color: lightgrey; -fx-border-radius: 5;" text="<" textFill="#5b5b5b" GridPane.halignment="CENTER" GridPane.valignment="CENTER">
|
||||||
|
<font>
|
||||||
|
<Font name="System Bold" size="13.0" />
|
||||||
|
</font></JFXButton>
|
||||||
|
<JFXButton fx:id="nextMapButton" maxHeight="300.0" minHeight="300.0" minWidth="35.0" prefHeight="300.0" style="-fx-border-color: lightgrey; -fx-border-radius: 5;" text=">" textFill="#5b5b5b" GridPane.columnIndex="2" GridPane.valignment="CENTER">
|
||||||
|
<font>
|
||||||
|
<Font name="System Bold" size="13.0" />
|
||||||
|
</font></JFXButton>
|
||||||
|
<GridPane style="-fx-background-color: lightblue; -fx-border-color: grey; -fx-border-radius: 5; -fx-background-radius: 5;" GridPane.columnIndex="1">
|
||||||
|
<columnConstraints>
|
||||||
|
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
|
||||||
|
</columnConstraints>
|
||||||
|
<rowConstraints>
|
||||||
|
<RowConstraints maxHeight="25.0" minHeight="25.0" prefHeight="25.0" vgrow="SOMETIMES" />
|
||||||
|
<RowConstraints maxHeight="342.0" minHeight="10.0" prefHeight="336.0" vgrow="SOMETIMES" />
|
||||||
|
</rowConstraints>
|
||||||
|
<children>
|
||||||
|
<Label fx:id="mapNameLabel" text="MAP NAME" GridPane.halignment="CENTER" />
|
||||||
|
<AnchorPane fx:id="mapHolder" prefHeight="333.0" prefWidth="404.0" GridPane.rowIndex="1" />
|
||||||
|
</children>
|
||||||
|
</GridPane>
|
||||||
|
</children>
|
||||||
|
</GridPane>
|
||||||
</children>
|
</children>
|
||||||
</GridPane>
|
</GridPane>
|
||||||
</children>
|
<Label fx:id="hostDialogHeader" text="HOST A GAME SERVER" GridPane.halignment="CENTER">
|
||||||
</GridPane>
|
<font>
|
||||||
</children>
|
<Font size="20.0" />
|
||||||
<stylesheets>
|
</font></Label>
|
||||||
<String fx:value="/css/dialogs/ServerCreation.css" />
|
</children>
|
||||||
<String fx:value="/css/Master.css"/>
|
<columnConstraints>
|
||||||
</stylesheets>
|
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
|
||||||
|
</columnConstraints>
|
||||||
|
<rowConstraints>
|
||||||
|
<RowConstraints maxHeight="100.0" minHeight="100.0" prefHeight="100.0" vgrow="SOMETIMES" />
|
||||||
|
<RowConstraints maxHeight="511.0" minHeight="90.0" prefHeight="370.0" vgrow="SOMETIMES" />
|
||||||
|
<RowConstraints maxHeight="102.0" minHeight="100.0" prefHeight="100.0" vgrow="SOMETIMES" />
|
||||||
|
</rowConstraints>
|
||||||
|
</GridPane>
|
||||||
|
</children>
|
||||||
</JFXDialogLayout>
|
</JFXDialogLayout>
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
Feature: Multiple Maps
|
||||||
|
|
||||||
|
Scenario:
|
||||||
|
Given that the game has multiple race xml files
|
||||||
|
Then all of them can be seen
|
||||||
|
|
||||||
|
Scenario:
|
||||||
|
Given that I choose a race
|
||||||
|
Then that race's course is received by clients
|
||||||
|
|
||||||
|
Scenario:
|
||||||
|
Given that I choose a name for the server
|
||||||
|
Then that name is sent to the client
|
||||||
|
|
||||||
|
Scenario:
|
||||||
|
Given that the client has received a race
|
||||||
|
Then the name of that race shown to the host is the course name
|
||||||