Compare commits

..

49 Commits

Author SHA1 Message Date
William Muir 22fdf1e4ac Changed the boatType attribute from all around the place from String lit to enum
#story[1274]
2017-09-22 21:00:28 +12:00
William Muir da8c91f5c1 Review fixes for merge request.
PlayerCell now takes in the yacht for construction rather than taking in a whole lot of values extracted from the yacht

Reduced boiler plate in BoatCustomizeController

#story[1274]
2017-09-22 20:44:06 +12:00
Kusal Ekanayake c4a6113f6c Minor bug fixes (like all enemy sails being toggled in when they should be out)
#story[1274]
2017-09-20 21:07:49 +12:00
Kusal Ekanayake 307e79ecfc Completed working boat selection screen.
When a user selects a different boat, it is sent to all other clients and updates accordingly. Boats are all shown with their correct models in game.

#story[1274]
2017-09-20 20:46:23 +12:00
Kusal Ekanayake 7d8a6afa5f Merge branch 'new_meshes' into Custom_boat_selection 2017-09-20 19:40:43 +12:00
Peter Galloway ea0be5e952 Added pirate ship meshes to application. Updated boat model to allow for jib sails and a fixed sail. #story[1274] 2017-09-20 17:56:07 +12:00
Peter Galloway 7197bc2bee created meshes for pirate ship #story[1274] 2017-09-20 17:33:32 +12:00
Calum fba522d0c3 Fixed BoatMeshType enum names.
#fix
2017-09-20 16:44:38 +12:00
Calum 0e829874c2 Fixed BoatMeshType enum names.
#fix
2017-09-20 16:43:04 +12:00
Calum c5d56065b6 Fixed cat ate a meringue sail rotation.
#fix #story[1274]
2017-09-20 16:42:26 +12:00
Kusal Ekanayake 410d765745 Started working on the boat selection screen.
Customised the boat customisation UI to contain it. Need to have another boat to test whether we can switch boats and also if the messages get sent correctly.

#story[1274]
2017-09-20 16:36:27 +12:00
Calum fe76e85c71 Merge branch 'develop' into new_meshes 2017-09-20 15:59:01 +12:00
Calum 9d61a43bd7 Added catamaran mesh to possible boat meshes. Made catamaran the default boat.
#implement #story[1274]
2017-09-20 15:58:22 +12:00
Kusal Ekanayake c39582de5c Updated PartyParrot logo 2017-09-20 15:41:20 +12:00
Peter Galloway 9ed52a1225 created catamaran mesh #story[1274] 2017-09-19 19:43:03 +12:00
Calum da263355f4 Changed raceview background.
#fix
2017-09-19 14:55:26 +12:00
Calum ebecd25ed2 Merge remote-tracking branch 'origin/develop' into develop 2017-09-19 14:54:15 +12:00
Calum 0f5137c2b6 Fixed the orientation of .stl files.
#fix
2017-09-19 14:52:02 +12:00
Kusal Ekanayake 73799954e4 Fixed tests that failed when running on lower end computers. Needed to add a couple of thread.sleeps 2017-09-15 12:47:40 +12:00
Haoming Yin edfeb2b287 Merge remote-tracking branch 'origin/NewUI_merge' into NewUI_merge 2017-09-14 15:40:26 +12:00
Haoming Yin 0355784000 Broadcast messages when boats pass legs or a token is picked up or expired.
tags: #story[1250] #pair[hyi25, zyt10]
2017-09-14 15:40:12 +12:00
Alistair McIntyre 02df69b7b4 - Merged Dev into branch
Tags: #story[1245]
2017-09-14 15:27:10 +12:00
Alistair McIntyre 242132b800 Merge remote-tracking branch 'origin/develop' into NewUI_merge
# Conflicts:
#	src/main/resources/views/RaceView.fxml
2017-09-14 15:26:57 +12:00
Alistair McIntyre 3a671d4ed0 - Added Values to Finish Dialog.
Tags: #story[1245]
2017-09-14 15:24:58 +12:00
Alistair McIntyre 482d987839 - Fixed Null Pointer
- Build Should pass

Tags: #story[1245]
2017-09-14 15:10:48 +12:00
Haoming Yin cc124b2d19 Merge remote-tracking branch 'origin/NewUI_merge' into NewUI_merge
# Conflicts:
#	src/main/java/seng302/gameServer/GameState.java
2017-09-14 14:50:49 +12:00
Haoming Yin b3320ad805 Fixed server message sender
tags: #story[1246]
2017-09-14 14:49:25 +12:00
Alistair McIntyre 33779ad5c1 Merge remote-tracking branch 'origin/NewUI_merge' into NewUI_merge
# Conflicts:
#	src/main/resources/views/RaceView.fxml
2017-09-14 14:42:57 +12:00
Alistair McIntyre 3a41c27d8d - Race Finish Dialog showing up, unsure if its actually showing the correct ordering or not.
tags : #story[1245]
2017-09-14 14:42:25 +12:00
Calum e24203904b Removed print statements.
#chore
2017-09-14 14:37:22 +12:00
Calum eb188495ce Fixed position issues on exit arrows.
#implement #story[1266] #fix
2017-09-14 14:32:45 +12:00
Calum 62a7e2b8fa Fixed position issues on entry arrows.
#implement #story[1266] #fix
2017-09-14 14:21:04 +12:00
Michael Rausch acd0e790fe Added method to send server debug messages to players
Tags: #story[1246]
2017-09-14 14:14:21 +12:00
Zhi You Tan 46013474c0 Merge remote-tracking branch 'origin/NewUI_merge' into NewUI_merge 2017-09-14 13:37:01 +12:00
Alistair McIntyre bf427f24d3 - Created a Race Finish Dialog.
tags : #story[1245]
2017-09-14 13:34:48 +12:00
Alistair McIntyre 7d0a47446d - Fixed bug in customize dialog.
tags : #story[1245]
2017-09-14 13:02:31 +12:00
Alistair McIntyre 889098bb50 - Commented out broken test (non-deterministic thing)
- Merged 3d factory branch in

tags : #story[1245]
2017-09-14 12:46:17 +12:00
Alistair McIntyre 6223a8fc0b Merge remote-tracking branch 'origin/story1266_3d_model_factory' into NewUI_merge
# Conflicts:
#	src/main/java/seng302/visualiser/GameView3D.java
2017-09-14 12:40:20 +12:00
Calum 391bd33548 Fixed position issues on first 2 mark arrows.
#implement #story[1266]
2017-09-14 12:38:36 +12:00
Alistair McIntyre 7e0c2abbfd - Fixed a shutdown bug that left the game process running long after the window shut
- Changed SVG Icon for volume toggle to something a bit nicer

tags : #story[1245]
2017-09-14 12:31:49 +12:00
Calum 42a5e86bf8 Merge remote-tracking branch 'origin/NewUI_merge' into story1266_3d_model_factory
# Conflicts:
#	src/main/java/seng302/visualiser/GameView3D.java
2017-09-14 12:06:19 +12:00
Calum 20d73d8f2f Removed dead code from fxObjects and GameView 3D
#chore
2017-09-14 12:05:20 +12:00
Calum 0a62c538ca Added 3D mark arrows and cleaned up other classes. 2017-09-14 11:28:50 +12:00
Zhi You Tan 24a04aa530 Fix the wind direction arrow rotation.
#story[1245]
2017-09-14 01:05:52 +12:00
Haoming Yin 7ee6a09626 Fixed that wind speed did not updated frequently and UI polishing.
- added shadow for raceview boxes
- split up message history and input text block
- changed timer font

