Merge remote-tracking branch 'origin/develop' into develop

This commit is contained in:
William Muir
2017-08-16 20:09:20 +12:00
11 changed files with 238 additions and 98 deletions
+72 -14
View File
@@ -6,8 +6,12 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
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.server.messages.BoatAction;
import seng302.gameServer.server.messages.BoatStatus;
import seng302.gameServer.server.messages.MarkRoundingMessage;
@@ -16,6 +20,7 @@ import seng302.gameServer.server.messages.Message;
import seng302.gameServer.server.messages.RoundingBoatStatus;
import seng302.gameServer.server.messages.YachtEventCodeMessage;
import seng302.model.GeoPoint;
import seng302.model.Limit;
import seng302.model.Player;
import seng302.model.PolarTable;
import seng302.model.ServerYacht;
@@ -23,6 +28,7 @@ import seng302.model.mark.CompoundMark;
import seng302.model.mark.Mark;
import seng302.model.mark.MarkOrder;
import seng302.utilities.GeoUtility;
import seng302.utilities.XMLParser;
/**
* A Static class to hold information about the current state of the game (model)
@@ -33,6 +39,7 @@ public class GameState implements Runnable {
@FunctionalInterface
interface NewMessageListener {
void notify(Message message);
}
@@ -59,6 +66,7 @@ public class GameState implements Runnable {
private static MarkOrder markOrder;
private static long startTime;
private static Set<Mark> marks;
private static List<Limit> courseLimit;
private static List<NewMessageListener> markListeners;
@@ -81,7 +89,7 @@ public class GameState implements Runnable {
yachts = new HashMap<>();
players = new ArrayList<>();
GameState.hostIpAddress = hostIpAddress;
;
currentStage = GameStages.LOBBYING;
isRaceStarted = false;
//set this when game stage changes to prerace
@@ -94,13 +102,29 @@ public class GameState implements Runnable {
new Thread(this, "GameState").start(); //Run the auto updates on the game state
marks = new MarkOrder().getAllMarks();
setCourseLimit("/server_config/race.xml");
}
private void setCourseLimit(String url) {
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
documentBuilderFactory.setNamespaceAware(true);
DocumentBuilder documentBuilder;
Document document = null;
try {
documentBuilder = documentBuilderFactory.newDocumentBuilder();
document = documentBuilder.parse(new InputSource(getClass().getResourceAsStream(url)));
} catch (Exception e) {
// sorry, we have to catch general one, otherwise we have to catch five different exceptions.
logger.trace("Failed to load course limit for boundary collision detection.", e);
}
courseLimit = XMLParser.parseRace(document).getCourseLimit();
}
public static String getHostIpAddress() {
return hostIpAddress;
}
public static Set<Mark> getMarks(){
public static Set<Mark> getMarks() {
return Collections.unmodifiableSet(marks);
}
@@ -144,7 +168,7 @@ public class GameState implements Runnable {
return markOrder;
}
public static long getStartTime(){
public static long getStartTime() {
return startTime;
}
@@ -243,7 +267,7 @@ public class GameState implements Runnable {
yacht.runAutoPilot();
yacht.updateLocation(timeInterval);
if (yacht.getBoatStatus() != BoatStatus.FINISHED) {
checkForCollision(yacht);
checkCollision(yacht);
checkForLegProgression(yacht);
raceFinished = false;
}
@@ -254,9 +278,28 @@ public class GameState implements Runnable {
}
}
/**
* Check if the yacht has crossed the course limit
*
* @param yacht the yacht to be tested
* @return a boolean value of if there is a boundary collision
*/
private static Boolean checkBoundaryCollision(ServerYacht yacht) {
for (int i = 0; i < courseLimit.size() - 1; i++) {
if (GeoUtility.checkCrossedLine(courseLimit.get(i), courseLimit.get(i + 1),
yacht.getLastLocation(), yacht.getLocation()) != 0) {
return true;
}
}
if (GeoUtility.checkCrossedLine(courseLimit.get(courseLimit.size() - 1), courseLimit.get(0),
yacht.getLastLocation(), yacht.getLocation()) != 0) {
return true;
}
return false;
}
public static void checkForCollision(ServerYacht serverYacht) {
ServerYacht collidedYacht = checkCollision(serverYacht);
public static void checkCollision(ServerYacht serverYacht) {
ServerYacht collidedYacht = checkYachtCollision(serverYacht);
if (collidedYacht != null) {
GeoPoint originalLocation = serverYacht.getLocation();
serverYacht.setLocation(
@@ -275,7 +318,7 @@ public class GameState implements Runnable {
new YachtEventCodeMessage(serverYacht.getSourceId())
);
} else {
Mark collidedMark = markCollidedWith(serverYacht);
Mark collidedMark = checkMarkCollision(serverYacht);
if (collidedMark != null) {
serverYacht.setLocation(
calculateBounceBack(serverYacht, collidedMark, BOUNCE_DISTANCE_MARK)
@@ -286,6 +329,17 @@ public class GameState implements Runnable {
notifyMessageListeners(
new YachtEventCodeMessage(serverYacht.getSourceId())
);
} else if (checkBoundaryCollision(serverYacht)) {
serverYacht.setLocation(
calculateBounceBack(serverYacht, serverYacht.getLocation(),
BOUNCE_DISTANCE_YACHT)
);
serverYacht.setCurrentVelocity(
serverYacht.getCurrentVelocity() * COLLISION_VELOCITY_PENALTY
);
notifyMessageListeners(
new YachtEventCodeMessage(serverYacht.getSourceId())
);
}
}
}
@@ -310,7 +364,7 @@ public class GameState implements Runnable {
yacht.changeVelocity(-velocity / 200);
} else if (velocity > 100) {
yacht.changeVelocity(-velocity / 50);
} else if (velocity <= 100){
} else if (velocity <= 100) {
yacht.setCurrentVelocity(0d);
}
}
@@ -352,6 +406,7 @@ public class GameState implements Runnable {
/**
* 4 Different cases of progression in the race 1 - Passing the start line 2 - Passing any
* in-race Gate 3 - Passing any in-race Mark 4 - Passing the finish line
*
* @param yacht the current yacht to check for progression
*/
private void checkForLegProgression(ServerYacht yacht) {
@@ -515,7 +570,7 @@ public class GameState implements Runnable {
}
private static Mark markCollidedWith(ServerYacht yacht) {
private static Mark checkMarkCollision(ServerYacht yacht) {
Set<Mark> marksInRace = GameState.getMarks();
for (Mark mark : marksInRace) {
if (GeoUtility.getDistance(yacht.getLocation(), mark)
@@ -531,12 +586,14 @@ public class GameState implements Runnable {
*
* @return The boats new position
*/
private static GeoPoint calculateBounceBack(ServerYacht yacht, GeoPoint collidedWith, Double bounceDistance) {
Double heading = GeoUtility.getBearing(yacht.getLocation(), collidedWith);
private static GeoPoint calculateBounceBack(ServerYacht yacht, GeoPoint collidedWith,
Double bounceDistance) {
Double heading = GeoUtility.getBearing(yacht.getLastLocation(), collidedWith);
// Invert heading
heading -= 180;
Integer newHeading = Math.floorMod(heading.intValue(), 360);
return GeoUtility.getGeoCoordinate(yacht.getLocation(), newHeading.doubleValue(), bounceDistance);
return GeoUtility
.getGeoCoordinate(yacht.getLocation(), newHeading.doubleValue(), bounceDistance);
}
/**
@@ -545,11 +602,12 @@ public class GameState implements Runnable {
*
* @return yacht to compare to all other yachts.
*/
private static ServerYacht checkCollision(ServerYacht yacht) {
private static ServerYacht checkYachtCollision(ServerYacht yacht) {
for (ServerYacht otherYacht : GameState.getYachts().values()) {
if (otherYacht != yacht) {
Double distance = GeoUtility.getDistance(otherYacht.getLocation(), yacht.getLocation());
Double distance = GeoUtility
.getDistance(otherYacht.getLocation(), yacht.getLocation());
if (distance < YACHT_COLLISION_DISTANCE) {
return otherYacht;
}
+1 -1
View File
@@ -40,7 +40,7 @@ public class ClientYacht extends Observable {
private String country;
private Long estimateTimeAtFinish;
private Boolean sailIn = false;
private Boolean sailIn = true;
private Integer currentMarkSeqID = 0;
private Long markRoundTime;
private Long timeTillNext;
+1 -1
View File
@@ -60,7 +60,7 @@ public class ServerYacht extends Observable {
this.country = country;
this.sailIn = false;
this.isAuto = false;
this.location = new GeoPoint(57.670341, 11.826856);
this.location = new GeoPoint(57.67046, 11.83751);
this.lastLocation = location;
this.heading = 120.0; //In degrees
this.currentVelocity = 0d; //in mms-1
@@ -365,14 +365,15 @@ public class GameClient {
socketThread.sendBoatAction(BoatAction.TACK_GYBE); break;
//TODO Allow a zoom in and zoom out methods
case Z: // zoom in
System.out.println("Zoom in");
raceView.getGameView().zoomIn();
break;
case X: // zoom out
System.out.println("Zoom out");
raceView.getGameView().zoomOut();
break;
}
}
private void keyReleased(KeyEvent e) {
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)
+50 -19
View File
@@ -71,6 +71,7 @@ public class GameView extends Pane {
private Map<ClientYacht, BoatObject> boatObjects = new HashMap<>();
private Map<ClientYacht, AnnotationBox> annotations = new HashMap<>();
private ObservableList<Node> gameObjects;
private BoatObject selectedBoat = null;
private Group annotationsGroup = new Group();
private Group wakesGroup = new Group();
private Group boatObjectGroup = new Group();
@@ -93,18 +94,18 @@ public class GameView extends Pane {
double scaleFactor = 1;
public void zoomOut() {
scaleFactor = 0.95;
for (Node child : getChildren()) {
child.setScaleX(child.getScaleX() * scaleFactor);
child.setScaleY(child.getScaleY() * scaleFactor);
scaleFactor = 0.1;
if (this.getScaleX() > 0.5) {
this.setScaleX(this.getScaleX() - scaleFactor);
this.setScaleY(this.getScaleY() - scaleFactor);
}
}
public void zoomIn() {
scaleFactor = 1.05;
for (Node child : getChildren()) {
child.setScaleX(child.getScaleX() * scaleFactor);
child.setScaleY(child.getScaleY() * scaleFactor);
scaleFactor = 0.10;
if (this.getScaleX() < 2.5) {
this.setScaleX(this.getScaleX() + scaleFactor);
this.setScaleY(this.getScaleY() + scaleFactor);
}
}
@@ -113,14 +114,25 @@ public class GameView extends Pane {
VERTICAL
}
public GameView() {
private void trackBoat() {
if (selectedBoat != null) {
double x = selectedBoat.getBoatLayoutX();
double y = selectedBoat.getBoatLayoutY();
double displacementX = this.getWidth();
double displacementY = this.getHeight();
this.setLayoutX((-x + (displacementX / 2.0)) * this.getScaleX());
this.setLayoutY((-y + (displacementY / 2.0)) * this.getScaleY());
} else {
this.setLayoutX(0);
this.setLayoutY(0);
}
}
public GameView () {
gameObjects = this.getChildren();
// create image view for map, bind panel size to image
gameObjects.add(mapImage);
fpsDisplay.setLayoutX(5);
fpsDisplay.setLayoutY(20);
fpsDisplay.setStrokeWidth(2);
gameObjects.add(fpsDisplay);
gameObjects.add(raceBorder);
gameObjects.add(markers);
initializeTimer();
@@ -138,6 +150,7 @@ public class GameView extends Pane {
@Override
public void handle(long now) {
trackBoat();
if (lastTime == 0) {
lastTime = now;
} else {
@@ -161,9 +174,7 @@ public class GameView extends Pane {
lastTime = now;
}
}
// Platform.runLater(() ->
boatObjects.forEach((boat, boatObject) -> boatObject.updateLocation());
// );
boatObjects.forEach((boat, boatObject) -> boatObject.updateLocation());
}
};
}
@@ -343,6 +354,22 @@ public class GameView extends Pane {
// drawGoogleMap();
}
private void setSelectedBoat(BoatObject bo, Boolean isSelected) {
if (this.selectedBoat == bo && !isSelected) {
this.selectedBoat = null;
boatObjects.forEach((boat, group) ->
group.setIsSelected(false)
);
} else if (isSelected) {
this.selectedBoat = bo;
for (BoatObject group : boatObjects.values()) {
if (group != bo) {
group.setIsSelected(false);
}
}
}
}
/**
* Draws all the boats.
* @param clientYachts The yachts to set in the race
@@ -353,6 +380,7 @@ public class GameView extends Pane {
for (ClientYacht clientYacht : clientYachts) {
Paint colour = Colors.getColor();
newBoat = new BoatObject();
newBoat.addSelectedBoatListener(this::setSelectedBoat);
newBoat.setFill(colour);
boatObjects.put(clientYacht, newBoat);
createAndBindAnnotationBox(clientYacht, colour);
@@ -365,9 +393,6 @@ public class GameView extends Pane {
BoatObject bo = boatObjects.get(boat);
Point2D p2d = findScaledXY(lat, lon);
bo.moveTo(p2d.getX(), p2d.getY(), heading, velocity, sailIn, windDir);
// annotations.get(boat).setLayoutX(p2d.getX());
// annotations.get(boat).setLayoutY(p2d.getY());
// annotations.get(boat).setLocation(100d, 100d);
annotations.get(boat).setLocation(p2d.getX(), p2d.getY());
bo.setTrajectory(
heading,
@@ -630,6 +655,7 @@ public class GameView extends Pane {
public void setBoatAsPlayer (ClientYacht playerYacht) {
this.playerYacht = playerYacht;
playerYacht.toggleSail();
boatObjects.get(playerYacht).setAsPlayer();
annotations.get(playerYacht).addAnnotation(
"velocity",
@@ -679,4 +705,9 @@ public class GameView extends Pane {
timeline.setOnFinished(event -> gameObjects.remove(circle));
});
}
public void setFrameRateFXText(Text fpsDisplay) {
this.fpsDisplay = null;
this.fpsDisplay = fpsDisplay;
}
}
@@ -71,7 +71,8 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
private Button selectAnnotationBtn;
@FXML
private ComboBox<ClientYacht> yachtSelectionComboBox;
@FXML
private Text fpsDisplay;
//Race Data
private Map<Integer, ClientYacht> participants;
private Map<Integer, CompoundMark> markers;
@@ -115,11 +116,12 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
initialiseSparkLine();
gameView = new GameView();
Platform.runLater(() -> contentAnchorPane.getChildren().add(gameView));
gameView.setBoats(new ArrayList<>(participants.values()));
gameView.updateBorder(raceData.getCourseLimit());
gameView.updateCourse(
new ArrayList<>(raceData.getCompoundMarks().values()), raceData.getMarkSequence()
gameView.setFrameRateFXText(fpsDisplay);
Platform.runLater(() -> contentAnchorPane.getChildren().add(0, gameView));
gameView.setBoats(new ArrayList<>(participants.values()));
gameView.updateBorder(raceData.getCourseLimit());
gameView.updateCourse(
new ArrayList<>(raceData.getCompoundMarks().values()), raceData.getMarkSequence()
);
gameView.setBoatAsPlayer(player);
gameView.startRace();
@@ -95,7 +95,7 @@ public class AnnotationBox extends Group {
background.setStroke(theme);
background.setStrokeWidth(2);
background.setCache(true);
background.setCacheHint(CacheHint.SPEED);
background.setCacheHint(CacheHint.SCALE);
this.getChildren().add(background);
}
@@ -213,7 +213,7 @@ public class AnnotationBox extends Group {
Text text = new Text();
text.setFill(theme);
text.setStrokeWidth(2);
text.setCacheHint(CacheHint.SPEED);
// text.setCacheHint(CacheHint.QUALITY);
text.setCache(true);
return text;
}
@@ -1,9 +1,9 @@
package seng302.visualiser.fxObjects;
import java.util.ArrayList;
import java.util.List;
import javafx.application.Platform;
import javafx.geometry.Point2D;
import javafx.scene.CacheHint;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.paint.Color;
@@ -23,6 +23,12 @@ import javafx.scene.transform.Rotate;
*/
public class BoatObject extends Group {
@FunctionalInterface
public interface SelectedBoatListener {
void notifySelected(BoatObject boatObject, Boolean isSelected);
}
//Constants for drawing
private static final double BOAT_HEIGHT = 15d;
private static final double BOAT_WIDTH = 10d;
@@ -41,9 +47,11 @@ public class BoatObject extends Group {
private double distanceTravelled, lastRotation;
private Point2D lastPoint;
private Paint colour = Color.BLACK;
private Boolean isSelected, destinationSet; //All boats are initialised as selected
private Boolean isSelected = false, destinationSet; //All boats are initialised as selected
private boolean isPlayer = false;
private List<SelectedBoatListener> selectedBoatListenerListeners = new ArrayList<>();
/**
* Creates a BoatGroup with the default triangular boat polygon.
*/
@@ -85,7 +93,7 @@ public class BoatObject extends Group {
});
boatPoly.setOnMouseClicked(event -> setIsSelected(!isSelected));
boatPoly.setCache(true);
boatPoly.setCacheHint(CacheHint.SPEED);
// boatPoly.setCacheHint(CacheHint.SPEED);
// annotationBox = new AnnotationBox();
// annotationBox.setFill(colour);
@@ -287,6 +295,7 @@ public class BoatObject extends Group {
// }
public void setIsSelected(Boolean isSelected) {
updateListener(isSelected);
this.isSelected = isSelected;
setLineGroupVisible(isSelected);
setWakeVisible(isSelected);
@@ -365,6 +374,10 @@ public class BoatObject extends Group {
lastHeading = heading;
}
public Boolean getSelected() {
return isSelected;
}
public void setTrajectory(double heading, double velocity, double scaleFactorX, double scaleFactorY) {
// wake.setRotation(lastHeading - heading, velocity);
// rotateTo(heading);
@@ -372,4 +385,14 @@ public class BoatObject extends Group {
// yVelocity = Math.sin(Math.toRadians(heading)) * velocity * scaleFactorY;
lastHeading = heading;
}
private void updateListener(Boolean isSelected) {
for (SelectedBoatListener sbl : selectedBoatListenerListeners) {
sbl.notifySelected(this, isSelected);
}
}
public void addSelectedBoatListener(SelectedBoatListener sbl) {
selectedBoatListenerListeners.add(sbl);
}
}