You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

319 lines
9.0 KiB

package shared.model;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.Property;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleObjectProperty;
import mock.model.collider.ColliderRegistry;
import network.Messages.Enums.RaceStatusEnum;
import network.Messages.Enums.RaceTypeEnum;
import shared.dataInput.BoatDataSource;
import shared.dataInput.RaceDataSource;
import shared.dataInput.RegattaDataSource;
import java.util.List;
/**
* Represents a yacht race.
* Has a course, state, wind, boundaries, etc.... Boats are added by inheriting classes (see {@link Boat}, {@link mock.model.MockBoat}, {@link visualiser.model.VisualiserBoat}.
*/
public abstract class Race {
/**
* The source of race related data.
*/
protected RaceDataSource raceDataSource;
/**
* The source of boat related data.
*/
protected BoatDataSource boatDataSource;
/**
* The source of regatta related data.
*/
protected RegattaDataSource regattaDataSource;
/**
* A list of compound marks in the race.
*/
protected List<CompoundMark> compoundMarks;
/**
* A list of legs in the race.
*/
protected List<Leg> legs;
/**
* A list of coordinates describing the boundary of the course.
*/
protected List<GPSCoordinate> boundary;
/**
* The clock which tracks the race's start time, current time, and elapsed duration.
*/
protected RaceClock raceClock;
/**
* The race ID of the course.
*/
protected int raceId;
/**
* The name of the regatta.
*/
protected String regattaName;
/**
* The current status of the race.
*/
protected RaceStatusEnum raceStatusEnum;
/**
* The type of race this is.
*/
protected RaceTypeEnum raceType;
/**
* The race's wind.
*/
protected Property<Wind> raceWind = new SimpleObjectProperty<>();
/**
* Registry for all collider object in this race
*/
protected ColliderRegistry colliderRegistry;
/**
* The number of frames per second.
* We essentially track the number of frames generated per second, over a one second period. When {@link #lastFpsResetTime} reaches 1 second, currentFps is reset.
*/
private int currentFps = 0;
/**
* The number of frames per second we generated over the last 1 second period.
*/
private IntegerProperty lastFps = new SimpleIntegerProperty(0);
/**
* The time, in milliseconds, since we last reset our {@link #currentFps} counter.
*/
private long lastFpsResetTime;
/**
* Constructs a race object with a given BoatDataSource, RaceDataSource, and RegattaDataSource.
* @param boatDataSource Data source for boat related data (yachts and marker boats).
* @param raceDataSource Data source for race related data (participating boats, legs, etc...).
* @param regattaDataSource Data source for race related data (course name, location, timezone, etc...).
*/
public Race(BoatDataSource boatDataSource, RaceDataSource raceDataSource, RegattaDataSource regattaDataSource) {
//Keep a reference to data sources.
this.raceDataSource = raceDataSource;
this.boatDataSource = boatDataSource;
this.regattaDataSource = regattaDataSource;
//Marks.
this.compoundMarks = raceDataSource.getCompoundMarks();
//Boundaries.
this.boundary = raceDataSource.getBoundary();
//Legs.
this.useLegsList(raceDataSource.getLegs());
//Race ID.
this.raceId = raceDataSource.getRaceId();
//Regatta name.
this.regattaName = regattaDataSource.getRegattaName();
//Race clock.
this.raceClock = new RaceClock(this.raceDataSource.getStartDateTime());
//Race status.
this.setRaceStatusEnum(RaceStatusEnum.NOT_ACTIVE);
//Race type.
this.raceType = raceDataSource.getRaceType();
//Wind.
this.setWind(Bearing.fromDegrees(0), 0);
// Set up colliders
this.colliderRegistry = new ColliderRegistry();
for(CompoundMark mark: compoundMarks) {
colliderRegistry.addCollider(mark.getMark1());
if(mark.getMark2() != null) colliderRegistry.addCollider(mark.getMark2());
}
}
public ColliderRegistry getColliderRegistry() {
return colliderRegistry;
}
/**
* Initialise the boats in the race.
* This sets their starting positions and current legs.
*/
protected abstract void initialiseBoats();
/**
* Updates the race to use a new list of legs, and adds a dummy "Finish" leg at the end.
* @param legs The new list of legs to use.
*/
protected void useLegsList(List<Leg> legs) {
//We add a "dummy" leg at the end of the race.
this.legs = legs;
this.legs.add(new Leg("Finish", this.legs.size()));
}
/**
* Determines whether or not a specific leg is the last leg in the race.
* @param leg The leg to check.
* @return Returns true if it is the last, false otherwise.
*/
protected boolean isLastLeg(Leg leg) {
//Get the last leg.
Leg lastLeg = this.legs.get(this.legs.size() - 1);
//Check its ID.
int lastLegID = lastLeg.getLegNumber();
//Get the specified leg's ID.
int legID = leg.getLegNumber();
//Check if they are the same.
return legID == lastLegID;
}
/**
* Returns the current race status.
* @return The current race status.
*/
public RaceStatusEnum getRaceStatusEnum() {
return raceStatusEnum;
}
/**
* Sets the current race status.
* @param raceStatusEnum The new status of the race.
*/
public void setRaceStatusEnum(RaceStatusEnum raceStatusEnum) {
this.raceStatusEnum = raceStatusEnum;
}
/**
* Returns the type of race this is.
* @return The type of race this is.
*/
public RaceTypeEnum getRaceType() {
return raceType;
}
/**
* Returns the name of the regatta.
* @return The name of the regatta.
*/
public String getRegattaName() {
return regattaName;
}
/**
* Updates the race to have a specified wind bearing and speed.
* @param windBearing New wind bearing.
* @param windSpeedKnots New wind speed, in knots.
*/
protected void setWind(Bearing windBearing, double windSpeedKnots) {
Wind wind = new Wind(windBearing, windSpeedKnots);
setWind(wind);
}
/**
* Updates the race to have a specified wind (bearing and speed).
* @param wind New wind.
*/
protected void setWind(Wind wind) {
this.raceWind.setValue(wind);
}
/**
* Returns the wind bearing.
* @return The wind bearing.
*/
public Bearing getWindDirection() {
return raceWind.getValue().getWindDirection();
}
/**
* Returns the wind speed.
* Measured in knots.
* @return The wind speed.
*/
public double getWindSpeed() {
return raceWind.getValue().getWindSpeed();
}
/**
* Returns the RaceClock for this race.
* This is used to track the start time, current time, and elapsed duration of the race.
* @return The RaceClock for the race.
*/
public RaceClock getRaceClock() {
return raceClock;
}
/**
* Returns the RaceDataSource used for the race.
* @return The RaceDataSource used for the race.
*/
public RaceDataSource getRaceDataSource() {
return raceDataSource;
}
/**
* Returns the number of legs in the race.
* @return The number of legs in the race.
*/
public int getLegCount() {
//We minus one, as we have added an extra "dummy" leg.
return legs.size() - 1;
}
/**
* Returns the race boundary.
* @return The race boundary.
*/
public List<GPSCoordinate> getBoundary() {
return boundary;
}
/**
* Returns the marks of the race.
* @return Marks of the race.
*/
public List<CompoundMark> getCompoundMarks() {
return compoundMarks;
}
/**
* Returns the legs of the race.
* @return Legs of the race.
*/
public List<Leg> getLegs() {
return legs;
}
/**
* Returns the fps property.
* @return The fps property.
*/
public IntegerProperty fpsProperty() {
return lastFps;
}
/**
* Increments the FPS counter, and adds timePeriod milliseconds to our FPS reset timer.
* @param timePeriod Time, in milliseconds, to add to {@link #lastFpsResetTime}.
*/
protected void incrementFps(long timePeriod) {
//Increment.
this.currentFps++;
//Add period to timer.
this.lastFpsResetTime += timePeriod;
//If we have reached 1 second period, snapshot the framerate and reset.
if (this.lastFpsResetTime > 1000) {
this.lastFps.set(this.currentFps);
this.currentFps = 0;
this.lastFpsResetTime = 0;
}
}
public int getRaceId() {
return raceId;
}
}