mirror of
https://github.com/michaelrausch/Party-Parrots-At-Sea.git
synced 2026-05-09 06:18:44 +00:00
6cae338c1e
#bug
503 lines
15 KiB
Java
503 lines
15 KiB
Java
package seng302.model;
|
|
|
|
import static seng302.utilities.GeoUtility.getGeoCoordinate;
|
|
|
|
import java.text.DateFormat;
|
|
import java.text.SimpleDateFormat;
|
|
import java.util.ArrayList;
|
|
import java.util.HashMap;
|
|
import java.util.List;
|
|
import javafx.beans.property.ReadOnlyDoubleProperty;
|
|
import javafx.beans.property.ReadOnlyDoubleWrapper;
|
|
import javafx.beans.property.ReadOnlyLongProperty;
|
|
import javafx.beans.property.ReadOnlyLongWrapper;
|
|
import javafx.scene.paint.Color;
|
|
import seng302.gameServer.GameState;
|
|
import seng302.model.mark.Mark;
|
|
import seng302.utilities.GeoPoint;
|
|
|
|
/**
|
|
* Yacht class for the racing boat.
|
|
*
|
|
* 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 Yacht {
|
|
|
|
@FunctionalInterface
|
|
public interface YachtLocationListener {
|
|
void notifyLocation(Yacht yacht, double lat, double lon, double heading, double velocity);
|
|
}
|
|
|
|
@FunctionalInterface
|
|
public interface YachtPositionListener {
|
|
void notifyPosition(int position);
|
|
}
|
|
|
|
//BOTH AFAIK
|
|
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 Long estimateTimeAtFinish;
|
|
private Long timeTillNext;
|
|
private Long markRoundTime;
|
|
private Double heading;
|
|
private Double lat;
|
|
private Double lon;
|
|
private Integer legNumber = 0;
|
|
|
|
//SERVER SIDE
|
|
private final Double TURN_STEP = 5.0;
|
|
private Double lastHeading;
|
|
private Boolean sailIn;
|
|
private String position;
|
|
private GeoPoint location;
|
|
private Integer boatStatus;
|
|
private Double velocity;
|
|
|
|
//CLIENT SIDE
|
|
private List<YachtLocationListener> locationListeners = new ArrayList<>();
|
|
private ReadOnlyDoubleWrapper velocityProperty = new ReadOnlyDoubleWrapper();
|
|
private ReadOnlyLongWrapper timeTillNextProperty = new ReadOnlyLongWrapper();
|
|
private ReadOnlyLongWrapper timeSinceLastMarkProperty = new ReadOnlyLongWrapper();
|
|
// private ReadOnlyDoubleWrapper headingProperty = new ReadOnlyDoubleWrapper();
|
|
// private ReadOnlyDoubleWrapper latitudeProperty = new ReadOnlyDoubleWrapper();
|
|
// private ReadOnlyDoubleWrapper longitudeProperty = new ReadOnlyDoubleWrapper();
|
|
private Mark lastMarkRounded;
|
|
private Mark nextMark;
|
|
private Integer positionInt = 0;
|
|
private Color colour;
|
|
|
|
|
|
/**
|
|
* @param location latlon location of the boat stored in a geopoint
|
|
* @param heading heading of the boat in degrees from 0 to 365 with 0 being north
|
|
*/
|
|
public Yacht(GeoPoint location, Double heading) {
|
|
this.location = location;
|
|
this.heading = heading;
|
|
this.velocity = 0.0;
|
|
this.sailIn = false;
|
|
}
|
|
|
|
|
|
/**
|
|
* Used in EventTest and RaceTest.
|
|
*
|
|
* @param boatName Create a yacht object with name.
|
|
*/
|
|
public Yacht(String boatName, String shortName, GeoPoint location, Double heading) {
|
|
this.boatName = boatName;
|
|
this.shortName = shortName;
|
|
this.location = location;
|
|
this.heading = heading;
|
|
this.velocity = 0.0;
|
|
this.sailIn = false;
|
|
}
|
|
|
|
/**
|
|
* Used in BoatGroupTest.
|
|
*
|
|
* @param boatName The name of the team sailing the boat
|
|
* @param boatVelocity The speed of the boat in meters/second
|
|
* @param shortName A shorter version of the teams name
|
|
*/
|
|
public Yacht(String boatName, double boatVelocity, String shortName, int id) {
|
|
this.boatName = boatName;
|
|
this.velocity = boatVelocity;
|
|
this.shortName = shortName;
|
|
this.sourceId = id;
|
|
this.sailIn = false;
|
|
}
|
|
|
|
|
|
public Yacht(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.position = "-";
|
|
this.sailIn = false;
|
|
this.location = new GeoPoint(57.670341, 11.826856);
|
|
this.heading = 120.0; //In degrees
|
|
this.velocity = 0d; //in mms-1
|
|
}
|
|
|
|
/**
|
|
* @param timeInterval since last update in milliseconds
|
|
*/
|
|
public void update(Long timeInterval) {
|
|
|
|
Double secondsElapsed = timeInterval / 1000000.0;
|
|
Double windSpeedKnots = GameState.getWindSpeedKnots();
|
|
Double trueWindAngle = Math.abs(GameState.getWindDirection() - heading);
|
|
Double boatSpeedInKnots = PolarTable.getBoatSpeed(windSpeedKnots, trueWindAngle);
|
|
Double maxBoatSpeed = boatSpeedInKnots / 1.943844492 * 1000;
|
|
if (sailIn && velocity <= maxBoatSpeed && maxBoatSpeed != 0d) {
|
|
|
|
if (velocity < maxBoatSpeed) {
|
|
velocity += maxBoatSpeed / 15; // Acceleration
|
|
}
|
|
if (velocity > maxBoatSpeed) {
|
|
velocity = maxBoatSpeed; // Prevent the boats from exceeding top speed
|
|
}
|
|
|
|
} else { // Deceleration
|
|
|
|
if (velocity > 0d) {
|
|
if (maxBoatSpeed != 0d) {
|
|
velocity -= maxBoatSpeed / 600;
|
|
} else {
|
|
velocity -= velocity / 100;
|
|
}
|
|
if (velocity < 0) {
|
|
velocity = 0d;
|
|
}
|
|
}
|
|
}
|
|
// if (sailIn) {
|
|
// Double secondsElapsed = timeInterval / 1000000.0;
|
|
// Double windSpeedKnots = GameState.getWindSpeedKnots();
|
|
// Double trueWindAngle = Math.abs(GameState.getWindDirection() - heading);
|
|
// Double boatSpeedInKnots = PolarTable.getBoatSpeed(windSpeedKnots, trueWindAngle);
|
|
// velocity = boatSpeedInKnots / 1.943844492 * 1000; // TODO: 26/07/17 cir27 - Remove magic number
|
|
// Double metersCovered = velocity * secondsElapsed;
|
|
// location = getGeoCoordinate(location, heading, metersCovered);
|
|
// } else {
|
|
// velocity = 0d;
|
|
// }
|
|
Double metersCovered = velocity * secondsElapsed;
|
|
location = getGeoCoordinate(location, heading, metersCovered);
|
|
}
|
|
|
|
public void adjustHeading(Double amount) {
|
|
Double newVal = heading + amount;
|
|
lastHeading = heading;
|
|
// TODO: 24/07/17 wmu16 - '%' in java does remainder, we need modulo. All this must be changed here, this is why we have neg values!
|
|
heading = (double) Math.floorMod(newVal.longValue(), 360L);
|
|
}
|
|
|
|
public void tackGybe(Double windDirection) {
|
|
Double normalizedHeading = normalizeHeading();
|
|
adjustHeading(-2 * normalizedHeading);
|
|
}
|
|
|
|
public void toggleSailIn() {
|
|
sailIn = !sailIn;
|
|
}
|
|
|
|
public void turnUpwind() {
|
|
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() {
|
|
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 turnToVMG() {
|
|
Double normalizedHeading = normalizeHeading();
|
|
Double optimalHeading;
|
|
HashMap<Double, Double> optimalPolarMap;
|
|
|
|
if (normalizedHeading >= 90 && normalizedHeading <= 270) { // Downwind
|
|
optimalPolarMap = PolarTable.getOptimalDownwindVMG(GameState.getWindSpeedKnots());
|
|
optimalHeading = optimalPolarMap.keySet().iterator().next();
|
|
} else {
|
|
optimalPolarMap = PolarTable.getOptimalUpwindVMG(GameState.getWindSpeedKnots());
|
|
optimalHeading = optimalPolarMap.keySet().iterator().next();
|
|
}
|
|
// Take optimal heading and turn into correct
|
|
optimalHeading =
|
|
optimalHeading + (double) Math.floorMod(GameState.getWindDirection().longValue(), 360L);
|
|
|
|
turnTowardsHeading(optimalHeading);
|
|
|
|
}
|
|
|
|
private void turnTowardsHeading(Double newHeading) {
|
|
System.out.println(newHeading);
|
|
if (heading < 90 && newHeading > 270) {
|
|
adjustHeading(-TURN_STEP);
|
|
} else {
|
|
if (heading < newHeading) {
|
|
adjustHeading(TURN_STEP);
|
|
} else {
|
|
adjustHeading(-TURN_STEP);
|
|
}
|
|
}
|
|
}
|
|
|
|
private Double normalizeHeading() {
|
|
Double normalizedHeading = heading - GameState.windDirection;
|
|
normalizedHeading = (double) Math.floorMod(normalizedHeading.longValue(), 360L);
|
|
return normalizedHeading;
|
|
}
|
|
|
|
public String getBoatType() {
|
|
return boatType;
|
|
}
|
|
|
|
public Integer getSourceId() {
|
|
//@TODO Remove and merge with Creating Game Loop
|
|
if (sourceId == null) return 0;
|
|
return sourceId;
|
|
}
|
|
|
|
public String getHullID() {
|
|
if (hullID == null) return "";
|
|
return hullID;
|
|
}
|
|
|
|
public String getShortName() {
|
|
return shortName;
|
|
}
|
|
|
|
public String getBoatName() {
|
|
return boatName;
|
|
}
|
|
|
|
public String getCountry() {
|
|
if (country == null) return "";
|
|
return country;
|
|
}
|
|
|
|
public Integer getBoatStatus() {
|
|
return boatStatus;
|
|
}
|
|
|
|
public void setBoatStatus(Integer boatStatus) {
|
|
this.boatStatus = boatStatus;
|
|
}
|
|
|
|
public Integer getLegNumber() {
|
|
return legNumber;
|
|
}
|
|
|
|
public void setLegNumber(Integer legNumber) {
|
|
// if (colour != null && position != "-" && legNumber != this.legNumber) {
|
|
// RaceViewController.updateYachtPositionSparkline(this, legNumber);
|
|
// }
|
|
this.legNumber = legNumber;
|
|
}
|
|
|
|
public void setEstimateTimeTillNextMark(Long estimateTimeTillNextMark) {
|
|
timeTillNext = estimateTimeTillNextMark;
|
|
}
|
|
|
|
public String getEstimateTimeAtFinish() {
|
|
DateFormat format = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");
|
|
return format.format(estimateTimeAtFinish);
|
|
}
|
|
|
|
public void setEstimateTimeAtFinish(Long estimateTimeAtFinish) {
|
|
this.estimateTimeAtFinish = estimateTimeAtFinish;
|
|
}
|
|
|
|
public Integer getPositionInteger() {
|
|
return positionInt;
|
|
}
|
|
|
|
public void setPositionInteger(Integer position) {
|
|
this.positionInt = position;
|
|
}
|
|
|
|
public void updateVelocityProperty(double velocity) {
|
|
this.velocityProperty.set(velocity);
|
|
}
|
|
|
|
public void setMarkRoundingTime(Long markRoundingTime) {
|
|
this.markRoundTime = markRoundingTime;
|
|
}
|
|
|
|
public ReadOnlyDoubleProperty getVelocityProperty() {
|
|
return velocityProperty.getReadOnlyProperty();
|
|
}
|
|
|
|
public double getVelocityMMS() {
|
|
return velocity;
|
|
}
|
|
|
|
public ReadOnlyLongProperty timeTillNextProperty() {
|
|
return timeTillNextProperty.getReadOnlyProperty();
|
|
}
|
|
|
|
public Double getVelocityKnots() {
|
|
return velocity / 1000 * 1.943844492; // TODO: 26/07/17 cir27 - remove magic number
|
|
}
|
|
|
|
public Long getTimeTillNext() {
|
|
return timeTillNext;
|
|
}
|
|
|
|
public Long getMarkRoundTime() {
|
|
return markRoundTime;
|
|
}
|
|
|
|
public Mark getLastMarkRounded() {
|
|
return lastMarkRounded;
|
|
}
|
|
|
|
public void setLastMarkRounded(Mark lastMarkRounded) {
|
|
this.lastMarkRounded = lastMarkRounded;
|
|
}
|
|
|
|
public void setNextMark(Mark nextMark) {
|
|
this.nextMark = nextMark;
|
|
}
|
|
|
|
public Mark getNextMark(){
|
|
return nextMark;
|
|
}
|
|
|
|
public Double getLat() {
|
|
return lat;
|
|
}
|
|
|
|
public void setLat(Double lat) {
|
|
this.lat = lat;
|
|
}
|
|
|
|
public Double getLon() {
|
|
return lon;
|
|
}
|
|
|
|
public void setLon(Double lon) {
|
|
this.lon = lon;
|
|
}
|
|
|
|
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 GeoPoint getLocation() {
|
|
return location;
|
|
}
|
|
|
|
public void updateTimeSinceLastMarkProperty(long timeSinceLastMark) {
|
|
this.timeSinceLastMarkProperty.set(timeSinceLastMark);
|
|
}
|
|
|
|
public ReadOnlyLongProperty timeSinceLastMarkProperty () {
|
|
return timeSinceLastMarkProperty.getReadOnlyProperty();
|
|
}
|
|
|
|
public void setTimeTillNext(Long timeTillNext) {
|
|
this.timeTillNext = timeTillNext;
|
|
}
|
|
|
|
|
|
public Color getColour() {
|
|
return colour;
|
|
}
|
|
|
|
public void setColour(Color colour) {
|
|
this.colour = colour;
|
|
}
|
|
|
|
|
|
public Double getVelocity() {
|
|
return velocity;
|
|
}
|
|
|
|
public void setVelocity(Double velocity) {
|
|
this.velocity = velocity;
|
|
}
|
|
|
|
// public void updateLatitudeProperty (Double lat) {
|
|
// latitudeProperty.set(lat);
|
|
// }
|
|
//
|
|
// public void updateLongitudeProperty (double lon) {
|
|
// longitudeProperty.set(lon);
|
|
// }
|
|
//
|
|
// public void updateHeadingProperty (double heading) {
|
|
// headingProperty.set(heading);
|
|
// }
|
|
//
|
|
// public ReadOnlyDoubleProperty latitudeProperty () {
|
|
// return latitudeProperty.getReadOnlyProperty();
|
|
// }
|
|
//
|
|
// public ReadOnlyDoubleProperty longitudeProperty () {
|
|
// return longitudeProperty.getReadOnlyProperty();
|
|
// }
|
|
//
|
|
// public ReadOnlyDoubleProperty headingProperty () {
|
|
// return headingProperty;
|
|
// }
|
|
|
|
public void updateLocation (double lat, double lon, double heading, double velocity) {
|
|
this.lat = lat;
|
|
this.lon = lon;
|
|
this.heading = heading;
|
|
this.velocity = velocity;
|
|
updateVelocityProperty(velocity);
|
|
for (YachtLocationListener yll : locationListeners) {
|
|
yll.notifyLocation(this, lat, lon, heading, velocity);
|
|
}
|
|
}
|
|
|
|
public void addLocationListener (YachtLocationListener listener) {
|
|
locationListeners.add(listener);
|
|
}
|
|
|
|
public void addPositionListener (YachtPositionListener listener) {
|
|
|
|
}
|
|
}
|