Compare commits

..

49 Commits

Author SHA1 Message Date
Zhi You Tan 0e93be7b36 Fixed send button traversable issue.
- removed sensitive characters.

#story[1278] #pair[hyi25, zyt10]
2017-09-25 17:06:36 +13:00
Zhi You Tan 191b818e38 Added close button for keyBindingDialog.
- fixed that you cannot bind the key you are using.

#story[1278] #pair[hyi25, zyt10]
2017-09-25 16:31:28 +13:00
Haoming Yin 19db6668da Fixed merge conflicts in server yacht
tags #story[1278]
2017-09-25 11:09:14 +13:00
Haoming Yin 44275aec04 Merge branch 'develop' into Story1278_keybindings
# Conflicts:
#	src/main/java/seng302/model/ServerYacht.java
2017-09-25 11:06:28 +13:00
Zhi You Tan 64245833cd Merge branch 'Story1274_custom_boat_stats' into 'develop'
Story1274 custom boat stats

# Changes
- Added 3 areas for game play variation with the boats (stats)
    - Max speed
    - Handling
    - Acceleration
- Added stat bars on the customize boat screen so players can see the stats

# Testing
- Manual testing
- No JUnits made since no real processing methods were added


See merge request !72
2017-09-24 18:53:15 +13:00
Kusal Ekanayake aa0149b9a7 Merge branch 'develop' into Story1274_custom_boat_stats 2017-09-24 18:08:54 +13:00
Kusal Ekanayake f6b41f0513 Fixes Issue #59 2017-09-24 18:06:26 +13:00
Haoming Yin 8dfdb228e9 Fixed a bug that game client tries to send turning mode packet when there is no socketThread
- add a if statement to check if socketThread is initialized before sending packet.

#story[1278]
2017-09-23 21:04:57 +12:00
Haoming Yin 1042817e4e Snackbar's color can be changed according to the message type
- load a separate css file to change the color
- if the assignment failed, the snackbar prompt will be red, otherwise theme color

#story[1278]
2017-09-23 20:59:29 +12:00
Haoming Yin 066557584f Implemented turning mode toggle
- when the mode is toggled, a boat action package will be sent to notify server
to change the boat's turning mode
- turning mode toggle is now fully functional

#story[1245]
2017-09-23 19:37:13 +12:00
Haoming Yin 4011295b8b Slightly optimised code style and add more functionality
- optimised UI
- check conflicts when change key bind if the key has already been in use
- abstract keybind as a separate singleton class so all class can access it
- [WIP] turning mode is need to be finished

#story[1245]
2017-09-23 17:52:48 +12:00
Kusal Ekanayake 0a885dd8fd Clean up changes
#story[1274]
2017-09-23 15:37:16 +12:00
Kusal Ekanayake e9b50038a9 Balance changes. Always wanted to use that as a commit message.
#story[1274]
2017-09-23 15:09:22 +12:00
Kusal Ekanayake 364264377a Fixed merge errors and reimplemented handling multiplier
#story[1274]
2017-09-23 15:04:11 +12:00
Kusal Ekanayake 9112183ac3 Merge branch 'develop' into Story1274_custom_boat_stats
# Conflicts:
#	src/main/java/seng302/model/ServerYacht.java
#	src/main/java/seng302/visualiser/controllers/dialogs/BoatCustomizeController.java
2017-09-23 14:48:50 +12:00
Zhi You Tan 957821f1f2 [WIP] Created a snackbar for notification. Currently used for keybinding success/fail. Need to show red if fails.
#story[1278]
2017-09-23 01:39:26 +12:00
Zhi You Tan 094eb4c1cf Merge remote-tracking branch 'origin/develop' into Story1278_keybindings
# Conflicts:
#	src/main/resources/views/RaceView.fxml
2017-09-22 21:22:06 +12:00
William Muir 607acff7c6 Merge branch 'Custom_boat_selection' into 'develop'
Custom boat selection

# Story 1274 Feature Custom Boat Selection
## Changes
- 2 new boats!
- A boat selector in the customisation for boat dialog
- The potential for everyone to use whatever boats and for everyone to see

## Testing
- Basic JUnit tests added to test basic util methods added to the BoatMeshType class
- Manual testing completed

