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]
This commit is contained in:
Michael Rausch
2017-08-09 21:57:50 +12:00
parent 8813d06010
commit 4cc48a355e
3 changed files with 88 additions and 13 deletions
@@ -1,9 +1,7 @@
package seng302.gameServer; package seng302.gameServer;
import java.util.ArrayList; import java.util.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javafx.application.Platform; import javafx.application.Platform;
import javafx.collections.FXCollections; import javafx.collections.FXCollections;
import javafx.collections.ObservableList; import javafx.collections.ObservableList;
@@ -13,6 +11,8 @@ import seng302.model.Player;
import seng302.model.Yacht; import seng302.model.Yacht;
import seng302.gameServer.server.messages.BoatActionType; import seng302.gameServer.server.messages.BoatActionType;
import seng302.model.mark.CompoundMark; import seng302.model.mark.CompoundMark;
import seng302.model.mark.Mark;
import seng302.model.mark.MarkOrder;
import seng302.utilities.GeoUtility; import seng302.utilities.GeoUtility;
/** /**
@@ -33,6 +33,7 @@ public class GameState implements Runnable {
private static Boolean isRaceStarted; private static Boolean isRaceStarted;
private static GameStages currentStage; private static GameStages currentStage;
private static long startTime; private static long startTime;
private static Set<Mark> marks;
private static Map<Player, String> playerStringMap = new HashMap<>(); private static Map<Player, String> playerStringMap = new HashMap<>();
/* /*
@@ -62,12 +63,18 @@ public class GameState implements Runnable {
yachts = new HashMap<>(); yachts = new HashMap<>();
new Thread(this).start(); new Thread(this).start();
marks = new MarkOrder().getAllMarks();
} }
public static String getHostIpAddress() { public static String getHostIpAddress() {
return hostIpAddress; return hostIpAddress;
} }
public static Set<Mark> getMarks(){
return Collections.unmodifiableSet(marks);
}
public static List<Player> getPlayers() { public static List<Player> getPlayers() {
return players; return players;
} }
+67 -3
View File
@@ -7,6 +7,8 @@ import java.text.SimpleDateFormat;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Set;
import javafx.beans.property.ReadOnlyDoubleProperty; import javafx.beans.property.ReadOnlyDoubleProperty;
import javafx.beans.property.ReadOnlyDoubleWrapper; import javafx.beans.property.ReadOnlyDoubleWrapper;
import javafx.beans.property.ReadOnlyLongProperty; 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 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 //BOTH AFAIK
private String boatType; 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 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 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 Boolean hasPassedSecondLine; //The line extrapolated from the last mark to the current mark
private Long lastCollisionUpdate;
//CLIENT SIDE //CLIENT SIDE
private List<YachtLocationListener> locationListeners = new ArrayList<>(); private List<YachtLocationListener> locationListeners = new ArrayList<>();
@@ -90,6 +96,18 @@ public class Yacht {
this.hasPassedSecondLine = false; this.hasPassedSecondLine = false;
} }
public Mark markCollidedWith(){
Set<Mark> 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 * @param timeInterval since last update in milliseconds
*/ */
@@ -126,14 +144,21 @@ public class Yacht {
Double metersCovered = velocity * secondsElapsed; Double metersCovered = velocity * secondsElapsed;
GeoPoint calculatedPoint = getGeoCoordinate(location, heading, metersCovered); GeoPoint calculatedPoint = getGeoCoordinate(location, heading, metersCovered);
// Collision detection. Update boat only if no collision. if (shouldDoCollisionUpdate()){
Yacht collidedYacht = checkCollision(calculatedPoint); Yacht collidedYacht = checkCollision(calculatedPoint);
if (collidedYacht != null) {
// System.out.println("Collision of boat " + this.getSourceId() + " and " + collidedYacht.getSourceId()); if (collidedYacht != null || markCollidedWith() != null) {
location = calculateBounceBack(new GeoPoint(markCollidedWith().getLat(), markCollidedWith().getLng()));
} else { } else {
location = calculatedPoint; location = calculatedPoint;
} }
lastCollisionUpdate = System.currentTimeMillis();
}
else {
location = calculatedPoint;
}
//CHECK FOR MARK ROUNDING //CHECK FOR MARK ROUNDING
distanceToNextMark = calcDistanceToNextMark(); distanceToNextMark = calcDistanceToNextMark();
if (distanceToNextMark < ROUNDING_DISTANCE) { if (distanceToNextMark < ROUNDING_DISTANCE) {
@@ -143,6 +168,45 @@ public class Yacht {
// TODO: 3/08/17 wmu16 - Implement line cross check here // 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). * Calculates the distance to the next mark (closest of the two if a gate mark).
@@ -15,10 +15,7 @@ import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.ParserConfigurationException;
import java.io.IOException; import java.io.IOException;
import java.io.StringReader; import java.io.StringReader;
import java.util.ArrayList; import java.util.*;
import java.util.Collections;
import java.util.List;
import java.util.Map;
/** /**
* Class to hold the order of the marks in the race. * Class to hold the order of the marks in the race.
@@ -26,6 +23,7 @@ import java.util.Map;
public class MarkOrder { public class MarkOrder {
private List<Mark> raceMarkOrder; private List<Mark> raceMarkOrder;
private Logger logger = LoggerFactory.getLogger(MarkOrder.class); private Logger logger = LoggerFactory.getLogger(MarkOrder.class);
private Set<Mark> allMarks;
public MarkOrder(){ public MarkOrder(){
loadRaceProperties(); loadRaceProperties();
@@ -67,6 +65,10 @@ public class MarkOrder {
return nextRacePosition; return nextRacePosition;
} }
public Set<Mark> getAllMarks(){
return Collections.unmodifiableSet(allMarks);
}
/** /**
* Loads the race order from an XML string * Loads the race order from an XML string
* @param xml An AC35 RaceXML * @param xml An AC35 RaceXML
@@ -77,6 +79,7 @@ public class MarkOrder {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db; DocumentBuilder db;
Document doc; Document doc;
allMarks = new HashSet<>();
try { try {
db = dbf.newDocumentBuilder(); db = dbf.newDocumentBuilder();
@@ -97,6 +100,7 @@ public class MarkOrder {
for (Corner corner : corners){ for (Corner corner : corners){
CompoundMark compoundMark = marks.get(corner.getCompoundMarkID()); CompoundMark compoundMark = marks.get(corner.getCompoundMarkID());
course.add(compoundMark.getMarks().get(0)); course.add(compoundMark.getMarks().get(0));
allMarks.addAll(compoundMark.getMarks());
} }
return course; return course;