Merge branch 'storyB-)' into 'master'
B) [V,M] As a player I would like to have the game run smoothly and have a unique game experience Acceptance criteria: * Boat moves smoothly when executing command * The appearance of the game is unique and consistent This merge request also closes issue #42. See merge request !42
This commit is contained in:
Generated
+3
@@ -0,0 +1,3 @@
|
|||||||
|
<component name="CopyrightManager">
|
||||||
|
<settings default="" />
|
||||||
|
</component>
|
||||||
@@ -75,9 +75,6 @@ public class Event {
|
|||||||
* @throws EventConstructionException Thrown if we cannot create an Event for any reason.
|
* @throws EventConstructionException Thrown if we cannot create an Event for any reason.
|
||||||
*/
|
*/
|
||||||
public Event(boolean singlePlayer, int mapIndex) throws EventConstructionException {
|
public Event(boolean singlePlayer, int mapIndex) throws EventConstructionException {
|
||||||
|
|
||||||
// System.out.println(XMLUtilities.validateXML(this.getClass().getClassLoader().getResource("mock/mockXML/iMapLayout.xml").toString()
|
|
||||||
// , this.getClass().getClassLoader().getResource("mock/mockXML/schema/raceSchema.xsd")));
|
|
||||||
this.mapIndex = mapIndex;
|
this.mapIndex = mapIndex;
|
||||||
String raceXMLFile;
|
String raceXMLFile;
|
||||||
String boatsXMLFile = "mock/mockXML/boatTest.xml";
|
String boatsXMLFile = "mock/mockXML/boatTest.xml";
|
||||||
|
|||||||
@@ -34,7 +34,10 @@ public class MockBoat extends Boat {
|
|||||||
*/
|
*/
|
||||||
private boolean autoVMG = false;
|
private boolean autoVMG = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates whether boat velocity is determined by wind
|
||||||
|
*/
|
||||||
|
private boolean velocityDefault = true;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a boat object with a given sourceID, name, country/team abbreviation, and polars table.
|
* Constructs a boat object with a given sourceID, name, country/team abbreviation, and polars table.
|
||||||
@@ -300,4 +303,12 @@ public class MockBoat extends Boat {
|
|||||||
public void setAutoVMG(boolean autoVMG) {
|
public void setAutoVMG(boolean autoVMG) {
|
||||||
this.autoVMG = autoVMG;
|
this.autoVMG = autoVMG;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isVelocityDefault() {
|
||||||
|
return velocityDefault;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setVelocityDefault(boolean velocityDefault) {
|
||||||
|
this.velocityDefault = velocityDefault;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
package mock.model;
|
package mock.model;
|
||||||
|
|
||||||
|
import mock.model.commandFactory.ActiveObserverCommand;
|
||||||
|
import mock.model.commandFactory.ObserverCommand;
|
||||||
import mock.model.wind.WindGenerator;
|
import mock.model.wind.WindGenerator;
|
||||||
import javafx.animation.AnimationTimer;
|
import javafx.animation.AnimationTimer;
|
||||||
import mock.model.collider.ColliderRegistry;
|
import mock.model.collider.ColliderRegistry;
|
||||||
@@ -64,6 +66,8 @@ public class MockRace extends RaceState {
|
|||||||
*/
|
*/
|
||||||
private Polars polars;
|
private Polars polars;
|
||||||
|
|
||||||
|
private ActiveObserverCommand activeObserverCommand;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -81,6 +85,7 @@ public class MockRace extends RaceState {
|
|||||||
this.setRaceDataSource(raceDataSource);
|
this.setRaceDataSource(raceDataSource);
|
||||||
this.setRegattaDataSource(regattaDataSource);
|
this.setRegattaDataSource(regattaDataSource);
|
||||||
|
|
||||||
|
this.activeObserverCommand = new ActiveObserverCommand();
|
||||||
this.polars = polars;
|
this.polars = polars;
|
||||||
this.scaleFactor = timeScale;
|
this.scaleFactor = timeScale;
|
||||||
|
|
||||||
@@ -355,70 +360,25 @@ public class MockRace extends RaceState {
|
|||||||
//Checks if the current boat has finished the race or not.
|
//Checks if the current boat has finished the race or not.
|
||||||
boolean finish = this.isLastLeg(boat.getCurrentLeg());
|
boolean finish = this.isLastLeg(boat.getCurrentLeg());
|
||||||
|
|
||||||
if (!finish && totalElapsedMilliseconds >= updatePeriodMilliseconds && boat.isSailsOut()) {
|
if (!finish && totalElapsedMilliseconds >= updatePeriodMilliseconds) {
|
||||||
|
|
||||||
checkPosition(boat, totalElapsedMilliseconds);
|
checkPosition(boat, totalElapsedMilliseconds);
|
||||||
|
|
||||||
if (boat.getCurrentSpeed() == 0) {
|
if(boat.isVelocityDefault()) setBoatSpeed(boat);
|
||||||
newOptimalVMG(boat);
|
|
||||||
boat.setBearing(boat.calculateBearingToNextMarker());
|
|
||||||
}
|
|
||||||
|
|
||||||
setBoatSpeed(boat);
|
|
||||||
|
|
||||||
//Calculates the distance travelled, in meters, in the current timeslice.
|
//Calculates the distance travelled, in meters, in the current timeslice.
|
||||||
double distanceTravelledMeters = boat.calculateMetersTravelled(updatePeriodMilliseconds);
|
double distanceTravelledMeters = boat.calculateMetersTravelled(updatePeriodMilliseconds) * this.scaleFactor;
|
||||||
|
|
||||||
//Scale it.
|
|
||||||
distanceTravelledMeters = distanceTravelledMeters * this.scaleFactor;
|
|
||||||
|
|
||||||
|
|
||||||
//Move the boat forwards that many meters, and advances its time counters by enough milliseconds.
|
//Move the boat forwards that many meters, and advances its time counters by enough milliseconds.
|
||||||
boat.moveForwards(distanceTravelledMeters);
|
boat.moveForwards(distanceTravelledMeters);
|
||||||
boat.setTimeSinceTackChange(boat.getTimeSinceTackChange() + updatePeriodMilliseconds);
|
boat.setTimeSinceTackChange(boat.getTimeSinceTackChange() + updatePeriodMilliseconds);
|
||||||
|
|
||||||
if (boat.getAutoVMG()) {
|
|
||||||
newOptimalVMG(boat);
|
|
||||||
boat.setAutoVMG(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
boat.setCurrentSpeed(0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.updateEstimatedTime(boat);
|
this.updateEstimatedTime(boat);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void newOptimalVMG(MockBoat boat) {
|
|
||||||
long tackPeriod = 1000;
|
|
||||||
if (boat.getTimeSinceTackChange() > tackPeriod) {
|
|
||||||
//System.out.println("optim called");
|
|
||||||
//Calculate the new VMG.
|
|
||||||
// VMG newVMG = boat.getPolars().calculateVMG(
|
|
||||||
// this.getWindDirection(),
|
|
||||||
// this.getWindSpeed(),
|
|
||||||
// boat.calculateBearingToNextMarker(),
|
|
||||||
// Bearing.fromDegrees(0d),
|
|
||||||
// Bearing.fromDegrees(359.99999d));
|
|
||||||
|
|
||||||
VMG newVMG = NewPolars.setBestVMG(this.getWindDirection(), this.getWindSpeed(), boat.getBearing());
|
|
||||||
//System.out.println(newVMG);
|
|
||||||
//If the new vmg improves velocity, use it.
|
|
||||||
/*if (improvesVelocity(boat, newVMG)) {
|
|
||||||
}*/
|
|
||||||
boat.setVMG(newVMG);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setBoatSpeed(MockBoat boat) {
|
private void setBoatSpeed(MockBoat boat) {
|
||||||
// VMG vmg = boat.getPolars().calculateVMG(
|
|
||||||
// this.getWindDirection(),
|
|
||||||
// this.getWindSpeed(),
|
|
||||||
// boat.getBearing(),
|
|
||||||
// Bearing.fromDegrees(boat.getBearing().degrees() - 1),
|
|
||||||
// Bearing.fromDegrees(boat.getBearing().degrees() + 1));
|
|
||||||
//VMG vmg = boat.getPolars().setBestVMG(this.getWindDirection(), this.getWindSpeed(), boat.getBearing());
|
|
||||||
VMG vmg = new VMG(NewPolars.calculateSpeed(
|
VMG vmg = new VMG(NewPolars.calculateSpeed(
|
||||||
this.getWindDirection(),
|
this.getWindDirection(),
|
||||||
this.getWindSpeed(),
|
this.getWindSpeed(),
|
||||||
@@ -754,4 +714,18 @@ public class MockRace extends RaceState {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Made public, so race logic can control it
|
||||||
|
*/
|
||||||
|
public void setChanged() {
|
||||||
|
super.setChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addVelocityCommand(ObserverCommand c) {
|
||||||
|
this.activeObserverCommand.changeVelocityCommand(this, c);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addAngularCommand(ObserverCommand c) {
|
||||||
|
this.activeObserverCommand.changeAngularCommand(this, c);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -145,8 +145,6 @@ public class NewPolars {
|
|||||||
* @return the best vmg that the boat can change to
|
* @return the best vmg that the boat can change to
|
||||||
*/
|
*/
|
||||||
public static VMG setBestVMG(Bearing trueWindAngle, double trueWindSpeed, Bearing boatAngle){
|
public static VMG setBestVMG(Bearing trueWindAngle, double trueWindSpeed, Bearing boatAngle){
|
||||||
//System.out.println("VMG AUTO CALLED");
|
|
||||||
//speed
|
|
||||||
double closestSpeed = getClosest(trueWindSpeed, polars.keySet());
|
double closestSpeed = getClosest(trueWindSpeed, polars.keySet());
|
||||||
|
|
||||||
double angle = modulateAngle(boatAngle.degrees() - trueWindAngle.degrees());
|
double angle = modulateAngle(boatAngle.degrees() - trueWindAngle.degrees());
|
||||||
@@ -181,15 +179,29 @@ public class NewPolars {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gets the angle bound between 0 and 360 following modular arithmetic
|
||||||
|
* @param angle angle to modulate
|
||||||
|
* @return resultant angle after modulation.
|
||||||
|
*/
|
||||||
public static double modulateAngle(double angle){
|
public static double modulateAngle(double angle){
|
||||||
return (angle % 360 + 360) % 360;
|
return (angle % 360 + 360) % 360;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DO NOT DELETE THIS FUNCTIONS THEY ARE USED FOR TESTING PURPOSES
|
||||||
|
* @return current polars map
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unused")
|
||||||
private Map<Double, TreeMap<Double, Double>> getPolars(){
|
private Map<Double, TreeMap<Double, Double>> getPolars(){
|
||||||
//this function is just for testing so therefore it is private
|
//this function is just for testing so therefore it is private
|
||||||
return polars;
|
return polars;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DO NOT DELETE THESE FUNCTIONS THEY ARE USED FOR TESTING PURPOSES
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unused")
|
||||||
private void printOutLinearInterpolated(){
|
private void printOutLinearInterpolated(){
|
||||||
for (double tws: polars.keySet()){
|
for (double tws: polars.keySet()){
|
||||||
System.out.println("==================================================");
|
System.out.println("==================================================");
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package mock.model;
|
|||||||
|
|
||||||
import javafx.animation.AnimationTimer;
|
import javafx.animation.AnimationTimer;
|
||||||
import mock.model.collider.Collision;
|
import mock.model.collider.Collision;
|
||||||
|
import mock.model.commandFactory.CollisionCommand;
|
||||||
import mock.model.commandFactory.Command;
|
import mock.model.commandFactory.Command;
|
||||||
import mock.model.commandFactory.CompositeCommand;
|
import mock.model.commandFactory.CompositeCommand;
|
||||||
import mock.model.commandFactory.CommandFactory;
|
import mock.model.commandFactory.CommandFactory;
|
||||||
@@ -148,6 +149,10 @@ public class RaceLogic implements RunnableWithFramePeriod, Observer {
|
|||||||
// Execute commands from clients.
|
// Execute commands from clients.
|
||||||
commands.execute();
|
commands.execute();
|
||||||
|
|
||||||
|
// Notify Observers
|
||||||
|
race.setChanged();
|
||||||
|
race.notifyObservers();
|
||||||
|
|
||||||
//Update race time.
|
//Update race time.
|
||||||
race.updateRaceTime(currentTime);
|
race.updateRaceTime(currentTime);
|
||||||
|
|
||||||
@@ -218,11 +223,9 @@ public class RaceLogic implements RunnableWithFramePeriod, Observer {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void update(Observable o, Object arg) {
|
public void update(Observable o, Object arg) {
|
||||||
Collision e = (Collision)arg;
|
if(arg instanceof Collision) {
|
||||||
|
Collision collision = (Collision)arg;
|
||||||
// if(e.getBearing().degrees() == 0) System.out.println("Ahead");
|
commands.addCommand(new CollisionCommand(race, (MockBoat)collision.getBoat()));
|
||||||
// else if(e.getBearing().degrees() < 90) System.out.println("Starboard");
|
}
|
||||||
// else if(e.getBearing().degrees() > 270) System.out.println("Port");
|
|
||||||
// else System.out.println("Behind");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,13 +25,9 @@ public abstract class Collider extends Observable implements Locatable {
|
|||||||
Bearing relative = Bearing.fromDegrees(absolute.degrees() - boat.getBearing().degrees());
|
Bearing relative = Bearing.fromDegrees(absolute.degrees() - boat.getBearing().degrees());
|
||||||
|
|
||||||
if(actualDistance <= distance) {
|
if(actualDistance <= distance) {
|
||||||
Collision collision = new Collision(relative, distance);
|
Collision collision = new Collision(boat, relative, distance);
|
||||||
// Notify object of collision
|
// Notify object of collision
|
||||||
onCollisionEnter(boat, collision);
|
onCollisionEnter(collision);
|
||||||
// Notify observers of collision
|
|
||||||
notifyObservers(collision);
|
|
||||||
this.setChanged();
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
} else return false;
|
} else return false;
|
||||||
}
|
}
|
||||||
@@ -45,8 +41,7 @@ public abstract class Collider extends Observable implements Locatable {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle a collision event
|
* Handle a collision event
|
||||||
* @param collider Boat that is colliding
|
|
||||||
* @param e details of collision
|
* @param e details of collision
|
||||||
*/
|
*/
|
||||||
public abstract void onCollisionEnter(Boat collider, Collision e);
|
public abstract void onCollisionEnter(Collision e);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package mock.model.collider;
|
package mock.model.collider;
|
||||||
|
|
||||||
|
import mock.model.MockBoat;
|
||||||
import shared.model.Boat;
|
import shared.model.Boat;
|
||||||
import shared.model.GPSCoordinate;
|
import shared.model.GPSCoordinate;
|
||||||
|
|
||||||
@@ -39,7 +40,7 @@ public class ColliderRegistry extends Collider implements Observer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCollisionEnter(Boat collider, Collision e) {}
|
public void onCollisionEnter(Collision e) {}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public GPSCoordinate getPosition() {
|
public GPSCoordinate getPosition() {
|
||||||
@@ -60,7 +61,7 @@ public class ColliderRegistry extends Collider implements Observer {
|
|||||||
public void update(Observable o, Object arg) {
|
public void update(Observable o, Object arg) {
|
||||||
Collision collision = (Collision)arg;
|
Collision collision = (Collision)arg;
|
||||||
|
|
||||||
notifyObservers(collision);
|
|
||||||
this.setChanged();
|
this.setChanged();
|
||||||
|
notifyObservers(collision);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package mock.model.collider;
|
package mock.model.collider;
|
||||||
|
|
||||||
import shared.model.Bearing;
|
import shared.model.Bearing;
|
||||||
|
import shared.model.Boat;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Data structure for holding collision details for ray casting and event handling.
|
* Data structure for holding collision details for ray casting and event handling.
|
||||||
@@ -14,13 +15,19 @@ public class Collision {
|
|||||||
* Distance from boat centre to target centre
|
* Distance from boat centre to target centre
|
||||||
*/
|
*/
|
||||||
private double distance;
|
private double distance;
|
||||||
|
/**
|
||||||
|
* Boat involved in the collision
|
||||||
|
*/
|
||||||
|
private Boat boat;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor for Collision structure
|
* Constructor for Collision structure
|
||||||
|
* @param boat involved in collision
|
||||||
* @param bearing from boat heading to target
|
* @param bearing from boat heading to target
|
||||||
* @param distance from boat centre to target centre
|
* @param distance from boat centre to target centre
|
||||||
*/
|
*/
|
||||||
public Collision(Bearing bearing, double distance) {
|
public Collision(Boat boat, Bearing bearing, double distance) {
|
||||||
|
this.boat = boat;
|
||||||
this.bearing = bearing;
|
this.bearing = bearing;
|
||||||
this.distance = distance;
|
this.distance = distance;
|
||||||
}
|
}
|
||||||
@@ -32,4 +39,8 @@ public class Collision {
|
|||||||
public double getDistance() {
|
public double getDistance() {
|
||||||
return distance;
|
return distance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Boat getBoat() {
|
||||||
|
return boat;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,27 @@
|
|||||||
|
package mock.model.commandFactory;
|
||||||
|
|
||||||
|
import java.util.Observable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to track the current active observer command. This is to ensure two commands that do similar things do not overlap.
|
||||||
|
*/
|
||||||
|
public class ActiveObserverCommand {
|
||||||
|
private ObserverCommand currentVelocityCommand;
|
||||||
|
private ObserverCommand currentAngularCommand;
|
||||||
|
|
||||||
|
public ActiveObserverCommand() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void changeVelocityCommand(Observable o, ObserverCommand c) {
|
||||||
|
o.deleteObserver(currentVelocityCommand);
|
||||||
|
o.addObserver(c);
|
||||||
|
currentVelocityCommand = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void changeAngularCommand(Observable o, ObserverCommand c) {
|
||||||
|
o.deleteObserver(currentAngularCommand);
|
||||||
|
o.addObserver(c);
|
||||||
|
currentAngularCommand = c;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
package mock.model.commandFactory;
|
||||||
|
|
||||||
|
import mock.model.MockBoat;
|
||||||
|
import mock.model.MockRace;
|
||||||
|
import shared.model.Azimuth;
|
||||||
|
import shared.model.GPSCoordinate;
|
||||||
|
|
||||||
|
import java.util.Observable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Command class for collisions
|
||||||
|
*/
|
||||||
|
public class CollisionCommand extends ObserverCommand {
|
||||||
|
private GPSCoordinate startingPosition;
|
||||||
|
private Azimuth azimuth;
|
||||||
|
private double distance;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor for class
|
||||||
|
* @param race race context
|
||||||
|
* @param boat boat controlled by command
|
||||||
|
*/
|
||||||
|
public CollisionCommand(MockRace race, MockBoat boat) {
|
||||||
|
super(race, boat);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute() {
|
||||||
|
this.azimuth = Azimuth.fromDegrees(boat.getBearing().degrees() - 180d);
|
||||||
|
this.startingPosition = boat.getPosition();
|
||||||
|
this.distance = 30;
|
||||||
|
boat.setVelocityDefault(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void update(Observable o, Object arg) {
|
||||||
|
if(GPSCoordinate.calculateDistanceMeters(boat.getPosition(), startingPosition) < distance) {
|
||||||
|
boat.setPosition(GPSCoordinate.calculateNewPosition(boat.getPosition(), 2, azimuth));
|
||||||
|
} else {
|
||||||
|
race.deleteObserver(this);
|
||||||
|
boat.setVelocityDefault(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,6 +3,8 @@ package mock.model.commandFactory;
|
|||||||
import mock.model.MockBoat;
|
import mock.model.MockBoat;
|
||||||
import mock.model.MockRace;
|
import mock.model.MockRace;
|
||||||
|
|
||||||
|
import java.util.Observer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Allows RaceLogic to control MockRace state according to the Command pattern
|
* Allows RaceLogic to control MockRace state according to the Command pattern
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
package mock.model.commandFactory;
|
||||||
|
|
||||||
|
import mock.model.MockBoat;
|
||||||
|
import mock.model.MockRace;
|
||||||
|
|
||||||
|
import java.util.Observer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Command that can observe the race
|
||||||
|
*/
|
||||||
|
public abstract class ObserverCommand implements Command, Observer {
|
||||||
|
MockRace race;
|
||||||
|
MockBoat boat;
|
||||||
|
|
||||||
|
public ObserverCommand(MockRace race, MockBoat boat) {
|
||||||
|
this.race = race;
|
||||||
|
this.boat = boat;
|
||||||
|
boat.setAutoVMG(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,20 +2,50 @@ package mock.model.commandFactory;
|
|||||||
|
|
||||||
import mock.model.MockBoat;
|
import mock.model.MockBoat;
|
||||||
import mock.model.MockRace;
|
import mock.model.MockRace;
|
||||||
|
import mock.model.NewPolars;
|
||||||
|
import mock.model.VMG;
|
||||||
|
|
||||||
public class SailsCommand implements Command {
|
import java.util.Observable;
|
||||||
private MockRace race;
|
|
||||||
private MockBoat boat;
|
public class SailsCommand extends ObserverCommand {
|
||||||
private boolean sailsOut;
|
private boolean sailsOut;
|
||||||
|
private double goalVelocity;
|
||||||
|
|
||||||
public SailsCommand(MockRace race, MockBoat boat, Boolean sailsOut) {
|
public SailsCommand(MockRace race, MockBoat boat, boolean sailsOut) {
|
||||||
this.race = race;
|
super(race, boat);
|
||||||
this.boat = boat;
|
race.addVelocityCommand(this);
|
||||||
this.sailsOut = sailsOut;
|
this.sailsOut = sailsOut;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void execute() {
|
public void execute() {
|
||||||
this.boat.setSailsOut(this.sailsOut);
|
this.boat.setSailsOut(this.sailsOut);
|
||||||
|
boat.setVelocityDefault(false);
|
||||||
|
|
||||||
|
if(sailsOut) {
|
||||||
|
// Accelerate to VMG speed
|
||||||
|
double polarSpeed = NewPolars.calculateSpeed(race.getWindDirection(), race.getWindSpeed(), boat.getBearing());
|
||||||
|
VMG vmg = new VMG(polarSpeed, boat.getBearing());
|
||||||
|
goalVelocity = vmg.getSpeed();
|
||||||
|
} else {
|
||||||
|
// Decelerate to 0
|
||||||
|
goalVelocity = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void update(Observable o, Object arg) {
|
||||||
|
double acceleration = 0.5;
|
||||||
|
|
||||||
|
if(sailsOut && boat.getCurrentSpeed() < goalVelocity) {
|
||||||
|
boat.setCurrentSpeed(Math.min(goalVelocity, boat.getCurrentSpeed() + acceleration));
|
||||||
|
} else if (!sailsOut && boat.getCurrentSpeed() > goalVelocity) {
|
||||||
|
// Apply deceleration to strictly 0 speed
|
||||||
|
boat.setCurrentSpeed(Math.max(0, boat.getCurrentSpeed() - acceleration));
|
||||||
|
} else {
|
||||||
|
// Release boat from SailsCommand control
|
||||||
|
if(sailsOut) boat.setVelocityDefault(true);
|
||||||
|
race.deleteObserver(this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,12 +4,16 @@ import mock.model.MockBoat;
|
|||||||
import mock.model.MockRace;
|
import mock.model.MockRace;
|
||||||
import shared.model.Bearing;
|
import shared.model.Bearing;
|
||||||
|
|
||||||
|
import java.util.Observable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Command class for tacking and gybing
|
* Command class for tacking and gybing
|
||||||
*/
|
*/
|
||||||
public class TackGybeCommand implements Command {
|
public class TackGybeCommand extends ObserverCommand {
|
||||||
private MockRace race;
|
private double goalRotation;
|
||||||
private MockBoat boat;
|
private double totalRotation = 0;
|
||||||
|
private int direction; // -1 for anticlockwise, 1 for clockwise
|
||||||
|
private double goalAngle;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor for class
|
* Constructor for class
|
||||||
@@ -17,24 +21,32 @@ public class TackGybeCommand implements Command {
|
|||||||
* @param boat mock boat to update
|
* @param boat mock boat to update
|
||||||
*/
|
*/
|
||||||
public TackGybeCommand(MockRace race, MockBoat boat) {
|
public TackGybeCommand(MockRace race, MockBoat boat) {
|
||||||
this.race = race;
|
super(race, boat);
|
||||||
this.boat = boat;
|
race.addAngularCommand(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void execute() {
|
public void execute() {
|
||||||
|
|
||||||
boat.setAutoVMG(false);
|
|
||||||
|
|
||||||
double boatAngle = boat.getBearing().degrees();
|
double boatAngle = boat.getBearing().degrees();
|
||||||
double windAngle = race.getWindDirection().degrees();
|
double windAngle = race.getWindDirection().degrees();
|
||||||
double differenceAngle = calcDistance(boatAngle, windAngle);
|
double differenceAngle = calcDistance(boatAngle, windAngle);
|
||||||
double angleA = windAngle + differenceAngle;
|
double angleA = windAngle + differenceAngle;
|
||||||
double angleB = windAngle - differenceAngle;
|
double angleB = windAngle - differenceAngle;
|
||||||
if (angleA % 360 == boatAngle) {
|
if (angleA % 360 == boatAngle) {
|
||||||
boat.setBearing(Bearing.fromDegrees(angleB));
|
goalAngle = angleB % 360;
|
||||||
} else {
|
} else {
|
||||||
boat.setBearing(Bearing.fromDegrees(angleA));
|
goalAngle = angleA % 360;
|
||||||
|
}
|
||||||
|
|
||||||
|
goalRotation = goalAngle - boatAngle;
|
||||||
|
if (goalRotation < 0) {
|
||||||
|
goalRotation += 360;
|
||||||
|
}
|
||||||
|
if (goalRotation > 180) {
|
||||||
|
goalRotation = 360 - goalRotation;
|
||||||
|
direction = -1;
|
||||||
|
} else {
|
||||||
|
direction = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -49,5 +61,16 @@ public class TackGybeCommand implements Command {
|
|||||||
return phi > 180 ? 360 - phi : phi;
|
return phi > 180 ? 360 - phi : phi;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void update(Observable o, Object arg) {
|
||||||
|
double offset = 3.0;
|
||||||
|
if (totalRotation < goalRotation) {
|
||||||
|
boat.setBearing(Bearing.fromDegrees(boat.getBearing().degrees() + offset * direction));
|
||||||
|
totalRotation += offset;
|
||||||
|
} else {
|
||||||
|
boat.setBearing(Bearing.fromDegrees(goalAngle));
|
||||||
|
race.deleteObserver(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,13 +2,20 @@ package mock.model.commandFactory;
|
|||||||
|
|
||||||
import mock.model.MockBoat;
|
import mock.model.MockBoat;
|
||||||
import mock.model.MockRace;
|
import mock.model.MockRace;
|
||||||
|
import mock.model.NewPolars;
|
||||||
|
import mock.model.VMG;
|
||||||
|
import shared.model.Bearing;
|
||||||
|
|
||||||
|
import java.util.Observable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Command class for autoVMG
|
* Command class for autoVMG
|
||||||
*/
|
*/
|
||||||
public class VMGCommand implements Command {
|
public class VMGCommand extends ObserverCommand {
|
||||||
private MockRace race;
|
private double goalAngle;
|
||||||
private MockBoat boat;
|
private double goalRotation;
|
||||||
|
private double totalRotation = 0;
|
||||||
|
private int direction;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor for class
|
* Constructor for class
|
||||||
@@ -16,8 +23,8 @@ public class VMGCommand implements Command {
|
|||||||
* @param boat mock boat to update
|
* @param boat mock boat to update
|
||||||
*/
|
*/
|
||||||
public VMGCommand(MockRace race, MockBoat boat) {
|
public VMGCommand(MockRace race, MockBoat boat) {
|
||||||
this.race = race;
|
super(race, boat);
|
||||||
this.boat = boat;
|
race.addAngularCommand(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -27,5 +34,37 @@ public class VMGCommand implements Command {
|
|||||||
} else {
|
} else {
|
||||||
boat.setAutoVMG(true);
|
boat.setAutoVMG(true);
|
||||||
}
|
}
|
||||||
|
newOptimalVMG(boat);
|
||||||
|
|
||||||
|
goalRotation = goalAngle - boat.getBearing().degrees();
|
||||||
|
if (goalRotation < 0) {
|
||||||
|
goalRotation += 360;
|
||||||
|
}
|
||||||
|
if (goalRotation > 180) {
|
||||||
|
goalRotation = 360 - goalRotation;
|
||||||
|
direction = -1;
|
||||||
|
} else {
|
||||||
|
direction = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void newOptimalVMG(MockBoat boat) {
|
||||||
|
long tackPeriod = 1000;
|
||||||
|
if (boat.getTimeSinceTackChange() > tackPeriod) {
|
||||||
|
VMG newVMG = NewPolars.setBestVMG(race.getWindDirection(), race.getWindSpeed(), boat.getBearing());
|
||||||
|
goalAngle = newVMG.getBearing().degrees();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void update(Observable o, Object arg) {
|
||||||
|
double offset = 3.0;
|
||||||
|
if (totalRotation < goalRotation) {
|
||||||
|
boat.setBearing(Bearing.fromDegrees(boat.getBearing().degrees() + offset * direction));
|
||||||
|
totalRotation += offset;
|
||||||
|
} else {
|
||||||
|
boat.setBearing(Bearing.fromDegrees(goalAngle));
|
||||||
|
race.deleteObserver(this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,17 +4,23 @@ import mock.model.MockBoat;
|
|||||||
import mock.model.MockRace;
|
import mock.model.MockRace;
|
||||||
import shared.model.Bearing;
|
import shared.model.Bearing;
|
||||||
|
|
||||||
|
import java.util.Observable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by connortaylorbrown on 4/08/17.
|
* Command class for upwind and downwind controls
|
||||||
*/
|
*/
|
||||||
public class WindCommand implements Command {
|
public class WindCommand extends ObserverCommand {
|
||||||
private MockRace race;
|
|
||||||
private MockBoat boat;
|
|
||||||
private int direction;
|
private int direction;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor for class
|
||||||
|
* @param race race context
|
||||||
|
* @param boat boat controlled by command
|
||||||
|
* @param upwind if true, downwind if false
|
||||||
|
*/
|
||||||
public WindCommand(MockRace race, MockBoat boat, boolean upwind) {
|
public WindCommand(MockRace race, MockBoat boat, boolean upwind) {
|
||||||
this.race = race;
|
super(race, boat);
|
||||||
this.boat = boat;
|
race.addAngularCommand(this);
|
||||||
this.direction = upwind? -1 : 1;
|
this.direction = upwind? -1 : 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -34,4 +40,9 @@ public class WindCommand implements Command {
|
|||||||
|
|
||||||
boat.setBearing(Bearing.fromDegrees(heading + offset));
|
boat.setBearing(Bearing.fromDegrees(heading + offset));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void update(Observable o, Object arg) {
|
||||||
|
race.deleteObserver(this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -105,7 +105,6 @@ public class ShiftingWindGenerator implements WindGenerator {
|
|||||||
if (shiftedSoFar >= 180){
|
if (shiftedSoFar >= 180){
|
||||||
shiftAnticlockwise = Math.random() > 0.5;
|
shiftAnticlockwise = Math.random() > 0.5;
|
||||||
shiftedSoFar = 0;
|
shiftedSoFar = 0;
|
||||||
// System.out.println("Swapping");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
timeOfLastShift = System.currentTimeMillis();
|
timeOfLastShift = System.currentTimeMillis();
|
||||||
|
|||||||
@@ -41,7 +41,6 @@ public class AC35DumpReader {
|
|||||||
messLen[1] = dump[pointer + 13];
|
messLen[1] = dump[pointer + 13];
|
||||||
messLen[0] = dump[pointer + 14];
|
messLen[0] = dump[pointer + 14];
|
||||||
int messageLength = ByteBuffer.wrap(messLen).getShort();
|
int messageLength = ByteBuffer.wrap(messLen).getShort();
|
||||||
//System.out.println(messageLength);
|
|
||||||
|
|
||||||
packets.add(new AC35Packet(Arrays.copyOfRange(dump, pointer, pointer + messageLength + 19)));
|
packets.add(new AC35Packet(Arrays.copyOfRange(dump, pointer, pointer + messageLength + 19)));
|
||||||
|
|
||||||
|
|||||||
@@ -403,10 +403,6 @@ public class Boat extends Collider {
|
|||||||
public boolean isSailsOut() {
|
public boolean isSailsOut() {
|
||||||
return sailsOut;
|
return sailsOut;
|
||||||
}
|
}
|
||||||
public void bounce(double repulsionRadius) {
|
|
||||||
Azimuth reverseAzimuth = Azimuth.fromDegrees(getBearing().degrees() - 180d);
|
|
||||||
setPosition(GPSCoordinate.calculateNewPosition(getPosition(), 2 * repulsionRadius, reverseAzimuth));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean rayCast(Boat boat) {
|
public boolean rayCast(Boat boat) {
|
||||||
@@ -416,9 +412,11 @@ public class Boat extends Collider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCollisionEnter(Boat collider, Collision e) {
|
public void onCollisionEnter(Collision e) {
|
||||||
if(e.getBearing().degrees() > 270 || e.getBearing().degrees() < 90) {
|
if(e.getBearing().degrees() > 270 || e.getBearing().degrees() < 90) {
|
||||||
collider.bounce(100);
|
// Notify observers of collision
|
||||||
|
this.setChanged();
|
||||||
|
notifyObservers(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ package shared.model;
|
|||||||
* Created by Erika on 19-Mar-17.
|
* Created by Erika on 19-Mar-17.
|
||||||
*/
|
*/
|
||||||
public class Constants {
|
public class Constants {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Multiply by this factor to convert nautical miles to meters.
|
* Multiply by this factor to convert nautical miles to meters.
|
||||||
* <br>
|
* <br>
|
||||||
@@ -15,8 +14,6 @@ public class Constants {
|
|||||||
*/
|
*/
|
||||||
public static final int NMToMetersConversion = 1852;
|
public static final int NMToMetersConversion = 1852;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Multiply by this factor to convert Knots to millimeters per second.
|
* Multiply by this factor to convert Knots to millimeters per second.
|
||||||
* <br>
|
* <br>
|
||||||
@@ -26,8 +23,6 @@ public class Constants {
|
|||||||
*/
|
*/
|
||||||
public static final double KnotsToMMPerSecond = 514.444;
|
public static final double KnotsToMMPerSecond = 514.444;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The scale factor of the race.
|
* The scale factor of the race.
|
||||||
* Frame periods are multiplied by this to get the amount of time a single frame represents.
|
* Frame periods are multiplied by this to get the amount of time a single frame represents.
|
||||||
@@ -36,23 +31,15 @@ public class Constants {
|
|||||||
public static final int RaceTimeScale = 2;//10;
|
public static final int RaceTimeScale = 2;//10;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The race pre-start time, in milliseconds. 3 minutes (30 seconds for development).
|
* The race pre-start time, in milliseconds. 3 minutes.
|
||||||
*/
|
*/
|
||||||
// public static final long RacePreStartTime = 30 * 1000;
|
public static final long RacePreStartTime = 3 * 60 * 1000;
|
||||||
public static final long RacePreStartTime = 1000;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The race preparatory time, in milliseconds. 1 minute.
|
* The race preparatory time, in milliseconds. 1 minute.
|
||||||
*/
|
*/
|
||||||
// public static final long RacePreparatoryTime = 60 * 1000;
|
|
||||||
public static final long RacePreparatoryTime = 1 * 60 * 1000;
|
public static final long RacePreparatoryTime = 1 * 60 * 1000;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The number of milliseconds in one hour.
|
* The number of milliseconds in one hour.
|
||||||
* <br>
|
* <br>
|
||||||
@@ -70,7 +57,4 @@ public class Constants {
|
|||||||
* Divide by this factor to convert hours to seconds.
|
* Divide by this factor to convert hours to seconds.
|
||||||
*/
|
*/
|
||||||
public static long OneHourSeconds = 1 * 60 * 60;
|
public static long OneHourSeconds = 1 * 60 * 60;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -101,7 +101,8 @@ public class Mark extends Collider{
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCollisionEnter(Boat collider, Collision e) {
|
public void onCollisionEnter(Collision e) {
|
||||||
collider.bounce(repulsionRadius);
|
this.setChanged();
|
||||||
|
notifyObservers(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import shared.dataInput.RegattaDataSource;
|
|||||||
import java.time.ZonedDateTime;
|
import java.time.ZonedDateTime;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Observable;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -20,7 +21,7 @@ import java.util.List;
|
|||||||
* This is a base class inherited by {@link mock.model.MockRace} and {@link visualiser.model.VisualiserRaceState}.
|
* This is a base class inherited by {@link mock.model.MockRace} and {@link visualiser.model.VisualiserRaceState}.
|
||||||
* Has a course, state, wind, boundaries, etc.... Boats are added by inheriting classes (see {@link Boat}, {@link mock.model.MockBoat}, {@link visualiser.model.VisualiserBoat}.
|
* 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 RaceState {
|
public abstract class RaceState extends Observable{
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -27,7 +27,6 @@ public class InputChecker {
|
|||||||
ControlKey controlKey = keyFactory.getKey(codeString);
|
ControlKey controlKey = keyFactory.getKey(codeString);
|
||||||
if (controlKey != null) {
|
if (controlKey != null) {
|
||||||
controlKey.onAction();
|
controlKey.onAction();
|
||||||
// System.out.println(controlKey.toString() + " is Pressed.");
|
|
||||||
}
|
}
|
||||||
currentlyActiveKeys.put(codeString, true);
|
currentlyActiveKeys.put(codeString, true);
|
||||||
}
|
}
|
||||||
@@ -38,7 +37,6 @@ public class InputChecker {
|
|||||||
ControlKey controlKey = keyFactory.getKey(codeString);
|
ControlKey controlKey = keyFactory.getKey(codeString);
|
||||||
if (controlKey != null) {
|
if (controlKey != null) {
|
||||||
controlKey.onRelease();
|
controlKey.onRelease();
|
||||||
// System.out.println(controlKey.toString() + " is Released.");
|
|
||||||
}
|
}
|
||||||
currentlyActiveKeys.remove(event.getCode().toString());
|
currentlyActiveKeys.remove(event.getCode().toString());
|
||||||
});
|
});
|
||||||
@@ -50,15 +48,8 @@ public class InputChecker {
|
|||||||
ControlKey controlKey = keyFactory.getKey(key);
|
ControlKey controlKey = keyFactory.getKey(key);
|
||||||
if (controlKey != null){
|
if (controlKey != null){
|
||||||
controlKey.onHold();
|
controlKey.onHold();
|
||||||
// System.out.println(controlKey.toString() + " is Held.");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// for (String key : InputKeys.stringKeysMap.keySet()){
|
|
||||||
// if (removeActiveKey(key)) {
|
|
||||||
// System.out.println(key);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}.start();
|
}.start();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +0,0 @@
|
|||||||
package shared.model;
|
|
||||||
|
|
||||||
public class BearingTest {
|
|
||||||
//TODO
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user