See merge request !71
2017-09-22 21:14:12 +12:00
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 52dc7a956d Turned handling into a multiplier.
#story[1274]
2017-09-22 17:42:32 +12:00
Kusal Ekanayake 9f64b2380d Implemented acceleration and full loading bars.
#story[1274]
2017-09-22 17:28:42 +12:00
Kusal Ekanayake b05580f018 Worked on making a visual component to the stats. Need to implement acceleration.
#story[1274]
2017-09-22 16:45:10 +12:00
Haoming Yin c20c6fb264 [WIP] Added new toggle for steer turning mode and submit and reset button (restore the setting to default)
- minor fix of UI elements to make the font smaller
- centred labels and buttons

tags: #story[1246]
2017-09-22 13:53:36 +12:00
Kusal Ekanayake faeece27ff Started working on individual boat stats. Already modified turning rate. Need to add a vsual component.
#story[1274]
2017-09-22 13:52:35 +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
Zhi You Tan d4d7ddf8e2 Keybinding now works in the actual race. A map of keybind is shared between GameClient and KeyBindDialogController.
#story[1278]
2017-09-20 11:02:13 +12:00
Zhi You Tan a1933c2869 - Created keybindingcontroller which can detect keypress and can save the keybind throughout the app
- Changed keybindingglyph to keyboard icon
- Fix button hover CSS to change text fill

#story[1278]
2017-09-20 02:42:02 +12:00
Zhi You Tan 8084a61333 Fix keybinding dialog creating on top of another keybinding dialog.
#story[1278]
2017-09-19 23:41:06 +12:00
Zhi You Tan 03f5f91043 Done some CSS on keybindingdialog
#story[1278]
2017-09-19 19:49:36 +12:00
Peter Galloway 9ed52a1225 created catamaran mesh #story[1274] 2017-09-19 19:43:03 +12:00
Zhi You Tan 027324cc4f - Fixed JFXDialog initialised in lobby, raceview, serverlist controller by default. Now, dialog only appears when called.
- [WIP] Created keybindingdialog fxml. CSS not yet done.
 - Removed top most anchorpane on raceview so parent is stackpane like other views.

