From 4cc48a355e9ddf469e35aaa5654e4290e3cb8f82 Mon Sep 17 00:00:00 2001 From: Michael Rausch Date: Wed, 9 Aug 2017 21:57:50 +1200 Subject: [PATCH] Added mark collisions - Boats now collide with marks - Added method to MarkOrder to get all marks - Reduced the frequency at which collisions are detected. This fixed some performance issues - Added method to bounce the boat off a mark Tags: #story[1117] --- .../java/seng302/gameServer/GameState.java | 15 +++- src/main/java/seng302/model/Yacht.java | 74 +++++++++++++++++-- .../java/seng302/model/mark/MarkOrder.java | 12 ++- 3 files changed, 88 insertions(+), 13 deletions(-) diff --git a/src/main/java/seng302/gameServer/GameState.java b/src/main/java/seng302/gameServer/GameState.java index f679bb75..f055c3dd 100644 --- a/src/main/java/seng302/gameServer/GameState.java +++ b/src/main/java/seng302/gameServer/GameState.java @@ -1,9 +1,7 @@ package seng302.gameServer; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; + import javafx.application.Platform; import javafx.collections.FXCollections; import javafx.collections.ObservableList; @@ -13,6 +11,8 @@ import seng302.model.Player; import seng302.model.Yacht; import seng302.gameServer.server.messages.BoatActionType; import seng302.model.mark.CompoundMark; +import seng302.model.mark.Mark; +import seng302.model.mark.MarkOrder; import seng302.utilities.GeoUtility; /** @@ -33,6 +33,7 @@ public class GameState implements Runnable { private static Boolean isRaceStarted; private static GameStages currentStage; private static long startTime; + private static Set marks; private static Map playerStringMap = new HashMap<>(); /* @@ -62,12 +63,18 @@ public class GameState implements Runnable { yachts = new HashMap<>(); new Thread(this).start(); + + marks = new MarkOrder().getAllMarks(); } public static String getHostIpAddress() { return hostIpAddress; } + public static Set getMarks(){ + return Collections.unmodifiableSet(marks); + } + public static List getPlayers() { return players; } diff --git a/src/main/java/seng302/model/Yacht.java b/src/main/java/seng302/model/Yacht.java index d92c1c8b..cc114189 100644 --- a/src/main/java/seng302/model/Yacht.java +++ b/src/main/java/seng302/model/Yacht.java @@ -7,6 +7,8 @@ import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.HashMap; import java.util.List; +import java.util.Set; + import javafx.beans.property.ReadOnlyDoubleProperty; import javafx.beans.property.ReadOnlyDoubleWrapper; import javafx.beans.property.ReadOnlyLongProperty; @@ -31,6 +33,9 @@ public class Yacht { } private static final Double ROUNDING_DISTANCE = 15d; // TODO: 3/08/17 wmu16 - Look into this value further + private static final Double COLLISION_DISTANCE = ROUNDING_DISTANCE - 8d; + private static final Double BOUNCE_FACTOR = 0.0001; + private static final Integer COLLISION_UPDATE_INTERVAL = 100; //BOTH AFAIK private String boatType; @@ -61,6 +66,7 @@ public class Yacht { private Boolean hasEnteredRoundingZone; //The distance that the boat must be from the mark to round private Boolean hasPassedFirstLine; //The line extrapolated from the next mark to the current mark private Boolean hasPassedSecondLine; //The line extrapolated from the last mark to the current mark + private Long lastCollisionUpdate; //CLIENT SIDE private List locationListeners = new ArrayList<>(); @@ -90,6 +96,18 @@ public class Yacht { this.hasPassedSecondLine = false; } + public Mark markCollidedWith(){ + Set marksInRace = GameState.getMarks(); + + for (Mark mark : marksInRace){ + if (GeoUtility.getDistance(getLocation(), new GeoPoint(mark.getLat(), mark.getLng())) <= COLLISION_DISTANCE){ + return mark; + } + } + + return null; + } + /** * @param timeInterval since last update in milliseconds */ @@ -126,11 +144,18 @@ public class Yacht { Double metersCovered = velocity * secondsElapsed; GeoPoint calculatedPoint = getGeoCoordinate(location, heading, metersCovered); - // Collision detection. Update boat only if no collision. - Yacht collidedYacht = checkCollision(calculatedPoint); - if (collidedYacht != null) { -// System.out.println("Collision of boat " + this.getSourceId() + " and " + collidedYacht.getSourceId()); - } else { + if (shouldDoCollisionUpdate()){ + Yacht collidedYacht = checkCollision(calculatedPoint); + + if (collidedYacht != null || markCollidedWith() != null) { + location = calculateBounceBack(new GeoPoint(markCollidedWith().getLat(), markCollidedWith().getLng())); + } else { + location = calculatedPoint; + } + + lastCollisionUpdate = System.currentTimeMillis(); + } + else { location = calculatedPoint; } @@ -143,6 +168,45 @@ public class Yacht { // TODO: 3/08/17 wmu16 - Implement line cross check here } + /** + * @return true if COLLISION_UPDATE_INTERVAL has elapsed since the last collision update + */ + private Boolean shouldDoCollisionUpdate(){ + if (lastCollisionUpdate == null) { + lastCollisionUpdate = System.currentTimeMillis(); + } + + return System.currentTimeMillis() - lastCollisionUpdate > COLLISION_UPDATE_INTERVAL; + } + + /** + * Calculate the new position of the boat after it has had a collision + * @return The boats new position + */ + private GeoPoint calculateBounceBack(GeoPoint collidedWith){ + Double lat = location.getLat(); + Double lon = location.getLng(); + + Double heading = GeoUtility.getBearing(location, collidedWith); + + + if (heading >= 0 && heading <= 180){ + lat -= BOUNCE_FACTOR; + } + else{ + lat += BOUNCE_FACTOR; + } + + if (heading >= 90 && heading <= 360-90){ + lon += BOUNCE_FACTOR; + } + else{ + lon -= BOUNCE_FACTOR; + } + + return new GeoPoint(lat, lon); + } + /** * Calculates the distance to the next mark (closest of the two if a gate mark). diff --git a/src/main/java/seng302/model/mark/MarkOrder.java b/src/main/java/seng302/model/mark/MarkOrder.java index ca2b4356..b2437957 100644 --- a/src/main/java/seng302/model/mark/MarkOrder.java +++ b/src/main/java/seng302/model/mark/MarkOrder.java @@ -15,10 +15,7 @@ import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import java.io.IOException; import java.io.StringReader; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Map; +import java.util.*; /** * Class to hold the order of the marks in the race. @@ -26,6 +23,7 @@ import java.util.Map; public class MarkOrder { private List raceMarkOrder; private Logger logger = LoggerFactory.getLogger(MarkOrder.class); + private Set allMarks; public MarkOrder(){ loadRaceProperties(); @@ -67,6 +65,10 @@ public class MarkOrder { return nextRacePosition; } + public Set getAllMarks(){ + return Collections.unmodifiableSet(allMarks); + } + /** * Loads the race order from an XML string * @param xml An AC35 RaceXML @@ -77,6 +79,7 @@ public class MarkOrder { DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); DocumentBuilder db; Document doc; + allMarks = new HashSet<>(); try { db = dbf.newDocumentBuilder(); @@ -97,6 +100,7 @@ public class MarkOrder { for (Corner corner : corners){ CompoundMark compoundMark = marks.get(corner.getCompoundMarkID()); course.add(compoundMark.getMarks().get(0)); + allMarks.addAll(compoundMark.getMarks()); } return course;