mirror of
https://github.com/michaelrausch/Party-Parrots-At-Sea.git
synced 2026-05-09 14:28:43 +00:00
WIP: Second commit for seperating server and client yacht classes
tags: #story[1124]
This commit is contained in:
@@ -0,0 +1,376 @@
|
|||||||
|
package seng302.model;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Observable;
|
||||||
|
import java.util.Observer;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import seng302.gameServer.GameState;
|
||||||
|
import seng302.model.mark.Mark;
|
||||||
|
import seng302.utilities.GeoUtility;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Yacht class for the racing boat. <p> Class created to store more variables (eg. boat statuses)
|
||||||
|
* compared to the XMLParser boat class, also done outside Boat class because some old variables are
|
||||||
|
* not used anymore.
|
||||||
|
*/
|
||||||
|
public class ServerYacht extends Observable {
|
||||||
|
|
||||||
|
private Logger logger = LoggerFactory.getLogger(Yacht.class);
|
||||||
|
|
||||||
|
public static final Double TURN_STEP = 5.0;
|
||||||
|
|
||||||
|
private String boatType;
|
||||||
|
private Integer sourceId;
|
||||||
|
private String hullID; //matches HullNum in the XML spec.
|
||||||
|
private String shortName;
|
||||||
|
private String boatName;
|
||||||
|
private String country;
|
||||||
|
|
||||||
|
private Double lastHeading;
|
||||||
|
private Boolean sailIn;
|
||||||
|
private Double heading;
|
||||||
|
private GeoPoint location;
|
||||||
|
private Double currentVelocity;
|
||||||
|
private Boolean isAuto;
|
||||||
|
private Double autoHeading;
|
||||||
|
|
||||||
|
private Integer currentMarkSeqID = 0;
|
||||||
|
private GeoPoint lastLocation;
|
||||||
|
private Boolean hasEnteredRoundingZone;
|
||||||
|
private Mark closestCurrentMark;
|
||||||
|
private Boolean hasPassedLine;
|
||||||
|
private Boolean hasPassedThroughGate;
|
||||||
|
private Boolean finishedRace;
|
||||||
|
|
||||||
|
|
||||||
|
public ServerYacht(String boatType, Integer sourceId, String hullID, String shortName,
|
||||||
|
String boatName, String country) {
|
||||||
|
this.boatType = boatType;
|
||||||
|
this.sourceId = sourceId;
|
||||||
|
this.hullID = hullID;
|
||||||
|
this.shortName = shortName;
|
||||||
|
this.boatName = boatName;
|
||||||
|
this.country = country;
|
||||||
|
this.sailIn = false;
|
||||||
|
this.isAuto = false;
|
||||||
|
this.location = new GeoPoint(57.670341, 11.826856);
|
||||||
|
this.lastLocation = location;
|
||||||
|
this.heading = 120.0; //In degrees
|
||||||
|
this.currentVelocity = 0d; //in mms-1
|
||||||
|
|
||||||
|
this.hasEnteredRoundingZone = false;
|
||||||
|
this.hasPassedLine = false;
|
||||||
|
this.hasPassedThroughGate = false;
|
||||||
|
this.finishedRace = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Changes the boats current currentVelocity by a set amount, positive or negative
|
||||||
|
*
|
||||||
|
* @param velocityChange The ammount to change the currentVelocity by, in mms-1
|
||||||
|
*/
|
||||||
|
public void changeVelocity(Double velocityChange) {
|
||||||
|
currentVelocity += velocityChange;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the boat to a new GeoPoint whilst preserving the last location
|
||||||
|
*
|
||||||
|
* @param secondsElapsed The seconds elapsed since the last update of this yacht
|
||||||
|
*/
|
||||||
|
public void updateLocation(Double secondsElapsed) {
|
||||||
|
lastLocation = location;
|
||||||
|
location = GeoUtility.getGeoCoordinate(location, heading, currentVelocity * secondsElapsed);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add ServerToClientThread as the observer, this observer pattern mainly server for the boat
|
||||||
|
* rounding package.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void addObserver(Observer o) {
|
||||||
|
super.addObserver(o);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adjusts the heading of the boat by a given amount, while recording the boats last heading.
|
||||||
|
*
|
||||||
|
* @param amount the amount by which to adjust the boat heading.
|
||||||
|
*/
|
||||||
|
public void adjustHeading(Double amount) {
|
||||||
|
Double newVal = heading + amount;
|
||||||
|
lastHeading = heading;
|
||||||
|
heading = (double) Math.floorMod(newVal.longValue(), 360L);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Swaps the boats direction from one side of the wind to the other.
|
||||||
|
*/
|
||||||
|
public void tackGybe(Double windDirection) {
|
||||||
|
if (isAuto) {
|
||||||
|
disableAutoPilot();
|
||||||
|
} else {
|
||||||
|
Double normalizedHeading = normalizeHeading();
|
||||||
|
Double newVal = (-2 * normalizedHeading) + heading;
|
||||||
|
Double newHeading = (double) Math.floorMod(newVal.longValue(), 360L);
|
||||||
|
setAutoPilot(newHeading);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enables the boats auto pilot feature, which will move the boat towards a given heading.
|
||||||
|
*
|
||||||
|
* @param thisHeading The heading to move the boat towards.
|
||||||
|
*/
|
||||||
|
private void setAutoPilot(Double thisHeading) {
|
||||||
|
isAuto = true;
|
||||||
|
autoHeading = thisHeading;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disables the auto pilot function.
|
||||||
|
*/
|
||||||
|
public void disableAutoPilot() {
|
||||||
|
isAuto = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Moves the boat towards the given heading when the auto pilot was set. Disables the auto pilot
|
||||||
|
* in the event that the boat is within the range of 1 turn step of its goal.
|
||||||
|
*/
|
||||||
|
public void runAutoPilot() {
|
||||||
|
if (isAuto) {
|
||||||
|
turnTowardsHeading(autoHeading);
|
||||||
|
if (Math.abs(heading - autoHeading)
|
||||||
|
<= TURN_STEP) { //Cancel when within 1 turn step of target.
|
||||||
|
isAuto = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void toggleSailIn() {
|
||||||
|
sailIn = !sailIn;
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
} else {
|
||||||
|
adjustHeading(TURN_STEP);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
} else {
|
||||||
|
adjustHeading(-TURN_STEP);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Takes the VMG from the polartable for upwind or downwind depending on the boats direction,
|
||||||
|
* and uses this to calculate a heading to move the yacht towards.
|
||||||
|
*/
|
||||||
|
public void turnToVMG() {
|
||||||
|
if (isAuto) {
|
||||||
|
disableAutoPilot();
|
||||||
|
} else {
|
||||||
|
Double normalizedHeading = normalizeHeading();
|
||||||
|
Double optimalHeading;
|
||||||
|
HashMap<Double, Double> optimalPolarMap;
|
||||||
|
|
||||||
|
if (normalizedHeading >= 90 && normalizedHeading <= 270) { // Downwind
|
||||||
|
optimalPolarMap = PolarTable.getOptimalDownwindVMG(GameState.getWindSpeedKnots());
|
||||||
|
} else {
|
||||||
|
optimalPolarMap = PolarTable.getOptimalUpwindVMG(GameState.getWindSpeedKnots());
|
||||||
|
}
|
||||||
|
optimalHeading = optimalPolarMap.keySet().iterator().next();
|
||||||
|
|
||||||
|
if (normalizedHeading > 180) {
|
||||||
|
optimalHeading = 360 - optimalHeading;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Take optimal heading and turn into a boat heading rather than a wind heading.
|
||||||
|
optimalHeading =
|
||||||
|
optimalHeading + GameState.getWindDirection();
|
||||||
|
|
||||||
|
setAutoPilot(optimalHeading);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Takes a given heading and rotates the boat towards that heading. This does not care about
|
||||||
|
* being upwind or downwind, just which direction will reach a given heading faster.
|
||||||
|
*
|
||||||
|
* @param newHeading The heading to turn the yacht towards.
|
||||||
|
*/
|
||||||
|
private void turnTowardsHeading(Double newHeading) {
|
||||||
|
Double newVal = heading - newHeading;
|
||||||
|
if (Math.floorMod(newVal.longValue(), 360L) > 180) {
|
||||||
|
adjustHeading(TURN_STEP / 5);
|
||||||
|
} else {
|
||||||
|
adjustHeading(-TURN_STEP / 5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a heading normalized for the wind direction. Heading direction into the wind is 0,
|
||||||
|
* directly away is 180.
|
||||||
|
*
|
||||||
|
* @return The normalized heading accounting for wind direction.
|
||||||
|
*/
|
||||||
|
private Double normalizeHeading() {
|
||||||
|
Double normalizedHeading = heading - GameState.windDirection;
|
||||||
|
normalizedHeading = (double) Math.floorMod(normalizedHeading.longValue(), 360L);
|
||||||
|
return normalizedHeading;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getSourceId() {
|
||||||
|
//@TODO Remove and merge with Creating Game Loop
|
||||||
|
if (sourceId == null) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return sourceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: 15/08/17 EXTREME BUG DO NOT DELETE THIS FUNCTION BREAKS PROGRAM IDK WHY ¯\_(ツ)_/¯
|
||||||
|
public String getHullID() {
|
||||||
|
System.out.println("HullId");
|
||||||
|
if (hullID == null) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
return hullID;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: 15/08/17 EXTREME BUG DO NOT DELETE THIS FUNCTION BREAKS PROGRAM IDK WHY ¯\_(ツ)_/¯
|
||||||
|
public String getShortName() {
|
||||||
|
System.out.println("shortName");
|
||||||
|
return shortName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getBoatName() {
|
||||||
|
return boatName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCountry() {
|
||||||
|
if (country == null) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
return country;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public GeoPoint getLocation() {
|
||||||
|
return location;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public Double getHeading() {
|
||||||
|
return heading;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHeading(Double heading) {
|
||||||
|
this.heading = heading;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean getSailIn() {
|
||||||
|
return sailIn;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return boatName;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void setIsFinished(Boolean isFinished) {
|
||||||
|
finishedRace = isFinished;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean getFinishedRace() {
|
||||||
|
return finishedRace;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Double getCurrentVelocity() {
|
||||||
|
return currentVelocity;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCurrentVelocity(Double currentVelocity) {
|
||||||
|
this.currentVelocity = currentVelocity;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getCurrentMarkSeqID() {
|
||||||
|
return currentMarkSeqID;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GeoPoint getLastLocation() {
|
||||||
|
return lastLocation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Mark getClosestCurrentMark() {
|
||||||
|
return closestCurrentMark;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setClosestCurrentMark(Mark closestCurrentMark) {
|
||||||
|
this.closestCurrentMark = closestCurrentMark;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHasEnteredRoundingZone(Boolean hasEnteredRoundingZone) {
|
||||||
|
this.hasEnteredRoundingZone = hasEnteredRoundingZone;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHasPassedLine(Boolean hasPassedLine) {
|
||||||
|
this.hasPassedLine = hasPassedLine;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHasPassedThroughGate(Boolean hasPassedThroughGate) {
|
||||||
|
this.hasPassedThroughGate = hasPassedThroughGate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void incrementMarkSeqID() {
|
||||||
|
currentMarkSeqID++;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean hasEnteredRoundingZone() {
|
||||||
|
return hasEnteredRoundingZone;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean hasPassedThroughGate() {
|
||||||
|
return hasPassedThroughGate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean hasPassedLine() {
|
||||||
|
return hasPassedLine;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,7 +3,6 @@ package seng302.model;
|
|||||||
import java.text.DateFormat;
|
import java.text.DateFormat;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Observable;
|
import java.util.Observable;
|
||||||
import java.util.Observer;
|
import java.util.Observer;
|
||||||
@@ -14,10 +13,7 @@ import javafx.beans.property.ReadOnlyLongWrapper;
|
|||||||
import javafx.scene.paint.Color;
|
import javafx.scene.paint.Color;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import seng302.gameServer.GameState;
|
|
||||||
import seng302.model.mark.CompoundMark;
|
import seng302.model.mark.CompoundMark;
|
||||||
import seng302.model.mark.Mark;
|
|
||||||
import seng302.utilities.GeoUtility;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Yacht class for the racing boat. <p> Class created to store more variables (eg. boat statuses)
|
* Yacht class for the racing boat. <p> Class created to store more variables (eg. boat statuses)
|
||||||
@@ -46,29 +42,12 @@ public class Yacht extends Observable {
|
|||||||
private Long estimateTimeAtFinish;
|
private Long estimateTimeAtFinish;
|
||||||
private Integer currentMarkSeqID = 0;
|
private Integer currentMarkSeqID = 0;
|
||||||
private Long markRoundTime;
|
private Long markRoundTime;
|
||||||
private Double distanceToCurrentMark;
|
|
||||||
private Long timeTillNext;
|
private Long timeTillNext;
|
||||||
private Double heading;
|
private Double heading;
|
||||||
private Integer legNumber = 0;
|
private Integer legNumber = 0;
|
||||||
|
|
||||||
//SERVER SIDE
|
|
||||||
public static final Double TURN_STEP = 5.0; //This should be in some utils class somewhere 2bh. Public for tests sake.
|
|
||||||
private Double lastHeading;
|
|
||||||
private Boolean sailIn;
|
|
||||||
private GeoPoint location;
|
private GeoPoint location;
|
||||||
private Integer boatStatus;
|
private Integer boatStatus;
|
||||||
private Double currentVelocity;
|
private Double currentVelocity;
|
||||||
private Double currentMaxVelocity;
|
|
||||||
private Boolean isAuto;
|
|
||||||
private Double autoHeading;
|
|
||||||
|
|
||||||
//MARK ROUNDING INFO
|
|
||||||
private GeoPoint lastLocation; //For purposes of mark rounding calculations
|
|
||||||
private Boolean hasEnteredRoundingZone; //The distance that the boat must be from the mark to round
|
|
||||||
private Mark closestCurrentMark;
|
|
||||||
private Boolean hasPassedLine;
|
|
||||||
private Boolean hasPassedThroughGate;
|
|
||||||
private Boolean finishedRace;
|
|
||||||
|
|
||||||
//CLIENT SIDE
|
//CLIENT SIDE
|
||||||
private List<YachtLocationListener> locationListeners = new ArrayList<>();
|
private List<YachtLocationListener> locationListeners = new ArrayList<>();
|
||||||
@@ -87,36 +66,9 @@ public class Yacht extends Observable {
|
|||||||
this.shortName = shortName;
|
this.shortName = shortName;
|
||||||
this.boatName = boatName;
|
this.boatName = boatName;
|
||||||
this.country = country;
|
this.country = country;
|
||||||
this.sailIn = false;
|
|
||||||
this.isAuto = false;
|
|
||||||
this.location = new GeoPoint(57.670341, 11.826856);
|
this.location = new GeoPoint(57.670341, 11.826856);
|
||||||
this.lastLocation = location;
|
|
||||||
this.heading = 120.0; //In degrees
|
this.heading = 120.0; //In degrees
|
||||||
this.currentVelocity = 0d; //in mms-1
|
this.currentVelocity = 0d;
|
||||||
|
|
||||||
this.hasEnteredRoundingZone = false;
|
|
||||||
this.hasPassedLine = false;
|
|
||||||
this.hasPassedThroughGate = false;
|
|
||||||
this.finishedRace = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Changes the boats current currentVelocity by a set amount, positive or negative
|
|
||||||
* @param velocityChange The ammount to change the currentVelocity by, in mms-1
|
|
||||||
*/
|
|
||||||
public void changeVelocity(Double velocityChange) {
|
|
||||||
currentVelocity += velocityChange;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Updates the boat to a new GeoPoint whilst preserving the last location
|
|
||||||
*
|
|
||||||
* @param secondsElapsed The seconds elapsed since the last update of this yacht
|
|
||||||
*/
|
|
||||||
public void updateLocation(Double secondsElapsed) {
|
|
||||||
lastLocation = location;
|
|
||||||
location = GeoUtility.getGeoCoordinate(location, heading, currentVelocity * secondsElapsed);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -128,169 +80,6 @@ public class Yacht extends Observable {
|
|||||||
super.addObserver(o);
|
super.addObserver(o);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adjusts the heading of the boat by a given amount, while recording the boats last heading.
|
|
||||||
*
|
|
||||||
* @param amount the amount by which to adjust the boat heading.
|
|
||||||
*/
|
|
||||||
public void adjustHeading(Double amount) {
|
|
||||||
Double newVal = heading + amount;
|
|
||||||
lastHeading = heading;
|
|
||||||
heading = (double) Math.floorMod(newVal.longValue(), 360L);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Swaps the boats direction from one side of the wind to the other.
|
|
||||||
*/
|
|
||||||
public void tackGybe(Double windDirection) {
|
|
||||||
if (isAuto) {
|
|
||||||
disableAutoPilot();
|
|
||||||
} else {
|
|
||||||
Double normalizedHeading = normalizeHeading();
|
|
||||||
Double newVal = (-2 * normalizedHeading) + heading;
|
|
||||||
Double newHeading = (double) Math.floorMod(newVal.longValue(), 360L);
|
|
||||||
setAutoPilot(newHeading);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Enables the boats auto pilot feature, which will move the boat towards a given heading.
|
|
||||||
*
|
|
||||||
* @param thisHeading The heading to move the boat towards.
|
|
||||||
*/
|
|
||||||
private void setAutoPilot(Double thisHeading) {
|
|
||||||
isAuto = true;
|
|
||||||
autoHeading = thisHeading;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Disables the auto pilot function.
|
|
||||||
*/
|
|
||||||
public void disableAutoPilot() {
|
|
||||||
isAuto = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Moves the boat towards the given heading when the auto pilot was set. Disables the auto pilot
|
|
||||||
* in the event that the boat is within the range of 1 turn step of its goal.
|
|
||||||
*/
|
|
||||||
public void runAutoPilot() {
|
|
||||||
if (isAuto) {
|
|
||||||
turnTowardsHeading(autoHeading);
|
|
||||||
if (Math.abs(heading - autoHeading)
|
|
||||||
<= TURN_STEP) { //Cancel when within 1 turn step of target.
|
|
||||||
isAuto = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void toggleSailIn() {
|
|
||||||
sailIn = !sailIn;
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
} else {
|
|
||||||
adjustHeading(TURN_STEP);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
} else {
|
|
||||||
adjustHeading(-TURN_STEP);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Takes the VMG from the polartable for upwind or downwind depending on the boats direction,
|
|
||||||
* and uses this to calculate a heading to move the yacht towards.
|
|
||||||
*/
|
|
||||||
public void turnToVMG() {
|
|
||||||
if (isAuto) {
|
|
||||||
disableAutoPilot();
|
|
||||||
} else {
|
|
||||||
Double normalizedHeading = normalizeHeading();
|
|
||||||
Double optimalHeading;
|
|
||||||
HashMap<Double, Double> optimalPolarMap;
|
|
||||||
|
|
||||||
if (normalizedHeading >= 90 && normalizedHeading <= 270) { // Downwind
|
|
||||||
optimalPolarMap = PolarTable.getOptimalDownwindVMG(GameState.getWindSpeedKnots());
|
|
||||||
} else {
|
|
||||||
optimalPolarMap = PolarTable.getOptimalUpwindVMG(GameState.getWindSpeedKnots());
|
|
||||||
}
|
|
||||||
optimalHeading = optimalPolarMap.keySet().iterator().next();
|
|
||||||
|
|
||||||
if (normalizedHeading > 180) {
|
|
||||||
optimalHeading = 360 - optimalHeading;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Take optimal heading and turn into a boat heading rather than a wind heading.
|
|
||||||
optimalHeading =
|
|
||||||
optimalHeading + GameState.getWindDirection();
|
|
||||||
|
|
||||||
setAutoPilot(optimalHeading);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Takes a given heading and rotates the boat towards that heading. This does not care about
|
|
||||||
* being upwind or downwind, just which direction will reach a given heading faster.
|
|
||||||
*
|
|
||||||
* @param newHeading The heading to turn the yacht towards.
|
|
||||||
*/
|
|
||||||
private void turnTowardsHeading(Double newHeading) {
|
|
||||||
Double newVal = heading - newHeading;
|
|
||||||
if (Math.floorMod(newVal.longValue(), 360L) > 180) {
|
|
||||||
adjustHeading(TURN_STEP / 5);
|
|
||||||
} else {
|
|
||||||
adjustHeading(-TURN_STEP / 5);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a heading normalized for the wind direction. Heading direction into the wind is 0,
|
|
||||||
* directly away is 180.
|
|
||||||
*
|
|
||||||
* @return The normalized heading accounting for wind direction.
|
|
||||||
*/
|
|
||||||
private Double normalizeHeading() {
|
|
||||||
Double normalizedHeading = heading - GameState.windDirection;
|
|
||||||
normalizedHeading = (double) Math.floorMod(normalizedHeading.longValue(), 360L);
|
|
||||||
return normalizedHeading;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getBoatType() {
|
public String getBoatType() {
|
||||||
return boatType;
|
return boatType;
|
||||||
}
|
}
|
||||||
@@ -338,9 +127,6 @@ public class Yacht extends Observable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void setLegNumber(Integer legNumber) {
|
public void setLegNumber(Integer legNumber) {
|
||||||
// if (colour != null && position != "-" && legNumber != this.legNumber) {
|
|
||||||
// RaceViewController.updateYachtPositionSparkline(this, legNumber);
|
|
||||||
// }
|
|
||||||
this.legNumber = legNumber;
|
this.legNumber = legNumber;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -377,18 +163,10 @@ public class Yacht extends Observable {
|
|||||||
return velocityProperty.getReadOnlyProperty();
|
return velocityProperty.getReadOnlyProperty();
|
||||||
}
|
}
|
||||||
|
|
||||||
public double getVelocityMMS() {
|
|
||||||
return currentVelocity;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ReadOnlyLongProperty timeTillNextProperty() {
|
public ReadOnlyLongProperty timeTillNextProperty() {
|
||||||
return timeTillNextProperty.getReadOnlyProperty();
|
return timeTillNextProperty.getReadOnlyProperty();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Double getVelocityKnots() {
|
|
||||||
return currentVelocity / 1000 * 1.943844492; // TODO: 26/07/17 cir27 - remove magic number
|
|
||||||
}
|
|
||||||
|
|
||||||
public Long getTimeTillNext() {
|
public Long getTimeTillNext() {
|
||||||
return timeTillNext;
|
return timeTillNext;
|
||||||
}
|
}
|
||||||
@@ -416,8 +194,6 @@ public class Yacht extends Observable {
|
|||||||
* @param lng Longitude
|
* @param lng Longitude
|
||||||
*/
|
*/
|
||||||
public void setLocation(Double lat, Double lng) {
|
public void setLocation(Double lat, Double lng) {
|
||||||
lastLocation.setLat(location.getLat());
|
|
||||||
lastLocation.setLng(location.getLng());
|
|
||||||
location.setLat(lat);
|
location.setLat(lat);
|
||||||
location.setLng(lng);
|
location.setLng(lng);
|
||||||
}
|
}
|
||||||
@@ -430,10 +206,6 @@ public class Yacht extends Observable {
|
|||||||
this.heading = heading;
|
this.heading = heading;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Boolean getSailIn() {
|
|
||||||
return sailIn;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return boatName;
|
return boatName;
|
||||||
@@ -460,82 +232,19 @@ public class Yacht extends Observable {
|
|||||||
this.colour = colour;
|
this.colour = colour;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setIsFinished(Boolean isFinished) {
|
// public Double getCurrentVelocity() {
|
||||||
finishedRace = isFinished;
|
// return currentVelocity;
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
|
// public void setCurrentVelocity(Double currentVelocity) {
|
||||||
|
// this.currentVelocity = currentVelocity;
|
||||||
|
// }
|
||||||
|
|
||||||
public Boolean getFinishedRace() {
|
|
||||||
return finishedRace;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Double getCurrentVelocity() {
|
|
||||||
return currentVelocity;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setCurrentVelocity(Double currentVelocity) {
|
|
||||||
this.currentVelocity = currentVelocity;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Integer getCurrentMarkSeqID() {
|
|
||||||
return currentMarkSeqID;
|
|
||||||
}
|
|
||||||
|
|
||||||
public GeoPoint getLastLocation() {
|
|
||||||
return lastLocation;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Mark getClosestCurrentMark() {
|
|
||||||
return closestCurrentMark;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setClosestCurrentMark(Mark closestCurrentMark) {
|
|
||||||
this.closestCurrentMark = closestCurrentMark;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setHasEnteredRoundingZone(Boolean hasEnteredRoundingZone) {
|
|
||||||
this.hasEnteredRoundingZone = hasEnteredRoundingZone;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setHasPassedLine(Boolean hasPassedLine) {
|
|
||||||
this.hasPassedLine = hasPassedLine;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setHasPassedThroughGate(Boolean hasPassedThroughGate) {
|
|
||||||
this.hasPassedThroughGate = hasPassedThroughGate;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void incrementMarkSeqID() {
|
|
||||||
currentMarkSeqID++;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Boolean hasEnteredRoundingZone() {
|
|
||||||
return hasEnteredRoundingZone;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Boolean hasPassedThroughGate() {
|
|
||||||
return hasPassedThroughGate;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Boolean hasPassedLine() {
|
|
||||||
return hasPassedLine;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Double getDistanceToCurrentMark() {
|
|
||||||
return distanceToCurrentMark;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Double getCurrentMaxVelocity() {
|
|
||||||
return currentMaxVelocity;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setCurrentMaxVelocity(Double currentMaxVelocity) {
|
|
||||||
this.currentMaxVelocity = currentMaxVelocity;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void updateLocation(double lat, double lng, double heading, double velocity) {
|
public void updateLocation(double lat, double lng, double heading, double velocity) {
|
||||||
setLocation(lat, lng);
|
setLocation(lat, lng);
|
||||||
this.heading = heading;
|
this.heading = heading;
|
||||||
this.currentVelocity = velocity;
|
// this.currentVelocity = velocity;
|
||||||
updateVelocityProperty(velocity);
|
updateVelocityProperty(velocity);
|
||||||
for (YachtLocationListener yll : locationListeners) {
|
for (YachtLocationListener yll : locationListeners) {
|
||||||
yll.notifyLocation(this, lat, lng, heading, velocity);
|
yll.notifyLocation(this, lat, lng, heading, velocity);
|
||||||
|
|||||||
@@ -8,12 +8,12 @@ import org.junit.BeforeClass;
|
|||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import seng302.gameServer.GameState;
|
import seng302.gameServer.GameState;
|
||||||
import seng302.model.PolarTable;
|
import seng302.model.PolarTable;
|
||||||
import seng302.model.Yacht;
|
import seng302.model.ServerYacht;
|
||||||
|
|
||||||
|
|
||||||
public class YachtTest {
|
public class YachtTest {
|
||||||
|
|
||||||
private static Yacht y1;
|
private static ServerYacht y1;
|
||||||
//Yacht y2;
|
//Yacht y2;
|
||||||
private static Double windDirection = 180d;
|
private static Double windDirection = 180d;
|
||||||
private static Double windSpeed = 20d;
|
private static Double windSpeed = 20d;
|
||||||
@@ -21,7 +21,7 @@ public class YachtTest {
|
|||||||
|
|
||||||
@BeforeClass
|
@BeforeClass
|
||||||
public static void setUp() {
|
public static void setUp() {
|
||||||
y1 = new Yacht("Yacht", 101, "Y1", "Y1", "Yacht 1", "C1");
|
y1 = new ServerYacht("Yacht", 101, "Y1", "Y1", "Yacht 1", "C1");
|
||||||
gs = new GameState("localhost");
|
gs = new GameState("localhost");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ import seng302.gameServer.GameState;
|
|||||||
import seng302.gameServer.MainServerThread;
|
import seng302.gameServer.MainServerThread;
|
||||||
import seng302.gameServer.server.messages.BoatAction;
|
import seng302.gameServer.server.messages.BoatAction;
|
||||||
import seng302.model.ServerYacht;
|
import seng302.model.ServerYacht;
|
||||||
import seng302.model.Yacht;
|
|
||||||
import seng302.visualiser.ClientToServerThread;
|
import seng302.visualiser.ClientToServerThread;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -46,7 +45,8 @@ public class RegularPacketsTest {
|
|||||||
long endTime = System.currentTimeMillis();
|
long endTime = System.currentTimeMillis();
|
||||||
SleepThreadMaxDelay();
|
SleepThreadMaxDelay();
|
||||||
//Allowed to be two loops of delay due to loop delay and processing delay at client + server ends.
|
//Allowed to be two loops of delay due to loop delay and processing delay at client + server ends.
|
||||||
Assert.assertEquals(TEST_DISTANCE / Yacht.TURN_STEP * ClientToServerThread.PACKET_SENDING_INTERVAL_MS,
|
Assert.assertEquals(
|
||||||
|
TEST_DISTANCE / ServerYacht.TURN_STEP * ClientToServerThread.PACKET_SENDING_INTERVAL_MS,
|
||||||
(endTime - startTime), 2 * ClientToServerThread.PACKET_SENDING_INTERVAL_MS);
|
(endTime - startTime), 2 * ClientToServerThread.PACKET_SENDING_INTERVAL_MS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user