#story[1278]
2017-09-19 18:40:01 +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
51 changed files with 1371 additions and 557 deletions
+50 -24
View File
@@ -1,12 +1,35 @@
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.*;
import seng302.model.*;
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;
@@ -14,10 +37,7 @@ import seng302.model.token.Token;
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)
@@ -271,6 +291,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;
}
}
@@ -323,6 +349,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!");
}
}
@@ -433,6 +460,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
@@ -447,7 +475,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;
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
@@ -459,17 +487,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);
}
@@ -531,6 +559,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);
@@ -565,6 +596,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;
}
}
@@ -668,6 +700,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;
}
}
@@ -695,6 +728,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));
}
}
@@ -788,12 +824,7 @@ public class GameState implements Runnable {
try {
setSpeedMultiplier(Double.valueOf(words[3]));
sendServerMessage(chatterMessage.getMessage_type(),
"SERVER: Speed modifier set to x" + words[3]);
System.out.println(chatterMessage.getMessage_type());
// notifyMessageListeners(new ChatterMessage(
// chatterMessage.getMessage_type(),
// "SERVER: Speed modifier set to x" + words[3]
// ));
"Speed modifier set to x" + words[3]);
} catch (Exception e) {
Logger logger = LoggerFactory.getLogger(GameState.class);
logger.error("cannot parse >speed value");
@@ -801,12 +832,7 @@ public class GameState implements Runnable {
return;
case "/finish":
sendServerMessage(chatterMessage.getMessage_type(),
"SERVER: Game will now finish");
System.out.println(chatterMessage.getMessage_type());
// notifyMessageListeners(new ChatterMessage(
// chatterMessage.getMessage_type(),
// "SERVER: Game will now finish"
// ));
"Game will now finish");
endRace();
return;
}
@@ -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);
@@ -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<Integer, BoatAction> intToTypeMap = new HashMap<>();
+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;
}
@@ -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<KeyCode, KeyAction> keyToActionMap;
private Map<KeyAction, KeyCode> actionToKeyMap;
private Boolean continuouslyTurning;
private GameKeyBind() {
setToDefault();
}
public void setToDefault() {
actionToKeyMap = new HashMap<>();
keyToActionMap = new HashMap<>();
continuouslyTurning = false;
// default key bindings
ArrayList<KeyCode> keys = new ArrayList<>();
keys.add(KeyCode.Z);
keys.add(KeyCode.X);
keys.add(KeyCode.SPACE);
keys.add(KeyCode.SHIFT);
keys.add(KeyCode.ENTER);
keys.add(KeyCode.PAGE_UP);
keys.add(KeyCode.PAGE_DOWN);
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;
}
}
@@ -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<Integer, KeyAction> intToTypeMap = new HashMap<>();
static {
for (KeyAction type : KeyAction.values()) {
intToTypeMap.put(type.getValue(), type);
}
}
KeyAction(int type) {
this.type = type;
}
public static KeyAction getType(int value) {
return intToTypeMap.get(value);
}
public int getValue() {
return this.type;
}
}
+79 -44
View File
@@ -1,5 +1,6 @@
package seng302.model;
import java.util.HashMap;
import javafx.scene.paint.Color;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -8,10 +9,7 @@ import seng302.gameServer.messages.BoatStatus;
import seng302.model.mark.Mark;
import seng302.model.token.TokenType;
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 +18,14 @@ import java.util.Observer;
*/
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;
@@ -56,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;
@@ -80,6 +82,8 @@ public class ServerYacht {
this.hasEnteredRoundingZone = false;
this.hasPassedLine = false;
this.hasPassedThroughGate = false;
this.continuouslyTurning = false;
}
@@ -129,7 +133,7 @@ public class ServerYacht {
* @param amount the amount by which to adjust the boat heading.
*/
public void adjustHeading(Double amount) {
Double newVal = heading + amount;
Double newVal = heading + (amount * turnStepMultiplier);
lastHeading = heading;
heading = (double) Math.floorMod(newVal.longValue(), 360L);
}
@@ -174,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;
}
}
@@ -187,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);
}
}
}
@@ -268,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);
}
}
@@ -421,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;
}
}
+15 -7
View File
@@ -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);
@@ -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;
@@ -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<ClientYacht> finishedBoats = new ArrayList<>();
private GameKeyBind gameKeyBind; // all the key binding setting.
private ObservableList<String> 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,13 @@ 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
socketThread.sendBoatAction(BoatAction.SAILS_IN);
allBoatsMap.get(socketThread.getClientId()).toggleSail();
break;
case PAGE_UP:
case PAGE_DOWN:
socketThread.sendBoatAction(BoatAction.MAINTAIN_HEADING); break;
if (gameKeyBind.getKeyCode(KeyAction.SAILS_STATE) == e.getCode()) { // sails in/sails out
socketThread.sendBoatAction(BoatAction.SAILS_IN);
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 +459,14 @@ public class GameClient {
public Map<Integer, ClientYacht> getAllBoatsMap() {
return allBoatsMap;
}
public void sendToggleTurningModePacket() {
if (socketThread != null) {
if (gameKeyBind.isContinuouslyTurning()) {
socketThread.sendBoatAction(BoatAction.CONTINUOUSLY_TURNING);
} else {
socketThread.sendBoatAction(BoatAction.DEFAULT_TURNING);
}
}
}
}
@@ -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<Group> 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;
@@ -33,6 +33,7 @@ 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 {
@@ -90,16 +91,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());
@@ -129,6 +130,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;
}
@@ -202,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();
@@ -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<Boolean>() {
@@ -200,26 +199,27 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
public void showFinishDialog(ArrayList<ClientYacht> finishedBoats) {
raceState.setRaceStarted(false);
finishDialogController.setFinishedBoats(finishedBoats);
finishScreenDialog.show();
createFinishDialog(finishedBoats);
}
private JFXDialog createFinishDialog() {
/**
* Create finishScreenDialog and set up finishDialogController.
*/
private void createFinishDialog(ArrayList<ClientYacht> 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;
}
@@ -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) {
logger.warn("Could not create Server Creation Dialog.");
}
@@ -2,6 +2,9 @@ package seng302.visualiser.controllers;
import com.jfoenix.controls.JFXButton;
import com.jfoenix.controls.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<String, String> properties; //TODO is this the best way to do this??
private ObservableList<String> 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<Node> nodes) {
boolean foundJFXDialog = false;
for (Node node : nodes) {
if (node instanceof JFXDialog) {
return true;
} else if (node instanceof StackPane) {
foundJFXDialog = checkDialogOpened(((StackPane) node).getChildren());
}
}
return foundJFXDialog;
}
private void showKeyBindingDialog() throws IOException {
FXMLLoader dialogContent = new FXMLLoader(getClass().getResource(
"/views/dialogs/KeyBindingDialog.fxml"));
for (Node node : decorator.getChildren()) {
if (node instanceof StackPane) {
keyBindingDialog = new JFXDialog((StackPane) node,
dialogContent.load(),
DialogTransition.CENTER);
KeyBindingDialogController keyBindingDialogController = dialogContent
.getController();
keyBindingDialogController.setGameClient(this.gameClient);
keyBindingDialog.show();
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;
}
}
@@ -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());
}
@@ -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);
}
}
@@ -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<JFXButton> buttons = new ArrayList<>();
private Map<Button, KeyAction> buttonActionMap;
private GameClient gameClient; // to send turning mode packet
@Override
public void initialize(URL location, ResourceBundle resources) {
gameKeyBind = GameKeyBind.getInstance();
buttons = new ArrayList<>();
Collections.addAll(buttons,
zoomInbtn, zoomOutBtn, vmgBtn, sailInOutBtn, tackGybeBtn, upwindBtn, downwindBtn);
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;
}
}
@@ -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, 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, 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;
}
}
@@ -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;
}
}
@@ -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<SelectedBoatListener> 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);
@@ -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(
@@ -78,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.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);
@@ -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

