diff --git a/src/main/java/seng302/gameServer/GameState.java b/src/main/java/seng302/gameServer/GameState.java index bc3fb188..790817e0 100644 --- a/src/main/java/seng302/gameServer/GameState.java +++ b/src/main/java/seng302/gameServer/GameState.java @@ -9,7 +9,17 @@ import java.util.List; import java.util.Map; import java.util.Random; import java.util.Set; +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 seng302.gameServer.messages.BoatAction; @@ -27,6 +37,23 @@ import seng302.model.Limit; import seng302.model.Player; import seng302.model.PolarTable; import seng302.model.ServerYacht; +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.model.mark.CompoundMark; import seng302.model.mark.Mark; import seng302.model.mark.MarkOrder; @@ -34,6 +61,8 @@ import seng302.model.stream.xml.parser.RaceXMLData; import seng302.model.token.Token; import seng302.model.token.TokenType; import seng302.utilities.GeoUtility; +import seng302.utilities.XMLParser; +import seng302.visualiser.fxObjects.assets_3D.BoatMeshType; /** * A Static class to hold information about the current state of the game (model) @@ -237,7 +266,6 @@ public class GameState implements Runnable { System.out.println("[GameState] interrupted exception"); } if (currentStage == GameStages.PRE_RACE || currentStage == GameStages.RACING) { -// System.out.println("update"); update(); } } @@ -264,6 +292,12 @@ public class GameState implements Runnable { case DOWNWIND: playerYacht.turnDownwind(); break; + case CONTINUOUSLY_TURNING: + playerYacht.setContinuouslyTurning(true); + break; + case DEFAULT_TURNING: + playerYacht.setContinuouslyTurning(false); + break; } } @@ -442,8 +476,7 @@ public class GameState implements Runnable { private void updateVelocity(ServerYacht yacht) { Double trueWindAngle = Math.abs(windDirection - yacht.getHeading()); Double boatSpeedInKnots = PolarTable.getBoatSpeed(getWindSpeedKnots(), trueWindAngle); - Double maxBoatSpeed = GeoUtility.knotsToMMS(boatSpeedInKnots) * speedMultiplier; - System.out.println(maxBoatSpeed); + Double maxBoatSpeed = GeoUtility.knotsToMMS(boatSpeedInKnots) * speedMultiplier * yacht.getMaxSpeedMultiplier(); if (yacht.getPowerUp() != null) { if (yacht.getPowerUp().equals(TokenType.BOOST)) { // TODO: 11/09/17 wmu16 CHANGE THIS TO MAGIC NUMBER @@ -455,17 +488,17 @@ public class GameState implements Runnable { // TODO: 15/08/17 remove magic numbers from these equations. if (yacht.getSailIn()) { if (currentVelocity < maxBoatSpeed - 500) { - yacht.changeVelocity(maxBoatSpeed / 100); + yacht.changeVelocity((maxBoatSpeed / 100) * yacht.getAccelerationMultiplier()); } else if (currentVelocity > maxBoatSpeed + 500) { - yacht.changeVelocity(-currentVelocity / 200); + yacht.changeVelocity((-currentVelocity / 200) * yacht.getAccelerationMultiplier()); } else { - yacht.setCurrentVelocity(maxBoatSpeed); + yacht.setCurrentVelocity((maxBoatSpeed) * yacht.getAccelerationMultiplier()); } } else { if (currentVelocity > 3000) { - yacht.changeVelocity(-currentVelocity / 200); + yacht.changeVelocity((-currentVelocity / 200) * yacht.getAccelerationMultiplier()); } else if (currentVelocity > 100) { - yacht.changeVelocity(-currentVelocity / 50); + yacht.changeVelocity((-currentVelocity / 50) * yacht.getAccelerationMultiplier()); } else if (currentVelocity <= 100) { yacht.setCurrentVelocity(0d); } @@ -696,6 +729,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)); } } diff --git a/src/main/java/seng302/gameServer/ServerToClientThread.java b/src/main/java/seng302/gameServer/ServerToClientThread.java index 60bbb9e4..29c892a3 100644 --- a/src/main/java/seng302/gameServer/ServerToClientThread.java +++ b/src/main/java/seng302/gameServer/ServerToClientThread.java @@ -30,6 +30,7 @@ import seng302.model.stream.xml.parser.RaceXMLData; import seng302.model.stream.xml.parser.RegattaXMLData; import seng302.utilities.StreamParser; import seng302.utilities.XMLGenerator; +import seng302.visualiser.fxObjects.assets_3D.BoatMeshType; import seng302.utilities.XMLParser; /** @@ -104,7 +105,7 @@ public class ServerToClientThread implements Runnable { String fName = "Player " + GameState.getNumberOfPlayers().toString(); String lName = ""; 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); diff --git a/src/main/java/seng302/gameServer/messages/BoatAction.java b/src/main/java/seng302/gameServer/messages/BoatAction.java index 9003958a..9bd2131f 100644 --- a/src/main/java/seng302/gameServer/messages/BoatAction.java +++ b/src/main/java/seng302/gameServer/messages/BoatAction.java @@ -14,7 +14,9 @@ public enum BoatAction { TACK_GYBE(4), UPWIND(5), DOWNWIND(6), - MAINTAIN_HEADING(7); + MAINTAIN_HEADING(7), + CONTINUOUSLY_TURNING(8), + DEFAULT_TURNING(9); private final int type; private static final Map intToTypeMap = new HashMap<>(); diff --git a/src/main/java/seng302/gameServer/messages/BoatActionMessage.java b/src/main/java/seng302/gameServer/messages/BoatActionMessage.java index 419bf72e..8fa78195 100644 --- a/src/main/java/seng302/gameServer/messages/BoatActionMessage.java +++ b/src/main/java/seng302/gameServer/messages/BoatActionMessage.java @@ -5,19 +5,19 @@ package seng302.gameServer.messages; */ public class BoatActionMessage extends Message{ private final MessageType MESSAGE_TYPE = MessageType.BOAT_ACTION; - private final int MESSAGE_SIZE = 1; + private final int MESSAGE_SIZE = 5; private BoatAction actionType; - public BoatActionMessage(BoatAction actionType) { + public BoatActionMessage(BoatAction actionType, int sourceId) { this.actionType = actionType; - setHeader(new Header(MessageType.BOAT_ACTION, 0, (short) 1)); // the second variable is the source id + setHeader(new Header(MessageType.BOAT_ACTION, sourceId, (short) MESSAGE_SIZE)); // the second variable is the source id allocateBuffer(); writeHeaderToBuffer(); // Write message fields putInt(actionType.getValue(), 1); + putInt(sourceId, 4); writeCRC(); rewind(); - } @Override diff --git a/src/main/java/seng302/gameServer/messages/RegistrationRequestMessage.java b/src/main/java/seng302/gameServer/messages/RegistrationRequestMessage.java index c7b2a1db..6a8e76ad 100644 --- a/src/main/java/seng302/gameServer/messages/RegistrationRequestMessage.java +++ b/src/main/java/seng302/gameServer/messages/RegistrationRequestMessage.java @@ -4,8 +4,8 @@ package seng302.gameServer.messages; public class RegistrationRequestMessage extends Message { private static int MESSAGE_LENGTH = 2; - public RegistrationRequestMessage(ClientType type){ - setHeader(new Header(MessageType.REGISTRATION_REQUEST, 1, (short) getSize())); + public RegistrationRequestMessage(ClientType type, int clientID){ + setHeader(new Header(MessageType.REGISTRATION_REQUEST, clientID, (short) getSize())); allocateBuffer(); writeHeaderToBuffer(); diff --git a/src/main/java/seng302/model/ClientYacht.java b/src/main/java/seng302/model/ClientYacht.java index 89715852..2bc1ed91 100644 --- a/src/main/java/seng302/model/ClientYacht.java +++ b/src/main/java/seng302/model/ClientYacht.java @@ -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.

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; } diff --git a/src/main/java/seng302/model/GameKeyBind.java b/src/main/java/seng302/model/GameKeyBind.java new file mode 100644 index 00000000..1c765adc --- /dev/null +++ b/src/main/java/seng302/model/GameKeyBind.java @@ -0,0 +1,78 @@ +package seng302.model; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; +import javafx.scene.input.KeyCode; + +public class GameKeyBind { + + private static GameKeyBind instance; + private Map keyToActionMap; + private Map actionToKeyMap; + private Boolean continuouslyTurning; + + + private GameKeyBind() { + setToDefault(); + } + + public void setToDefault() { + actionToKeyMap = new HashMap<>(); + keyToActionMap = new HashMap<>(); + continuouslyTurning = false; + // default key bindings + ArrayList keys = new ArrayList<>(); + keys.add(KeyCode.Z); + keys.add(KeyCode.X); + keys.add(KeyCode.SPACE); + keys.add(KeyCode.SHIFT); + keys.add(KeyCode.ENTER); + keys.add(KeyCode.PAGE_UP); + keys.add(KeyCode.PAGE_DOWN); + for (int i = 0; i < 7; i++) { + actionToKeyMap.put(KeyAction.getType(i + 1), keys.get(i)); + keyToActionMap.put(keys.get(i), KeyAction.getType(i + 1)); + } + } + + public static GameKeyBind getInstance() { + if (instance == null) { + instance = new GameKeyBind(); + } + return instance; + } + + public KeyCode getKeyCode(KeyAction keyAction) { + return instance.actionToKeyMap.get(keyAction); + } + + /** + * Binds a key to a key action + * + * @return true if successfully bind + */ + public boolean bindKeyToAction(KeyCode keyCode, KeyAction keyAction) { + if (instance.keyToActionMap.containsKey(keyCode)) { + // if the key has been bound to other action, return false + return false; + } else { + instance.keyToActionMap.put(keyCode, keyAction); // add key -> action + KeyCode oldKeyCode = instance.actionToKeyMap + .get(keyAction); // get old key for the action + instance.keyToActionMap.remove(oldKeyCode); // remove the old key -> action + instance.actionToKeyMap + .replace(keyAction, keyCode); // replace the old key by the newer one + return true; + } + } + + public void toggleTurningMode() { + continuouslyTurning = !continuouslyTurning; + } + + public Boolean isContinuouslyTurning() { + return continuouslyTurning; + } + +} diff --git a/src/main/java/seng302/model/KeyAction.java b/src/main/java/seng302/model/KeyAction.java new file mode 100644 index 00000000..1b8c2fa1 --- /dev/null +++ b/src/main/java/seng302/model/KeyAction.java @@ -0,0 +1,35 @@ +package seng302.model; + +import java.util.HashMap; +import java.util.Map; + +public enum KeyAction { + ZOOM_IN(1), + ZOOM_OUT(2), + VMG(3), + SAILS_STATE(4), + TACK_GYBE(5), + UPWIND(6), + DOWNWIND(7); + + private final int type; + private static final Map intToTypeMap = new HashMap<>(); + + static { + for (KeyAction type : KeyAction.values()) { + intToTypeMap.put(type.getValue(), type); + } + } + + KeyAction(int type) { + this.type = type; + } + + public static KeyAction getType(int value) { + return intToTypeMap.get(value); + } + + public int getValue() { + return this.type; + } +} diff --git a/src/main/java/seng302/model/ServerYacht.java b/src/main/java/seng302/model/ServerYacht.java index 3f9545c1..5822b248 100644 --- a/src/main/java/seng302/model/ServerYacht.java +++ b/src/main/java/seng302/model/ServerYacht.java @@ -9,6 +9,7 @@ import seng302.gameServer.messages.BoatStatus; import seng302.model.mark.Mark; import seng302.model.token.TokenType; import seng302.utilities.GeoUtility; +import seng302.visualiser.fxObjects.assets_3D.BoatMeshType; /** * Yacht class for the racing boat.

Class created to store more variables (eg. boat statuses) @@ -17,12 +18,14 @@ import seng302.utilities.GeoUtility; */ public class ServerYacht { - private Logger logger = LoggerFactory.getLogger(ClientYacht.class); - - public static final Double TURN_STEP = 5.0; + private Logger logger = LoggerFactory.getLogger(ServerYacht.class); //Boat info - private String boatType; + private BoatMeshType boatType; + private Double turnStep = 5.0; + private Double maxSpeedMultiplier = 1.0; + private Double turnStepMultiplier = 1.0; + private Double accelerationMultiplier = 1.0; private Integer sourceId; private String hullID; //matches HullNum in the XML spec. private String shortName; @@ -53,10 +56,12 @@ public class ServerYacht { private TokenType powerUp; private Long powerUpStartTime; + //turning mode + private Boolean continuouslyTurning; - public ServerYacht(String boatType, Integer sourceId, String hullID, String shortName, + public ServerYacht(BoatMeshType boatType, Integer sourceId, String hullID, String shortName, String boatName, String country) { - this.boatType = boatType; + setBoatType(boatType); this.boatStatus = BoatStatus.PRESTART; this.sourceId = sourceId; this.hullID = hullID; @@ -77,6 +82,8 @@ public class ServerYacht { this.hasEnteredRoundingZone = false; this.hasPassedLine = false; this.hasPassedThroughGate = false; + + this.continuouslyTurning = false; } @@ -126,7 +133,7 @@ public class ServerYacht { * @param amount the amount by which to adjust the boat heading. */ public void adjustHeading(Double amount) { - Double newVal = heading + amount; + Double newVal = heading + (amount * turnStepMultiplier); lastHeading = heading; heading = (double) Math.floorMod(newVal.longValue(), 360L); } @@ -171,7 +178,7 @@ public class ServerYacht { if (isAuto) { turnTowardsHeading(autoHeading); if (Math.abs(heading - autoHeading) - <= TURN_STEP) { //Cancel when within 1 turn step of target. + <= turnStep) { //Cancel when within 1 turn step of target. isAuto = false; } } @@ -184,44 +191,52 @@ public class ServerYacht { public void turnUpwind() { disableAutoPilot(); Double normalizedHeading = normalizeHeading(); - if (normalizedHeading == 0) { - if (lastHeading < 180) { - adjustHeading(-TURN_STEP); - } else { - adjustHeading(TURN_STEP); - } - } else if (normalizedHeading == 180) { - if (lastHeading < 180) { - adjustHeading(TURN_STEP); - } else { - adjustHeading(-TURN_STEP); - } - } else if (normalizedHeading < 180) { - adjustHeading(-TURN_STEP); + if (continuouslyTurning) { + adjustHeading(turnStep); } else { - adjustHeading(TURN_STEP); + if (normalizedHeading == 0) { + if (lastHeading < 180) { + adjustHeading(-turnStep); + } else { + adjustHeading(turnStep); + } + } else if (normalizedHeading == 180) { + if (lastHeading < 180) { + adjustHeading(turnStep); + } else { + adjustHeading(-turnStep); + } + } else if (normalizedHeading < 180) { + adjustHeading(-turnStep); + } else { + adjustHeading(turnStep); + } } } public void turnDownwind() { disableAutoPilot(); Double normalizedHeading = normalizeHeading(); - if (normalizedHeading == 0) { - if (lastHeading < 180) { - adjustHeading(TURN_STEP); - } else { - adjustHeading(-TURN_STEP); - } - } else if (normalizedHeading == 180) { - if (lastHeading < 180) { - adjustHeading(-TURN_STEP); - } else { - adjustHeading(TURN_STEP); - } - } else if (normalizedHeading < 180) { - adjustHeading(TURN_STEP); + if (continuouslyTurning) { + adjustHeading(-turnStep); } else { - adjustHeading(-TURN_STEP); + if (normalizedHeading == 0) { + if (lastHeading < 180) { + adjustHeading(turnStep); + } else { + adjustHeading(-turnStep); + } + } else if (normalizedHeading == 180) { + if (lastHeading < 180) { + adjustHeading(-turnStep); + } else { + adjustHeading(turnStep); + } + } else if (normalizedHeading < 180) { + adjustHeading(turnStep); + } else { + adjustHeading(-turnStep); + } } } @@ -265,9 +280,9 @@ public class ServerYacht { private void turnTowardsHeading(Double newHeading) { Double newVal = heading - newHeading; if (Math.floorMod(newVal.longValue(), 360L) > 180) { - adjustHeading(TURN_STEP / 5); + adjustHeading(turnStep / 5); } else { - adjustHeading(-TURN_STEP / 5); + adjustHeading(-turnStep / 5); } } @@ -418,4 +433,27 @@ public class ServerYacht { return boatColor; } + public void setBoatType(BoatMeshType boatType) { + this.accelerationMultiplier = boatType.accelerationMultiplier; + this.maxSpeedMultiplier = boatType.maxSpeedMultiplier; + this.turnStepMultiplier = boatType.turnStep; + this.boatType = boatType; + } + + public Double getMaxSpeedMultiplier() { + return maxSpeedMultiplier; + } + + public Double getAccelerationMultiplier(){ + return accelerationMultiplier; + } + + + public BoatMeshType getBoatType() { + return boatType; + } + + public void setContinuouslyTurning(Boolean continuouslyTurning) { + this.continuouslyTurning = continuouslyTurning; + } } diff --git a/src/main/java/seng302/utilities/Sounds.java b/src/main/java/seng302/utilities/Sounds.java index 944fa93f..f8257b1f 100644 --- a/src/main/java/seng302/utilities/Sounds.java +++ b/src/main/java/seng302/utilities/Sounds.java @@ -14,8 +14,10 @@ public class Sounds { private static MediaPlayer soundEffect; private static MediaPlayer soundPlayer; private static MediaPlayer hoverSoundPlayer; + private static MediaPlayer crashSoundPlayer; private static boolean hoverInitialized = false; + private static boolean crashInitialized = false; private static boolean musicMuted = false; private static boolean soundEffectsMuted = false; @@ -155,11 +157,17 @@ public class Sounds { public static void playCrashSound() { if (!soundEffectsMuted) { - Media crashSound = new Media( - Sounds.class.getClassLoader().getResource("sounds/Large-metal-door-slam.mp3") - .toString()); - soundPlayer = new MediaPlayer(crashSound); - soundPlayer.play(); + if (!crashInitialized) { + Media pickupSound = new Media( + Sounds.class.getClassLoader().getResource("sounds/Large-metal-door-slam.mp3") + .toString()); + crashSoundPlayer = new MediaPlayer(pickupSound); + crashInitialized = true; + } + if (crashSoundPlayer != null) { + crashSoundPlayer.stop(); + } + crashSoundPlayer.play(); } } @@ -176,10 +184,10 @@ public class Sounds { public static void playHoverSound() { if (!soundEffectsMuted) { if (!hoverInitialized) { - Media crashSound = new Media( + Media hoverSound = new Media( Sounds.class.getClassLoader().getResource("sounds/Error-sound-effect.mp3") .toString()); - hoverSoundPlayer = new MediaPlayer(crashSound); + hoverSoundPlayer = new MediaPlayer(hoverSound); hoverInitialized = true; } hoverSoundPlayer.setVolume(0.5); diff --git a/src/main/java/seng302/utilities/XMLParser.java b/src/main/java/seng302/utilities/XMLParser.java index 755fde3b..c5aa0edc 100644 --- a/src/main/java/seng302/utilities/XMLParser.java +++ b/src/main/java/seng302/utilities/XMLParser.java @@ -5,6 +5,7 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Random; import javafx.scene.paint.Color; import javafx.util.Pair; import javax.xml.parsers.DocumentBuilder; @@ -16,6 +17,7 @@ import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.SAXException; import seng302.model.ClientYacht; +import seng302.model.Colors; import seng302.model.Limit; import seng302.model.mark.CompoundMark; import seng302.model.mark.Corner; @@ -26,6 +28,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 @@ -146,17 +149,27 @@ public class XMLParser { Node currentBoat = boatsList.item(i); if (currentBoat.getNodeName().equals("Boat")) { // Boat boat = new Boat(currentBoat); + BoatMeshType boatMeshType; + try { + boatMeshType = BoatMeshType.valueOf(XMLParser.getNodeAttributeString(currentBoat, "Type")); + } catch (IllegalArgumentException e){ + boatMeshType = BoatMeshType.DINGHY; + } + Color color; + try { + color = Color.web(getNodeAttributeString(currentBoat, "Color")); + } catch (NullPointerException npe) { + color = Colors.getColor(new Random().nextInt(8)); + } ClientYacht yacht = new ClientYacht( - XMLParser.getNodeAttributeString(currentBoat, "Type"), + boatMeshType, 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); - } + yacht.setColour(color); + competingBoats.put(yacht.getSourceId(), yacht); } } return competingBoats; @@ -204,17 +217,20 @@ public class XMLParser { */ private static List extractTokens(Element docEle) { List tokens = new ArrayList<>(); - NodeList tokenList = docEle.getElementsByTagName("Tokens").item(0).getChildNodes(); - for (int i = 0; i < tokenList.getLength(); i++) { - Node tokenNode = tokenList.item(i); - if (tokenNode.getNodeName().equals("Token")) { - String tokenType = getNodeAttributeString(tokenNode, "TokenType"); - Double lat = getNodeAttributeDouble(tokenNode, "TargetLat"); - Double lng = getNodeAttributeDouble(tokenNode, "TargetLng"); - tokens.add(new Token(TokenType.valueOf(tokenType), lat, lng)); + try { + NodeList tokenList = docEle.getElementsByTagName("Tokens").item(0).getChildNodes(); + for (int i = 0; i < tokenList.getLength(); i++) { + Node tokenNode = tokenList.item(i); + if (tokenNode.getNodeName().equals("Token")) { + String tokenType = getNodeAttributeString(tokenNode, "TokenType"); + Double lat = getNodeAttributeDouble(tokenNode, "TargetLat"); + Double lng = getNodeAttributeDouble(tokenNode, "TargetLng"); + tokens.add(new Token(TokenType.valueOf(tokenType), lat, lng)); + } } + } catch (NullPointerException npe) { + return new ArrayList<>(); } - return tokens; } diff --git a/src/main/java/seng302/visualiser/ClientToServerThread.java b/src/main/java/seng302/visualiser/ClientToServerThread.java index a821e8fa..dec50b6d 100644 --- a/src/main/java/seng302/visualiser/ClientToServerThread.java +++ b/src/main/java/seng302/visualiser/ClientToServerThread.java @@ -179,7 +179,7 @@ public class ClientToServerThread implements Runnable { * Sends a request to the server asking for a source ID */ private void sendRegistrationRequest() { - RegistrationRequestMessage requestMessage = new RegistrationRequestMessage(ClientType.PLAYER); + RegistrationRequestMessage requestMessage = new RegistrationRequestMessage(ClientType.PLAYER, clientId); try { os.write(requestMessage.getBuffer()); @@ -197,9 +197,6 @@ public class ClientToServerThread implements Runnable { private void processRegistrationResponse(StreamPacket packet){ int sourceId = (int) Message.bytesToLong(Arrays.copyOfRange(packet.getPayload(), 0, 4)); int statusCode = (int) Message.bytesToLong(Arrays.copyOfRange(packet.getPayload(), 4,5)); - System.out.println("sourceId = " + sourceId); - System.out.println("statusCode = " + statusCode); - RegistrationResponseStatus status = RegistrationResponseStatus.getResponseStatus(statusCode); if (status.equals(RegistrationResponseStatus.SUCCESS_PLAYING)){ @@ -249,7 +246,7 @@ public class ClientToServerThread implements Runnable { new TimerTask() { @Override public void run() { - sendBoatActionMessage(new BoatActionMessage(BoatAction.DOWNWIND)); + sendBoatActionMessage(new BoatActionMessage(BoatAction.DOWNWIND, clientId)); } }, 0, PACKET_SENDING_INTERVAL_MS ); @@ -262,14 +259,14 @@ public class ClientToServerThread implements Runnable { new TimerTask() { @Override public void run() { - sendBoatActionMessage(new BoatActionMessage(BoatAction.UPWIND)); + sendBoatActionMessage(new BoatActionMessage(BoatAction.UPWIND, clientId)); } }, 0, PACKET_SENDING_INTERVAL_MS ); } break; default: - sendBoatActionMessage(new BoatActionMessage(actionType)); + sendBoatActionMessage(new BoatActionMessage(actionType, clientId)); break; } } diff --git a/src/main/java/seng302/visualiser/GameClient.java b/src/main/java/seng302/visualiser/GameClient.java index 6a857d70..b2ade01c 100644 --- a/src/main/java/seng302/visualiser/GameClient.java +++ b/src/main/java/seng302/visualiser/GameClient.java @@ -28,6 +28,8 @@ import seng302.gameServer.messages.BoatAction; import seng302.gameServer.messages.BoatStatus; import seng302.gameServer.messages.YachtEventType; import seng302.model.ClientYacht; +import seng302.model.GameKeyBind; +import seng302.model.KeyAction; import seng302.model.RaceState; import seng302.model.stream.packets.StreamPacket; import seng302.model.stream.parser.MarkRoundingData; @@ -66,6 +68,8 @@ public class GameClient { private ArrayList finishedBoats = new ArrayList<>(); + private GameKeyBind gameKeyBind; // all the key binding setting. + private ObservableList clientLobbyList = FXCollections.observableArrayList(); /** @@ -75,6 +79,7 @@ public class GameClient { */ public GameClient(Pane holder) { this.holderPane = holder; + this.gameKeyBind = GameKeyBind.getInstance(); } /** @@ -373,16 +378,16 @@ public class GameClient { } return; } - switch (e.getCode()) { - case SPACE: // align with vmg - socketThread.sendBoatAction(BoatAction.VMG); break; - case PAGE_UP: // upwind - socketThread.sendBoatAction(BoatAction.UPWIND); break; - case PAGE_DOWN: // downwind - socketThread.sendBoatAction(BoatAction.DOWNWIND); break; - case ENTER: // tack/gybe - // if chat box is active take whatever is in there and send it to server - socketThread.sendBoatAction(BoatAction.TACK_GYBE); break; + + if (gameKeyBind.getKeyCode(KeyAction.VMG) == e.getCode()) { // align with vmg + socketThread.sendBoatAction(BoatAction.VMG); + } else if (gameKeyBind.getKeyCode(KeyAction.UPWIND) == e.getCode()) { // upwind + socketThread.sendBoatAction(BoatAction.UPWIND); + } else if (gameKeyBind.getKeyCode(KeyAction.DOWNWIND) == e.getCode()) { // downwind + socketThread.sendBoatAction(BoatAction.DOWNWIND); + } else if (gameKeyBind.getKeyCode(KeyAction.TACK_GYBE) == e.getCode()) { // tack/gybe + // if chat box is active take whatever is in there and send it to server + socketThread.sendBoatAction(BoatAction.TACK_GYBE); } } @@ -391,15 +396,17 @@ public class GameClient { if (raceView.isChatInputFocused()) { return; } - switch (e.getCode()) { - //TODO 12/07/17 Determine the sail state and send the appropriate packet (eg. if sails are in, send a sail out packet) - case SHIFT: // sails in/sails out + + if (gameKeyBind.getKeyCode(KeyAction.SAILS_STATE) == e.getCode()) { // sails in/sails out + if (allBoatsMap.get(socketThread.getClientId()).getSailIn()) { + socketThread.sendBoatAction(BoatAction.SAILS_OUT); + } else { socketThread.sendBoatAction(BoatAction.SAILS_IN); - allBoatsMap.get(socketThread.getClientId()).toggleSail(); - break; - case PAGE_UP: - case PAGE_DOWN: - socketThread.sendBoatAction(BoatAction.MAINTAIN_HEADING); break; + } + allBoatsMap.get(socketThread.getClientId()).toggleSail(); + } else if (gameKeyBind.getKeyCode(KeyAction.UPWIND) == e.getCode() + || gameKeyBind.getKeyCode(KeyAction.DOWNWIND) == e.getCode()) { + socketThread.sendBoatAction(BoatAction.MAINTAIN_HEADING); } } @@ -456,4 +463,14 @@ public class GameClient { public Map getAllBoatsMap() { return allBoatsMap; } + + public void sendToggleTurningModePacket() { + if (socketThread != null) { + if (gameKeyBind.isContinuouslyTurning()) { + socketThread.sendBoatAction(BoatAction.CONTINUOUSLY_TURNING); + } else { + socketThread.sendBoatAction(BoatAction.DEFAULT_TURNING); + } + } + } } diff --git a/src/main/java/seng302/visualiser/GameView3D.java b/src/main/java/seng302/visualiser/GameView3D.java index c5b52286..63d0203d 100644 --- a/src/main/java/seng302/visualiser/GameView3D.java +++ b/src/main/java/seng302/visualiser/GameView3D.java @@ -30,6 +30,7 @@ import seng302.model.token.Token; import seng302.utilities.GeoUtility; 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; @@ -459,7 +460,7 @@ public class GameView3D { final List wakes = new ArrayList<>(); for (ClientYacht clientYacht : yachts) { Color colour = clientYacht.getColour(); - newBoat = new BoatObject(); + newBoat = new BoatObject(clientYacht.getBoatType()); newBoat.setFill(colour); boatObjects.put(clientYacht, newBoat); wakesGroup.getChildren().add(newBoat.getWake()); @@ -568,6 +569,7 @@ public class GameView3D { } public void setBoatAsPlayer (ClientYacht playerYacht) { + playerYacht.toggleSail(); playerBoatAnimationTimer = new AnimationTimer() { double count = 60; diff --git a/src/main/java/seng302/visualiser/controllers/FinishScreenViewController.java b/src/main/java/seng302/visualiser/controllers/FinishScreenViewController.java index 7eb9b4fd..86e39ead 100644 --- a/src/main/java/seng302/visualiser/controllers/FinishScreenViewController.java +++ b/src/main/java/seng302/visualiser/controllers/FinishScreenViewController.java @@ -88,7 +88,6 @@ public class FinishScreenViewController implements Initializable { public void switchToStartScreenView() { Sounds.playButtonClick(); - //TODO merge fix setContentPane("/views/StartScreenView.fxml"); } diff --git a/src/main/java/seng302/visualiser/controllers/LobbyController.java b/src/main/java/seng302/visualiser/controllers/LobbyController.java index fce55a9a..d0280736 100644 --- a/src/main/java/seng302/visualiser/controllers/LobbyController.java +++ b/src/main/java/seng302/visualiser/controllers/LobbyController.java @@ -59,7 +59,6 @@ public class LobbyController implements Initializable { private JFXDialog customizationDialog; public Color playersColor; private Map playerBoats; - private Double mapWidth = INITIAL_MAP_WIDTH, mapHeight = INITIAL_MAP_HEIGHT; private GameView gameView; @@ -93,16 +92,16 @@ public class LobbyController implements Initializable { ViewManager.getInstance().getPlayerList().setAll(ViewManager.getInstance().getPlayerList().sorted()); }); + customizeButton.setOnMouseReleased(event -> { + customizationDialog = createCustomizeDialog(); + Sounds.playButtonClick(); + customizationDialog.show(); + }); + Platform.runLater(() -> { Integer playerId = ViewManager.getInstance().getGameClient().getServerThread().getClientId(); playersColor = Colors.getColor(playerId - 1); - customizationDialog = createCustomizeDialog(); - - customizeButton.setOnMouseReleased(event -> { - Sounds.playButtonClick(); - customizationDialog.show(); - }); }); leaveLobbyButton.setOnMouseEntered(e -> Sounds.playHoverSound()); @@ -132,6 +131,8 @@ public class LobbyController implements Initializable { controller.setPlayerName(this.playerBoats .get(ViewManager.getInstance().getGameClient().getServerThread().getClientId()) .getBoatName()); + controller.setCurrentBoat(this.playerBoats.get(ViewManager.getInstance().getGameClient().getServerThread().getClientId()) + .getBoatType().toString()); return customizationDialog; } @@ -190,7 +191,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(); diff --git a/src/main/java/seng302/visualiser/controllers/RaceViewController.java b/src/main/java/seng302/visualiser/controllers/RaceViewController.java index 2ac06dfb..3d011a0d 100644 --- a/src/main/java/seng302/visualiser/controllers/RaceViewController.java +++ b/src/main/java/seng302/visualiser/controllers/RaceViewController.java @@ -87,7 +87,7 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel @FXML private Label timerLabel; @FXML - private StackPane contentAnchorPane; + private StackPane contentStackPane; private GridPane contentGridPane; @FXML @@ -134,8 +134,6 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel Sounds.stopMusic(); Sounds.playRaceMusic(); - finishScreenDialog = createFinishDialog(); - // Load a default important annotation state //importantAnnotations = new ImportantAnnotationsState(); @@ -180,9 +178,10 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel // chatHistory.textProperty().addListener((obs, oldValue, newValue) -> { // chatHistory.setScrollTop(Double.MAX_VALUE); // }); - rvAnchorPane.setOnMouseClicked((event) -> - rvAnchorPane.requestFocus() - ); + + contentStackPane.setOnMouseClicked(event -> { + contentStackPane.requestFocus(); + }); //Makes the chat history non transparent when clicked on chatInput.focusedProperty().addListener(new ChangeListener() { @@ -200,26 +199,27 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel public void showFinishDialog(ArrayList finishedBoats) { raceState.setRaceStarted(false); - finishDialogController.setFinishedBoats(finishedBoats); - finishScreenDialog.show(); + createFinishDialog(finishedBoats); } - private JFXDialog createFinishDialog() { + /** + * Create finishScreenDialog and set up finishDialogController. + */ + private void createFinishDialog(ArrayList finishedBoats) { 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; + Platform.runLater(() -> { + try { + finishScreenDialog = new JFXDialog(contentStackPane, dialog.load(), + JFXDialog.DialogTransition.CENTER); + finishDialogController = dialog.getController(); + finishDialogController.setFinishedBoats(finishedBoats); + finishScreenDialog.show(); + } catch (IOException e) { + e.printStackTrace(); + } + }); } public void loadRace ( @@ -245,7 +245,7 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel gameView = new GameView3D(); // gameView.setFrameRateFXText(fpsDisplay); Platform.runLater(() -> { - contentAnchorPane.getChildren().add(0, gameView.getAssets()); + contentStackPane.getChildren().add(0, gameView.getAssets()); ((SubScene) gameView.getAssets()).widthProperty() .bind(ViewManager.getInstance().getStage().widthProperty()); ((SubScene) gameView.getAssets()).heightProperty() @@ -805,7 +805,7 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel public String readChatInput() { String chat = chatInput.getText(); chatInput.clear(); - rvAnchorPane.requestFocus(); + contentStackPane.requestFocus(); return chat; } diff --git a/src/main/java/seng302/visualiser/controllers/ServerListController.java b/src/main/java/seng302/visualiser/controllers/ServerListController.java index 5c13d4f8..db8ce5e1 100644 --- a/src/main/java/seng302/visualiser/controllers/ServerListController.java +++ b/src/main/java/seng302/visualiser/controllers/ServerListController.java @@ -112,16 +112,23 @@ public class ServerListController implements Initializable, ServerListenerDelega serverListVBox.getChildren().add(noServersFound); // Set up dialog for server creation + serverListHostButton.setOnAction(action -> { + showServerCreationDialog(); + }); + } + + /** + * Shows Server Creation Dialog when "Host" button is clicked. + */ + private void showServerCreationDialog() { Platform.runLater(() -> { FXMLLoader dialogContent = new FXMLLoader(getClass().getResource( "/views/dialogs/ServerCreationDialog.fxml")); try { JFXDialog dialog = new JFXDialog(serverListMainStackPane, dialogContent.load(), DialogTransition.CENTER); - serverListHostButton.setOnAction(action -> { - dialog.show(); - Sounds.playButtonClick(); - }); + dialog.show(); + Sounds.playButtonClick(); } catch (IOException e) { e.printStackTrace(); logger.warn("Could not create Server Creation Dialog."); diff --git a/src/main/java/seng302/visualiser/controllers/ViewManager.java b/src/main/java/seng302/visualiser/controllers/ViewManager.java index 165d0c39..8f98824c 100644 --- a/src/main/java/seng302/visualiser/controllers/ViewManager.java +++ b/src/main/java/seng302/visualiser/controllers/ViewManager.java @@ -2,6 +2,9 @@ package seng302.visualiser.controllers; import com.jfoenix.controls.JFXButton; import com.jfoenix.controls.JFXDecorator; +import com.jfoenix.controls.JFXDialog; +import com.jfoenix.controls.JFXDialog.DialogTransition; +import com.jfoenix.controls.JFXSnackbar; import com.jfoenix.svg.SVGGlyph; import java.io.IOException; import java.util.HashMap; @@ -15,6 +18,7 @@ import javafx.scene.Scene; import javafx.scene.SceneAntialiasing; import javafx.scene.image.Image; import javafx.scene.layout.HBox; +import javafx.scene.layout.StackPane; import javafx.scene.paint.Color; import javafx.stage.Stage; import org.slf4j.Logger; @@ -23,6 +27,7 @@ import seng302.gameServer.ServerAdvertiser; import seng302.utilities.BonjourInstallChecker; import seng302.utilities.Sounds; import seng302.visualiser.GameClient; +import seng302.visualiser.controllers.dialogs.KeyBindingDialogController; public class ViewManager { @@ -32,12 +37,9 @@ public class ViewManager { private HashMap properties; //TODO is this the best way to do this?? private ObservableList playerList; private Logger logger = LoggerFactory.getLogger(ViewManager.class); - - public Stage getStage() { - return stage; - } - private Stage stage; + private JFXSnackbar jfxSnackbar; + private JFXDialog keyBindingDialog; private ViewManager() { properties = new HashMap<>(); @@ -99,6 +101,8 @@ public class ViewManager { gameClient.stopGame(); System.exit(0); }); + + jfxSnackbar = new JFXSnackbar(decorator); } /** @@ -119,12 +123,31 @@ public class ViewManager { //Get the button box HBox btns = (HBox) decorator.getChildren().get(0); + //Create settings button -- [WIP] + JFXButton btnKeyBinding = new JFXButton(); + btnKeyBinding.setText(" Key Bindings"); + btnKeyBinding.setStyle("-fx-text-fill:#fff"); + btnKeyBinding.getStyleClass().add("jfx-decorator-button"); + btnKeyBinding.setCursor(Cursor.HAND); + btnKeyBinding.setFocusTraversable(false); + + btnKeyBinding.setOnMouseClicked(event -> Platform.runLater(() -> { + try { + if (!checkDialogOpened(decorator.getChildren())) { + showKeyBindingDialog(); + } + } catch (IOException e) { + logger.warn("Something went wrong when opening key bind dialog"); + } + })); + //Create new button JFXButton btnMute = new JFXButton(); btnMute.setText(" Toggle Sound"); btnMute.setStyle("-fx-text-fill:#fff"); btnMute.getStyleClass().add("jfx-decorator-button"); btnMute.setCursor(Cursor.HAND); + btnMute.setFocusTraversable(false); //Create Graphics SVGGlyph spacer = new SVGGlyph(0, "SPACER", "", Color.WHITE); @@ -134,9 +157,13 @@ public class ViewManager { SVGGlyph volumeOff = new SVGGlyph(0, "VOLUME_ON", "M13.5,9 C13.5,7.2 12.5,5.7 11,5 L11,7.2 L13.5,9.7 L13.5,9 L13.5,9 Z M16,9 C16,9.9 15.8,10.8 15.5,11.6 L17,13.1 C17.7,11.9 18,10.4 18,8.9 C18,4.6 15,1 11,0.1 L11,2.2 C13.9,3.2 16,5.8 16,9 L16,9 Z M1.3,0 L0,1.3 L4.7,6 L0,6 L0,12 L4,12 L9,17 L9,10.3 L13.3,14.6 C12.6,15.1 11.9,15.5 11,15.8 L11,17.9 C12.4,17.6 13.6,17 14.7,16.1 L16.7,18.1 L18,16.8 L9,7.8 L1.3,0 L1.3,0 Z M9,1 L6.9,3.1 L9,5.2 L9,1 L9,1 Z", Color.WHITE); + SVGGlyph keyBindingGlyph = new SVGGlyph(0, "KEY_BINDING", + "M20 5H4c-1.1 0-1.99.9-1.99 2L2 17c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2zm-9 3h2v2h-2V8zm0 3h2v2h-2v-2zM8 8h2v2H8V8zm0 3h2v2H8v-2zm-1 2H5v-2h2v2zm0-3H5V8h2v2zm9 7H8v-2h8v2zm0-4h-2v-2h2v2zm0-3h-2V8h2v2zm3 3h-2v-2h2v2zm0-3h-2V8h2v2z", + Color.WHITE); volumeOn.setSize(16, 16); volumeOff.setSize(16, 16); spacer.setSize(40, 16); + keyBindingGlyph.setSize(24, 16); // Determine which graphic should go on the button if (Sounds.isMusicMuted() && Sounds.isSoundEffectsMuted()) { @@ -145,9 +172,12 @@ public class ViewManager { btnMute.setGraphic(volumeOn); } + btnKeyBinding.setGraphic(keyBindingGlyph); + // Add Buttons btns.getChildren().add(0, spacer); btns.getChildren().add(0, btnMute); + btns.getChildren().add(0, btnKeyBinding); btnMute.setOnAction((action) -> { Sounds.toggleAllSounds(); if (btnMute.getGraphic().equals(volumeOff)) { @@ -159,6 +189,63 @@ public class ViewManager { } + /** + * Recursively find JFXDialog given a starting node. Will traverse children of StackPane. + * + * @param nodes children nodes to be check. + * @return true if node contains JFXDialog. + */ + private Boolean checkDialogOpened(ObservableList nodes) { + boolean foundJFXDialog = false; + for (Node node : nodes) { + if (node instanceof JFXDialog) { + return true; + } else if (node instanceof StackPane) { + foundJFXDialog = checkDialogOpened(((StackPane) node).getChildren()); + } + } + return foundJFXDialog; + } + + private void showKeyBindingDialog() throws IOException { + FXMLLoader dialogContent = new FXMLLoader(getClass().getResource( + "/views/dialogs/KeyBindingDialog.fxml")); + for (Node node : decorator.getChildren()) { + if (node instanceof StackPane) { + keyBindingDialog = new JFXDialog((StackPane) node, + dialogContent.load(), + DialogTransition.CENTER); + + KeyBindingDialogController keyBindingDialogController = dialogContent + .getController(); + keyBindingDialogController.setGameClient(this.gameClient); + keyBindingDialog.show(); + Sounds.playButtonClick(); + } + } + } + + public void closeKeyBindingDialog() { + keyBindingDialog.close(); + } + + /** + * Show a snackbar at the bottom of the app for 1 second. + * + * @param snackbarText text to be displayed. + */ + public void showSnackbar(String snackbarText, boolean isWarning) { + if (isWarning) { + decorator.getStylesheets() + .add(getClass().getResource("/css/dialogs/Snackbar.css").toExternalForm()); + } else { + if (decorator.getStylesheets().size() > 1) { + decorator.getStylesheets().remove(1); + } + } + jfxSnackbar.show(snackbarText, 1500); + } + /** * Determines if a PC has compatibility with the bonjour protocol for server detection. */ @@ -221,6 +308,7 @@ public class ViewManager { /** * Change the view to the Lobby Screen + * * @param disableReadyButton Boolean value so that clients can't try start a game. * @return A LobbyController object for the Lobby Screen. */ @@ -243,6 +331,7 @@ public class ViewManager { /** * Sets up the view for the race. Creating a new decorator and destroying the old one. + * * @return A RaceViewController for the race view screen. */ @@ -267,17 +356,10 @@ public class ViewManager { scene.setOnKeyPressed(gameClient::keyPressed); scene.setOnKeyReleased(gameClient::keyReleased); - // uncomment to make it full screen -// Rectangle2D visualBounds = Screen.getPrimary().getVisualBounds(); -// stage.setX(visualBounds.getMinX()); -// stage.setY(visualBounds.getMinY()); -// stage.setWidth(visualBounds.getWidth()); -// stage.setHeight(visualBounds.getHeight()); -// stage.setMaximized(true); -// stage.setFullScreen(true); - stage.setMinHeight(500); stage.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(); @@ -286,7 +368,7 @@ public class ViewManager { } }); - while (loader.getController() == null){ + while (loader.getController() == null) { try { Thread.sleep(50); } catch (InterruptedException e) { @@ -296,4 +378,9 @@ public class ViewManager { return loader.getController(); } + + public Stage getStage() { + return stage; + } + } diff --git a/src/main/java/seng302/visualiser/controllers/cells/PlayerCell.java b/src/main/java/seng302/visualiser/controllers/cells/PlayerCell.java index 6fb35708..21bd6644 100644 --- a/src/main/java/seng302/visualiser/controllers/cells/PlayerCell.java +++ b/src/main/java/seng302/visualiser/controllers/cells/PlayerCell.java @@ -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()); } diff --git a/src/main/java/seng302/visualiser/controllers/dialogs/BoatCustomizeController.java b/src/main/java/seng302/visualiser/controllers/dialogs/BoatCustomizeController.java index 339f08b8..67fb089a 100644 --- a/src/main/java/seng302/visualiser/controllers/dialogs/BoatCustomizeController.java +++ b/src/main/java/seng302/visualiser/controllers/dialogs/BoatCustomizeController.java @@ -6,15 +6,25 @@ 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.control.ProgressBar; +import javafx.scene.layout.Background; +import javafx.scene.layout.BackgroundFill; +import javafx.scene.layout.CornerRadii; +import javafx.scene.layout.Pane; import javafx.scene.paint.Color; import 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; @@ -24,23 +34,35 @@ public class BoatCustomizeController implements Initializable{ @FXML private JFXColorPicker colorPicker; @FXML + private ProgressBar speedBar; + @FXML + private ProgressBar accelBar; + @FXML + private ProgressBar handleBar; + @FXML private JFXButton submitBtn; @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; + private Double maxSpeedMultiplier = 1.0; + private Double maxTurnRateMultiplier = 1.0; + private Double maxAccelerationMultiplier = 1.0; @Override public void initialize(URL location, ResourceBundle resources) { socketThread = ViewManager.getInstance().getGameClient().getServerThread(); - + findMaxStats(); RequiredFieldValidator playerNameReqValidator = new RequiredFieldValidator(); playerNameReqValidator.setMessage("Player name required."); @@ -48,6 +70,8 @@ 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(); @@ -78,7 +102,10 @@ public class BoatCustomizeController implements Initializable{ colorArray[2] = (byte) blue; socketThread.sendCustomizationRequest(CustomizeRequestType.COLOR, colorArray); + socketThread.sendCustomizationRequest(CustomizeRequestType.SHAPE, currentBoat.toString().getBytes()); lobbyController.closeCustomizationDialog(); + + } } @@ -93,4 +120,61 @@ public class BoatCustomizeController implements Initializable{ public void setParentController(LobbyController lobbyController){ this.lobbyController = lobbyController; } + + public void setCurrentBoat(String boatType) { + currentBoat = BoatMeshType.valueOf(boatType); + displayCurrentBoat(); + refreshStatBars(currentBoat); + } + + public void nextBoat() { + currentBoat = BoatMeshType.getNextBoatType(currentBoat); + displayCurrentBoat(); + refreshStatBars(currentBoat); + } + + public void prevBoat() { + currentBoat = BoatMeshType.getPrevBoatType(currentBoat); + displayCurrentBoat(); + refreshStatBars(currentBoat); + + } + + private void displayCurrentBoat() { + boatPane.getChildren().clear(); + Group group = new Group(); + boatPane.getChildren().add(group); + BoatModel bo = ModelFactory.boatCustomiseView(currentBoat, colorPicker.getValue()); + group.getChildren().add(bo.getAssets()); + group.getChildren().add(new PointLight()); + } + + private void refreshBoat() { + boatPane.getChildren().clear(); + Group group = new Group(); + boatPane.getChildren().add(group); + BoatModel bo = ModelFactory.boatCustomiseView(currentBoat, colorPicker.getValue()); + group.getChildren().add(bo.getAssets()); + refreshStatBars(currentBoat); + } + + private void findMaxStats() { + for (BoatMeshType bmt: BoatMeshType.values()) { + if (bmt.turnStep > maxTurnRateMultiplier) { + maxTurnRateMultiplier = bmt.turnStep; + } + if (bmt.maxSpeedMultiplier > maxSpeedMultiplier) { + maxSpeedMultiplier = bmt.maxSpeedMultiplier; + } + if (bmt.accelerationMultiplier > maxAccelerationMultiplier) { + maxAccelerationMultiplier = bmt.accelerationMultiplier; + } + } + } + + private void refreshStatBars(BoatMeshType bo) { + speedBar.setProgress((bo.maxSpeedMultiplier) / maxSpeedMultiplier); + accelBar.setProgress(bo.accelerationMultiplier / maxAccelerationMultiplier); + handleBar.setProgress(bo.turnStep / maxTurnRateMultiplier); + } } diff --git a/src/main/java/seng302/visualiser/controllers/dialogs/KeyBindingDialogController.java b/src/main/java/seng302/visualiser/controllers/dialogs/KeyBindingDialogController.java new file mode 100644 index 00000000..2a286ec4 --- /dev/null +++ b/src/main/java/seng302/visualiser/controllers/dialogs/KeyBindingDialogController.java @@ -0,0 +1,185 @@ +package seng302.visualiser.controllers.dialogs; + +import com.jfoenix.controls.JFXButton; +import com.jfoenix.controls.JFXToggleButton; +import java.net.URL; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.ResourceBundle; +import javafx.fxml.FXML; +import javafx.fxml.Initializable; +import javafx.scene.control.Button; +import javafx.scene.control.Label; +import javafx.scene.input.KeyEvent; +import seng302.model.GameKeyBind; +import seng302.model.KeyAction; +import seng302.visualiser.GameClient; +import seng302.visualiser.controllers.ViewManager; + +public class KeyBindingDialogController implements Initializable { + + //--------FXML BEGIN--------// + @FXML + private Label keyBindingDialogHeader; + @FXML + private Label closeLabel; + @FXML + private JFXButton zoomInbtn; + @FXML + private JFXButton zoomOutBtn; + @FXML + private JFXButton vmgBtn; + @FXML + private JFXButton sailInOutBtn; + @FXML + private JFXButton tackGybeBtn; + @FXML + private JFXButton upwindBtn; + @FXML + private JFXButton downwindBtn; + @FXML + private JFXButton resetBtn; + @FXML + private Label upwindLabel; + @FXML + private Label downwindLabel; + @FXML + private JFXToggleButton turningToggle; + //---------FXML END---------// + + private GameKeyBind gameKeyBind; + private List buttons = new ArrayList<>(); + private Map buttonActionMap; + private GameClient gameClient; // to send turning mode packet + + @Override + public void initialize(URL location, ResourceBundle resources) { + gameKeyBind = GameKeyBind.getInstance(); + buttons = new ArrayList<>(); + Collections.addAll(buttons, + zoomInbtn, zoomOutBtn, vmgBtn, sailInOutBtn, tackGybeBtn, upwindBtn, downwindBtn); + bindButtonWithAction(); + loadKeyBind(); + + buttons.forEach(button -> { + button.setOnMouseEntered(event -> mouseEnter(button)); + button.setOnMousePressed(event -> buttonPressed(button)); + button.setOnMouseExited(event -> mouseExit(button)); + button.setOnKeyPressed(event -> keyPressed(event, button)); + }); + + turningToggle.setOnMouseClicked(event -> toggleTurningMode()); + + resetBtn.setOnMouseClicked(event -> { + gameKeyBind.setToDefault(); + loadKeyBind(); + }); + + closeLabel.setOnMouseClicked(event -> ViewManager.getInstance().closeKeyBindingDialog()); + + keyBindingDialogHeader.setFocusTraversable(true); + keyBindingDialogHeader.requestFocus(); + } + + /** + * Set buttons' label according to GameKeyBind settings + */ + private void loadKeyBind() { + buttons.forEach( + button -> button + .setText(gameKeyBind.getKeyCode(buttonActionMap.get(button)).getName())); + turningToggle.setSelected(gameKeyBind.isContinuouslyTurning()); + if (gameKeyBind.isContinuouslyTurning()) { + upwindLabel.setText("ClOCKWISE TURNING"); + downwindLabel.setText("ANTICLOCKWISE TURNING"); + } else { + upwindLabel.setText("UPWIND"); + downwindLabel.setText("DOWNWIND"); + } + } + + /** + * Bind buttons with specific action in a map. + */ + private void bindButtonWithAction() { + buttonActionMap = new HashMap<>(); + for (int i = 0; i < 7; i++) { + buttonActionMap.put(buttons.get(i), KeyAction.getType(i + 1)); + } + } + + /** + * Prompt success / failure message for reassigning key action + */ + private void showSnackBar(String message, Boolean isWarning) { + ViewManager.getInstance().showSnackbar(message, isWarning); + } + + /** + * When a mouse enters the button, the color and font size should change to highlight + * @param button + */ + private void mouseEnter(Button button) { + button.setStyle("" + + "-fx-background-color: -fx-pp-theme-color;" + + "-fx-text-fill: -fx-pp-front-color;" + + "-fx-font-size: 15;"); + } + + /** + * Prompt "press key..." to inform users assign a new key bind by pressing a key + * @param button + */ + private void buttonPressed(Button button) { + button.setText("PRESS KEY..."); + } + + + /** + * When mouse leaves the button, return the button to the normal state in terms of text, + * color and font size + * @param button + */ + private void mouseExit(Button button) { + button.setText(GameKeyBind.getInstance().getKeyCode(buttonActionMap.get(button)).getName()); + button.setStyle("" + + "-fx-background-color: -fx-pp-front-color; " + + "-fx-text-fill: -fx-pp-theme-color; " + + "-fx-font-size: 13;"); + } + + /** + * When a key is pressed, check if the new binding conflicts to any existed settings, if not + * assign the selected action with the new key binding to GameKeyBind. + * @param event + * @param button + */ + private void keyPressed(KeyEvent event, Button button) { + event.consume(); + KeyAction buttonAction = buttonActionMap.get(button); + if (gameKeyBind.bindKeyToAction(event.getCode(), buttonAction)) { + showSnackBar(button.getId() + " is set to " + event.getCode().getName(), false); + button.setText(gameKeyBind.getKeyCode(buttonAction).getName()); + } else { + loadKeyBind(); + showSnackBar(event.getCode().getName() + " is already in use", true); + } + } + + /** + * When the turning mode is toggled, update gameKeyBind and send out packet to notify the server + */ + private void toggleTurningMode() { + gameKeyBind.toggleTurningMode(); + gameClient.sendToggleTurningModePacket(); + loadKeyBind(); + } + + public void setGameClient(GameClient gameClient) { + this.gameClient = gameClient; + } + +} diff --git a/src/main/java/seng302/visualiser/fxObjects/assets_3D/BoatMeshType.java b/src/main/java/seng302/visualiser/fxObjects/assets_3D/BoatMeshType.java index 9b74aa69..292c636a 100644 --- a/src/main/java/seng302/visualiser/fxObjects/assets_3D/BoatMeshType.java +++ b/src/main/java/seng302/visualiser/fxObjects/assets_3D/BoatMeshType.java @@ -2,21 +2,59 @@ package seng302.visualiser.fxObjects.assets_3D; /** * Enum for boat meshes. Enum values should be of the form : - * ENUM_VALUE (hull file, mast file, Y offset of mast CoR from origin, sail file, Y 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, 1.8, 1.0, 1.0), + CATAMARAN("catamaran_hull.stl", "catamaran_mast.stl", 0.997, "catamaran_sail.stl", + 0.997, null, false, 1.0, 1.4, 2.0), + PIRATE_SHIP("pirateship_hull.stl", "pirateship_mast.stl", -0.5415, "pirateship_mainsail.stl", + -0.5415, "pirateship_frontsail.stl", true, 1.2, 1.6, 1.2); - final String hullFile, mastFile, sailFile; + final String hullFile, mastFile, sailFile, jibFile; final double mastOffset, sailOffset; + public final double maxSpeedMultiplier; + public final double accelerationMultiplier; + public final double turnStep; + final boolean fixedSail; + final static BoatMeshType[] boatTypes = new BoatMeshType[]{DINGHY, CATAMARAN, PIRATE_SHIP}; - BoatMeshType(String hullFile, String mastFile, double mastOffset, String sailFile, double sailOffset) { + BoatMeshType(String hullFile, String mastFile, double mastOffset, String sailFile, + double sailOffset, String jibFile, boolean fixedSail, double maxSpeedMultiplier, double accelerationMultiplier, double turnStep) { this.hullFile = hullFile; this.mastFile = mastFile; this.mastOffset = mastOffset; this.sailFile = sailFile; this.sailOffset = sailOffset; + this.jibFile = jibFile; + this.fixedSail = fixedSail; + this.maxSpeedMultiplier = maxSpeedMultiplier; + this.accelerationMultiplier = accelerationMultiplier; + this.turnStep = turnStep; + } + + + public static BoatMeshType getNextBoatType(BoatMeshType boatType) { + for (int i = 0; i < boatTypes.length; i++) { + if (i == boatTypes.length -1) { + return boatTypes[0]; + } else if (boatType == boatTypes[i]) { + return boatTypes[i+1]; + } + } + return boatType; + } + + public static BoatMeshType getPrevBoatType(BoatMeshType boatType) { + for (int i = 0; i < boatTypes.length; i++) { + if (i == 0 && boatType == boatTypes[i]) { + return boatTypes[boatTypes.length -1]; + } else if (boatType == boatTypes[i]) { + return boatTypes[i-1]; + } + } + return boatType; } } diff --git a/src/main/java/seng302/visualiser/fxObjects/assets_3D/BoatModel.java b/src/main/java/seng302/visualiser/fxObjects/assets_3D/BoatModel.java index b1373c67..e056b14d 100644 --- a/src/main/java/seng302/visualiser/fxObjects/assets_3D/BoatModel.java +++ b/src/main/java/seng302/visualiser/fxObjects/assets_3D/BoatModel.java @@ -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() { @@ -69,4 +71,8 @@ public class BoatModel extends Model { private MeshView getMeshViewChild(int index) { return (MeshView) assets.getChildren().get(index); } + + public BoatMeshType getMeshType() { + return meshType; + } } \ No newline at end of file diff --git a/src/main/java/seng302/visualiser/fxObjects/assets_3D/BoatObject.java b/src/main/java/seng302/visualiser/fxObjects/assets_3D/BoatObject.java index 57975935..abf969a8 100644 --- a/src/main/java/seng302/visualiser/fxObjects/assets_3D/BoatObject.java +++ b/src/main/java/seng302/visualiser/fxObjects/assets_3D/BoatObject.java @@ -11,7 +11,7 @@ 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 boats velocity. The + * a wake object and two text labels to annotate the boat teams name and the boatTypes velocity. The * boat will update it's position onscreen everytime UpdatePosition is called unless the window is * minimized in which case it attempts to store animations and apply them when the window is * maximised. @@ -28,15 +28,15 @@ public class BoatObject extends Group { private Group wake; private Color colour = Color.BLACK; private Boolean isSelected = false; - private Rotate rotation = new Rotate(0,0,1); + private Rotate rotation = new Rotate(0, new Point3D(0,0,1)); private List selectedBoatListenerListeners = new ArrayList<>(); /** * Creates a BoatGroup with the default triangular boat polygon. */ - public BoatObject() { - boatAssets = ModelFactory.boatGameView(BoatMeshType.DINGHY, colour); + public BoatObject(BoatMeshType boatMeshType) { + boatAssets = ModelFactory.boatGameView(boatMeshType, colour); boatAssets.hideSail(); boatAssets.getAssets().getTransforms().addAll( rotation @@ -66,8 +66,6 @@ public class BoatObject extends Group { * @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); this.layoutXProperty().setValue(x); diff --git a/src/main/java/seng302/visualiser/fxObjects/assets_3D/ModelFactory.java b/src/main/java/seng302/visualiser/fxObjects/assets_3D/ModelFactory.java index b49c36c1..91f832ad 100644 --- a/src/main/java/seng302/visualiser/fxObjects/assets_3D/ModelFactory.java +++ b/src/main/java/seng302/visualiser/fxObjects/assets_3D/ModelFactory.java @@ -7,6 +7,7 @@ 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; @@ -18,7 +19,7 @@ import javafx.scene.transform.Translate; /** - * Factory class for creating 3D models of boats. + * Factory class for creating 3D models of boatTypes. */ public class ModelFactory { @@ -51,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( @@ -84,20 +114,29 @@ public class ModelFactory { } 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); diff --git a/src/main/resources/PP.png b/src/main/resources/PP.png index 1cc88a95..6db4eb3d 100644 Binary files a/src/main/resources/PP.png and b/src/main/resources/PP.png differ diff --git a/src/main/resources/css/Master.css b/src/main/resources/css/Master.css index 8636a88a..cb50a645 100644 --- a/src/main/resources/css/Master.css +++ b/src/main/resources/css/Master.css @@ -44,6 +44,11 @@ -fx-border-color: -fx-decorator-color; -fx-border-width: 0 4 4 4; } + +.jfx-decorator-button { + -fx-focus-traversable: false; /* so decorator button will not be focused */ +} + /********* customised scroll bar for scroll pane ***********/ /* The main scrollbar **track** CSS class */ @@ -99,4 +104,16 @@ .slider .track { -fx-background-color: -fx-pp-dark-text-color; +} + +.jfx-snackbar-content { + -fx-background-color: -fx-pp-front-color; + -fx-padding: 0 5 0 5; + -fx-spacing: 0 5 0 5; + -fx-font-size: 15; +} + +.jfx-snackbar-toast { + -fx-text-fill: -fx-pp-theme-color; + -fx-font-size: 15; } \ No newline at end of file diff --git a/src/main/resources/css/RaceView.css b/src/main/resources/css/RaceView.css index 11e8f285..f38216c8 100644 --- a/src/main/resources/css/RaceView.css +++ b/src/main/resources/css/RaceView.css @@ -48,6 +48,7 @@ GridPane .timer * { -fx-text-fill: -fx-pp-theme-color; -fx-font-size: 13px; -fx-pref-height: 35px; + -fx-focus-traversable: false; } #chatSend:hover { diff --git a/src/main/resources/css/StartScreenView.css b/src/main/resources/css/StartScreenView.css index 04338028..bffc296f 100644 --- a/src/main/resources/css/StartScreenView.css +++ b/src/main/resources/css/StartScreenView.css @@ -2,6 +2,7 @@ -fx-font-size: 20px; -fx-text-fill: -fx-pp-light-text-color; -fx-background-color: -fx-pp-theme-color; + -fx-focus-traversable: false; } .jfx-rippler { diff --git a/src/main/resources/css/dialogs/KeyBindingDialog.css b/src/main/resources/css/dialogs/KeyBindingDialog.css new file mode 100644 index 00000000..8d09e130 --- /dev/null +++ b/src/main/resources/css/dialogs/KeyBindingDialog.css @@ -0,0 +1,54 @@ +#keyBindingDialogHeader { + -fx-font-size: 27px; + -fx-text-fill: -fx-pp-dark-text-color; +} + +#closeLabel { + -fx-font-size: 30; + -fx-text-fill: -fx-pp-dark-text-color; +} + +#closeLabel:hover { + -fx-text-fill: -fx-pp-theme-color; + -fx-font-size: 33; +} + +JFXButton { + -fx-background-color: -fx-pp-light-text-color; + -fx-text-fill: -fx-pp-theme-color; + -fx-font-size: 13px; +} + +Label { + -fx-font-size: 15px; + -fx-text-fill: -fx-pp-theme-color; + -fx-effect: -fx-pp-dropshadow-light; +} + +JFXToggleButton { + -jfx-toggle-color: -fx-pp-theme-color; + -fx-text-fill: -fx-pp-theme-color; +} + +#resetBtn { + -fx-background-color: -fx-pp-theme-color; + -fx-text-fill: -fx-pp-front-color; + -fx-effect: -fx-pp-dropshadow-light; + -fx-font-size: 18; +} + +#resetBtn:hover { + -fx-font-size: 20; +} + +.jfx-snackbar-content { + -fx-background-color: #323232; +} + +.jfx-snackbar-toast { + -fx-text-fill: WHITE; +} + +.jfx-snackbar-action { + -fx-text-fill: #ff4081; +} \ No newline at end of file diff --git a/src/main/resources/css/dialogs/Snackbar.css b/src/main/resources/css/dialogs/Snackbar.css new file mode 100644 index 00000000..0fbe23b2 --- /dev/null +++ b/src/main/resources/css/dialogs/Snackbar.css @@ -0,0 +1,4 @@ +/* a separate file to dynamically change snackbar's color */ +.jfx-snackbar-toast { + -fx-text-fill: red !important; +} \ No newline at end of file diff --git a/src/main/resources/meshes/boatSTLs/catamaran_hull.stl b/src/main/resources/meshes/boatSTLs/catamaran_hull.stl new file mode 100644 index 00000000..a7f70e54 Binary files /dev/null and b/src/main/resources/meshes/boatSTLs/catamaran_hull.stl differ diff --git a/src/main/resources/meshes/boatSTLs/catamaran_mast.stl b/src/main/resources/meshes/boatSTLs/catamaran_mast.stl new file mode 100644 index 00000000..536184da Binary files /dev/null and b/src/main/resources/meshes/boatSTLs/catamaran_mast.stl differ diff --git a/src/main/resources/meshes/boatSTLs/catamaran_sail.stl b/src/main/resources/meshes/boatSTLs/catamaran_sail.stl new file mode 100644 index 00000000..273b1d5b Binary files /dev/null and b/src/main/resources/meshes/boatSTLs/catamaran_sail.stl differ diff --git a/src/main/resources/meshes/boatSTLs/dinghy_hull.stl b/src/main/resources/meshes/boatSTLs/dinghy_hull.stl new file mode 100644 index 00000000..9450b75f Binary files /dev/null and b/src/main/resources/meshes/boatSTLs/dinghy_hull.stl differ diff --git a/src/main/resources/meshes/boatSTLs/dinghy_mast.stl b/src/main/resources/meshes/boatSTLs/dinghy_mast.stl new file mode 100644 index 00000000..2ab71fcf Binary files /dev/null and b/src/main/resources/meshes/boatSTLs/dinghy_mast.stl differ diff --git a/src/main/resources/meshes/boatSTLs/dinghy_sail.stl b/src/main/resources/meshes/boatSTLs/dinghy_sail.stl new file mode 100644 index 00000000..f10f0c78 Binary files /dev/null and b/src/main/resources/meshes/boatSTLs/dinghy_sail.stl differ diff --git a/src/main/resources/meshes/boatSTLs/pirateship_frontsail.stl b/src/main/resources/meshes/boatSTLs/pirateship_frontsail.stl new file mode 100644 index 00000000..b344e825 Binary files /dev/null and b/src/main/resources/meshes/boatSTLs/pirateship_frontsail.stl differ diff --git a/src/main/resources/meshes/boatSTLs/pirateship_hull.stl b/src/main/resources/meshes/boatSTLs/pirateship_hull.stl new file mode 100644 index 00000000..b15804b8 Binary files /dev/null and b/src/main/resources/meshes/boatSTLs/pirateship_hull.stl differ diff --git a/src/main/resources/meshes/boatSTLs/pirateship_mainsail.stl b/src/main/resources/meshes/boatSTLs/pirateship_mainsail.stl new file mode 100644 index 00000000..c421901a Binary files /dev/null and b/src/main/resources/meshes/boatSTLs/pirateship_mainsail.stl differ diff --git a/src/main/resources/meshes/boatSTLs/pirateship_mast.stl b/src/main/resources/meshes/boatSTLs/pirateship_mast.stl new file mode 100644 index 00000000..d15ab860 Binary files /dev/null and b/src/main/resources/meshes/boatSTLs/pirateship_mast.stl differ diff --git a/src/main/resources/meshes/dinghy_hull.stl b/src/main/resources/meshes/dinghy_hull.stl deleted file mode 100644 index 56a443a7..00000000 Binary files a/src/main/resources/meshes/dinghy_hull.stl and /dev/null differ diff --git a/src/main/resources/meshes/dinghy_mast.stl b/src/main/resources/meshes/dinghy_mast.stl deleted file mode 100644 index d4040f90..00000000 Binary files a/src/main/resources/meshes/dinghy_mast.stl and /dev/null differ diff --git a/src/main/resources/meshes/dinghy_sail.stl b/src/main/resources/meshes/dinghy_sail.stl deleted file mode 100644 index 12f4b334..00000000 Binary files a/src/main/resources/meshes/dinghy_sail.stl and /dev/null differ diff --git a/src/main/resources/server_config/xml_templates/boats.ftlh b/src/main/resources/server_config/xml_templates/boats.ftlh index 8186e000..26fae383 100644 --- a/src/main/resources/server_config/xml_templates/boats.ftlh +++ b/src/main/resources/server_config/xml_templates/boats.ftlh @@ -12,7 +12,7 @@ <#list boats as boat> - diff --git a/src/main/resources/views/RaceView.fxml b/src/main/resources/views/RaceView.fxml index a2c22e09..879b2f22 100644 --- a/src/main/resources/views/RaceView.fxml +++ b/src/main/resources/views/RaceView.fxml @@ -14,234 +14,232 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + - + diff --git a/src/main/resources/views/dialogs/BoatCustomizeDialog.fxml b/src/main/resources/views/dialogs/BoatCustomizeDialog.fxml index 8e8653cf..809b96a2 100644 --- a/src/main/resources/views/dialogs/BoatCustomizeDialog.fxml +++ b/src/main/resources/views/dialogs/BoatCustomizeDialog.fxml @@ -1,5 +1,11 @@ + + + + + + @@ -10,54 +16,45 @@ - + + - - - - + + + + + + - - - + + diff --git a/src/main/resources/views/dialogs/KeyBindingDialog.fxml b/src/main/resources/views/dialogs/KeyBindingDialog.fxml new file mode 100644 index 00000000..4a677797 --- /dev/null +++ b/src/main/resources/views/dialogs/KeyBindingDialog.fxml @@ -0,0 +1,122 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/test/java/seng302/model/UpdateYachtTest.java b/src/test/java/seng302/model/UpdateYachtTest.java index 6c0b1550..cdce3708 100644 --- a/src/test/java/seng302/model/UpdateYachtTest.java +++ b/src/test/java/seng302/model/UpdateYachtTest.java @@ -7,6 +7,7 @@ import org.junit.Before; import org.junit.Test; import seng302.gameServer.GameState; import seng302.utilities.GeoUtility; +import seng302.visualiser.fxObjects.assets_3D.BoatMeshType; /** * Test update function in Yacht.java to make sure yacht will not be collide each other within 25.0 @@ -14,8 +15,10 @@ import seng302.utilities.GeoUtility; */ 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); diff --git a/src/test/java/seng302/models/YachtTest.java b/src/test/java/seng302/models/YachtTest.java index a1000402..859a83c8 100644 --- a/src/test/java/seng302/models/YachtTest.java +++ b/src/test/java/seng302/models/YachtTest.java @@ -4,6 +4,8 @@ import org.junit.AfterClass; import org.junit.BeforeClass; import seng302.gameServer.GameState; import seng302.model.ServerYacht; +import seng302.visualiser.fxObjects.assets_3D.BoatMeshType; +import seng302.visualiser.fxObjects.assets_3D.BoatMeshType; public class YachtTest { @@ -17,7 +19,7 @@ public class YachtTest { @BeforeClass public static void setUp() { new GameState(); - y1 = new ServerYacht("Yacht", 1, "Y1", "Y1", "Yacht 1", "C1"); + y1 = new ServerYacht(BoatMeshType.DINGHY, 1, "Y1", "Y1", "Yacht 1", "C1"); gs = new GameState(); } diff --git a/src/test/java/seng302/utilities/BoatMeshTypeTest.java b/src/test/java/seng302/utilities/BoatMeshTypeTest.java new file mode 100644 index 00000000..8f0d30b9 --- /dev/null +++ b/src/test/java/seng302/utilities/BoatMeshTypeTest.java @@ -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.CATAMARAN, nextBoat); + } + + @Test + public void testPreviousBoatMeshType() { + BoatMeshType currentBoat = BoatMeshType.CATAMARAN; + BoatMeshType prevBoat = BoatMeshType.getPrevBoatType(currentBoat); + Assert.assertEquals(BoatMeshType.DINGHY, prevBoat); + } + +} diff --git a/src/test/java/seng302/visualiser/map/BoatSailAnimationToggleTest.java b/src/test/java/seng302/visualiser/map/BoatSailAnimationToggleTest.java index 70c5c80b..9e95f169 100644 --- a/src/test/java/seng302/visualiser/map/BoatSailAnimationToggleTest.java +++ b/src/test/java/seng302/visualiser/map/BoatSailAnimationToggleTest.java @@ -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 diff --git a/src/test/java/steps/ToggleSailSteps.java b/src/test/java/steps/ToggleSailSteps.java index 4bf20242..5c82a614 100644 --- a/src/test/java/steps/ToggleSailSteps.java +++ b/src/test/java/steps/ToggleSailSteps.java @@ -13,6 +13,7 @@ import seng302.model.ServerYacht; import seng302.visualiser.ClientToServerThread; /** + * * Created by kre39 on 7/08/17. */ public class ToggleSailSteps {