#story[1245]
2017-09-13 21:11:40 +12:00
Calum d5ce61a0ff Merge branch 'NewUI_merge' into story1266_3d_model_factory
# Conflicts:
#	src/main/java/seng302/visualiser/controllers/RaceViewController.java
2017-09-12 17:09:47 +12:00
Peter Galloway 71f626f57e fixed sail rotation broken from port to 3d #story[1266] 2017-09-12 16:30:20 +12:00
Calum 8dc3e54186 Merge remote-tracking branch 'origin/story1266_3d_model_factory' into story1266_3d_model_factory 2017-09-12 14:11:11 +12:00
Calum 8fd35392b0 Added experimental assets for water.
#story[1266] #implement
2017-09-12 14:11:00 +12:00
73 changed files with 1672 additions and 1553 deletions
+29 -35
View File
@@ -1,35 +1,12 @@
package seng302.gameServer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import javafx.scene.paint.Color;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.xml.sax.InputSource;
import seng302.gameServer.messages.BoatAction;
import seng302.gameServer.messages.BoatStatus;
import seng302.gameServer.messages.ChatterMessage;
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.gameServer.messages.*;
import seng302.model.*;
import seng302.model.mark.CompoundMark;
import seng302.model.mark.Mark;
import seng302.model.mark.MarkOrder;
@@ -38,6 +15,11 @@ import seng302.model.token.TokenType;
import seng302.utilities.GeoUtility;
import seng302.utilities.XMLParser;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.util.*;
import seng302.visualiser.fxObjects.assets_3D.BoatMeshType;
/**
* A Static class to hold information about the current state of the game (model)
* Also contains logic for updating itself on regular time intervals on its own thread
@@ -342,6 +324,7 @@ public class GameState implements Runnable {
if (yacht.getPowerUp() != null) {
if (System.currentTimeMillis() - yacht.getPowerUpStartTime() > POWERUP_TIMEOUT_MS) {
yacht.powerDown();
sendServerMessage(yacht.getSourceId(), yacht.getBoatName() + "'s power-up token expired");
logger.debug("Yacht: " + yacht.getShortName() + " powered down!");
}
}
@@ -452,6 +435,7 @@ public class GameState implements Runnable {
//Token Collision
Token collidedToken = checkTokenPickUp(serverYacht);
if (collidedToken != null) {
sendServerMessage(serverYacht.getSourceId(), serverYacht.getBoatName() + " has picked speed-up token");
tokensInPlay.remove(collidedToken);
serverYacht.powerUp(collidedToken.getTokenType());
logger.debug("Yacht: " + serverYacht.getShortName() + " got powerup " + collidedToken
@@ -550,6 +534,9 @@ public class GameState implements Runnable {
}
if (hasProgressed) {
if (currentMarkSeqID != 0 && !markOrder.isLastMark(currentMarkSeqID)) {
sendServerMessage(yacht.getSourceId(), yacht.getBoatName() + " passed leg " + yacht.getLegNumber());
}
yacht.incrementLegNumber();
sendMarkRoundingMessage(yacht);
logMarkRounding(yacht);
@@ -584,6 +571,7 @@ public class GameState implements Runnable {
if (crossedLine == 2 && isClockwiseCross || crossedLine == 1 && !isClockwiseCross) {
yacht.setClosestCurrentMark(mark1);
yacht.setBoatStatus(BoatStatus.RACING);
sendServerMessage(yacht.getSourceId(), yacht.getBoatName() + " passed start line");
return true;
}
}
@@ -687,6 +675,7 @@ public class GameState implements Runnable {
if (crossedLine == 1 && isClockwiseCross || crossedLine == 2 && !isClockwiseCross) {
yacht.setClosestCurrentMark(mark1);
yacht.setBoatStatus(BoatStatus.FINISHED);
sendServerMessage(yacht.getSourceId(), yacht.getBoatName() + " passed finish line");
return true;
}
}
@@ -714,6 +703,9 @@ public class GameState implements Runnable {
int blue = customizeData[2] & 0xFF;
Color yachtColor = Color.rgb(red, green, blue);
playerYacht.setBoatColor(yachtColor);
} else if (requestType.equals(CustomizeRequestType.SHAPE)) {
String type = new String(customizeData);
playerYacht.setBoatType(BoatMeshType.valueOf(type));
}
}
@@ -792,28 +784,30 @@ public class GameState implements Runnable {
}
public static void sendServerMessage(Integer messageType, String message) {
notifyMessageListeners(new ChatterMessage(
messageType, "SERVER: " + message
));
}
public static void processChatter(ChatterMessage chatterMessage, boolean isHost) {
String chatterText = chatterMessage.getMessage();
String[] words = chatterText.split("\\s+");
if (words.length > 2 && isHost) {
switch (words[2].trim()) {
case ">speed":
case "/speed":
try {
setSpeedMultiplier(Double.valueOf(words[3]));
notifyMessageListeners(new ChatterMessage(
chatterMessage.getMessage_type(),
"SERVER: Speed modifier set to x" + words[3]
));
sendServerMessage(chatterMessage.getMessage_type(),
"Speed modifier set to x" + words[3]);
} catch (Exception e) {
Logger logger = LoggerFactory.getLogger(GameState.class);
logger.error("cannot parse >speed value");
}
return;
case ">finish":
notifyMessageListeners(new ChatterMessage(
chatterMessage.getMessage_type(),
"SERVER: Game will now finish"
));
case "/finish":
sendServerMessage(chatterMessage.getMessage_type(),
"Game will now finish");
endRace();
return;
}
@@ -135,7 +135,6 @@ public class MainServerThread implements Runnable, ClientConnectionDelegate {
}
if (GameState.getCurrentStage() == GameStages.LOBBYING && GameState
.getCustomizationFlag()) {
// TODO: 16/08/17 ajm412: This can probably be done in a nicer way via those fancy functional interfaces.
sendSetupMessages();
GameState.resetCustomizationFlag();
}
@@ -196,21 +195,21 @@ public class MainServerThread implements Runnable, ClientConnectionDelegate {
if (Math.floorMod(random.nextInt(), 2) == 0){
direction += random.nextInt(4);
windSpeed += random.nextInt(20) + 50;
windSpeed += random.nextInt(20) + 459;
}
else{
direction -= random.nextInt(4);
windSpeed -= random.nextInt(20) + 50;
windSpeed -= random.nextInt(20) + 459;
}
direction = Math.floorMod(direction, 360);
if (windSpeed > MAX_WIND_SPEED){
windSpeed -= random.nextInt(1000);
windSpeed -= random.nextInt(500);
}
if (windSpeed <= MIN_WIND_SPEED){
windSpeed += random.nextInt(1000);
windSpeed += random.nextInt(500);
}
GameState.setWindSpeed(Double.valueOf(windSpeed));
@@ -33,6 +33,7 @@ import seng302.model.stream.packets.PacketType;
import seng302.model.stream.packets.StreamPacket;
import seng302.model.stream.xml.generator.RaceXMLTemplate;
import seng302.utilities.XMLGenerator;
import seng302.visualiser.fxObjects.assets_3D.BoatMeshType;
/**
* A class describing a single connection to a Client for the purposes of sending and receiving on
@@ -125,7 +126,7 @@ public class ServerToClientThread implements Runnable {
lName = all.get(ThreadLocalRandom.current().nextInt(0, all.size()));
ServerYacht yacht = new ServerYacht(
"Yacht", sourceId, sourceId.toString(), fName, fName + " " + lName, "NZ"
BoatMeshType.DINGHY, sourceId, sourceId.toString(), fName, fName + " " + lName, "NZ"
);
player = new Player(socket, yacht);
@@ -237,8 +238,6 @@ public class ServerToClientThread implements Runnable {
xmlGenerator.setRaceTemplate(race);
System.out.println(xmlGenerator.getRegatta().getName());
XMLMessage xmlMessage;
xmlMessage = new XMLMessage(xmlGenerator.getRegattaAsXml(), XMLMessageSubType.REGATTA,
xmlGenerator.getRegattaAsXml().length());
+5 -4
View File
@@ -15,6 +15,7 @@ import javafx.beans.property.ReadOnlyLongWrapper;
import javafx.scene.paint.Color;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import seng302.visualiser.fxObjects.assets_3D.BoatMeshType;
/**
* Yacht class for the racing boat. <p> Class created to store more variables (eg. boat statuses)
@@ -37,7 +38,7 @@ public class ClientYacht extends Observable {
private Logger logger = LoggerFactory.getLogger(ClientYacht.class);
private String boatType;
private BoatMeshType boatType;
private Integer sourceId;
private String hullID; //matches HullNum in the XML spec.
private String shortName;
@@ -46,7 +47,7 @@ public class ClientYacht extends Observable {
private Integer position;
private Long estimateTimeAtFinish;
private Boolean sailIn = false;
private Boolean sailIn = true;
private Integer currentMarkSeqID = 0;
private Long markRoundTime;
private Long timeTillNext;
@@ -64,7 +65,7 @@ public class ClientYacht extends Observable {
private ReadOnlyIntegerWrapper placingProperty = new ReadOnlyIntegerWrapper();
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) {
this.boatType = boatType;
this.sourceId = sourceId;
@@ -88,7 +89,7 @@ public class ClientYacht extends Observable {
super.addObserver(o);
}
public String getBoatType() {
public BoatMeshType getBoatType() {
return boatType;
}
+15 -6
View File
@@ -3,11 +3,8 @@ package seng302.model;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Collection;
import java.util.Comparator;
import java.util.List;
import java.util.Observable;
import java.util.TimeZone;
import javafx.beans.property.ReadOnlyDoubleProperty;
import javafx.beans.property.ReadOnlyDoubleWrapper;
@@ -34,8 +31,9 @@ public class RaceState {
private ReadOnlyDoubleWrapper windDirection = new ReadOnlyDoubleWrapper();
private long serverSystemTime;
private long expectedStartTime;
private boolean isRaceStarted = false;
private boolean raceRunning = false;
private boolean gunFired = false;
private boolean raceFinished = false;
long timeTillStart;
private ObservableList<ClientYacht> playerPositions;
private List<ClientYacht> collisions = new ArrayList<>();
@@ -50,7 +48,7 @@ public class RaceState {
this.windDirection.set(data.getWindDirection());
this.serverSystemTime = data.getCurrentTime();
this.expectedStartTime = data.getExpectedStartTime();
this.isRaceStarted = data.isRaceStarted();
this.raceRunning = data.isRaceStarted();
}
public void setTimeZone (TimeZone timeZone) {
@@ -95,9 +93,12 @@ public class RaceState {
}
public boolean isRaceStarted () {
return isRaceStarted;
return raceRunning;
}
public void setRaceStarted(Boolean value) {
this.raceRunning = value;
}
public void setBoats(Collection<ClientYacht> clientYachts) {
playerPositions.setAll(clientYachts);
}
@@ -125,4 +126,12 @@ public class RaceState {
public void removeCollisionListener(CollisionListener collisionListener) {
collisionListeners.remove(collisionListener);
}
public void setRaceFinished() {
raceFinished = true;
}
public Boolean getRaceFinished() {
return raceFinished;
}
}
+11 -3
View File
@@ -12,6 +12,7 @@ import seng302.utilities.GeoUtility;
import java.util.HashMap;
import java.util.Observable;
import java.util.Observer;
import seng302.visualiser.fxObjects.assets_3D.BoatMeshType;
/**
* Yacht class for the racing boat. <p> Class created to store more variables (eg. boat statuses)
@@ -20,12 +21,12 @@ import java.util.Observer;
*/
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
private String boatType;
private BoatMeshType boatType;
private Integer sourceId;
private String hullID; //matches HullNum in the XML spec.
private String shortName;
@@ -57,7 +58,7 @@ public class ServerYacht {
private Long powerUpStartTime;
public ServerYacht(String boatType, Integer sourceId, String hullID, String shortName,
public ServerYacht(BoatMeshType boatType, Integer sourceId, String hullID, String shortName,
String boatName, String country) {
this.boatType = boatType;
this.boatStatus = BoatStatus.PRESTART;
@@ -421,4 +422,11 @@ public class ServerYacht {
return boatColor;
}
public void setBoatType(BoatMeshType boatType) {
this.boatType = boatType;
}
public BoatMeshType getBoatType() {
return boatType;
}
}
@@ -2,7 +2,6 @@ package seng302.utilities;
import java.io.IOException;
import java.io.StringReader;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@@ -15,8 +14,12 @@ import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import seng302.model.stream.packets.PacketType;
import seng302.model.stream.packets.StreamPacket;
import seng302.model.stream.parser.*;
import seng302.model.stream.parser.MarkRoundingData;
import seng302.model.stream.parser.PositionUpdateData;
import seng302.model.stream.parser.PositionUpdateData.DeviceType;
import seng302.model.stream.parser.RaceStartData;
import seng302.model.stream.parser.RaceStatusData;
import seng302.model.stream.parser.YachtEventData;
/**
* StreamParser is a utilities class for taking byte data, formatted according to the AC35 streaming
@@ -37,7 +40,6 @@ public class StreamParser {
return null;
}
long heartbeat = bytesToLong(packet.getPayload());
System.out.println("heartbeat = " + heartbeat);
return heartbeat;
}
@@ -18,6 +18,7 @@ import seng302.model.stream.xml.parser.RaceXMLData;
import seng302.model.stream.xml.parser.RegattaXMLData;
import seng302.model.token.Token;
import seng302.model.token.TokenType;
import seng302.visualiser.fxObjects.assets_3D.BoatMeshType;
/**
* Utilities for parsing XML documents
@@ -139,16 +140,14 @@ public class XMLParser {
if (currentBoat.getNodeName().equals("Boat")) {
// Boat boat = new Boat(currentBoat);
ClientYacht yacht = new ClientYacht(
XMLParser.getNodeAttributeString(currentBoat, "Type"),
BoatMeshType.valueOf(XMLParser.getNodeAttributeString(currentBoat, "Type")),
XMLParser.getNodeAttributeInt(currentBoat, "SourceID"),
XMLParser.getNodeAttributeString(currentBoat, "HullNum"),
XMLParser.getNodeAttributeString(currentBoat, "ShortName"),
XMLParser.getNodeAttributeString(currentBoat, "BoatName"),
XMLParser.getNodeAttributeString(currentBoat, "Country"));
yacht.setColour(Color.web(getNodeAttributeString(currentBoat, "Color")));
if (yacht.getBoatType().equals("Yacht")) {
competingBoats.put(yacht.getSourceId(), yacht);
}
competingBoats.put(yacht.getSourceId(), yacht);
}
}
return competingBoats;
@@ -14,7 +14,6 @@ import javafx.application.Platform;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXMLLoader;
import javafx.scene.Node;
import javafx.scene.control.Alert;
import javafx.scene.control.Alert.AlertType;
import javafx.scene.input.KeyCode;
@@ -42,7 +41,6 @@ import seng302.utilities.Sounds;
import seng302.utilities.StreamParser;
import seng302.utilities.XMLGenerator;
import seng302.utilities.XMLParser;
import seng302.visualiser.controllers.FinishScreenViewController;
import seng302.visualiser.controllers.LobbyController;
import seng302.visualiser.controllers.RaceViewController;
import seng302.visualiser.controllers.ViewManager;
@@ -64,6 +62,7 @@ public class GameClient {
private RaceXMLData courseData;
private RaceState raceState = new RaceState();
private LobbyController lobbyController;
private RaceViewController raceViewController;
private ArrayList<ClientYacht> finishedBoats = new ArrayList<>();
@@ -76,17 +75,6 @@ public class GameClient {
*/
public GameClient(Pane holder) {
this.holderPane = holder;
// if (holderPane.getParent() == null) {
// this.holderPane.parentProperty().addListener(((observable, oldValue, newValue) -> {
// if (newValue != null) {
// newValue.getScene().setOnKeyPressed(this::keyPressed);
// newValue.getScene().setOnKeyReleased(this::keyReleased);
// }
// }));
// } else {
// this.holderPane.getParent().getScene().setOnKeyPressed(this::keyPressed);
// this.holderPane.getParent().getScene().setOnKeyReleased(this::keyReleased);
// }
}
/**
@@ -117,22 +105,10 @@ public class GameClient {
ViewManager.getInstance().setProperty("serverName", regattaData.getRegattaName());
ViewManager.getInstance().setProperty("mapName", regattaData.getCourseName());
// TODO disable ready button;
//LobbyController_old lobbyController = loadLobby();
//lobbyController.setSocketThread(socketThread);
//lobbyController.setPlayerID(socketThread.getClientId());
//lobbyController.setPlayerListSource(clientLobbyList);
//lobbyController.disableReadyButton();
// lobbyController.addCloseListener((exitCause) -> this.loadStartScreen());
this.lobbyController = ViewManager.getInstance().goToLobby(true);
} catch (IOException ioe) {
showConnectionError("Unable to find server");
//Platform.runLater(this::loadStartScreen);
}
}
@@ -200,41 +176,8 @@ public class GameClient {
socketThread.addStreamObserver(this::parsePackets);
}
private void loadRaceView() {
FXMLLoader fxmlLoader = loadFXMLToHolder("/views/RaceView.fxml");
holderPane.getScene().setOnKeyPressed(this::keyPressed);
holderPane.getScene().setOnKeyReleased(this::keyReleased);
raceView = fxmlLoader.getController();
ClientYacht player = allBoatsMap.get(socketThread.getClientId());
raceView.loadRace(allBoatsMap, courseData, raceState, player);
}
private void loadFinishScreenView() {
Sounds.stopMusic();
Sounds.stopSoundEffects();
Sounds.playFinishMusic();
FXMLLoader fxmlLoader = loadFXMLToHolder("/views/FinishScreenView.fxml");
FinishScreenViewController controller = fxmlLoader.getController();
controller.setFinishers(raceState.getPlayerPositions());
}
private FXMLLoader loadFXMLToHolder(String fxmlLocation) {
FXMLLoader fxmlLoader = new FXMLLoader(
getClass().getResource(fxmlLocation)
);
try {
final Node fxmlLoaderFX = fxmlLoader.load();
Platform.runLater(() -> {
holderPane.getChildren().clear();
holderPane.getChildren().add(fxmlLoaderFX);
});
} catch (IOException e) {
e.printStackTrace();
}
return fxmlLoader;
public void setRaceViewController(RaceViewController controller) {
this.raceViewController = controller;
}
private void parsePackets() {
@@ -398,10 +341,13 @@ public class GameClient {
}
if (raceFinished) {
raceViewController.showFinishDialog(finishedBoats);
Sounds.playFinishSound();
close();
loadFinishScreenView();
ViewManager.getInstance().getGameClient().stopGame();
//loadFinishScreenView();
}
raceState.setRaceFinished();
}
}
@@ -416,7 +362,6 @@ public class GameClient {
socketThread.setSocketToClose();
}
/**
* Handle the key-pressed event from the text field.
* @param e The key event triggering this call
@@ -504,6 +449,8 @@ public class GameClient {
GameState.setCurrentStage(GameStages.CANCELLED);
if (server != null) server.terminate();
if (socketThread != null) socketThread.setSocketToClose();
server = null;
// socketThread = null;
}
public Map<Integer, ClientYacht> getAllBoatsMap() {
@@ -16,6 +16,7 @@ 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.*;
import java.util.*;
+111 -277
View File
@@ -1,31 +1,21 @@
package seng302.visualiser;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;
import javafx.animation.AnimationTimer;
import javafx.application.Platform;
import javafx.geometry.Point2D;
import javafx.geometry.Point3D;
import javafx.scene.AmbientLight;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.PerspectiveCamera;
import javafx.scene.PointLight;
import javafx.scene.SceneAntialiasing;
import javafx.scene.SubScene;
import javafx.scene.effect.BlendMode;
import javafx.scene.image.ImageView;
import javafx.scene.input.KeyEvent;
import javafx.scene.paint.Color;
import javafx.scene.paint.PhongMaterial;
import javafx.scene.shape.Sphere;
import javafx.scene.text.Text;
import javafx.scene.transform.Rotate;
import javafx.scene.transform.Scale;
import javafx.scene.transform.Translate;
@@ -38,7 +28,11 @@ import seng302.model.mark.Corner;
import seng302.model.mark.Mark;
import seng302.model.token.Token;
import seng302.utilities.GeoUtility;
import seng302.visualiser.fxObjects.assets_2D.BoatObject;
import seng302.utilities.Sounds;
import seng302.visualiser.fxObjects.MarkArrowFactory;
import seng302.visualiser.fxObjects.assets_3D.BoatMeshType;
import seng302.visualiser.fxObjects.assets_3D.BoatObject;
import seng302.visualiser.fxObjects.assets_3D.Marker3D;
import seng302.visualiser.fxObjects.assets_3D.ModelFactory;
import seng302.visualiser.fxObjects.assets_3D.ModelType;
@@ -48,12 +42,15 @@ import seng302.visualiser.fxObjects.assets_3D.ModelType;
public class GameView3D {
private final double FOV = 60;
private final double DEFAULT_CAMERA_DEPTH = 100;
private final double DEFAULT_CAMERA_DEPTH = -125;
private final double DEFAULT_CAMERA_X = 0;
private final double DEFAULT_CAMERA_Y = 155;
private Group root3D;
private SubScene view;
// ParallelCamera camera;
// ParallelCamera camera;
private PerspectiveCamera camera;
private Group gameObjects;
@@ -62,24 +59,16 @@ public class GameView3D {
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 double metersPerPixelX, metersPerPixelY;
final double SCALE_DELTA = 1.1;
private Text fpsDisplay = new Text();
private Group raceBorder = new Group();
/* 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, Group> markerObjects;
private Map<Mark, Marker3D> markerObjects;
private Map<ClientYacht, BoatObject> boatObjects = new HashMap<>();
private BoatObject selectedBoat = null;
@@ -87,196 +76,42 @@ public class GameView3D {
private Group boatObjectGroup = new Group();
private Group markers = new Group();
private Group tokens = new Group();
private Group playerAnnotation = new Group();
private List<CompoundMark> course = new ArrayList<>();
private List<Node> mapTokens;
private Timer playerBoatAnimationTimer = new Timer();
private AnimationTimer playerBoatAnimationTimer;
private Group trail = new Group();
private ImageView mapImage = new ImageView();
//FRAME RATE
private AnimationTimer timer;
private int NUM_SAMPLES = 10;
private final long[] frameTimes = new long[NUM_SAMPLES];
private Double frameRate = 60.0;
private int frameTimeIndex = 0;
private boolean arrayFilled = false;
private ClientYacht playerYacht;
private double windDir = 0.0;
double scaleFactor = 1;
private Double windDir;
private enum ScaleDirection {
HORIZONTAL,
VERTICAL
}
public GameView3D () {
camera = new PerspectiveCamera(true);
// camera = new ParallelCamera();
// gameObjects.getTransforms().add(new Scale(4,4,4));
// camera.setLayoutX(camera.getLayoutX()-400);
// camera.setLayoutY(camera.getLayoutY()-400);
camera.getTransforms().addAll(
new Translate(0,0, -DEFAULT_CAMERA_DEPTH)
new Translate(DEFAULT_CAMERA_X,DEFAULT_CAMERA_Y, DEFAULT_CAMERA_DEPTH)
);
camera.setFarClip(Double.MAX_VALUE);
camera.setFarClip(600);
camera.setNearClip(0.1);
camera.setFieldOfView(FOV);
gameObjects = new Group();
PointLight pl = new PointLight(Color.DARKGRAY);
pl.setLightOn(true);
pl.setBlendMode(BlendMode.ADD);
pl.setOpacity(0.5);
pl.getTransforms().add(new Translate(0,0,-500));
AmbientLight al = new AmbientLight();
al.setLightOn(true);
al.setBlendMode(BlendMode.SOFT_LIGHT);
al.getTransforms().add(new Translate(0, 0, -100));
root3D = new Group(camera, gameObjects);
view = new SubScene(
root3D, 1000, 1000, true, SceneAntialiasing.BALANCED
);
view.setCamera(camera);
// view.setFill(Color.LIGHTBLUE);
camera.getTransforms().add(new Rotate(30, new Point3D(1,0,0)));
// gameObjects.getChildren().addAll(raceBorder, markers, tokens);
System.out.println(camera.getLayoutX());
System.out.println(camera.getTranslateX());
System.out.println(camera.getLayoutY());
System.out.println(camera.getTranslateY());
System.out.println(camera.getTranslateZ());
camera.setTranslateZ(-80);
camera.setTranslateY(170);
Sphere red = new Sphere(1);
red.setMaterial(new PhongMaterial(Color.RED));
red.setLayoutX(0);
red.setLayoutY(0);
Sphere blue = new Sphere(1);
blue.setMaterial(new PhongMaterial(Color.BLUE));
blue.setLayoutX(1);
blue.setLayoutY(0);
Sphere green = new Sphere(1);
green.setMaterial(new PhongMaterial(Color.GREEN));
green.setLayoutX(-.5);
green.setLayoutY(0);
Sphere white = new Sphere(1);
white.setMaterial(new PhongMaterial(Color.WHITE));
white.setLayoutX(-.25);
white.setLayoutY(0);
Sphere black = new Sphere(1);
black.setMaterial(new PhongMaterial(Color.BLACK));
black.setLayoutX(-.125);
black.setLayoutY(0);
gameObjects.getChildren().addAll(
// ModelFactory.importModel(ModelType.OCEAN).getAssets(),
raceBorder, trail, markers, tokens, playerAnnotation,
white, blue, green, black, red
ModelFactory.importModel(ModelType.OCEAN).getAssets(),
raceBorder, trail, markers, tokens
);
System.out.println(camera.getLayoutX());
System.out.println(camera.getTranslateX());
System.out.println(camera.getLayoutY());
System.out.println(camera.getTranslateY());
System.out.println(camera.getTranslateZ());
// Sphere s = new Sphere(1);
// s.setMaterial(new PhongMaterial(Color.RED));
// Sphere left = new Sphere(1);
// left.setMaterial(new PhongMaterial(Color.LEMONCHIFFON));
// left.getTransforms().add(new Translate(-Math.tan(Math.toRadians(FOV / 2)) * DEFAULT_CAMERA_DEPTH, 0, 0));
// Sphere right = new Sphere(1);
// right.setMaterial(new PhongMaterial(Color.ROSYBROWN));
// right.getTransforms().add(new Translate(Math.tan(Math.toRadians(FOV / 2)) * DEFAULT_CAMERA_DEPTH, 0, 0));
// Sphere top = new Sphere(1);
// top.setMaterial(new PhongMaterial(Color.TEAL));
// top.getTransforms().add(new Translate(0,-Math.tan(Math.toRadians(FOV / 2)) * DEFAULT_CAMERA_DEPTH, 0));
// Sphere bottom = new Sphere(1);
// bottom.setMaterial(new PhongMaterial(Color.BLANCHEDALMOND));
// bottom.getTransforms().add(new Translate(0, Math.tan(Math.toRadians(FOV / 2)) * DEFAULT_CAMERA_DEPTH, 0));
//
// Node boat = ModelFactory.boatGameView(BoatMeshType.DINGHY, Color.BLUE).getAssets();
// Node boat2 = ModelFactory.boatGameView(BoatMeshType.DINGHY, Color.BROWN).getAssets();
// boat2.getTransforms().add(new Translate(0,20, 0));
// Node boat3 = ModelFactory.boatGameView(BoatMeshType.DINGHY, Color.RED).getAssets();
// boat3.getTransforms().add(new Translate(0,-20, 0));
//
// Node sMarker = ModelFactory.importModel(ModelType.START_MARKER).getAssets();
// sMarker.getTransforms().add(0, new Translate(30, 30, 0));
//
// Node fMarker = ModelFactory.importModel(ModelType.FINISH_MARKER).getAssets();
// fMarker.getTransforms().add(0, new Translate(30, -30, 0));
//
// Node marker = ModelFactory.importModel(ModelType.PLAIN_MARKER).getAssets();
// marker.getTransforms().add(0, new Translate(30, 0, 0));
//
// Node coin = ModelFactory.importModel(ModelType.VELOCITY_PICKUP).getAssets();
// coin.setTranslateX(coin.getTranslateX() - 30);
//
// gameObjects.getChildren().addAll(
// ModelFactory.importModel(ModelType.OCEAN).getAssets(),
// s, left, right, top, bottom,
// boat, boat2, boat3,
// sMarker, fMarker, marker,
// coin
// );
view.sceneProperty().addListener((obs, old, scene) -> {
if (scene != null) {
scene.addEventHandler(KeyEvent.KEY_PRESSED, this::cameraMovement);
}
});
initializeTimer();
}
private void initializeTimer() {
Arrays.fill(frameTimes, 1_000_000_000 / 60);
timer = new AnimationTimer() {
private long lastTime = 0;
private int FPSCount = 30;
private Double frameRate = 60.0;
private int index = 0;
private boolean arrayFilled = false;
private long sum = 1_000_000_000 / 3;
@Override
public void handle(long now) {
System.out.println(now);
if (lastTime == 0) {
lastTime = now;
} else {
if (now - lastTime >= (1e8 / 60)) { //Fix for framerate going above 60 when minimized
long oldFrameTime = frameTimes[frameTimeIndex];
frameTimes[frameTimeIndex] = now;
frameTimeIndex = (frameTimeIndex + 1) % frameTimes.length;
if (frameTimeIndex == 0) {
arrayFilled = true;
}
long elapsedNanos;
if (arrayFilled) {
elapsedNanos = now - oldFrameTime;
long elapsedNanosPerFrame = elapsedNanos / frameTimes.length;
frameRate = 1_000_000_000.0 / elapsedNanosPerFrame;
if (FPSCount-- == 0) {
FPSCount = 30;
drawFps(frameRate);
}
}
lastTime = now;
}
}
boatObjects.forEach((boat, boatObject) -> boatObject.updateLocation());
}
};
}
public void updateCourse(List<CompoundMark> newCourse, List<Corner> sequence) {
@@ -327,6 +162,8 @@ public class GameView3D {
}
}
createMarkArrows();
//Scale race to markers if there is no border.
if (borderPoints == null) {
rescaleRace(new ArrayList<>(markerObjects.keySet()));
@@ -334,7 +171,6 @@ public class GameView3D {
//Move the Markers to initial position.
markerObjects.forEach(((mark, marker) -> {
Point2D p2d = findScaledXY(mark.getLat(), mark.getLng());
System.out.println(mark.toString() + " " + p2d.toString());
marker.setLayoutX(p2d.getX());
marker.setLayoutY(p2d.getY());
}));
@@ -352,10 +188,7 @@ public class GameView3D {
* @param markerType the type of marker as a ModelType. Should be PLAIN_MARKER, START_MARKER or END_MARKER
*/
private void makeAndBindMarker(Mark observableMark, ModelType markerType) {
Group marker = ModelFactory.importModel(markerType).getAssets();
markerObjects.put(observableMark, marker);
markerObjects.put(observableMark, new Marker3D(markerType));
observableMark.addPositionListener((mark, lat, lon) -> {
Point2D p2d = findScaledXY(lat, lon);
markerObjects.get(mark).setLayoutX(p2d.getX());
@@ -393,6 +226,44 @@ public class GameView3D {
}
/**
* Calculates all the data needed for to create mark arrows. Requires that a course has been
* added to the gameview.
*/
private void createMarkArrows () {
for (int i=1; i < course.size()-1; i++) { //General case.
for (Mark mark : course.get(i).getMarks()) {
markerObjects.get(mark).addArrows(
mark.getRoundingSide() == RoundingSide.STARBOARD ? MarkArrowFactory.RoundingSide.STARBOARD : MarkArrowFactory.RoundingSide.PORT,
GeoUtility.getBearing(course.get(i-1).getMidPoint(), mark),
GeoUtility.getBearing(mark, course.get(i+1).getMidPoint())
);
}
}
createStartLineArrows();
createFinishLineArrows();
}
private void createStartLineArrows () {
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, course.get(1).getMidPoint())
);
}
}
private void createFinishLineArrows () {
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(course.get(course.size()-2).getMidPoint(), mark),
GeoUtility.getBearing(mark, mark)
);
}
}
/**
* Sets the class variables minLatPoint, maxLatPoint, minLonPoint, maxLonPoint to the point with
* the leftmost point, rightmost point, southern most point and northern most point
@@ -546,10 +417,10 @@ public class GameView3D {
case NUMPAD6:
camera.getTransforms().addAll(new Rotate(0.5, new Point3D(0,1,0)));
break;
case X:
case Z:
camera.getTransforms().addAll(new Translate(0, 0, 1.5));
break;
case Z:
case X:
camera.getTransforms().addAll(new Translate(0, 0, -1.5));
break;
case W:
@@ -589,36 +460,21 @@ public class GameView3D {
final List<Group> wakes = new ArrayList<>();
for (ClientYacht clientYacht : yachts) {
Color colour = clientYacht.getColour();
newBoat = new BoatObject();
// newBoat.addSelectedBoatListener(this::setSelectedBoat);
newBoat = new BoatObject(clientYacht.getBoatType());
newBoat.setFill(colour);
boatObjects.put(clientYacht, newBoat);
// createAndBindAnnotationBox(clientYacht, colour);
wakesGroup.getChildren().add(newBoat.getWake());
wakes.add(newBoat.getWake());
boatObjectGroup.getChildren().add(newBoat);
// trails.getChildren().add(newBoat.getTrail());
clientYacht.addLocationListener((boat, lat, lon, heading, sailIn, velocity) -> {
BoatObject bo = boatObjects.get(boat);
Point2D p2d = findScaledXY(lat, lon);
bo.moveTo(p2d.getX(), p2d.getY(), heading, velocity, sailIn, windDir);
// annotations.get(boat).setLocation(p2d.getX(), p2d.getY());
bo.setTrajectory(
heading,
velocity,
metersPerPixelX,
metersPerPixelY);
});
}
// annotationsGroup.getChildren().addAll(annotations.values());
Platform.runLater(() -> {
// gameObjects.addAll(trails);
gameObjects.getChildren().addAll(wakes);
gameObjects.getChildren().addAll(boatObjectGroup);
// gameObjects.addAll(annotationsGroup);
// gameObjects.addAll(boatObjectGroup);
});
}
@@ -659,7 +515,7 @@ public class GameView3D {
),
new Point3D(0,0,1)
),
new Scale((lastLocation.distance(location) / 15)-0.2, 1, 1)
new Scale((lastLocation.distance(location) / 10)-0.2, 1, 1)
);
Point2D midPoint = location.midpoint(lastLocation);
@@ -681,7 +537,7 @@ public class GameView3D {
),
new Point3D(0,0,1)
),
new Scale((firstLocation.distance(lastLocation) / 15)-0.2, 1, 1)
new Scale((firstLocation.distance(lastLocation) / 10)-0.2, 1, 1)
);
Point2D midPoint = lastLocation.midpoint(firstLocation);
@@ -713,88 +569,66 @@ public class GameView3D {
}
public void setBoatAsPlayer (ClientYacht playerYacht) {
this.playerYacht = playerYacht;
playerYacht.toggleSail();
playerBoatAnimationTimer = new AnimationTimer() {
Platform.runLater(() ->
playerAnnotation.getChildren().setAll(ModelFactory.importModel(ModelType.PLAYER_IDENTIFIER).getAssets())
);
BoatObject playerAssets = boatObjects.get(playerYacht);
playerAnnotation.layoutXProperty().bind(playerAssets.layoutXProperty());
playerAnnotation.layoutYProperty().bind(playerAssets.layoutYProperty());
playerBoatAnimationTimer.scheduleAtFixedRate(new TimerTask() {
private Point2D lastLocation = findScaledXY(playerYacht.getLocation());
double count = 60;
Point2D lastLocation = findScaledXY(playerYacht.getLocation());
@Override
public void run() {
Node segment = ModelFactory.importModel(ModelType.TRAIL_SEGMENT).getAssets();
Point2D location = findScaledXY(playerYacht.getLocation());
segment.getTransforms().addAll(
new Translate(location.getX(), location.getY()),
new Rotate(playerYacht.getHeading(), new Point3D(0,0,1)),
new Scale(1, lastLocation.distance(location) / 5)
);
Platform.runLater(() -> {
public void handle(long now) {
if (--count == 0) {
count = 60;
Node segment = ModelFactory.importModel(ModelType.TRAIL_SEGMENT).getAssets();
Point2D location = findScaledXY(playerYacht.getLocation());
segment.getTransforms().addAll(
new Translate(location.getX(), location.getY(), 0),
new Rotate(playerYacht.getHeading(), new Point3D(0,0,1)),
new Scale(1, lastLocation.distance(location) / 5, 1)
);
trail.getChildren().add(segment);
if (trail.getChildren().size() > 100) {
if (trail.getChildren().size() > 50) {
trail.getChildren().remove(0);
}
});
lastLocation = location;
// TODO: 11/09/2017 ROTATE PLAYER ICON
// double leg = playerYacht.getLegNumber();
// if (compoundMark != null) {
// for (Mark mark : compoundMark.getMarks()) {
//// System.out.println("markerObjects.get(mark) = " + markerObjects.get(mark));
// markerObjects.get(mark).showNextExitArrow();
// }
// }
// CompoundMark nextMark = null;
// if (legNumber < course.size() - 1) {
// nextMark = course.get(legNumber);
// for (Mark mark : nextMark.getMarks()) {
// markerObjects.get(mark).showNextEnterArrow();
// }
// }
lastLocation = location;
}
}
}, 0L, 500L);
// playerYacht.toggleSail();
// boatObjects.get(playerYacht).setAsPlayer();
// CompoundMark currentMark = course.get(playerYacht.getLegNumber());
// for (Mark mark : currentMark.getMarks()) {
// markerObjects.get(mark).showNextExitArrow();
// }
// annotations.get(playerYacht).addAnnotation(
// "velocity",
// playerYacht.getVelocityProperty(),
// (velocity) -> String.format("Speed: %.2f ms", velocity.doubleValue())
// );
// Platform.runLater(() -> {
// boatObjectGroup.getChildren().remove(boatObjects.get(playerYacht));
// gameObjects.add(boatObjects.get(playerYacht));
// annotationsGroup.getChildren().remove(annotations.get(playerYacht));
// gameObjects.add(annotations.get(playerYacht));
// });
// playerYacht.addMarkRoundingListener(this::updateMarkArrows);
};
playerBoatAnimationTimer.start();
playerYacht.addMarkRoundingListener(this::updateMarkArrows);
boatObjects.get(playerYacht).addSelectedBoatListener((boatObject, isSelected) -> {
System.out.println("IS SELECTED " + isSelected);
});
}
public void setWindDir(double windDir) {
this.windDir = windDir;
}
public void setFrameRateFXText(Text fpsDisplay) {
this.fpsDisplay = null;
this.fpsDisplay = fpsDisplay;
private void updateMarkArrows (ClientYacht yacht, int legNumber) {
CompoundMark compoundMark;
if (legNumber - 1 >= 0) {
Sounds.playMarkRoundingSound();
compoundMark = course.get(legNumber-1);
for (Mark mark : compoundMark.getMarks()) {
markerObjects.get(mark).showNextExitArrow();
}
}
CompoundMark nextMark = null;
if (legNumber < course.size() - 1) {
Sounds.playMarkRoundingSound();
nextMark = course.get(legNumber);
for (Mark mark : nextMark.getMarks()) {
markerObjects.get(mark).showNextEnterArrow();
}
}
if (legNumber - 2 >= 0) {
CompoundMark lastMark = course.get(Math.max(0, legNumber - 2));
if (lastMark != nextMark) {
for (Mark mark : lastMark.getMarks()) {
markerObjects.get(mark).hideAllArrows();
}
}
}
}
private void drawFps(Double fps) {
System.out.println(fps);
Platform.runLater(() -> fpsDisplay.setText(String.format("%d FPS", Math.round(fps))));
}
// public void setFPSVisibility(boolean visibility) {
// fpsDisplay.setVisible(visibility);
// }
}
@@ -42,8 +42,8 @@ public class FinishScreenViewController implements Initializable {
@Override
public void initialize(URL location, ResourceBundle resources) {
finishScreenGridPane.getStylesheets()
.add(getClass().getResource("/css/master.css").toString());
finishOrderTable.getStylesheets().add(getClass().getResource("/css/master.css").toString());
.add(getClass().getResource("/css/Master.css").toString());
finishOrderTable.getStylesheets().add(getClass().getResource("/css/Master.css").toString());
// set up data for table
finishOrderTable.setItems(data);
@@ -2,12 +2,6 @@ package seng302.visualiser.controllers;
import com.jfoenix.controls.JFXButton;
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.collections.ListChangeListener;
import javafx.fxml.FXML;
@@ -33,6 +27,14 @@ import seng302.visualiser.GameView;
import seng302.visualiser.controllers.cells.PlayerCell;
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;
import seng302.visualiser.fxObjects.assets_3D.BoatMeshType;
public class LobbyController implements Initializable {
//--------FXML BEGIN--------//
@@ -91,7 +93,6 @@ public class LobbyController implements Initializable {
Platform.runLater(() -> {
Integer playerId = ViewManager.getInstance().getGameClient().getServerThread().getClientId();
String name = ViewManager.getInstance().getGameClient().getPlayerNames().get(playerId - 1);
playersColor = Colors.getColor(playerId - 1);
customizationDialog = createCustomizeDialog();
@@ -110,7 +111,6 @@ public class LobbyController implements Initializable {
}
private JFXDialog createCustomizeDialog() {
// TODO: 12/09/17 ajm412: Why is this here? is there no better way we can do this? Ideally inside the LobbyController.
FXMLLoader dialog = new FXMLLoader(
getClass().getResource("/views/dialogs/BoatCustomizeDialog.fxml"));
@@ -119,7 +119,6 @@ public class LobbyController implements Initializable {
try {
customizationDialog = new JFXDialog(serverListMainStackPane, dialog.load(),
JFXDialog.DialogTransition.CENTER);
} catch (IOException e) {
e.printStackTrace();
}
@@ -128,6 +127,11 @@ public class LobbyController implements Initializable {
controller.setParentController(this);
controller.setPlayerColor(this.playersColor);
controller.setPlayerName(this.playerBoats
.get(ViewManager.getInstance().getGameClient().getServerThread().getClientId())
.getBoatName());
controller.setCurrentBoat(this.playerBoats.get(ViewManager.getInstance().getGameClient().getServerThread().getClientId())
.getBoatType());
return customizationDialog;
}
@@ -201,7 +205,7 @@ public class LobbyController implements Initializable {
FXMLLoader loader = new FXMLLoader(
getClass().getResource("/views/cells/PlayerCell.fxml"));
loader.setController(new PlayerCell(playerId, yacht.getBoatName(), yacht.getColour()));
loader.setController(new PlayerCell(playerId, yacht));
try {
pane = loader.load();
@@ -1,6 +1,7 @@
package seng302.visualiser.controllers;
import com.jfoenix.controls.JFXButton;
import com.jfoenix.controls.JFXDialog;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
@@ -55,9 +56,10 @@ import seng302.visualiser.GameView3D;
import seng302.visualiser.controllers.annotations.ImportantAnnotationController;
import seng302.visualiser.controllers.annotations.ImportantAnnotationDelegate;
import seng302.visualiser.controllers.annotations.ImportantAnnotationsState;
import seng302.visualiser.controllers.dialogs.FinishDialogController;
import seng302.visualiser.fxObjects.ChatHistory;
import seng302.visualiser.fxObjects.assets_2D.BoatObject;
import seng302.visualiser.fxObjects.assets_2D.WindArrow;
import seng302.visualiser.fxObjects.assets_3D.BoatObject;
/**
* Controller class that manages the display of a race
@@ -86,6 +88,7 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
private Label timerLabel;
@FXML
private StackPane contentAnchorPane;
private GridPane contentGridPane;
@FXML
private AnchorPane rvAnchorPane;
@@ -124,11 +127,15 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
private Polyline windArrow = new WindArrow(Color.LIGHTGRAY);
private ObservableList<ClientYacht> selectionComboBoxList = FXCollections.observableArrayList();
private ClientYacht player;
private JFXDialog finishScreenDialog;
private FinishDialogController finishDialogController;
public void initialize() {
Sounds.stopMusic();
Sounds.playRaceMusic();
finishScreenDialog = createFinishDialog();
// Load a default important annotation state
//importantAnnotations = new ImportantAnnotationsState();
@@ -191,6 +198,30 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
});
}
public void showFinishDialog(ArrayList<ClientYacht> finishedBoats) {
raceState.setRaceStarted(false);
finishDialogController.setFinishedBoats(finishedBoats);
finishScreenDialog.show();
}
private JFXDialog createFinishDialog() {
FXMLLoader dialog = new FXMLLoader(
getClass().getResource("/views/dialogs/RaceFinishDialog.fxml"));
JFXDialog finishScreenDialog = null;
try {
finishScreenDialog = new JFXDialog(contentAnchorPane, dialog.load(),
JFXDialog.DialogTransition.CENTER);
} catch (IOException e) {
e.printStackTrace();
}
finishDialogController = dialog.getController();
return finishScreenDialog;
}
public void loadRace (
Map<Integer, ClientYacht> participants, RaceXMLData raceData, RaceState raceState,
ClientYacht player) {
@@ -212,16 +243,13 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
updateOrder(raceState.getPlayerPositions());
gameView = new GameView3D();
gameView.setFrameRateFXText(fpsDisplay);
// gameView.setFrameRateFXText(fpsDisplay);
Platform.runLater(() -> {
contentAnchorPane.getChildren().add(0, gameView.getAssets());
((SubScene) gameView.getAssets()).widthProperty()
.bind(ViewManager.getInstance().getStage().widthProperty());
((SubScene) gameView.getAssets()).heightProperty()
.bind(ViewManager.getInstance().getStage().heightProperty());
System.out.println(((SubScene) gameView.getAssets()).getHeight());
System.out.println(((SubScene) gameView.getAssets()).getWidth());
});
gameView.setBoats(new ArrayList<>(participants.values()));
gameView.updateBorder(raceData.getCourseLimit());
@@ -245,33 +273,9 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
updateWindDirection(raceState.windDirectionProperty().doubleValue());
updateWindSpeed(raceState.getWindSpeed());
});
// gameView.setWindDir(raceState.windDirectionProperty().doubleValue());
//TODO extract chat stuff
// raceState.addCollisionListener(gameView::drawCollision);
// raceState.windDirectionProperty().addListener((obs, oldDirection, newDirection) -> {
// gameView.setWindDir(newDirection.doubleValue());
// updateWindDirection(newDirection.doubleValue());
// });
// raceState.windSpeedProperty().addListener((obs, oldSpeed, newSpeed) -> {
// updateWindSpeed(newSpeed.doubleValue());
// });
// updateWindDirection(raceState.windDirectionProperty().doubleValue());
// updateWindSpeed(raceState.getWindSpeed());
// gameView.setWindDir(raceState.windDirectionProperty().doubleValue());
// chatInput.focusedProperty().addListener((obs, oldValue, newValue) -> {
// if (newValue) {
// gameView.disableZoom();
// } else {
// gameView.enableZoom();
// }
// });
gameView.setWindDir(raceState.windDirectionProperty().doubleValue());
Platform.runLater(() -> {
initializeUpdateTimer();
// initialiseFPSCheckBox();
// initialiseAnnotationSlider();
// initialiseBoatSelectionComboBox();
// initialiseSparkLine();
});
}
@@ -313,11 +317,11 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
}
}
// private void initialiseFPSCheckBox() {
private void initialiseFPSCheckBox() {
// toggleFps.selectedProperty().addListener((obs, oldVal, newVal) ->
// gameView.setFPSVisibility(toggleFps.isSelected())
// );
// }
}
private void initialiseAnnotationSlider() {
// annotationSlider.setLabelFormatter(new StringConverter<Double>() {
@@ -70,10 +70,8 @@ public class ViewManager {
decorator.applyCss();
decorator.getStylesheets()
.add(getClass().getResource("/css/Master.css").toExternalForm());
setDecorator(decorator);
gameClient = new GameClient(decorator);
setDecorator(decorator);
stage.getIcons().add(new Image(getClass().getResourceAsStream("/PP.png")));
Scene scene = new Scene(decorator, 1200, 800, false, SceneAntialiasing.BALANCED);
@@ -112,6 +110,11 @@ public class ViewManager {
private void setDecorator(JFXDecorator newDecorator) {
decorator = newDecorator;
decorator.setOnCloseButtonAction(() -> {
gameClient.stopGame();
System.exit(0);
});
//Injecting a volume toggle into the decorator.
//Get the button box
HBox btns = (HBox) decorator.getChildren().get(0);
@@ -126,13 +129,13 @@ public class ViewManager {
//Create Graphics
SVGGlyph spacer = new SVGGlyph(0, "SPACER", "", Color.WHITE);
SVGGlyph volumeOn = new SVGGlyph(0, "VOLUME_ON",
"M39.389,13.769 22.235,28.606 6,28.606 6,47.699 21.989,47.699 39.389,62.75 39.389,13.769 M 48.128,49.03 C 50.057,45.934 51.19,42.291 51.19,38.377 C 51.19,34.399 50.026,30.703 48.043,27.577 M 55.082,20.537 C 58.777,25.523 60.966,31.694 60.966,38.377 C 60.966,44.998 58.815,51.115 55.178,56.076 M 61.71,62.611 C 66.977,55.945 70.128,47.531 70.128,38.378 C 70.128,29.161 66.936,20.696 61.609,14.01",
"M0,6 L0,12 L4,12 L9,17 L9,1 L4,6 L0,6 L0,6 Z M13.5,9 C13.5,7.2 12.5,5.7 11,5 L11,13 C12.5,12.3 13.5,10.8 13.5,9 L13.5,9 Z M11,0.2 L11,2.3 C13.9,3.2 16,5.8 16,9 C16,12.2 13.9,14.8 11,15.7 L11,17.8 C15,16.9 18,13.3 18,9 C18,4.7 15,1.1 11,0.2 L11,0.2 Z",
Color.WHITE);
SVGGlyph volumeOff = new SVGGlyph(0, "VOLUME_ON",
"M39.389,13.769 22.235,28.606 6,28.606 6,47.699 21.989,47.699 39.389,62.75 39.389,13.769",
"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);
volumeOn.setSize(16, 16);
volumeOff.setSize(12, 16);
volumeOff.setSize(16, 16);
spacer.setSize(40, 16);
// Determine which graphic should go on the button
@@ -245,14 +248,12 @@ public class ViewManager {
public RaceViewController loadRaceView() {
FXMLLoader loader = loadFxml("/views/RaceView.fxml");
// have to create a new stage and set the race view maximized as JFoenix decorator has
// bug causes stage cannot be fully maximised.
Platform.runLater(() -> {
try {
stage.close();
stage = new Stage();
JFXDecorator decorator = new JFXDecorator(stage, loader.load(), false, true, true);
decorator.setCustomMaximize(true);
decorator.applyCss();
@@ -260,6 +261,8 @@ public class ViewManager {
.add(getClass().getResource("/css/Master.css").toExternalForm());
setDecorator(decorator);
Scene scene = new Scene(decorator);
RaceViewController raceViewController = loader.getController();
gameClient.setRaceViewController(raceViewController);
// set key press event to catch key stoke
scene.setOnKeyPressed(gameClient::keyPressed);
scene.setOnKeyReleased(gameClient::keyReleased);
@@ -275,6 +278,8 @@ public class ViewManager {
stage.setMinHeight(500);
stage.setMinWidth(800);
stage.setTitle("Party Parrots At Sea");
stage.getIcons().add(new Image(getClass().getResourceAsStream("/PP.png")));
stage.setOnCloseRequest(e -> closeAll());
stage.setScene(scene);
stage.show();
@@ -6,6 +6,7 @@ import javafx.scene.control.Label;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import seng302.model.ClientYacht;
import seng302.visualiser.fxObjects.assets_3D.BoatMeshType;
import seng302.visualiser.fxObjects.assets_3D.BoatModel;
import seng302.visualiser.fxObjects.assets_3D.ModelFactory;
@@ -24,11 +25,13 @@ public class PlayerCell {
private String name;
private Color boatColor;
private Integer playerId;
private BoatMeshType boatType;
public PlayerCell(Integer playerId, String playerName, Color color) {
public PlayerCell(Integer playerId, ClientYacht yacht) {
this.playerId = playerId;
this.name = playerName;
this.boatColor = color;
this.name = yacht.getBoatName();
this.boatColor = yacht.getColour();
this.boatType = yacht.getBoatType();
}
public void initialize() {
@@ -37,7 +40,7 @@ public class PlayerCell {
// Add Rotating Boat to Player Cell with players color on it.
Group group = new Group();
boatPane.getChildren().add(group);
BoatModel bo = ModelFactory.boatIconView(BoatMeshType.DINGHY, this.boatColor);
BoatModel bo = ModelFactory.boatIconView(boatType, boatColor);
group.getChildren().add(bo.getAssets());
}
@@ -69,7 +69,6 @@ public class ServerCell implements Initializable {
* Attempts to connect to the chosen server using the button on the serverCell.
*/
private void joinServer() {
System.out.println("Connecting to " + serverName.getText());
ViewManager.getInstance().getGameClient().runAsClient(hostName, portNumber);
}
@@ -6,15 +6,24 @@ import com.jfoenix.controls.JFXTextField;
import com.jfoenix.validation.RequiredFieldValidator;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.geometry.Insets;
import javafx.scene.Group;
import javafx.scene.PointLight;
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 seng302.gameServer.messages.CustomizeRequestType;
import seng302.utilities.Sounds;
import seng302.visualiser.ClientToServerThread;
import seng302.visualiser.controllers.LobbyController;
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.ValidationTools;
@@ -28,20 +37,19 @@ public class BoatCustomizeController implements Initializable{
@FXML
private JFXTextField boatName;
@FXML
void colorChanged(ActionEvent event) {
Color color = colorPicker.getValue();
private Pane boatPane;
@FXML
void colorChanged() {
refreshBoat();
}
//---------FXML END---------//
private ClientToServerThread socketThread;
private LobbyController lobbyController;
private BoatMeshType currentBoat;
@Override
public void initialize(URL location, ResourceBundle resources) {
submitBtn.setOnMouseReleased(event -> {
Sounds.playButtonClick();
submitCustomization();
});
socketThread = ViewManager.getInstance().getGameClient().getServerThread();
@@ -52,6 +60,13 @@ public class BoatCustomizeController implements Initializable{
playerNameLengthValidator.setMessage("Player name too long.");
boatName.setValidators(playerNameLengthValidator, playerNameReqValidator);
boatPane.setBackground(
new Background(new BackgroundFill(Color.SKYBLUE, CornerRadii.EMPTY, Insets.EMPTY)));
submitBtn.setOnMouseReleased(event -> {
Sounds.playButtonClick();
submitCustomization();
});
submitBtn.setOnMouseEntered(e -> Sounds.playHoverSound());
}
@@ -77,7 +92,10 @@ public class BoatCustomizeController implements Initializable{
colorArray[2] = (byte) blue;
socketThread.sendCustomizationRequest(CustomizeRequestType.COLOR, colorArray);
socketThread.sendCustomizationRequest(CustomizeRequestType.SHAPE, currentBoat.toString().getBytes());
lobbyController.closeCustomizationDialog();
}
}
@@ -92,4 +110,36 @@ public class BoatCustomizeController implements Initializable{
public void setParentController(LobbyController lobbyController){
this.lobbyController = lobbyController;
}
public void setCurrentBoat(BoatMeshType boatType) {
currentBoat = boatType;
displayCurrentBoat();
}
public void nextBoat() {
currentBoat = BoatMeshType.getNextBoatType(currentBoat);
displayCurrentBoat();
}
public void prevBoat() {
currentBoat = BoatMeshType.getPrevBoatType(currentBoat);
displayCurrentBoat();
}
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());
}
}
@@ -0,0 +1,38 @@
package seng302.visualiser.controllers.dialogs;
import com.jfoenix.controls.JFXButton;
import com.jfoenix.controls.JFXListView;
import java.net.URL;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.ResourceBundle;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Label;
import seng302.model.ClientYacht;
import seng302.visualiser.controllers.ViewManager;
public class FinishDialogController implements Initializable {
//--------FXML BEGIN--------//
@FXML
private Label raceFinishLabel;
@FXML
private JFXListView<Label> finishersList;
@FXML
private JFXButton playAgain;
//---------FXML END---------//
@Override
public void initialize(URL location, ResourceBundle resources) {
playAgain.setOnAction(event -> ViewManager.getInstance().goToStartView());
}
public void setFinishedBoats(ArrayList<ClientYacht> finishedBoats) {
finishersList.getItems().clear();
for (int i = 0; i < finishedBoats.size(); i++) {
finishersList.getItems().add(new Label(Integer.toString(i+1) +". " + finishedBoats.get(i).getBoatName()));
}
}
}
@@ -1,10 +1,19 @@
package seng302.visualiser.fxObjects.assets_2D;
package seng302.visualiser.fxObjects;
import javafx.geometry.Point3D;
import javafx.scene.Group;
import javafx.scene.paint.Color;
import javafx.scene.paint.Paint;
import javafx.scene.shape.*;
import javafx.scene.shape.Arc;
import javafx.scene.shape.ArcType;
import javafx.scene.shape.Polygon;
import javafx.scene.shape.Polyline;
import javafx.scene.shape.StrokeLineCap;
import javafx.scene.transform.Rotate;
import javafx.scene.transform.Translate;
import seng302.visualiser.fxObjects.assets_3D.Model;
import seng302.visualiser.fxObjects.assets_3D.ModelFactory;
import seng302.visualiser.fxObjects.assets_3D.ModelType;
// TODO: 16/08/17 this class used to be well written... FeelsBadMan. Maybe lose the ternary operators.
/**
@@ -26,6 +35,47 @@ public class MarkArrowFactory {
public static final double ARROW_HEAD_WIDTH = 6;
public static final double STROKE_WIDTH = 3;
public static Model constructEntryArrow3D (
RoundingSide roundingSide, double angle, ModelType type) {
Model entryArrow = ModelFactory.importModel(type);
double angleDeg = angle;
angle = 180 - angle;
angle = Math.toRadians(angle);
int multiplier = roundingSide == RoundingSide.STARBOARD ? 1 : -1;
double relativeX = multiplier * 5.7 * Math.sin(angle + Math.PI / 2);
double relativeY = multiplier * 5.7 * Math.cos(angle + Math.PI / 2);
double xStart = relativeX + -10 * Math.sin(angle);
double yStart = relativeY + -10 * Math.cos(angle);
entryArrow.getAssets().getTransforms().addAll(
new Translate(xStart, yStart, 0),
new Rotate(angleDeg, new Point3D(0,0,1))
);
return entryArrow;
}
public static Model constructExitArrow3D (
RoundingSide roundingSide, double angle, ModelType type) {
Model exitArrow = ModelFactory.importModel(type);
double angleDeg = angle;
angle = 180 - angle;
angle = Math.toRadians(angle);
int multiplier = roundingSide == RoundingSide.STARBOARD ? 1 : -1;
double xStart = multiplier * 5.7 * Math.sin(angle + Math.PI / 2);
double yStart = multiplier * 5.7 * Math.cos(angle + Math.PI / 2);
exitArrow.getAssets().getTransforms().addAll(
new Translate(xStart, yStart, 0),
new Rotate(angleDeg, new Point3D(0,0,1))
);
return exitArrow;
}
/**
* Creates an entry arrow group showing an arrow into and out of the rounding area. It is centered on (0, 0).
* @param roundingSide The side of the boat that will be closest to the mark.
@@ -35,48 +85,72 @@ public class MarkArrowFactory {
* @return The group containing all JavaFX objects.
*/
public static Group constructEntryArrow (RoundingSide roundingSide, double angleOfEntry,
double angleOfExit, Paint colour) {
if (roundingSide == RoundingSide.PORT && angleOfEntry < angleOfExit && Math.abs(angleOfExit - angleOfEntry) < 180) {
double angleOfExit, Paint colour) {
// Check to see if the the angle around mark would take you inside of it. (less than 180)
// If so make interior angle.
if (roundingSide == RoundingSide.PORT && angleOfEntry < angleOfExit &&
Math.abs(angleOfExit - angleOfEntry) < 180) {
return makeInteriorAngle(roundingSide, angleOfExit, angleOfEntry, colour);
} else if (roundingSide == RoundingSide.STARBOARD && angleOfEntry > angleOfExit && -Math.abs(angleOfEntry - angleOfExit) > -180) {
} else if (roundingSide == RoundingSide.STARBOARD && angleOfEntry > angleOfExit &&
-Math.abs(angleOfEntry - angleOfExit) > -180) {
return makeInteriorAngle(roundingSide, angleOfExit, angleOfEntry, colour);
}
angleOfEntry = 180 - angleOfEntry;
//Create regular exit arrow.
Group arrow = new Group();
Group exitSection = constructExitArrow(roundingSide, angleOfExit, colour);
//Reverse angles to make arc
angleOfEntry = 180 - angleOfEntry;
angleOfExit = 180 - angleOfExit;
//Maker the arc
Arc roundSection = new Arc(
0, 0, MARK_ARROW_SEPARATION, MARK_ARROW_SEPARATION,
(roundingSide == RoundingSide.PORT ? -180 : 0) + angleOfEntry,
//Where to start drawing arc from
(roundingSide == RoundingSide.PORT ? 0 : angleOfEntry),
//Which way to go around the mark. (clockwise vs anticlockwise)
roundingSide == RoundingSide.PORT ? Math.abs(angleOfExit - angleOfEntry) : -Math.abs(angleOfEntry - angleOfExit)
);
roundSection.setStrokeWidth(STROKE_WIDTH);
roundSection.setType(ArcType.OPEN);
roundSection.setStroke(colour);
roundSection.setFill(new Color(0,0,0,0));
//Revert angle to normal for line segment. Invert Port/Starboard since it is an entry arrow.
Polygon entrySection = constructLineSegment(
roundingSide == RoundingSide.PORT ? RoundingSide.STARBOARD : RoundingSide.PORT, 180 + angleOfEntry, colour
roundingSide == RoundingSide.PORT ? RoundingSide.STARBOARD : RoundingSide.PORT,
180 + angleOfEntry, colour
);
arrow.getChildren().addAll(exitSection, roundSection, entrySection);
return arrow;
}
/**
* Make an arrow when the turning is not around the outside of the mark.
*
* @param roundingSide side to round on.
* @param angleOfExit angle of entry
* @param angleOfEntry angle of exit
* @param colour colour of arrow
* @return the arrow.
*/
private static Group makeInteriorAngle (RoundingSide roundingSide, double angleOfExit, double angleOfEntry, Paint colour) {
Group arrow = new Group();
Polygon lineSegment;
//Reverse angle of exit/entry to find position between them
angleOfEntry = Math.toRadians(360 - angleOfEntry);
angleOfExit = Math.toRadians(180 - angleOfExit);
//Find start of entry arrow if it was a regular arrow.
int multiplier = roundingSide == RoundingSide.STARBOARD ? -1 : 1;
double xStart = multiplier * MARK_ARROW_SEPARATION * Math.sin(angleOfEntry + Math.PI / 2);
double yStart = multiplier * MARK_ARROW_SEPARATION * Math.cos(angleOfEntry + Math.PI / 2);
xStart = xStart + (ARROW_LENGTH * Math.sin(angleOfEntry));
yStart = yStart + (ARROW_LENGTH * Math.cos(angleOfEntry));
//Find of end exit arrow if it was a regular arrow.
multiplier = roundingSide == RoundingSide.STARBOARD ? 1 : -1;
double xEnd = multiplier * MARK_ARROW_SEPARATION * Math.sin(angleOfExit + Math.PI / 2);
double yEnd = multiplier * MARK_ARROW_SEPARATION * Math.cos(angleOfExit + Math.PI / 2);
xEnd = xEnd + (ARROW_LENGTH * Math.sin(angleOfExit));
yEnd = yEnd + (ARROW_LENGTH * Math.cos(angleOfExit));
//Make line between these points.
lineSegment = new Polygon(
xStart, yStart,
xEnd, yEnd
@@ -85,12 +159,14 @@ public class MarkArrowFactory {
lineSegment.setFill(Color.BLUE);
lineSegment.setStrokeWidth(STROKE_WIDTH);
lineSegment.setStrokeLineCap(StrokeLineCap.ROUND);
//Make arrow head at the angle between these points.
Polyline arrowHead = constructArrowHead(
90 + Math.toDegrees(Math.atan2(yStart - yEnd, xEnd - xStart)),
colour
);
arrowHead.setLayoutX(xEnd);
arrowHead.setLayoutY(yEnd);
//Construct arrow.
arrow.getChildren().addAll(lineSegment, arrowHead);
return arrow;
}
@@ -113,6 +189,15 @@ public class MarkArrowFactory {
return arrow;
}
/**
* Constructs a line rotated to the correct angle and and in the correct position for a mark at
* position 0,0. Note that a line segment is assumed to be facing away from the mark so for
* entry Starboard make the RoundingSide Port and vice versa.
* @param roundingSide Rounding side of an exit arrow. (Reversed for entry)
* @param angle Angle of line segment.
* @param colour the desired colour of the line.
* @return Line segmented at correct rotation centered at (0,0)
*/
private static Polygon constructLineSegment (RoundingSide roundingSide, double angle, Paint colour) {
Polygon lineSegment;
angle = Math.toRadians(angle);
@@ -122,8 +207,8 @@ public class MarkArrowFactory {
double xEnd = xStart + (ARROW_LENGTH * Math.sin(angle));
double yEnd = yStart + (ARROW_LENGTH * Math.cos(angle));
lineSegment = new Polygon(
xStart, yStart,
xEnd, yEnd
xStart, yStart,
xEnd, yEnd
);
lineSegment.setStroke(colour);
lineSegment.setFill(Color.BLUE);
@@ -132,6 +217,12 @@ public class MarkArrowFactory {
return lineSegment;
}
/**
* Constructs a PolyLine in the shape of an arrow head.
* @param rotation direction for the arrow head to point.
* @param colour colour of the arrow head
* @return the arrowhead shaped PolyLine.
*/
private static Polyline constructArrowHead (double rotation, Paint colour) {
Polyline arrow = new Polyline(
-ARROW_HEAD_WIDTH, -ARROW_HEAD_DEPTH,
@@ -1,460 +0,0 @@
package seng302.visualiser.fxObjects.assets_2D;
import javafx.application.Platform;
import javafx.beans.property.ReadOnlyDoubleWrapper;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.geometry.Point2D;
import javafx.geometry.Point3D;
import javafx.scene.AmbientLight;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.PointLight;
import javafx.scene.paint.Color;
import javafx.scene.paint.PhongMaterial;
import javafx.scene.shape.Line;
import javafx.scene.shape.Polygon;
import javafx.scene.shape.Polyline;
import javafx.scene.shape.Shape3D;
import javafx.scene.transform.Rotate;
import javafx.scene.transform.Scale;
import javafx.scene.transform.Translate;
import seng302.visualiser.fxObjects.assets_3D.BoatMeshType;
import seng302.visualiser.fxObjects.assets_3D.BoatModel;
import seng302.visualiser.fxObjects.assets_3D.ModelFactory;
import seng302.visualiser.fxObjects.assets_3D.ModelType;
import java.util.ArrayList;
import java.util.List;
/**
* 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,
* a wake object and two text labels to annotate the boat teams name and the boats velocity. The
* 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
* maximised.
*/
public class BoatObject extends Group {
private static final double MODEL_SCALE_FACTOR = 400;
private static final double MODEL_X_OFFSET = 0; // standard
private static final double MODEL_Y_OFFSET = 0; // standard
private static final int VIEWPORT_SIZE = 800;
private static final Color lightColor = Color.rgb(244, 255, 250);
private static final Color jewelColor = Color.rgb(0, 190, 222);
@FunctionalInterface
public interface SelectedBoatListener {
void notifySelected(BoatObject boatObject, Boolean isSelected);
}
//Constants for drawing
private static final float BOAT_HEIGHT = 15f;
private static final float BOAT_WIDTH = 10f;
private double xVelocity;
private double yVelocity;
private double lastHeading;
private double sailState;
//Graphical objects
private Polyline trail = new Polyline();
private BoatModel boatAssets;
private Polygon sail;
private Group wake;
private Line leftLayLine;
private Line rightLayline;
private double distanceTravelled, lastRotation;
private Point2D lastPoint;
private Color colour = Color.BLACK;
private Boolean isSelected = false, destinationSet; //All boats are initialised as selected
private boolean isPlayer = false;
private Rotate rotation = new Rotate(0,0,1);
private List<SelectedBoatListener> selectedBoatListenerListeners = new ArrayList<>();
/**
* Creates a BoatGroup with the default triangular boat polygon.
*/
public BoatObject() {
this(-BOAT_WIDTH / 2, BOAT_HEIGHT / 2,
0.0, -BOAT_HEIGHT / 2,
BOAT_WIDTH / 2, BOAT_HEIGHT / 2);
}
/**
* Creates a BoatGroup with the boat being the default polygon. The head of the boat should be
* at point (0,0).
*
* @param points An array of co-ordinates x1,y1,x2,y2,x3,y3... that will make up the boat
* polygon.
*/
public BoatObject(double... points) {
initChildren(points);
}
/**
* Creates the javafx objects that will be the in the group by default.
*
* @param points An array of co-ordinates x1,y1,x2,y2,x3,y3... that will make up the boat
* polygon.
*/
private void initChildren(double... points) {
boatAssets = ModelFactory.boatGameView(BoatMeshType.DINGHY, colour);
boatAssets.hideSail();
boatAssets.getAssets().getTransforms().addAll(
// new Rotate(-40, new Point3D(1,0,0)),
rotation
// new Rotate(-90, new Point3D(0,0,1))
);
boatAssets.getAssets().getTransforms().add(new Scale(5, 5, 5));
// boatAssets.setDrawMode(DrawMode.FILL);
// boatAssets.setFill(colour);
// boatAssets.setFill(this.colour);
// boatAssets.setMaterial(new PhongMaterial(this.colour));
boatAssets.getAssets().setOnMouseEntered(event -> {
// boatAssets.setFill(Color.FLORALWHITE);
// boatAssets.setStroke(Color.RED);
// boatAssets.setMaterial(new PhongMaterial(Color.FLORALWHITE));
});
boatAssets.getAssets().setOnMouseExited(event -> {
// boatAssets.setMaterial(new PhongMaterial(this.colour));
// boatAssets.setFill(colour);
// boatAssets.setFill(this.colour);
// boatAssets.setStroke(Color.BLACK);
});
boatAssets.getAssets().setOnMouseClicked(event -> setIsSelected(!isSelected));
boatAssets.getAssets().setCache(true);
// boatAssets.setCacheHint(CacheHint.SPEED);
// annotationBox = new AnnotationBox();
// annotationBox.setFill(colour);
leftLayLine = new Line();
rightLayline = new Line();
trail.getStrokeDashArray().setAll(5d, 10d);
trail.setCache(true);
wake = ModelFactory.importModel(ModelType.WAKE).getAssets();
sail = new Polygon(0.0,BOAT_HEIGHT / 4,
0.0, BOAT_HEIGHT);
sailState = 0;
sail.setStrokeWidth(2.0);
sail.setStroke(Color.BLACK);
sail.setFill(Color.TRANSPARENT);
sail.setCache(true);
super.getChildren().clear();
PointLight pointLight = new PointLight(Color.WHITE);
// pointLight.setLightOn(true);
pointLight.getTransforms().add(new Translate(0, 0, -30));
super.getChildren().add(pointLight);
// pointLight = new PointLight(Color.WHITE);
//// pointLight.setLightOn(true);
// pointLight.getTransforms().add(new Translate(50, 50, -20));
// super.getChildren().add(pointLight);
// pointLight = new PointLight(Color.WHITE);
//// pointLight.setLightOn(true);
// pointLight.getTransforms().add(new Translate(50, -50, -20));
// super.getChildren().add(pointLight);
// pointLight = new PointLight(Color.WHITE);
//// pointLight.setLightOn(true);
// pointLight.getTransforms().add(new Translate(-50, -50, -20));
// super.getChildren().add(pointLight);
AmbientLight light = new AmbientLight(new Color(0.5,0.5,0.5,1));
super.getChildren().add(light);
super.getChildren().addAll(boatAssets.getAssets());
}
public void setFill (Color value) {
this.colour = value;
PhongMaterial pm = new PhongMaterial(this.colour);
pm.setSpecularPower(0.5);
pm.setSpecularColor(Color.BLACK);
for (int i=0;i<2;i++) {
Shape3D s = (Shape3D) boatAssets.getAssets().getChildren().get(i);
s.setMaterial(pm);
}
trail.setStroke(colour);
}
/**
* Moves the boat and its children annotations to coordinates specified
* @param x The X coordinate to move the boat to
* @param y The Y coordinate to move the boat to
* @param rotation The rotation by which the boat moves
* @param velocity The velocity the boat is moving
* @param sailIn Boolean to toggle sail state.
* @param 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(() -> {
rotateTo(rotation, sailIn, windDir);
boatAssets.getAssets().setLayoutX(x);
boatAssets.getAssets().setLayoutY(y);
// if (sailIn) {
//// sail.getPoints().clear();
//// sail.getPoints().addAll(0.0, 0.0, 4.0, 1.5, 8.0, 3.0, 12.0, 3.5, 16.0, 3.0, 20.0, 1.5, 24.0, 0.0);
//// sail.getPoints().addAll(0.0, 0.0, 24.0, 0.0);
// sail.setLayoutX(x);
// sail.setLayoutY(y);
// } else {
//// animateSail();
// sail.setLayoutX(x);
// sail.setLayoutY(y);
// }
wake.setLayoutX(x);
wake.setLayoutY(y);
});
// wake.setRotation(rotation, velocity);
// rotateTo(rotation);
// boatAssets.setLayoutX(x);
// boatAssets.setLayoutY(y);
// wake.setLayoutX(x);
// wake.setLayoutY(y);
// wake.rotate(rotation);
// wake.setRotation(rotation, groundSpeed);
// isStopped = false;
// destinationSet = true;
lastRotation = rotation;
distanceTravelled += Math.sqrt((dx * dx) + (dy * dy));
if (distanceTravelled > 15 && isPlayer) {
distanceTravelled = 0d;
Platform.runLater(() -> trail.getPoints().addAll(x, y));
}
}
private Double normalizeHeading(double heading, double windDirection) {
Double normalizedHeading = heading - windDirection;
normalizedHeading = (double) Math.floorMod(normalizedHeading.longValue(), 360L);
return normalizedHeading;
}
private void rotateTo(double heading, boolean sailsIn, double windDir) {
rotation.setAngle(heading);
wake.getTransforms().setAll(new Rotate(heading, new Point3D(0,0,1)));
if (sailsIn) {
boatAssets.showSail();
Double sailWindOffset = 30.0;
Double upwindAngleLimit = 15.0;
Double downwindAngleLimit = 10.0; //Upwind from normalised horizontal
Double normalizedHeading = normalizeHeading(heading, windDir);
if (normalizedHeading < 180) {
if (normalizedHeading < sailWindOffset + upwindAngleLimit){
boatAssets.rotateSail(-heading + 90 - upwindAngleLimit);
} else if (normalizedHeading > 90 + sailWindOffset){
boatAssets.rotateSail(-heading + downwindAngleLimit);
} else {
boatAssets.rotateSail(-heading + 90 + sailWindOffset);
}
} else {
// if (normalizedHeading > 360 - (sailWindOffset + upwindAngleLimit)){
// boatAssets.rotateSail(-heading + 90 + upwindAngleLimit);
// } else if (normalizedHeading < 270 - sailWindOffset){
// boatAssets.rotateSail(-heading + 180 - downwindAngleLimit);
// } else {
// boatAssets.rotateSail(-heading + 90 - sailWindOffset);
// }
}
} else {
boatAssets.hideSail();
}
}
private void animateSail(){
Double[] points = new Double[200];
double amplitude = 2.0;
double period = 10;
for (int i = 0; i < 50; i++) {
points[i * 2] = amplitude * Math.sin(((Math.PI * i) / period + sailState));
points[i * 2 + 1] = (double) (BOAT_HEIGHT * i) / BOAT_HEIGHT / 2;
points[199 - (i * 2)] = (double) (BOAT_HEIGHT * i) / BOAT_HEIGHT / 2;
points[199 - (i * 2 + 1)] = amplitude * Math.sin(((Math.PI * i) / period + sailState));
}
if (sailState == - 2 * Math.PI) {
sailState = 0;
} else {
sailState = sailState - Math.PI / 5;
}
sail.getPoints().clear();
sail.getPoints().addAll(points);
}
public void updateLocation() {
// boatAssets.getTransforms().add(new Rotate(2, new Point3D(1,1,1)));
// double dx = xVelocity / 60;
// double dy = yVelocity / 60;
//
// distanceTravelled += Math.abs(dx) + Math.abs(dy);
// moveGroupBy(dx, dy);
//
// if (distanceTravelled > 70) {
// distanceTravelled = 0d;
//
// if (lastPoint != null) {
// Line l = new Line(
// lastPoint.getX(),
// lastPoint.getY(),
// boatAssets.getLayoutX(),
// boatAssets.getLayoutY()
// );
// l.getStrokeDashArray().setAll(3d, 7d);
// l.setStroke(colour);
// l.setCache(true);
// l.setCacheHint(CacheHint.SPEED);
// lineGroup.getChildren().add(l);
// }
// lastPoint = new Point2D(boatAssets.getLayoutX(), boatAssets.getLayoutY());
// }
// wake.updatePosition();
}
// /**
// * This function works out if a boat is going upwind or down wind. It looks at the boats current position, the next
// * gates position and the current wind
// * If bot the wind vector from the next gate and the boat from the next gate lay on the same side, then the boat is
// * going up wind, if they are on different sides of the gate, then the boat is going downwind
// * @param canvasController
// */
// public Boolean isUpwindLeg(GameViewController canvasController, Mark nextMark) {
//
// Double windAngle = StreamParser.getWindDirection();
// GateMark thisGateMark = (GateMark) nextMark;
// SingleMark nextMark1 = thisGateMark.getSingleMark1();
// SingleMark nextMark2 = thisGateMark.getSingleMark2();
// Point2D nextMarkPoint1 = canvasController.findScaledXY(nextMark1.getLatitude(), nextMark1.getLongitude());
// Point2D nextMarkPoint2 = canvasController.findScaledXY(nextMark2.getLatitude(), nextMark2.getLongitude());
//
// Point2D boatCurrentPoint = new Point2D(boatAssets.getLayoutX(), boatAssets.getLayoutY());
// Point2D windTestPoint = GeoUtility.makeArbitraryVectorPoint(nextMarkPoint1, windAngle, 10d);
//
//
// Integer boatLineFuncResult = GeoUtility.lineFunction(nextMarkPoint1, nextMarkPoint2, boatCurrentPoint);
// Integer windLineFuncResult = GeoUtility.lineFunction(nextMarkPoint1, nextMarkPoint2, windTestPoint);
//
//
// /*
// If both the wind vector from the gate and the boat from the gate are on the same side of that gate, then the
// boat is travelling into the wind. thus upwind. Otherwise if they are on different sides, then the boat is going
// with the wind.
// */
// return boatLineFuncResult.equals(windLineFuncResult);
// return true;
// }
public void setIsSelected(Boolean isSelected) {
updateListener(isSelected);
this.isSelected = isSelected;
setLineGroupVisible(isSelected);
setWakeVisible(isSelected);
setLayLinesVisible(isSelected);
}
public void setVisibility (boolean teamName, boolean velocity, boolean estTime, boolean legTime,
boolean trail, boolean wake) {
// boatAnnotations.setVisible(teamName, velocity, estTime, legTime);
// this.wake.setVisible(wake);
this.trail.setVisible(trail);
}
public void setLineGroupVisible(Boolean visible) {
trail.setVisible(visible);
}
public void setWakeVisible(Boolean visible) {
// wake.setVisible(visible);
}
public void setLayLinesVisible(Boolean visible) {
leftLayLine.setVisible(visible);
rightLayline.setVisible(visible);
}
public void setLaylines(Line line1, Line line2) {
this.leftLayLine = line1;
this.rightLayline = line2;
}
public ArrayList<Line> getLaylines() {
ArrayList<Line> laylines = new ArrayList<>();
laylines.add(leftLayLine);
laylines.add(rightLayline);
return laylines;
}
public Group getWake () {
return wake;
}
public Node getTrail() {
return trail;
}
public Double getBoatLayoutX() {
return boatAssets.getAssets().getLayoutX();
}
public Double getBoatLayoutY() {
return boatAssets.getAssets().getLayoutY();
}
/**
* Sets this boat to appear highlighted
*/
public void setAsPlayer() {
// boatAssets.getPoints().setAll(
// -BOAT_WIDTH / 1.75, BOAT_HEIGHT / 1.75,
// 0.0, -BOAT_HEIGHT / 1.75,
// BOAT_WIDTH / 1.75, BOAT_HEIGHT / 1.75
// );
// boatAssets.setStroke(Color.BLACK);
// boatAssets.setStrokeWidth(2);
// boatAssets.setStrokeLineCap(StrokeLineCap.ROUND);
isPlayer = true;
animateSail();
}
public void setTrajectory(double heading, double velocity, double windDir) {
// wake.r(lastHeading - heading, velocity);
// rotateTo(heading, false, windDir);
xVelocity = Math.cos(Math.toRadians(heading)) * velocity;
yVelocity = Math.sin(Math.toRadians(heading)) * velocity;
lastHeading = heading;
}
public Boolean getSelected() {
return isSelected;
}
public void setTrajectory(double heading, double velocity, double scaleFactorX, double scaleFactorY) {
// wake.setRotation(lastHeading - heading, velocity);
// rotateTo(heading);
// xVelocity = Math.cos(Math.toRadians(heading)) * velocity * scaleFactorX;
// yVelocity = Math.sin(Math.toRadians(heading)) * velocity * scaleFactorY;
lastHeading = heading;
}
private void updateListener(Boolean isSelected) {
for (SelectedBoatListener sbl : selectedBoatListenerListeners) {
sbl.notifySelected(this, isSelected);
}
}
public void addSelectedBoatListener(SelectedBoatListener sbl) {
selectedBoatListenerListeners.add(sbl);
}
}
@@ -7,6 +7,7 @@ import javafx.scene.Group;
import javafx.scene.paint.Color;
import javafx.scene.paint.Paint;
import javafx.scene.shape.Circle;
import seng302.visualiser.fxObjects.MarkArrowFactory;
/**
* Visual object for a mark. Contains a coloured circle and any specified arrows.
@@ -2,21 +2,54 @@ package seng302.visualiser.fxObjects.assets_3D;
/**
* 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.
*/
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),
CAT_ATE_A_MERINGUE("catamaran_hull.stl", "catamaran_mast.stl", 0.997, "catamaran_sail.stl",
0.997, null, false),
PIRATE_SHIP("pirateship_hull.stl", "pirateship_mast.stl", -0.5415, "pirateship_mainsail.stl",
-0.5415, "pirateship_frontsail.stl", true);
final String hullFile, mastFile, sailFile;
final String hullFile, mastFile, sailFile, jibFile;
final double mastOffset, sailOffset;
final boolean fixedSail;
final static BoatMeshType[] boatTypes = new BoatMeshType[]{DINGHY, CAT_ATE_A_MERINGUE, 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) {
this.hullFile = hullFile;
this.mastFile = mastFile;
this.mastOffset = mastOffset;
this.sailFile = sailFile;
this.sailOffset = sailOffset;
this.jibFile = jibFile;
this.fixedSail = fixedSail;
}
//TODO kre39 make something not terrible to cycle through boat types
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
*/
public void rotateSail(double degrees) {
MeshView mast = getMeshViewChild(MAST_INDEX);
MeshView sail = getMeshViewChild(SAIL_INDEX);
mast.getTransforms().setAll(
new Rotate(degrees, -meshType.mastOffset, 0,0, new Point3D(0, 0, 1))
);
sail.getTransforms().setAll(
new Rotate(degrees, -meshType.sailOffset, 0,0, new Point3D(0, 0, 1))
);
if (!meshType.fixedSail) {
MeshView mast = getMeshViewChild(MAST_INDEX);
MeshView sail = getMeshViewChild(SAIL_INDEX);
mast.getTransforms().setAll(
new Rotate(degrees, 0, -meshType.mastOffset, 0, new Point3D(0, 0, 1))
);
sail.getTransforms().setAll(
new Rotate(degrees, 0, -meshType.sailOffset,0, new Point3D(0, 0, 1))
);
}
}
public void hideSail() {
@@ -58,7 +60,7 @@ public class BoatModel extends Model {
*/
public void changeColour(Color newColour) {
changeColourChild(HULL_INDEX, newColour);
changeColourChild(SAIL_INDEX, newColour);
changeColourChild(MAST_INDEX, newColour);
}
private void changeColourChild(int index, Color newColour) {
@@ -0,0 +1,133 @@
package seng302.visualiser.fxObjects.assets_3D;
import java.util.ArrayList;
import java.util.List;
import javafx.application.Platform;
import javafx.geometry.Point3D;
import javafx.scene.Group;
import javafx.scene.paint.Color;
import javafx.scene.transform.Rotate;
/**
* 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,
* 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
* minimized in which case it attempts to store animations and apply them when the window is
* maximised.
*/
public class BoatObject extends Group {
@FunctionalInterface
public interface SelectedBoatListener {
void notifySelected(BoatObject boatObject, Boolean isSelected);
}
private BoatModel boatAssets;
private Group wake;
private Color colour = Color.BLACK;
private Boolean isSelected = false;
private Rotate rotation = new Rotate(0, new Point3D(0,0,1));
private List<SelectedBoatListener> selectedBoatListenerListeners = new ArrayList<>();
/**
* Creates a BoatGroup with the default triangular boat polygon.
*/
public BoatObject(BoatMeshType boatMeshType) {
boatAssets = ModelFactory.boatGameView(boatMeshType, colour);
boatAssets.hideSail();
boatAssets.getAssets().getTransforms().addAll(
rotation
);
boatAssets.getAssets().setOnMouseClicked(event -> {
setIsSelected(!isSelected);
updateListeners();
});
boatAssets.getAssets().setCache(true);
wake = ModelFactory.importModel(ModelType.WAKE).getAssets();
super.getChildren().addAll(boatAssets.getAssets());
}
public void setFill (Color value) {
this.colour = value;
boatAssets.changeColour(colour);
}
/**
* Moves the boat and its children annotations to coordinates specified
* @param x The X coordinate to move the boat to
* @param y The Y coordinate to move the boat to
* @param rotation The rotation by which the boat moves
* @param velocity The velocity the boat is moving
* @param sailIn Boolean to toggle sail state.
* @param windDir .
*/
public void moveTo(double x, double y, double rotation, double velocity, Boolean sailIn, double windDir) {
Platform.runLater(() -> {
rotateTo(rotation, sailIn, windDir);
this.layoutXProperty().setValue(x);
this.layoutYProperty().setValue(y);
wake.setLayoutX(x);
wake.setLayoutY(y);
});
}
private Double normalizeHeading(double heading, double windDirection) {
Double normalizedHeading = heading - windDirection;
normalizedHeading = (double) Math.floorMod(normalizedHeading.longValue(), 360L);
return normalizedHeading;
}
private void rotateTo(double heading, boolean sailsIn, double windDir) {
rotation.setAngle(heading);
wake.getTransforms().setAll(new Rotate(heading, new Point3D(0,0,1)));
if (sailsIn) {
boatAssets.showSail();
Double sailWindOffset = 30.0;
Double upwindAngleLimit = 15.0;
Double downwindAngleLimit = 10.0; //Upwind from normalised horizontal
Double normalizedHeading = normalizeHeading(heading, windDir);
if (normalizedHeading < 180) {
if (normalizedHeading < sailWindOffset + upwindAngleLimit){
boatAssets.rotateSail(-upwindAngleLimit);
} else if (normalizedHeading > 90 + sailWindOffset){
boatAssets.rotateSail(-90 + downwindAngleLimit);
} else {
boatAssets.rotateSail(-heading + windDir + sailWindOffset);
}
} else {
if (normalizedHeading > 360 - (sailWindOffset + upwindAngleLimit)) {
boatAssets.rotateSail(upwindAngleLimit);
} else if (normalizedHeading < 270 - sailWindOffset) {
boatAssets.rotateSail(90 - downwindAngleLimit);
} else {
boatAssets.rotateSail(-heading + windDir - sailWindOffset);
}
}
} else {
boatAssets.hideSail();
}
}
public Group getWake () {
return wake;
}
public void setIsSelected(Boolean isSelected) {
this.isSelected = isSelected;
}
private void updateListeners() {
for (SelectedBoatListener sbl : selectedBoatListenerListeners) {
sbl.notifySelected(this, this.isSelected);
}
}
public void addSelectedBoatListener(SelectedBoatListener sbl) {
selectedBoatListenerListeners.add(sbl);
}
}
@@ -4,45 +4,42 @@ import java.util.ArrayList;
import java.util.List;
import javafx.application.Platform;
import javafx.scene.Group;
import javafx.scene.paint.Color;
import javafx.scene.paint.Paint;
import javafx.scene.transform.Scale;
import seng302.visualiser.fxObjects.assets_2D.MarkArrowFactory;
import seng302.visualiser.fxObjects.assets_2D.MarkArrowFactory.RoundingSide;
import seng302.visualiser.fxObjects.MarkArrowFactory;
import seng302.visualiser.fxObjects.MarkArrowFactory.RoundingSide;
/**
* Visual object for a mark. Contains a coloured circle and any specified arrows.
*/
public class Marker3D extends Group {
private Group mark = ModelFactory.importModel(ModelType.PLAIN_MARKER).getAssets();
private Paint colour = Color.BLACK;
private Model mark;
private List<Group> enterArrows = new ArrayList<>();
private List<Group> exitArrows = new ArrayList<>();
private int enterArrowIndex = 0;
private int exitArrowIndex = 0;
private ModelType markType;
private ModelType arrowType;
/**
* Creates a new Marker containing only a circle. The default colour is black.
*/
public Marker3D() {
// mark.setRadius(5);
// mark.setCenterX(0);
// mark.setCenterY(0);
Platform.runLater(() -> {
mark.getTransforms().add(new Scale(5,5,5));
this.getChildren().addAll(mark, new Group());
}); //Empty group placeholder or arrows.
}
/**
* Creates a new Marker containing only a circle of the given colour.
* @param colour the desired colour for the marker.
*/
public Marker3D(Paint colour) {
this();
this.colour = colour;
// mark.setFill(colour);
public Marker3D(ModelType modelType) {
markType = modelType;
switch (markType) {
case PLAIN_MARKER:
arrowType = ModelType.PLAIN_ARROW;
break;
case FINISH_MARKER:
arrowType = ModelType.FINISH_ARROW;
break;
case START_MARKER:
arrowType = ModelType.START_ARROW;
break;
}
mark = ModelFactory.importModel(modelType);
Platform.runLater(() ->
this.getChildren().addAll(mark.getAssets())
);
}
/**
@@ -53,13 +50,13 @@ public class Marker3D extends Group {
* @param exitAngle The angle the arrow wil point from the marker.
*/
public void addArrows(RoundingSide roundingSide, double entryAngle,
double exitAngle) {
double exitAngle) {
//Change Color.GRAY to this.colour to revert all gray arrows.
enterArrows.add(
MarkArrowFactory.constructEntryArrow(roundingSide, entryAngle, exitAngle, Color.GRAY)
MarkArrowFactory.constructEntryArrow3D(roundingSide, entryAngle, arrowType).getAssets()
);
exitArrows.add(
MarkArrowFactory.constructExitArrow(roundingSide, exitAngle, Color.GRAY)
MarkArrowFactory.constructExitArrow3D(roundingSide, exitAngle, arrowType).getAssets()
);
}
@@ -81,12 +78,9 @@ public class Marker3D extends Group {
private void showArrow(List<Group> arrowList, int arrowListIndex) {
if (arrowListIndex < arrowList.size()) {
if (arrowListIndex == 1) {;
}
Platform.runLater(() -> {
this.getChildren().remove(1);
this.getChildren().add(arrowList.get(arrowListIndex));
});
Platform.runLater(() ->
this.getChildren().setAll(mark.getAssets(), arrowList.get(arrowListIndex))
);
}
}
@@ -94,6 +88,6 @@ public class Marker3D extends Group {
* Hides all arrows.
*/
public void hideAllArrows() {
Platform.runLater(() -> this.getChildren().setAll(mark, new Group()));
Platform.runLater(() -> this.getChildren().setAll(mark.getAssets()));
}
}
@@ -8,10 +8,10 @@ import javafx.scene.Group;
*/
public class Model {
AnimationTimer animationTimer;
Group assets;
protected AnimationTimer animationTimer;
protected Group assets;
Model (Group assets, AnimationTimer animation) {
public Model (Group assets, AnimationTimer animation) {
this.assets = assets;
this.animationTimer = animation;
if (animation != null) {
@@ -25,7 +25,7 @@ public class Model {
}
}
public void setAnimation(AnimationTimer animation) {
void setAnimation(AnimationTimer animation) {
animationTimer = animation;
if (animation != null) {
animation.start();
@@ -7,8 +7,10 @@ import javafx.geometry.Point3D;
import javafx.scene.AmbientLight;
import javafx.scene.CacheHint;
import javafx.scene.Group;
import javafx.scene.PointLight;
import javafx.scene.paint.Color;
import javafx.scene.paint.PhongMaterial;
import javafx.scene.shape.Circle;
import javafx.scene.shape.MeshView;
import javafx.scene.transform.Rotate;
import javafx.scene.transform.Scale;
@@ -17,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 {
@@ -50,6 +52,35 @@ public class ModelFactory {
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) {
Group boatAssets = getUnmodifiedBoatModel(boatType, primaryColour);
boatAssets.getTransforms().addAll(
@@ -77,27 +108,35 @@ public class ModelFactory {
public static BoatModel boatGameView(BoatMeshType boatType, Color primaryColour) {
Group boatAssets = getUnmodifiedBoatModel(boatType, primaryColour);
boatAssets.getTransforms().setAll(
new Rotate(-90, new Point3D(0,0,1)),
new Scale(0.06, 0.06, 0.06)
new Scale(0.3, 0.3, 0.3)
);
return new BoatModel(boatAssets, null, boatType);
}
private static Group getUnmodifiedBoatModel(BoatMeshType boatType, Color primaryColour) {
Group boatAssets = new Group();
MeshView hull = importFile(boatType.hullFile);
MeshView hull = importSTL(boatType.hullFile);
hull.setMaterial(new PhongMaterial(primaryColour));
MeshView mast = importFile(boatType.mastFile);
MeshView mast = importSTL(boatType.mastFile);
mast.setMaterial(new PhongMaterial(primaryColour));
MeshView sail = importFile(boatType.sailFile);
MeshView sail = importSTL(boatType.sailFile);
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;
}
private static MeshView importFile(String fileName) {
private static MeshView importSTL(String fileName) {
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());
importedFile.setCache(true);
importedFile.setCacheHint(CacheHint.SCALE_AND_ROTATE);
@@ -137,6 +176,10 @@ public class ModelFactory {
return makeTrail(assets);
case PLAYER_IDENTIFIER:
return makeIdentifierIcon(assets);
case START_ARROW:
case FINISH_ARROW:
case PLAIN_ARROW:
makeArrow(assets);
default:
return new Model(new Group(assets), null);
}
@@ -174,23 +217,17 @@ public class ModelFactory {
}
private static Model makeOcean(Group group) {
// group.setScaleY(Double.MAX_VALUE);
// group.setScaleX(Double.MAX_VALUE);
group.getTransforms().addAll(
new Rotate(90, new Point3D(1, 0, 0)),
new Scale(10,4,10)
Circle ocean = new Circle(
0,0,250, Color.SKYBLUE
);
// group.getChildren().add(new AmbientLight());
// Circle ocean = new Circle(0,0,500, Color.SKYBLUE);
// ocean.setStroke(Color.TRANSPARENT);
// group.getChildren().add(ocean);
ocean.setStroke(Color.TRANSPARENT);
group.getChildren().add(ocean);
return new Model(new Group(group), null);
}
private static Model makeBarrier(Group assets) {
assets.getTransforms().addAll(
new Rotate(90, new Point3D(1,0,0)),
new Scale(1.5,1.5,1.5)
new Rotate(90, new Point3D(1,0,0))
);
return new Model(new Group(assets), null);
}
@@ -213,7 +250,8 @@ public class ModelFactory {
private static Model makeTrail(Group trailPiece) {
trailPiece.getTransforms().addAll(
new Rotate(90, new Point3D(0,0,1))
new Rotate(-90, new Point3D(0,0,1)),
new Rotate(90, new Point3D(1,0,0))
);
return new Model(new Group(trailPiece), null);
}
@@ -225,4 +263,11 @@ public class ModelFactory {
);
return new Model(assets, null);
}
private static Model makeArrow(Group assets) {
assets.getTransforms().addAll(
new Rotate(90, new Point3D(1,0,0))
);
return new Model(new Group(assets), null);
}
}
@@ -11,7 +11,7 @@ public enum ModelType {
START_MARKER ("start_marker.dae"),
PLAIN_MARKER ("plain_marker.dae"),
MARK_AREA ("mark_area.dae"),
OCEAN ("ocean.dae"),
OCEAN (null),
BORDER_PYLON ("barrier_pole.dae"),
BORDER_BARRIER ("barrier_segment.dae"),
FINISH_LINE ("finish_line.dae"),
@@ -19,12 +19,14 @@ public enum ModelType {
GATE_LINE ("gate_line.dae"),
WAKE ("wake.dae"),
TRAIL_SEGMENT ("trail_segment.dae"),
PLAYER_IDENTIFIER ("player_identifier.dae");
PLAYER_IDENTIFIER ("player_identifier.dae"),
PLAIN_ARROW ("arrow.dae"),
START_ARROW ("start_arrow.dae"),
FINISH_ARROW ("finish_arrow.dae");
final String filename;
ModelType(String filename) {
this.filename = filename;
}
}
}
@@ -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());
}
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

After

Width:  |  Height:  |  Size: 92 KiB

Binary file not shown.
+15 -6
View File
@@ -1,13 +1,15 @@
@font-face {
src: url("DJB-Get-Digital.ttf");
src: url("digital-7-mono.ttf");
}
#timerGrid{
-fx-background-color: rgba(255, 255, 255, 0.6);
-fx-effect: -fx-pp-dropshadow-light;
}
.timer Label {
-fx-font-family: "DJB Get Digital" !important;
GridPane .timer * {
-fx-font-family: "Digital-7 Mono" !important;
-fx-font-size: 30;
}
#timerLabel{
@@ -19,19 +21,26 @@
}
#chatGridPane {
-fx-background-color: rgba(255, 255, 255, 0.6);
-fx-background-color: transparent;
}
#chatHistoryHolder {
-fx-background-color: rgba(255, 255, 255, 0.6);
-fx-effect: -fx-pp-dropshadow-light;
}
#chatInputHolder {
-fx-background-color: rgba(255, 255, 255, 0.6);
-fx-effect: -fx-pp-dropshadow-light;
}
#windGridPane {
-fx-background-color: rgba(255, 255, 255, 0.6);
-fx-effect: -fx-pp-dropshadow-light;
}
#windHolder {
-fx-background-color: -fx-pp-front-color;
-fx-background-color: rgba(255, 255, 255, 0.5);
}
#chatSend {
@@ -52,5 +61,5 @@
}
#windImageView {
-fx-image: url("/images/wind.png");
-fx-image: url("/images/wind-180.png");
}
@@ -1,6 +1,3 @@
* {
-fx-text-fill: -fx-pp-dark-text-color;
}
#submitBtn {
-fx-background-color: -fx-pp-theme-color;
@@ -23,7 +20,15 @@
-fx-font-size: 18px;
}
#boatName, #boatColorLabel, #hostDialogHeader {
-fx-text-fill: -fx-pp-dark-text-color;
}
#boatName {
-fx-font-size: 18px;
-fx-prompt-text-fill: -fx-pp-dark-text-color;
}
#boatName .error-label {
-fx-font-size: 13px;
}
@@ -0,0 +1,21 @@
#raceFinishLabel {
-fx-font-size: 23px !important;
-fx-text-fill: -fx-pp-dark-text-color;
}
#finishersList {
}
#playAgain {
-fx-background-color: -fx-pp-theme-color;
-fx-text-fill: -fx-pp-light-text-color;
-fx-font-size: 20px !important;
-fx-effect: -fx-pp-dropshadow-dark;
-fx-min-width: 130px;
}
#playAgain:hover {
-fx-font-size: 23px !important;
-fx-background-color: -fx-pp-light-theme-color;
}
Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.3 KiB

After

Width:  |  Height:  |  Size: 49 KiB

File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+100
View File
@@ -0,0 +1,100 @@
<?xml version="1.0" encoding="utf-8"?>
<COLLADA xmlns="http://www.collada.org/2005/11/COLLADASchema" version="1.4.1">
<asset>
<contributor>
<author>Blender User</author>
<authoring_tool>Blender 2.78.0 commit date:2016-09-26, commit time:12:42, hash:4bb1e22</authoring_tool>
</contributor>
<created>2017-09-11T16:51:03</created>
<modified>2017-09-11T16:51:03</modified>
<unit name="meter" meter="1"/>
<up_axis>Z_UP</up_axis>
</asset>
<library_images/>
<library_effects>
<effect id="Material_004-effect">
<profile_COMMON>
<technique sid="common">
<phong>
<emission>
<color sid="emission">0 0 0 1</color>
</emission>
<ambient>
<color sid="ambient">0 0 0 1</color>
</ambient>
<diffuse>
<color sid="diffuse">0.01173657 0.01136953 0.01164411 1</color>
</diffuse>
<specular>
<color sid="specular">0 0 0 1</color>
</specular>
<shininess>
<float sid="shininess">50</float>
</shininess>
<index_of_refraction>
<float sid="index_of_refraction">1</float>
</index_of_refraction>
</phong>
</technique>
</profile_COMMON>
</effect>
</library_effects>
<library_materials>
<material id="Material_004-material" name="Material_004">
<instance_effect url="#Material_004-effect"/>
</material>
</library_materials>
<library_geometries>
<geometry id="Plane_004-mesh" name="Plane.004">
<mesh>
<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>
<technique_common>
<accessor source="#Plane_004-mesh-positions-array" count="80" stride="3">
<param name="X" type="float"/>
<param name="Y" type="float"/>
<param name="Z" type="float"/>
</accessor>
</technique_common>
</source>
<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>
<technique_common>
<accessor source="#Plane_004-mesh-normals-array" count="114" stride="3">
<param name="X" type="float"/>
<param name="Y" type="float"/>
<param name="Z" type="float"/>
</accessor>
</technique_common>
</source>
<vertices id="Plane_004-mesh-vertices">
<input semantic="POSITION" source="#Plane_004-mesh-positions"/>
</vertices>
<polylist material="Material_004-material" count="158">
<input semantic="VERTEX" source="#Plane_004-mesh-vertices" offset="0"/>
<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>
<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>
</polylist>
</mesh>
</geometry>
</library_geometries>
<library_controllers/>
<library_visual_scenes>
<visual_scene id="Scene" name="Scene">
<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>
<instance_geometry url="#Plane_004-mesh" name="Plane">
<bind_material>
<technique_common>
<instance_material symbol="Material_004-material" target="#Material_004-material"/>
</technique_common>
</bind_material>
</instance_geometry>
</node>
</visual_scene>
</library_visual_scenes>
<scene>
<instance_visual_scene url="#Scene"/>
</scene>
</COLLADA>
File diff suppressed because one or more lines are too long
Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 202 KiB

@@ -12,7 +12,7 @@
</BoatShapes>
<Boats>
<#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}">
<GPSposition Z="0" Y="3.7" X="0" />
<MastTop Z="0" Y="6.2" X="0" />
+219 -150
View File
@@ -14,162 +14,231 @@
<?import javafx.scene.layout.RowConstraints?>
<?import javafx.scene.layout.StackPane?>
<?import javafx.scene.text.Font?>
<AnchorPane fx:id="rvAnchorPane" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" minHeight="-Infinity" minWidth="-Infinity" prefHeight="800.0" prefWidth="1200.0" style="-fx-background-color: skyblue;" xmlns="http://javafx.com/javafx/8.0.112" xmlns:fx="http://javafx.com/fxml/1" fx:controller="seng302.visualiser.controllers.RaceViewController">
<AnchorPane fx:id="rvAnchorPane" maxHeight="1.7976931348623157E308"
maxWidth="1.7976931348623157E308" minHeight="-Infinity" minWidth="-Infinity" prefHeight="800.0"
prefWidth="1200.0" style="-fx-background-color: lightblue;" xmlns="http://javafx.com/javafx/8"
xmlns:fx="http://javafx.com/fxml/1"
fx:controller="seng302.visualiser.controllers.RaceViewController">
<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">
</StackPane>
<GridPane 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">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" maxWidth="250.0" minWidth="250.0" prefWidth="250.0" />
<ColumnConstraints hgrow="SOMETIMES" maxWidth="1.7976931348623157E308" />
<ColumnConstraints hgrow="SOMETIMES" maxWidth="-Infinity" minWidth="400.0" prefWidth="400.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints maxHeight="70.0" minHeight="70.0" prefHeight="70.0" vgrow="SOMETIMES" />
<RowConstraints maxHeight="1.7976931348623157E308" vgrow="SOMETIMES" />
<RowConstraints maxHeight="200.0" minHeight="200.0" prefHeight="200.0" vgrow="SOMETIMES" />
</rowConstraints>
<children>
<GridPane id="timerGrid" fx:id="timerGrid" prefWidth="192.0" styleClass=".timer">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" maxWidth="50.0" minWidth="50.0" prefWidth="50.0" />
<ColumnConstraints hgrow="SOMETIMES" maxWidth="130.0" minWidth="130.0" prefWidth="130.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
</rowConstraints>
<opaqueInsets>
<Insets />
</opaqueInsets>
<GridPane.margin>
<Insets left="10.0" right="200.0" top="10.0" />
</GridPane.margin>
<children>
<ImageView fitHeight="40.0" fitWidth="40.0" pickOnBounds="true" preserveRatio="true" GridPane.halignment="CENTER" GridPane.valignment="CENTER">
<image>
<Image url="@../images/timer.png" />
</image>
<GridPane.margin>
<Insets />
</GridPane.margin>
</ImageView>
<Label fx:id="timerLabel" text="00:03:34" GridPane.columnIndex="1" GridPane.halignment="CENTER" GridPane.valignment="CENTER">
<font>
<Font size="21.0" />
</font>
<GridPane.margin>
<Insets />
</GridPane.margin>
</Label>
</children>
</GridPane>
<GridPane GridPane.columnIndex="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>
<children>
<Text fx:id="fpsDisplay" strokeType="OUTSIDE" strokeWidth="0.0" text="60 Fps" GridPane.columnIndex="1" GridPane.halignment="RIGHT" GridPane.valignment="CENTER">
<GridPane.margin>
<Insets right="10.0" />
</GridPane.margin>
</Text>
</children>
</GridPane>
<GridPane fx:id="chatGridPane" GridPane.columnIndex="2" GridPane.rowIndex="2">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" maxWidth="1.7976931348623157E308" minWidth="300.0" prefWidth="300.0" />
<ColumnConstraints hgrow="SOMETIMES" maxWidth="-Infinity" minWidth="100.0" prefWidth="100.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints maxHeight="1.7976931348623157E308" vgrow="SOMETIMES" />
<RowConstraints maxHeight="50.0" minHeight="50.0" prefHeight="50.0" vgrow="SOMETIMES" />
</rowConstraints>
<children>
<Pane fx:id="chatHistoryHolder" prefHeight="200.0" prefWidth="200.0" GridPane.columnSpan="2" GridPane.hgrow="ALWAYS" GridPane.vgrow="ALWAYS">
<GridPane.margin>
<Insets />
</GridPane.margin>
<padding>
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
</padding>
</Pane>
<JFXButton fx:id="chatSend" alignment="CENTER" buttonType="RAISED" maxHeight="-Infinity" maxWidth="1.7976931348623157E308" minHeight="-Infinity" minWidth="-Infinity" prefHeight="40.0" text="SEND" GridPane.columnIndex="1" GridPane.halignment="CENTER" GridPane.rowIndex="1" GridPane.valignment="CENTER">
<GridPane.margin>
<Insets left="10.0" right="10.0" />
</GridPane.margin>
</JFXButton>
<JFXTextField fx:id="chatInput" maxHeight="35.0" minHeight="-Infinity" prefHeight="35.0" GridPane.rowIndex="1">
<GridPane.margin>
<Insets left="10.0" />
</GridPane.margin>
</JFXTextField>
</children>
</GridPane>
<GridPane fx:id="windGridPane" prefHeight="161.0" prefWidth="240.0" GridPane.halignment="CENTER" GridPane.rowIndex="2" GridPane.valignment="BOTTOM">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" maxWidth="110.0" minWidth="110.0" prefWidth="110.0" />
<ColumnConstraints hgrow="SOMETIMES" maxWidth="132.0" minWidth="10.0" prefWidth="132.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints maxHeight="120.0" minHeight="120.0" prefHeight="120.0" vgrow="SOMETIMES" />
<RowConstraints maxHeight="30.0" minHeight="30.0" prefHeight="30.0" vgrow="SOMETIMES" />
</rowConstraints>
<children>
<Label fx:id="positionLabel" text="Position:" GridPane.columnIndex="1" GridPane.halignment="LEFT" GridPane.rowSpan="2" GridPane.valignment="TOP">
<padding>
<Insets bottom="5.0" left="10.0" right="5.0" top="5.0" />
</padding>
</Label>
<Label fx:id="boatSpeedLabel" text="Boat Speed:" GridPane.columnIndex="1" GridPane.halignment="LEFT" GridPane.rowSpan="2" GridPane.valignment="CENTER">
<opaqueInsets>
<Insets />
</opaqueInsets>
<padding>
<Insets bottom="5.0" left="10.0" right="5.0" top="5.0" />
</padding></Label>
<Label fx:id="boatHeadingLabel" text="Boat Heading:" GridPane.columnIndex="1" GridPane.halignment="LEFT" GridPane.rowSpan="2" GridPane.valignment="BOTTOM">
<padding>
<Insets bottom="5.0" left="10.0" right="5.0" top="5.0" />
</padding>
</Label>
<GridPane fx:id="windHolder" GridPane.rowSpan="2">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints maxHeight="120.0" minHeight="120.0" prefHeight="120.0" vgrow="SOMETIMES" />
<RowConstraints maxHeight="30.0" minHeight="30.0" prefHeight="30.0" vgrow="SOMETIMES" />
</rowConstraints>
<children>
<ImageView fx:id="windImageView" fitHeight="92.0" fitWidth="109.0" pickOnBounds="true" preserveRatio="true" GridPane.halignment="CENTER" GridPane.rowSpan="2" GridPane.valignment="CENTER" />
<Label fx:id="windSpeedLabel" text="0.0 Knots" GridPane.halignment="RIGHT" GridPane.rowIndex="1" GridPane.valignment="CENTER">
<children>
<GridPane maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308"
prefHeight="800.0" prefWidth="1200.0">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" maxWidth="250.0" minWidth="250.0"
prefWidth="250.0"/>
<ColumnConstraints hgrow="SOMETIMES" maxWidth="1.7976931348623157E308"/>
<ColumnConstraints hgrow="SOMETIMES" maxWidth="-Infinity" minWidth="400.0"
prefWidth="400.0"/>
</columnConstraints>
<rowConstraints>
<RowConstraints maxHeight="70.0" minHeight="70.0" prefHeight="70.0"
vgrow="SOMETIMES"/>
<RowConstraints maxHeight="1.7976931348623157E308" vgrow="SOMETIMES"/>
<RowConstraints maxHeight="250.0" minHeight="250.0" prefHeight="250.0"
valignment="BOTTOM" vgrow="SOMETIMES"/>
</rowConstraints>
<children>
<GridPane id="timerGrid" fx:id="timerGrid" prefWidth="192.0"
styleClass="timer">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" maxWidth="50.0" minWidth="50.0"
prefWidth="50.0"/>
<ColumnConstraints hgrow="SOMETIMES" maxWidth="135.0"
minWidth="135.0" prefWidth="135.0"/>
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="10.0" prefHeight="30.0"
vgrow="SOMETIMES"/>
</rowConstraints>
<opaqueInsets>
<Insets/>
</opaqueInsets>
<GridPane.margin>
<Insets right="5.0" />
<Insets left="10.0" right="200.0" top="10.0"/>
</GridPane.margin>
</Label>
<Label fx:id="windDirectionLabel" text="180.0°" GridPane.halignment="LEFT" GridPane.rowIndex="1" GridPane.valignment="CENTER">
<children>
<ImageView fitHeight="40.0" fitWidth="40.0" pickOnBounds="true"
preserveRatio="true" GridPane.halignment="CENTER"
GridPane.valignment="CENTER">
<image>
<Image url="@../images/timer.png"/>
</image>
<GridPane.margin>
<Insets/>
</GridPane.margin>
</ImageView>
<Label fx:id="timerLabel" text="00:03:34" GridPane.columnIndex="1"
GridPane.halignment="CENTER" GridPane.valignment="CENTER">
<font>
<Font size="21.0"/>
</font>
<GridPane.margin>
<Insets/>
</GridPane.margin>
</Label>
</children>
</GridPane>
<GridPane GridPane.columnIndex="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>
</GridPane>
<GridPane fx:id="chatGridPane" GridPane.columnIndex="2"
GridPane.rowIndex="2">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" maxWidth="390.0"
minWidth="390.0" prefWidth="390.0"/>
</columnConstraints>
<rowConstraints>
<RowConstraints maxHeight="1.7976931348623157E308"
vgrow="SOMETIMES"/>
<RowConstraints maxHeight="60.0" minHeight="60.0" prefHeight="60.0"
vgrow="SOMETIMES"/>
</rowConstraints>
<children>
<Pane fx:id="chatHistoryHolder" prefHeight="200.0" prefWidth="200.0"
GridPane.hgrow="ALWAYS" GridPane.valignment="BOTTOM"
GridPane.vgrow="ALWAYS">
<GridPane.margin>
<Insets/>
</GridPane.margin>
<padding>
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0"/>
</padding>
</Pane>
<GridPane fx:id="chatInputHolder" GridPane.rowIndex="1">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0"
prefWidth="100.0"/>
<ColumnConstraints hgrow="SOMETIMES" maxWidth="-Infinity"
minWidth="90.0" prefWidth="90.0"/>
</columnConstraints>
<rowConstraints>
<RowConstraints maxHeight="50.0" minHeight="50.0"
prefHeight="50.0" valignment="CENTER" vgrow="SOMETIMES"/>
</rowConstraints>
<children>
<JFXButton fx:id="chatSend" alignment="CENTER"
buttonType="RAISED" maxHeight="-Infinity"
maxWidth="1.7976931348623157E308" minHeight="-Infinity"
minWidth="-Infinity" prefHeight="35.0" text="SEND"
GridPane.columnIndex="1">
<GridPane.margin>
<Insets bottom="10.0" left="10.0" right="10.0"
top="10.0"/>
</GridPane.margin>
</JFXButton>
<JFXTextField fx:id="chatInput" maxHeight="35.0"
minHeight="-Infinity" prefHeight="35.0">
<GridPane.margin>
<Insets bottom="10.0" left="20.0" right="10.0"/>
</GridPane.margin>
<padding>
<Insets right="15.0"/>
</padding>
</JFXTextField>
</children>
<GridPane.margin>
<Insets top="10.0"/>
</GridPane.margin>
</GridPane>
</children>
<GridPane.margin>
<Insets left="5.0" />
<Insets bottom="10.0" right="10.0"/>
</GridPane.margin>
</Label>
</children>
</GridPane>
</children>
<opaqueInsets>
<Insets />
</opaqueInsets>
<GridPane.margin>
<Insets bottom="10.0" left="10.0" top="40.0" />
</GridPane.margin>
</GridPane>
</children>
</GridPane>
</GridPane>
<GridPane fx:id="windGridPane" maxHeight="-Infinity" maxWidth="-Infinity"
prefHeight="150.0" prefWidth="240.0" GridPane.halignment="CENTER"
GridPane.rowIndex="2" GridPane.valignment="BOTTOM">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" maxWidth="110.0"
minWidth="110.0" prefWidth="110.0"/>
<ColumnConstraints hgrow="SOMETIMES" maxWidth="132.0" minWidth="10.0"
prefWidth="132.0"/>
</columnConstraints>
<rowConstraints>
<RowConstraints maxHeight="120.0" minHeight="120.0"
prefHeight="120.0" vgrow="SOMETIMES"/>
<RowConstraints maxHeight="30.0" minHeight="30.0" prefHeight="30.0"
vgrow="SOMETIMES"/>
</rowConstraints>
<children>
<Label fx:id="positionLabel" text="Position:"
GridPane.columnIndex="1" GridPane.halignment="LEFT"
GridPane.rowSpan="2" GridPane.valignment="TOP">
<padding>
<Insets bottom="5.0" left="10.0" right="5.0" top="5.0"/>
</padding>
</Label>
<Label fx:id="boatSpeedLabel" text="Boat Speed:"
GridPane.columnIndex="1" GridPane.halignment="LEFT"
GridPane.rowSpan="2" GridPane.valignment="CENTER">
<opaqueInsets>
<Insets/>
</opaqueInsets>
<padding>
<Insets bottom="5.0" left="10.0" right="5.0" top="5.0"/>
</padding>
</Label>
<Label fx:id="boatHeadingLabel" text="Boat Heading:"
GridPane.columnIndex="1" GridPane.halignment="LEFT"
GridPane.rowSpan="2" GridPane.valignment="BOTTOM">
<padding>
<Insets bottom="5.0" left="10.0" right="5.0" top="5.0"/>
</padding>
</Label>
<GridPane fx:id="windHolder" GridPane.rowSpan="2">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0"
prefWidth="100.0"/>
</columnConstraints>
<rowConstraints>
<RowConstraints maxHeight="120.0" minHeight="120.0"
prefHeight="120.0" vgrow="SOMETIMES"/>
<RowConstraints maxHeight="30.0" minHeight="30.0"
prefHeight="30.0" vgrow="SOMETIMES"/>
</rowConstraints>
<children>
<ImageView fx:id="windImageView" fitHeight="92.0"
fitWidth="109.0" pickOnBounds="true" preserveRatio="true"
GridPane.halignment="CENTER" GridPane.rowSpan="2"
GridPane.valignment="CENTER"/>
<Label fx:id="windSpeedLabel" text="0.0 Knots"
GridPane.halignment="RIGHT" GridPane.rowIndex="1"
GridPane.valignment="CENTER">
<GridPane.margin>
<Insets right="5.0"/>
</GridPane.margin>
</Label>
<Label fx:id="windDirectionLabel" text="180.0°"
GridPane.halignment="LEFT" GridPane.rowIndex="1"
GridPane.valignment="CENTER">
<GridPane.margin>
<Insets left="5.0"/>
</GridPane.margin>
</Label>
</children>
</GridPane>
</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>
<String fx:value="/css/Master.css" />
@@ -1,5 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<?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.JFXColorPicker?>
<?import com.jfoenix.controls.JFXDialogLayout?>
@@ -10,48 +15,44 @@
<?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="400.0" xmlns="http://javafx.com/javafx/8"
xmlns:fx="http://javafx.com/fxml/1"
fx:controller="seng302.visualiser.controllers.dialogs.BoatCustomizeController">
<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">
<children>
<GridPane>
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints maxHeight="90.0" minHeight="90.0" prefHeight="90.0" vgrow="SOMETIMES" />
<RowConstraints maxHeight="100.0" minHeight="100.0" prefHeight="100.0" vgrow="SOMETIMES" />
<RowConstraints maxHeight="125.0" minHeight="61.0" prefHeight="61.0" vgrow="SOMETIMES" />
<RowConstraints maxHeight="164.0" minHeight="100.0" prefHeight="164.0" vgrow="SOMETIMES" />
<RowConstraints maxHeight="90.0" minHeight="48.0" prefHeight="48.0" vgrow="SOMETIMES" />
<RowConstraints maxHeight="207.0" minHeight="93.0" prefHeight="181.0" vgrow="SOMETIMES" />
<RowConstraints maxHeight="145.0" minHeight="66.0" prefHeight="109.0" vgrow="SOMETIMES" />
<RowConstraints maxHeight="125.0" minHeight="24.0" prefHeight="72.0" vgrow="SOMETIMES" />
<RowConstraints maxHeight="164.0" minHeight="100.0" prefHeight="105.0" vgrow="SOMETIMES" />
</rowConstraints>
<children>
<Label fx:id="hostDialogHeader" text="Customize Boat" GridPane.halignment="CENTER"
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="1">
<Label fx:id="hostDialogHeader" text="Customize Boat" GridPane.halignment="CENTER" GridPane.valignment="CENTER" />
<JFXButton fx:id="submitBtn" prefHeight="45.0" prefWidth="220.0" text="Customize Boat" GridPane.halignment="CENTER" GridPane.rowIndex="4" GridPane.valignment="CENTER" />
<JFXTextField fx:id="boatName" focusColor="#6c6c6c" promptText="Boat Name" unFocusColor="#6b6b6b" GridPane.rowIndex="2">
<GridPane.margin>
<Insets left="30.0" right="30.0" />
</GridPane.margin></JFXTextField>
<GridPane GridPane.rowIndex="2">
<GridPane GridPane.halignment="CENTER" GridPane.rowIndex="3" GridPane.valignment="CENTER">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" maxWidth="139.0" minWidth="10.0" prefWidth="89.0" />
<ColumnConstraints hgrow="SOMETIMES" maxWidth="203.0" minWidth="10.0" prefWidth="203.0" />
<ColumnConstraints hgrow="SOMETIMES" maxWidth="139.0" minWidth="10.0" prefWidth="94.0" />
<ColumnConstraints hgrow="SOMETIMES" maxWidth="203.0" minWidth="10.0" prefWidth="198.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints maxHeight="69.0" minHeight="10.0" percentHeight="60.0" prefHeight="19.6" vgrow="SOMETIMES" />
<RowConstraints percentHeight="100.0" valignment="CENTER" vgrow="SOMETIMES" />
</rowConstraints>
<children>
<Label fx:id="boatColorLabel" prefHeight="25.0" prefWidth="96.0"
text="Boat Color">
<Label fx:id="boatColorLabel" prefHeight="25.0" prefWidth="96.0" text="Boat Color" GridPane.valignment="CENTER">
<GridPane.margin>
<Insets top="-10.0" />
</GridPane.margin>
</Label>
<JFXColorPicker fx:id="colorPicker" onAction="#colorChanged" GridPane.columnIndex="1">
<JFXColorPicker fx:id="colorPicker" onAction="#colorChanged" GridPane.columnIndex="1" GridPane.valignment="CENTER">
<GridPane.margin>
<Insets left="30.0" top="-10.0"/>
<Insets left="30.0" top="-10.0" />
</GridPane.margin>
</JFXColorPicker>
</children>
@@ -59,11 +60,26 @@
<Insets left="30.0" right="30.0" />
</GridPane.margin>
</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="&lt;" />
<JFXButton buttonType="RAISED" onAction="#nextBoat" prefHeight="200.0" prefWidth="50.0" text="&gt;" GridPane.columnIndex="2" />
</children>
</GridPane>
</children>
</GridPane>
</children>
<stylesheets>
<String fx:value="/css/dialogs/BoatCustomize.css"/>
<String fx:value="/css/Master.css"/>
<String fx:value="/css/dialogs/BoatCustomize.css" />
<String fx:value="/css/Master.css" />
</stylesheets>
</JFXDialogLayout>
@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import com.jfoenix.controls.JFXButton?>
<?import com.jfoenix.controls.JFXDialogLayout?>
<?import com.jfoenix.controls.JFXListView?>
<?import java.lang.String?>
<?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="400.0" xmlns="http://javafx.com/javafx/8"
xmlns:fx="http://javafx.com/fxml/1"
fx:controller="seng302.visualiser.controllers.dialogs.FinishDialogController">
<children>
<GridPane>
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0"/>
</columnConstraints>
<rowConstraints>
<RowConstraints maxHeight="90.0" minHeight="90.0" prefHeight="90.0"
vgrow="SOMETIMES"/>
<RowConstraints maxHeight="100.0" minHeight="100.0" prefHeight="100.0"
vgrow="SOMETIMES"/>
<RowConstraints maxHeight="164.0" minHeight="100.0" prefHeight="126.0"
vgrow="SOMETIMES"/>
</rowConstraints>
<children>
<JFXButton fx:id="playAgain" prefHeight="45.0" prefWidth="220.0" text="PLAY AGAIN"
GridPane.halignment="CENTER" GridPane.rowIndex="2" GridPane.valignment="CENTER"/>
<JFXListView fx:id="finishersList" GridPane.rowIndex="1"/>
<Label fx:id="raceFinishLabel" text="RACE OVER" GridPane.halignment="CENTER"
GridPane.valignment="CENTER"/>
</children>
</GridPane>
</children>
<stylesheets>
<String fx:value="/css/dialogs/FinishScreen.css"/>
<String fx:value="/css/Master.css"/>
</stylesheets>
</JFXDialogLayout>
@@ -61,7 +61,7 @@ public class ChatCommandsTest {
} catch (InterruptedException ie) {
ie.printStackTrace();
}
host.sendChatterMessage("[time_prefix] <name_prefix> >finish");
host.sendChatterMessage("[time_prefix] <name_prefix> /finish");
dcSent = true;
try {
Thread.sleep(2000);
@@ -104,7 +104,7 @@ public class ChatCommandsTest {
ie.printStackTrace();
}
mst.startGame();
host.sendChatterMessage("[time_prefix] <name_prefix> >speed 5");
host.sendChatterMessage("[time_prefix] <name_prefix> /speed 5");
try {
Thread.sleep(100);
} catch (InterruptedException ie) {
@@ -143,7 +143,7 @@ public class ChatCommandsTest {
ie.printStackTrace();
}
mst.startGame();
host.sendChatterMessage("[time_prefix] <name_prefix> >speed fdgdgdfg");
host.sendChatterMessage("[time_prefix] <name_prefix> /speed fdgdgdfg");
try {
Thread.sleep(100);
} catch (InterruptedException ie) {
@@ -188,7 +188,7 @@ public class ChatCommandsTest {
} catch (InterruptedException ie) {
ie.printStackTrace();
}
client.sendChatterMessage("[time_prefix] <name_prefix> >speed 5.0");
client.sendChatterMessage("[time_prefix] <name_prefix> /speed 5.0");
try {
Thread.sleep(200);
} catch (InterruptedException ie) {
@@ -248,7 +248,7 @@ public class ChatCommandsTest {
} catch (IOException ioe) {
ioe.printStackTrace();
}
host.sendChatterMessage("[time_prefix] <name_prefix> >finish");
host.sendChatterMessage("[time_prefix] <name_prefix> /finish");
dcSent = true;
}
}
@@ -5,6 +5,7 @@ import org.junit.Before;
import org.junit.Test;
import seng302.gameServer.GameState;
import seng302.utilities.GeoUtility;
import seng302.visualiser.fxObjects.assets_3D.BoatMeshType;
import static seng302.gameServer.GameState.checkCollision;
@@ -14,8 +15,10 @@ import static seng302.gameServer.GameState.checkCollision;
*/
public class UpdateYachtTest {
private ServerYacht yacht1 = new ServerYacht("Yacht", 1, "1", "Yacht" + 1, "Yacht" + 1, "Test1");
private ServerYacht yacht2 = new ServerYacht("Yacht", 2, "2", "Yacht" + 2, "Yacht" + 2, "Test2");
private ServerYacht yacht1 = new ServerYacht(BoatMeshType.DINGHY, 1, "1", "Yacht" + 1,
"Yacht" + 1, "Test1");
private ServerYacht yacht2 = new ServerYacht(BoatMeshType.DINGHY, 2, "2", "Yacht" + 2,
"Yacht" + 2, "Test2");
private GeoPoint geoPoint1 = new GeoPoint(50.0, 50.0);
private GeoPoint geoPoint2 = GeoUtility.getGeoCoordinate(geoPoint1, 90.0, 50.0);
+55 -61
View File
@@ -1,17 +1,10 @@
package seng302.models;
import static org.junit.Assert.assertEquals;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import javafx.util.Pair;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import seng302.gameServer.GameState;
import seng302.model.PolarTable;
import seng302.model.ServerYacht;
import seng302.visualiser.fxObjects.assets_3D.BoatMeshType;
public class YachtTest {
@@ -25,62 +18,63 @@ public class YachtTest {
@BeforeClass
public static void setUp() {
new GameState("localhost");
y1 = new ServerYacht("Yacht", 1, "Y1", "Y1", "Yacht 1", "C1");
y1 = new ServerYacht(BoatMeshType.DINGHY, 1, "Y1", "Y1", "Yacht 1", "C1");
gs = new GameState("localhost");
}
@Test
public void tackGybeTest() {
HashMap<Double, Double> values = new HashMap<>();
values.put(280.0, 80.0);
values.put(270.0, 90.0);
values.put(359.0, 1.0);
values.put(180.0, 180.0);
values.put(75.0, 285.0);
for (Double begin : values.keySet()) {
y1.setHeading(begin);
y1.tackGybe(windDirection);
for (int i = 0; i < 200; i++) {
y1.runAutoPilot();
}
assertEquals(values.get(begin), y1.getHeading(), 5.0);
}
}
@Test
public void vmgTest() {
PolarTable.parsePolarFile(getClass().getResourceAsStream("/config/acc_polars.csv"));
Double upwind = PolarTable.getOptimalUpwindVMG(windSpeed).keySet().iterator().next();
Double downwind = PolarTable.getOptimalDownwindVMG(windSpeed).keySet().iterator().next();
List<Pair<Double, Double>> values = new ArrayList<>();
upwind = (double) Math.floorMod(upwind.longValue() + windDirection.longValue(), 360L);
Double upwindRight = upwind;
Double upwindLeft = 360 - upwindRight;
downwind = (double) Math.floorMod(downwind.longValue() + windDirection.longValue(), 360L);
Double downwindRight = downwind;
Double downwindLeft = 360 - downwindRight;
values.add(new Pair<>(190d, upwindRight));
values.add(new Pair<>(170d, upwindLeft));
values.add(new Pair<>(10d, downwindLeft));
values.add(new Pair<>(350d, downwindRight));
for (Pair<Double, Double> beginEndPair : values) {
y1.setHeading(beginEndPair.getKey());
y1.turnToVMG();
for (int i = 0; i < 200; i++) {
y1.runAutoPilot();
}
y1.disableAutoPilot();
assertEquals(beginEndPair.getValue(), y1.getHeading(), 5.0);
}
}
//Commented out until can fix the weird non-deterministic bug.
// @Test
// public void tackGybeTest() {
// HashMap<Double, Double> values = new HashMap<>();
// values.put(280.0, 80.0);
// values.put(270.0, 90.0);
// values.put(359.0, 1.0);
// values.put(180.0, 180.0);
// values.put(75.0, 285.0);
//
// for (Double begin : values.keySet()) {
// y1.setHeading(begin);
// y1.tackGybe(windDirection);
//
// for (int i = 0; i < 200; i++) {
// y1.runAutoPilot();
// }
// assertEquals(values.get(begin), y1.getHeading(), 5.0);
// }
// }
//
// @Test
// public void vmgTest() {
//
// PolarTable.parsePolarFile(getClass().getResourceAsStream("/config/acc_polars.csv"));
// Double upwind = PolarTable.getOptimalUpwindVMG(windSpeed).keySet().iterator().next();
// Double downwind = PolarTable.getOptimalDownwindVMG(windSpeed).keySet().iterator().next();
//
// List<Pair<Double, Double>> values = new ArrayList<>();
//
// upwind = (double) Math.floorMod(upwind.longValue() + windDirection.longValue(), 360L);
// Double upwindRight = upwind;
// Double upwindLeft = 360 - upwindRight;
// downwind = (double) Math.floorMod(downwind.longValue() + windDirection.longValue(), 360L);
// Double downwindRight = downwind;
// Double downwindLeft = 360 - downwindRight;
//
// values.add(new Pair<>(190d, upwindRight));
// values.add(new Pair<>(170d, upwindLeft));
// values.add(new Pair<>(10d, downwindLeft));
// values.add(new Pair<>(350d, downwindRight));
//
// for (Pair<Double, Double> beginEndPair : values) {
// y1.setHeading(beginEndPair.getKey());
// y1.turnToVMG();
// for (int i = 0; i < 200; i++) {
// y1.runAutoPilot();
// }
// y1.disableAutoPilot();
// assertEquals(beginEndPair.getValue(), y1.getHeading(), 5.0);
// }
//
// }
@AfterClass
@@ -0,0 +1,28 @@
package seng302.utilities;
import org.junit.Assert;
import org.junit.Test;
import seng302.visualiser.fxObjects.assets_3D.BoatMeshType;
/**
* Basic tests for the next and previous methods
* Created by kre39 on 20/09/17.
*/
public class BoatMeshTypeTest {
@Test
public void testNextBoatMeshType() {
BoatMeshType currentBoat = BoatMeshType.DINGHY;
BoatMeshType nextBoat = BoatMeshType.getNextBoatType(currentBoat);
Assert.assertEquals(BoatMeshType.CAT_ATE_A_MERINGUE, nextBoat);
}
@Test
public void testPreviousBoatMeshType() {
BoatMeshType currentBoat = BoatMeshType.CAT_ATE_A_MERINGUE;
BoatMeshType prevBoat = BoatMeshType.getPrevBoatType(currentBoat);
Assert.assertEquals(BoatMeshType.DINGHY, prevBoat);
}
}
@@ -6,6 +6,7 @@ import static org.junit.Assert.assertTrue;
import org.junit.Before;
import org.junit.Test;
import seng302.model.ClientYacht;
import seng302.visualiser.fxObjects.assets_3D.BoatMeshType;
/**
* Created by kre39 on 6/08/17.
@@ -16,7 +17,7 @@ public class BoatSailAnimationToggleTest {
@Before
public void setup() throws Exception{
yacht = new ClientYacht("Yacht", 1, "YACHT", "YAC", "Test Yacht", "NZ");
yacht = new ClientYacht(BoatMeshType.DINGHY, 1, "YACHT", "YAC", "Test Yacht", "NZ");
}
@Test
+11
View File
@@ -24,7 +24,17 @@ public class ToggleSailSteps {
@Given("^The game is running$")
public void the_game_is_running() throws Throwable {
mst = new MainServerThread();
try {
Thread.sleep(100);
} catch (InterruptedException ie) {
ie.printStackTrace();
}
client = new ClientToServerThread("localhost", 4942);
try {
Thread.sleep(100);
} catch (InterruptedException ie) {
ie.printStackTrace();
}
GameState.setCurrentStage(GameStages.RACING);
Thread.sleep(200); // Sleep needed to help the threads all be up to speed with each other
ServerYacht yacht = (new ArrayList<>(GameState.getYachts().values())).get(0);
@@ -50,5 +60,6 @@ public class ToggleSailSteps {
Assert.assertFalse(yacht.getSailIn());
}
mst.terminate();
client.setSocketToClose();
}
}