+17
View File
@@ -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;
}
+1
View File
@@ -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 {
@@ -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 {
@@ -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;
}
@@ -0,0 +1,4 @@
/* a separate file to dynamically change snackbar's color */
.jfx-snackbar-toast {
-fx-text-fill: red !important;
}
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -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" />
+225 -227
View File
@@ -14,234 +14,232 @@
<?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"
<StackPane fx:id="contentStackPane" 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"
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">
<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 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>
</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 bottom="10.0" right="10.0"/>
</GridPane.margin>
</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>
<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 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>
</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 bottom="10.0" right="10.0"/>
</GridPane.margin>
</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>
<stylesheets>
<String fx:value="/css/Master.css" />
<String fx:value="/css/RaceView.css" />
<String fx:value="/css/Master.css"/>
<String fx:value="/css/RaceView.css"/>
</stylesheets>
</AnchorPane>
</StackPane>
@@ -1,5 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.text.*?>
<?import com.jfoenix.controls.*?>
<?import java.lang.*?>
<?import javafx.geometry.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import com.jfoenix.controls.JFXButton?>
<?import com.jfoenix.controls.JFXColorPicker?>
<?import com.jfoenix.controls.JFXDialogLayout?>
@@ -10,54 +16,45 @@
<?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="99.0"
vgrow="SOMETIMES"/>
<RowConstraints maxHeight="164.0" minHeight="100.0" prefHeight="126.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="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="5" GridPane.valignment="CENTER" />
<JFXTextField fx:id="boatName" focusColor="#6c6c6c" promptText="Boat Name" unFocusColor="#6b6b6b" GridPane.rowIndex="3">
<GridPane.margin>
<Insets left="30.0" right="30.0" />
</GridPane.margin></JFXTextField>
<GridPane GridPane.halignment="CENTER" GridPane.rowIndex="2"
GridPane.valignment="CENTER">
<GridPane GridPane.halignment="CENTER" GridPane.rowIndex="4" GridPane.valignment="CENTER">
<columnConstraints>
<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 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 percentHeight="100.0" valignment="CENTER" 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" GridPane.valignment="CENTER">
<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" GridPane.valignment="CENTER">
<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>
@@ -65,11 +62,45 @@
<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>
<GridPane GridPane.rowIndex="2">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
</rowConstraints>
<children>
<Text strokeType="OUTSIDE" strokeWidth="0.0" text="Max Speed:" GridPane.halignment="CENTER" GridPane.valignment="CENTER" />
<Text strokeType="OUTSIDE" strokeWidth="0.0" text="Acceleration:" GridPane.halignment="CENTER" GridPane.rowIndex="1" GridPane.valignment="CENTER" />
<Text strokeType="OUTSIDE" strokeWidth="0.0" text="Handling:" GridPane.halignment="CENTER" GridPane.rowIndex="2" GridPane.valignment="CENTER" />
<ProgressBar fx:id="speedBar" focusTraversable="false" prefWidth="200.0" progress="0.0" GridPane.columnIndex="1" />
<ProgressBar fx:id="accelBar" prefWidth="200.0" progress="0.0" GridPane.columnIndex="1" GridPane.rowIndex="1" />
<ProgressBar fx:id="handleBar" prefWidth="200.0" progress="0.0" GridPane.columnIndex="1" GridPane.rowIndex="2" />
</children>
</GridPane>
</children>
</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,122 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import com.jfoenix.controls.JFXButton?>
<?import com.jfoenix.controls.JFXDialogLayout?>
<?import com.jfoenix.controls.JFXToggleButton?>
<?import java.net.URL?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.RowConstraints?>
<JFXDialogLayout fx:id="keyBindDialog" maxHeight="-Infinity" maxWidth="-Infinity"
minHeight="-Infinity" minWidth="-Infinity" prefHeight="580.0" prefWidth="500.0"
xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1"
fx:controller="seng302.visualiser.controllers.dialogs.KeyBindingDialogController">
<children>
<GridPane>
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="100.0" prefWidth="100.0"/>
<ColumnConstraints hgrow="SOMETIMES" minWidth="100.0" prefWidth="100.0"/>
</columnConstraints>
<rowConstraints>
<RowConstraints maxHeight="60.0" minHeight="60.0" prefHeight="60.0" vgrow="SOMETIMES" />
<RowConstraints maxHeight="50.0" minHeight="50.0" prefHeight="50.0" vgrow="SOMETIMES"/>
<RowConstraints maxHeight="50.0" minHeight="50.0" prefHeight="50.0" vgrow="SOMETIMES"/>
<RowConstraints maxHeight="50.0" minHeight="50.0" prefHeight="50.0" vgrow="SOMETIMES"/>
<RowConstraints maxHeight="50.0" minHeight="50.0" prefHeight="50.0" vgrow="SOMETIMES"/>
<RowConstraints maxHeight="50.0" minHeight="50.0" prefHeight="50.0" vgrow="SOMETIMES"/>
<RowConstraints maxHeight="50.0" minHeight="50.0" prefHeight="50.0" vgrow="SOMETIMES"/>
<RowConstraints maxHeight="50.0" minHeight="50.0" prefHeight="50.0" vgrow="SOMETIMES"/>
<RowConstraints maxHeight="50.0" minHeight="50.0" prefHeight="50.0" vgrow="SOMETIMES"/>
<RowConstraints maxHeight="-Infinity" minHeight="-Infinity" prefHeight="70.0"
vgrow="SOMETIMES"/>
</rowConstraints>
<children>
<Label fx:id="keyBindingDialogHeader" text="CUSTOM KEYBIND" GridPane.columnSpan="2" GridPane.halignment="CENTER" GridPane.valignment="CENTER" />
<Label text="ZOOM IN" GridPane.halignment="CENTER" GridPane.rowIndex="1"
GridPane.valignment="CENTER">
<GridPane.margin>
<Insets/>
</GridPane.margin></Label>
<Label text="ZOOM OUT" GridPane.halignment="CENTER" GridPane.rowIndex="2"
GridPane.valignment="CENTER">
<GridPane.margin>
<Insets/>
</GridPane.margin></Label>
<Label text="VMG" GridPane.halignment="CENTER" GridPane.rowIndex="3"
GridPane.valignment="CENTER">
<GridPane.margin>
<Insets/>
</GridPane.margin></Label>
<Label text="SAILS IN/OUT" GridPane.halignment="CENTER" GridPane.rowIndex="4"
GridPane.valignment="CENTER">
<GridPane.margin>
<Insets/>
</GridPane.margin></Label>
<Label text="TACK/GYBE" GridPane.halignment="CENTER" GridPane.rowIndex="5"
GridPane.valignment="CENTER">
<GridPane.margin>
<Insets/>
</GridPane.margin></Label>
<Label fx:id="upwindLabel" text="UPWIND" GridPane.halignment="CENTER"
GridPane.rowIndex="6" GridPane.valignment="CENTER">
<GridPane.margin>
<Insets/>
</GridPane.margin></Label>
<Label fx:id="downwindLabel" text="DOWNWIND" GridPane.halignment="CENTER"
GridPane.rowIndex="7" GridPane.valignment="CENTER">
<GridPane.margin>
<Insets/>
</GridPane.margin></Label>
<JFXButton id="ZOOM IN" fx:id="zoomInbtn" buttonType="RAISED" maxHeight="-Infinity"
maxWidth="-Infinity" minHeight="35.0" minWidth="-Infinity" prefWidth="120.0" text="Z"
GridPane.columnIndex="1" GridPane.halignment="CENTER" GridPane.rowIndex="1"
GridPane.valignment="CENTER"/>
<JFXButton id="ZOOM OUT" fx:id="zoomOutBtn" buttonType="RAISED" maxHeight="-Infinity"
maxWidth="-Infinity" minHeight="35.0" minWidth="-Infinity" prefWidth="120.0" text="X"
GridPane.columnIndex="1" GridPane.halignment="CENTER" GridPane.rowIndex="2"
GridPane.valignment="CENTER"/>
<JFXButton id="VMG" fx:id="vmgBtn" buttonType="RAISED" maxHeight="-Infinity"
maxWidth="-Infinity" minHeight="35.0" minWidth="-Infinity" prefWidth="120.0"
text="SPACE" GridPane.columnIndex="1" GridPane.halignment="CENTER"
GridPane.rowIndex="3" GridPane.valignment="CENTER"/>
<JFXButton id="SAILS IN/OUT" fx:id="sailInOutBtn" buttonType="RAISED"
maxHeight="-Infinity" maxWidth="-Infinity" minHeight="35.0" minWidth="-Infinity"
prefWidth="120.0" text="SHIFT" GridPane.columnIndex="1" GridPane.halignment="CENTER"
GridPane.rowIndex="4" GridPane.valignment="CENTER"/>
<JFXButton id="TACK/GYBE" fx:id="tackGybeBtn" buttonType="RAISED" maxHeight="-Infinity"
maxWidth="-Infinity" minHeight="35.0" minWidth="-Infinity" prefWidth="120.0"
text="ENTER" GridPane.columnIndex="1" GridPane.halignment="CENTER"
GridPane.rowIndex="5" GridPane.valignment="CENTER"/>
<JFXButton id="UPWIND" fx:id="upwindBtn" buttonType="RAISED" maxHeight="-Infinity"
maxWidth="-Infinity" minHeight="35.0" minWidth="-Infinity" prefWidth="120.0"
text="PAGE_UP" GridPane.columnIndex="1" GridPane.halignment="CENTER"
GridPane.rowIndex="6" GridPane.valignment="CENTER"/>
<JFXButton id="DOWNWIND" fx:id="downwindBtn" buttonType="RAISED" maxHeight="-Infinity"
maxWidth="-Infinity" minHeight="35.0" minWidth="-Infinity" prefWidth="120.0"
text="PAGE_DOWN" GridPane.columnIndex="1" GridPane.halignment="CENTER"
GridPane.rowIndex="7" GridPane.valignment="CENTER"/>
<JFXToggleButton fx:id="turningToggle" minHeight="-Infinity" prefHeight="35.0"
text="OFF / ON" GridPane.columnIndex="1" GridPane.halignment="CENTER"
GridPane.rowIndex="8"/>
<Label text="CONTINUOUSLY TURNING" GridPane.halignment="CENTER" GridPane.rowIndex="8"
GridPane.valignment="CENTER">
<GridPane.margin>
<Insets/>
</GridPane.margin>
</Label>
<JFXButton fx:id="resetBtn" buttonType="RAISED" maxHeight="-Infinity"
maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="45.0"
prefWidth="150.0" text="RESET" GridPane.columnSpan="2" GridPane.halignment="CENTER"
GridPane.rowIndex="9" GridPane.valignment="CENTER"/>
<Label fx:id="closeLabel" text="✖" translateY="-5.0" GridPane.columnIndex="1"
GridPane.halignment="RIGHT" GridPane.valignment="TOP"/>
</children>
</GridPane>
</children>
<stylesheets>
<URL value="@../../css/dialogs/KeyBindingDialog.css" />
<URL value="@../../css/Master.css" />
</stylesheets>
</JFXDialogLayout>
@@ -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);
+2 -1
View File
@@ -4,6 +4,7 @@ import org.junit.AfterClass;
import org.junit.BeforeClass;
import seng302.gameServer.GameState;
import seng302.model.ServerYacht;
import seng302.visualiser.fxObjects.assets_3D.BoatMeshType;
public class YachtTest {
@@ -17,7 +18,7 @@ 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");
}
@@ -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);
}
}
@@ -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
+12
View File
@@ -13,6 +13,7 @@ import seng302.model.ServerYacht;
import seng302.visualiser.ClientToServerThread;
/**
*
* Created by kre39 on 7/08/17.
*/
public class ToggleSailSteps {
@@ -24,7 +25,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 +61,6 @@ public class ToggleSailSteps {
Assert.assertFalse(yacht.getSailIn());
}
mst.terminate();
client.setSocketToClose();
}
}