From 7474de9816817ecf4302439d17fec4f42af4960e Mon Sep 17 00:00:00 2001 From: Connor Taylor-Brown Date: Fri, 11 Aug 2017 14:05:36 +1200 Subject: [PATCH 01/14] Created foundation classes and interfaces for collision architecture. - Added Collider interface - Added Collision class - Added ColliderRegistry class #story[1100] --- .../java/mock/model/collider/Collider.java | 22 ++++++++++ .../mock/model/collider/ColliderRegistry.java | 42 +++++++++++++++++++ .../java/mock/model/collider/Collision.java | 35 ++++++++++++++++ 3 files changed, 99 insertions(+) create mode 100644 racevisionGame/src/main/java/mock/model/collider/Collider.java create mode 100644 racevisionGame/src/main/java/mock/model/collider/ColliderRegistry.java create mode 100644 racevisionGame/src/main/java/mock/model/collider/Collision.java diff --git a/racevisionGame/src/main/java/mock/model/collider/Collider.java b/racevisionGame/src/main/java/mock/model/collider/Collider.java new file mode 100644 index 00000000..ae11d063 --- /dev/null +++ b/racevisionGame/src/main/java/mock/model/collider/Collider.java @@ -0,0 +1,22 @@ +package mock.model.collider; + +import mock.model.MockBoat; + +/** + * Interface for all objects sensitive to collision in a race. + */ +public interface Collider { + /** + * Indicates whether a ray cast from a boat to a target collider triggers a collision. + * @param boat potentially colliding with target + * @param collision details of potential collision + * @return whether or not a collision has occurred + */ + boolean rayCast(MockBoat boat, Collision collision); + + /** + * Handle a collision event + * @param e details of collision + */ + void onCollisionEnter(Collision e); +} diff --git a/racevisionGame/src/main/java/mock/model/collider/ColliderRegistry.java b/racevisionGame/src/main/java/mock/model/collider/ColliderRegistry.java new file mode 100644 index 00000000..e44ef5e1 --- /dev/null +++ b/racevisionGame/src/main/java/mock/model/collider/ColliderRegistry.java @@ -0,0 +1,42 @@ +package mock.model.collider; + +import mock.model.MockBoat; + +import java.util.ArrayList; +import java.util.List; + +/** + * Registry for all Collider objects in a MockRace. Wraps the Collider interface as part of a Composite Pattern. + */ +public class ColliderRegistry implements Collider { + /** + * List of all registered Colliders + */ + private List colliders; + + /** + * Default constructor for ColliderRegistry + */ + public ColliderRegistry() { + this.colliders = new ArrayList<>(); + } + + public void addCollider(Collider collider) { + colliders.add(collider); + } + + public void removeCollider(Collider collider) { + colliders.remove(collider); + } + + @Override + public boolean rayCast(MockBoat boat, Collision collision) { + for(Collider collider: colliders) { + if(collider.rayCast(boat, collision)) return true; + } + return false; + } + + @Override + public void onCollisionEnter(Collision e) {} +} diff --git a/racevisionGame/src/main/java/mock/model/collider/Collision.java b/racevisionGame/src/main/java/mock/model/collider/Collision.java new file mode 100644 index 00000000..5a987bde --- /dev/null +++ b/racevisionGame/src/main/java/mock/model/collider/Collision.java @@ -0,0 +1,35 @@ +package mock.model.collider; + +import shared.model.Bearing; + +/** + * Data structure for holding collision details for ray casting and event handling. + */ +public class Collision { + /** + * Bearing from boat heading to target + */ + private Bearing bearing; + /** + * Distance from boat centre to target centre + */ + private double distance; + + /** + * Constructor for Collision structure + * @param bearing from boat heading to target + * @param distance from boat centre to target centre + */ + public Collision(Bearing bearing, double distance) { + this.bearing = bearing; + this.distance = distance; + } + + public Bearing getBearing() { + return bearing; + } + + public double getDistance() { + return distance; + } +} From 2fbb96afd77afe758c9e2318010354941a5a04bb Mon Sep 17 00:00:00 2001 From: cbt24 Date: Tue, 15 Aug 2017 12:57:26 +1200 Subject: [PATCH 02/14] Created ray casting methods for MockBoat and CompoundMark - Added ColliderRegistry to Race - Added collision triggering to RaceLogic - Created basic collision handlers for MockBoat and CompoundMark --- .../src/main/java/mock/model/MockBoat.java | 19 ++++++++- .../src/main/java/mock/model/MockRace.java | 5 ++- .../src/main/java/mock/model/RaceLogic.java | 4 +- .../java/mock/model/collider/Collider.java | 3 +- .../mock/model/collider/ColliderRegistry.java | 9 +++- .../main/java/shared/model/CompoundMark.java | 42 +++++++++++++++---- .../src/main/java/shared/model/Race.java | 41 +++++------------- 7 files changed, 73 insertions(+), 50 deletions(-) diff --git a/racevisionGame/src/main/java/mock/model/MockBoat.java b/racevisionGame/src/main/java/mock/model/MockBoat.java index 104fa264..24c94531 100644 --- a/racevisionGame/src/main/java/mock/model/MockBoat.java +++ b/racevisionGame/src/main/java/mock/model/MockBoat.java @@ -1,6 +1,8 @@ package mock.model; +import mock.model.collider.Collider; +import mock.model.collider.Collision; import shared.model.*; @@ -8,7 +10,7 @@ import shared.model.*; * Represents a Boat on the mock side of a race. * This adds mock specific functionality to a boat. */ -public class MockBoat extends Boat { +public class MockBoat extends Boat implements Collider { /** @@ -203,4 +205,19 @@ public class MockBoat extends Boat { public void setAutoVMG(boolean autoVMG) { this.autoVMG = autoVMG; } + + @Override + public boolean rayCast(MockBoat boat) { + double distance = GPSCoordinate.calculateDistanceMeters(boat.getCurrentPosition(), this.getCurrentPosition()); + Bearing bearing = Bearing.fromAzimuth(GPSCoordinate.calculateAzimuth(boat.getCurrentPosition(), this.getCurrentPosition())); + if(distance < 100 && boat != this) { + onCollisionEnter(new Collision(bearing, distance)); + return true; + } else return false; + } + + @Override + public void onCollisionEnter(Collision e) { + System.out.println(e.getBearing().degrees()); + } } diff --git a/racevisionGame/src/main/java/mock/model/MockRace.java b/racevisionGame/src/main/java/mock/model/MockRace.java index 0ae5cfcc..9d03ff14 100644 --- a/racevisionGame/src/main/java/mock/model/MockRace.java +++ b/racevisionGame/src/main/java/mock/model/MockRace.java @@ -1,5 +1,6 @@ package mock.model; +import mock.model.collider.ColliderRegistry; import network.Messages.Enums.BoatStatusEnum; import network.Messages.LatestMessages; import org.opengis.geometry.primitive.*; @@ -30,8 +31,6 @@ public class MockRace extends Race { */ private List boats; - - /** * A copy of the boundary list, except "shrunk" inwards by 50m. */ @@ -79,6 +78,8 @@ public class MockRace extends Race { //Wind. this.setWind(windGenerator.generateBaselineWind()); + + this.colliderRegistry.addAllColliders(boats); } /** diff --git a/racevisionGame/src/main/java/mock/model/RaceLogic.java b/racevisionGame/src/main/java/mock/model/RaceLogic.java index adc0fe37..42265646 100644 --- a/racevisionGame/src/main/java/mock/model/RaceLogic.java +++ b/racevisionGame/src/main/java/mock/model/RaceLogic.java @@ -1,7 +1,6 @@ package mock.model; import javafx.animation.AnimationTimer; -import mock.model.commandFactory.Command; import mock.model.commandFactory.CommandFactory; import mock.model.commandFactory.CompositeCommand; import network.Messages.Enums.BoatActionEnum; @@ -12,7 +11,6 @@ import visualiser.gameController.ControllerServer; import java.util.Observable; import java.util.Observer; -import java.util.Stack; public class RaceLogic implements Observer, Runnable { /** @@ -136,7 +134,7 @@ public class RaceLogic implements Observer, Runnable { if (boat.getStatus() == BoatStatusEnum.RACING) { commands.execute(); race.updatePosition(boat, framePeriod, race.getRaceClock().getDurationMilli()); - + race.getColliderRegistry().rayCast(boat); } } diff --git a/racevisionGame/src/main/java/mock/model/collider/Collider.java b/racevisionGame/src/main/java/mock/model/collider/Collider.java index ae11d063..a443d3f9 100644 --- a/racevisionGame/src/main/java/mock/model/collider/Collider.java +++ b/racevisionGame/src/main/java/mock/model/collider/Collider.java @@ -9,10 +9,9 @@ public interface Collider { /** * Indicates whether a ray cast from a boat to a target collider triggers a collision. * @param boat potentially colliding with target - * @param collision details of potential collision * @return whether or not a collision has occurred */ - boolean rayCast(MockBoat boat, Collision collision); + boolean rayCast(MockBoat boat); /** * Handle a collision event diff --git a/racevisionGame/src/main/java/mock/model/collider/ColliderRegistry.java b/racevisionGame/src/main/java/mock/model/collider/ColliderRegistry.java index e44ef5e1..e58a28f1 100644 --- a/racevisionGame/src/main/java/mock/model/collider/ColliderRegistry.java +++ b/racevisionGame/src/main/java/mock/model/collider/ColliderRegistry.java @@ -3,6 +3,7 @@ package mock.model.collider; import mock.model.MockBoat; import java.util.ArrayList; +import java.util.Collection; import java.util.List; /** @@ -29,10 +30,14 @@ public class ColliderRegistry implements Collider { colliders.remove(collider); } + public void addAllColliders(Collection colliders) { + for(Collider collider: colliders) addCollider(collider); + } + @Override - public boolean rayCast(MockBoat boat, Collision collision) { + public boolean rayCast(MockBoat boat) { for(Collider collider: colliders) { - if(collider.rayCast(boat, collision)) return true; + if(collider.rayCast(boat)) return true; } return false; } diff --git a/racevisionGame/src/main/java/shared/model/CompoundMark.java b/racevisionGame/src/main/java/shared/model/CompoundMark.java index b9f45753..f8080c8d 100644 --- a/racevisionGame/src/main/java/shared/model/CompoundMark.java +++ b/racevisionGame/src/main/java/shared/model/CompoundMark.java @@ -1,10 +1,19 @@ package shared.model; +import mock.model.MockBoat; +import mock.model.collider.Collider; +import mock.model.collider.Collision; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + /** * Represents a compound mark - that is, either one or two individual marks which form a single compound mark. */ -public class CompoundMark { +public class CompoundMark implements Collider { /** * The ID of the compound mark. @@ -110,7 +119,7 @@ public class CompoundMark { * @return The position of the second mark in the compound mark. */ public GPSCoordinate getMark2Position() { - return mark2.getPosition(); + return mark2 == null? mark1.getPosition() : mark2.getPosition(); } @@ -128,17 +137,32 @@ public class CompoundMark { * @return The average coordinate of the compound mark. */ private GPSCoordinate calculateAverage() { - - //If the compound mark only contains one mark, the average is simply the first mark's position. - if (this.mark2 == null) { - return this.getMark1Position(); - } - - //Otherwise, calculate the average of both marks. GPSCoordinate averageCoordinate = GPSCoordinate.calculateAverageCoordinate(this.getMark1Position(), this.getMark2Position()); return averageCoordinate; } + + private Mark closestMark(GPSCoordinate coordinate) { + double mark1distance = GPSCoordinate.calculateDistanceMeters(getMark1Position(), coordinate); + double mark2distance = GPSCoordinate.calculateDistanceMeters(getMark2Position(), coordinate); + return mark1distance <= mark2distance? mark1 : mark2; + } + + @Override + public boolean rayCast(MockBoat boat) { + GPSCoordinate position = boat.getCurrentPosition(); + double distance = GPSCoordinate.calculateDistanceMeters(position, closestMark(position).getPosition()); + Bearing bearing = Bearing.fromAzimuth(GPSCoordinate.calculateAzimuth(position, closestMark(position).getPosition())); + if(distance < 100) { + onCollisionEnter(new Collision(bearing, distance)); + return true; + } else return false; + } + + @Override + public void onCollisionEnter(Collision e) { + System.out.println(e.getBearing().degrees()); + } } diff --git a/racevisionGame/src/main/java/shared/model/Race.java b/racevisionGame/src/main/java/shared/model/Race.java index f9fc984e..00b6eaf0 100644 --- a/racevisionGame/src/main/java/shared/model/Race.java +++ b/racevisionGame/src/main/java/shared/model/Race.java @@ -4,6 +4,7 @@ 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 network.Messages.LatestMessages; @@ -20,90 +21,72 @@ import java.util.List; * 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; - /** * The collection of latest race messages. * Can be either read from or written to. */ protected LatestMessages latestMessages; - /** * A list of compound marks in the race. */ protected List compoundMarks; - /** * A list of legs in the race. */ protected List legs; - /** * A list of coordinates describing the boundary of the course. */ protected List 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 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, {@link #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. */ @@ -156,9 +139,13 @@ public abstract class Race { //Wind. this.setWind(Bearing.fromDegrees(0), 0); + this.colliderRegistry = new ColliderRegistry(); + this.colliderRegistry.addAllColliders(compoundMarks); } - + public ColliderRegistry getColliderRegistry() { + return colliderRegistry; + } /** * Initialise the boats in the race. @@ -272,14 +259,6 @@ public abstract class Race { return raceWind.getValue().getWindSpeed(); } - /** - * Returns the race's wind. - * @return The race's wind. - */ - public Property windProperty() { - return raceWind; - } - /** * Returns the RaceClock for this race. * This is used to track the start time, current time, and elapsed duration of the race. From 7d64a433500d08625b1227bfff934a84cf3ff0c1 Mon Sep 17 00:00:00 2001 From: cbt24 Date: Tue, 15 Aug 2017 13:47:59 +1200 Subject: [PATCH 03/14] Allow collision checking to provide collision parameters to ray casting method - Added tests for MockBoat collision direction and distance #story[1100] --- .../src/main/java/mock/model/MockBoat.java | 16 +++++++--- .../java/mock/model/collider/Collider.java | 10 +++++- .../mock/model/collider/ColliderRegistry.java | 5 +++ .../main/java/shared/model/CompoundMark.java | 22 +++++++------ .../test/java/mock/model/MockBoatTest.java | 32 ++++++++++++++++++- 5 files changed, 70 insertions(+), 15 deletions(-) diff --git a/racevisionGame/src/main/java/mock/model/MockBoat.java b/racevisionGame/src/main/java/mock/model/MockBoat.java index 24c94531..2a179f7e 100644 --- a/racevisionGame/src/main/java/mock/model/MockBoat.java +++ b/racevisionGame/src/main/java/mock/model/MockBoat.java @@ -207,15 +207,23 @@ public class MockBoat extends Boat implements Collider { } @Override - public boolean rayCast(MockBoat boat) { + public boolean rayCast(MockBoat boat, Collision collision) { double distance = GPSCoordinate.calculateDistanceMeters(boat.getCurrentPosition(), this.getCurrentPosition()); - Bearing bearing = Bearing.fromAzimuth(GPSCoordinate.calculateAzimuth(boat.getCurrentPosition(), this.getCurrentPosition())); - if(distance < 100 && boat != this) { - onCollisionEnter(new Collision(bearing, distance)); + Bearing bearing = GPSCoordinate.calculateBearing(boat.getCurrentPosition(), this.getCurrentPosition()); + + if(distance <= collision.getDistance() && (int)bearing.degrees() == (int)collision.getBearing().degrees()) { + onCollisionEnter(collision); return true; } else return false; } + @Override + public boolean rayCast(MockBoat boat) { + if(boat != this) { + return rayCast(boat, new Collision(Bearing.fromDegrees(0), 100)); + } else return false; + } + @Override public void onCollisionEnter(Collision e) { System.out.println(e.getBearing().degrees()); diff --git a/racevisionGame/src/main/java/mock/model/collider/Collider.java b/racevisionGame/src/main/java/mock/model/collider/Collider.java index a443d3f9..479cfc2f 100644 --- a/racevisionGame/src/main/java/mock/model/collider/Collider.java +++ b/racevisionGame/src/main/java/mock/model/collider/Collider.java @@ -7,7 +7,15 @@ import mock.model.MockBoat; */ public interface Collider { /** - * Indicates whether a ray cast from a boat to a target collider triggers a collision. + * Indicates whether a ray cast from a boat to a target collider triggers a collision with the specified parameters. + * @param boat potentially colliding with target + * @param collision parameters of valid collision + * @return whether or not a collision has occurred + */ + boolean rayCast(MockBoat boat, Collision collision); + + /** + * Indicates whether a ray cast from a boat to a target collider triggers a collision. Parameters are set by the object. * @param boat potentially colliding with target * @return whether or not a collision has occurred */ diff --git a/racevisionGame/src/main/java/mock/model/collider/ColliderRegistry.java b/racevisionGame/src/main/java/mock/model/collider/ColliderRegistry.java index e58a28f1..59eb742b 100644 --- a/racevisionGame/src/main/java/mock/model/collider/ColliderRegistry.java +++ b/racevisionGame/src/main/java/mock/model/collider/ColliderRegistry.java @@ -34,6 +34,11 @@ public class ColliderRegistry implements Collider { for(Collider collider: colliders) addCollider(collider); } + @Override + public boolean rayCast(MockBoat boat, Collision collision) { + return false; + } + @Override public boolean rayCast(MockBoat boat) { for(Collider collider: colliders) { diff --git a/racevisionGame/src/main/java/shared/model/CompoundMark.java b/racevisionGame/src/main/java/shared/model/CompoundMark.java index f8080c8d..1787562d 100644 --- a/racevisionGame/src/main/java/shared/model/CompoundMark.java +++ b/racevisionGame/src/main/java/shared/model/CompoundMark.java @@ -5,11 +5,6 @@ import mock.model.MockBoat; import mock.model.collider.Collider; import mock.model.collider.Collision; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.List; - /** * Represents a compound mark - that is, either one or two individual marks which form a single compound mark. */ @@ -151,16 +146,25 @@ public class CompoundMark implements Collider { } @Override - public boolean rayCast(MockBoat boat) { + public boolean rayCast(MockBoat boat, Collision collision) { GPSCoordinate position = boat.getCurrentPosition(); double distance = GPSCoordinate.calculateDistanceMeters(position, closestMark(position).getPosition()); - Bearing bearing = Bearing.fromAzimuth(GPSCoordinate.calculateAzimuth(position, closestMark(position).getPosition())); - if(distance < 100) { - onCollisionEnter(new Collision(bearing, distance)); + // Compass direction of collider + Bearing absolute = Bearing.fromAzimuth(GPSCoordinate.calculateAzimuth(position, closestMark(position).getPosition())); + // Direction of collider from heading + Bearing relative = Bearing.fromDegrees(absolute.degrees() - boat.getBearing().degrees()); + + if(distance <= collision.getDistance() && (int)relative.degrees() == (int)collision.getBearing().degrees()) { + onCollisionEnter(collision); return true; } else return false; } + @Override + public boolean rayCast(MockBoat boat) { + return rayCast(boat, new Collision(Bearing.fromDegrees(0), 100)); + } + @Override public void onCollisionEnter(Collision e) { System.out.println(e.getBearing().degrees()); diff --git a/racevisionGame/src/test/java/mock/model/MockBoatTest.java b/racevisionGame/src/test/java/mock/model/MockBoatTest.java index b1ee551c..61762192 100644 --- a/racevisionGame/src/test/java/mock/model/MockBoatTest.java +++ b/racevisionGame/src/test/java/mock/model/MockBoatTest.java @@ -1,7 +1,37 @@ package mock.model; +import mock.model.collider.Collision; +import org.junit.Before; +import org.junit.Test; +import shared.model.Bearing; +import shared.model.CompoundMark; +import shared.model.GPSCoordinate; +import shared.model.Mark; + import static org.junit.Assert.*; public class MockBoatTest { -//TODO + private MockBoat boat; + private CompoundMark ahead; + private CompoundMark behind; + + @Before + public void setUp() { + boat = new MockBoat(0, "Bob", "NZ", null); + boat.setCurrentPosition(new GPSCoordinate(0,0)); + boat.setBearing(Bearing.fromDegrees(180)); + + ahead = new CompoundMark(0, "Ahead", new Mark(0, "Ahead", new GPSCoordinate(-.0001, 0))); + behind = new CompoundMark(1, "Behind", new Mark(0, "Behind", new GPSCoordinate(.0001, 0))); + } + + @Test + public void markAheadOfBoat0() { + assertTrue(ahead.rayCast(boat, new Collision(Bearing.fromDegrees(0), 100))); + } + + @Test + public void markBehindBoat180() { + assertTrue(behind.rayCast(boat, new Collision(Bearing.fromDegrees(180), 100))); + } } From 9ca50aa66c9f8570f2ca5b209f6051627a9f5bc0 Mon Sep 17 00:00:00 2001 From: cbt24 Date: Tue, 15 Aug 2017 14:26:43 +1200 Subject: [PATCH 04/14] Ray casting now only supports distance specification. #story[1100] --- .../src/main/java/mock/model/MockBoat.java | 13 +++++++------ .../main/java/mock/model/collider/Collider.java | 8 ++++---- .../mock/model/collider/ColliderRegistry.java | 2 +- .../src/main/java/shared/model/CompoundMark.java | 13 +++++++------ .../src/test/java/mock/model/MockBoatTest.java | 16 ++++++++-------- 5 files changed, 27 insertions(+), 25 deletions(-) diff --git a/racevisionGame/src/main/java/mock/model/MockBoat.java b/racevisionGame/src/main/java/mock/model/MockBoat.java index 2a179f7e..6ab43cf3 100644 --- a/racevisionGame/src/main/java/mock/model/MockBoat.java +++ b/racevisionGame/src/main/java/mock/model/MockBoat.java @@ -207,12 +207,13 @@ public class MockBoat extends Boat implements Collider { } @Override - public boolean rayCast(MockBoat boat, Collision collision) { - double distance = GPSCoordinate.calculateDistanceMeters(boat.getCurrentPosition(), this.getCurrentPosition()); - Bearing bearing = GPSCoordinate.calculateBearing(boat.getCurrentPosition(), this.getCurrentPosition()); + public boolean rayCast(MockBoat boat, double distance) { + double actualDistance = GPSCoordinate.calculateDistanceMeters(boat.getCurrentPosition(), this.getCurrentPosition()); + Bearing absolute = GPSCoordinate.calculateBearing(boat.getCurrentPosition(), this.getCurrentPosition()); + Bearing relative = Bearing.fromDegrees(absolute.degrees() - boat.getBearing().degrees()); - if(distance <= collision.getDistance() && (int)bearing.degrees() == (int)collision.getBearing().degrees()) { - onCollisionEnter(collision); + if(actualDistance <= distance) { + onCollisionEnter(new Collision(relative, actualDistance)); return true; } else return false; } @@ -220,7 +221,7 @@ public class MockBoat extends Boat implements Collider { @Override public boolean rayCast(MockBoat boat) { if(boat != this) { - return rayCast(boat, new Collision(Bearing.fromDegrees(0), 100)); + return rayCast(boat, 100); } else return false; } diff --git a/racevisionGame/src/main/java/mock/model/collider/Collider.java b/racevisionGame/src/main/java/mock/model/collider/Collider.java index 479cfc2f..c7a2fa51 100644 --- a/racevisionGame/src/main/java/mock/model/collider/Collider.java +++ b/racevisionGame/src/main/java/mock/model/collider/Collider.java @@ -7,15 +7,15 @@ import mock.model.MockBoat; */ public interface Collider { /** - * Indicates whether a ray cast from a boat to a target collider triggers a collision with the specified parameters. + * Indicates whether a ray cast from a boat to a target collider is within the specified length. * @param boat potentially colliding with target - * @param collision parameters of valid collision + * @param distance distance for valid collision * @return whether or not a collision has occurred */ - boolean rayCast(MockBoat boat, Collision collision); + boolean rayCast(MockBoat boat, double distance); /** - * Indicates whether a ray cast from a boat to a target collider triggers a collision. Parameters are set by the object. + * Indicates whether a ray cast from a boat to a target collider triggers a collision. Distance is set by the object. * @param boat potentially colliding with target * @return whether or not a collision has occurred */ diff --git a/racevisionGame/src/main/java/mock/model/collider/ColliderRegistry.java b/racevisionGame/src/main/java/mock/model/collider/ColliderRegistry.java index 59eb742b..7127b75c 100644 --- a/racevisionGame/src/main/java/mock/model/collider/ColliderRegistry.java +++ b/racevisionGame/src/main/java/mock/model/collider/ColliderRegistry.java @@ -35,7 +35,7 @@ public class ColliderRegistry implements Collider { } @Override - public boolean rayCast(MockBoat boat, Collision collision) { + public boolean rayCast(MockBoat boat, double distance) { return false; } diff --git a/racevisionGame/src/main/java/shared/model/CompoundMark.java b/racevisionGame/src/main/java/shared/model/CompoundMark.java index 1787562d..29bbd10f 100644 --- a/racevisionGame/src/main/java/shared/model/CompoundMark.java +++ b/racevisionGame/src/main/java/shared/model/CompoundMark.java @@ -146,27 +146,28 @@ public class CompoundMark implements Collider { } @Override - public boolean rayCast(MockBoat boat, Collision collision) { + public boolean rayCast(MockBoat boat, double distance) { GPSCoordinate position = boat.getCurrentPosition(); - double distance = GPSCoordinate.calculateDistanceMeters(position, closestMark(position).getPosition()); + double actualDistance = GPSCoordinate.calculateDistanceMeters(position, closestMark(position).getPosition()); // Compass direction of collider Bearing absolute = Bearing.fromAzimuth(GPSCoordinate.calculateAzimuth(position, closestMark(position).getPosition())); // Direction of collider from heading Bearing relative = Bearing.fromDegrees(absolute.degrees() - boat.getBearing().degrees()); - if(distance <= collision.getDistance() && (int)relative.degrees() == (int)collision.getBearing().degrees()) { - onCollisionEnter(collision); + if(actualDistance <= distance) { + onCollisionEnter(new Collision(relative, distance)); return true; } else return false; } @Override public boolean rayCast(MockBoat boat) { - return rayCast(boat, new Collision(Bearing.fromDegrees(0), 100)); + return rayCast(boat, 100); } @Override public void onCollisionEnter(Collision e) { - System.out.println(e.getBearing().degrees()); + if(e.getBearing().degrees() < 90) System.out.println("Starboard"); + else if(e.getBearing().degrees() > 270) System.out.println("Port"); } } diff --git a/racevisionGame/src/test/java/mock/model/MockBoatTest.java b/racevisionGame/src/test/java/mock/model/MockBoatTest.java index 61762192..10792a12 100644 --- a/racevisionGame/src/test/java/mock/model/MockBoatTest.java +++ b/racevisionGame/src/test/java/mock/model/MockBoatTest.java @@ -12,8 +12,8 @@ import static org.junit.Assert.*; public class MockBoatTest { private MockBoat boat; - private CompoundMark ahead; - private CompoundMark behind; + private CompoundMark near; + private CompoundMark far; @Before public void setUp() { @@ -21,17 +21,17 @@ public class MockBoatTest { boat.setCurrentPosition(new GPSCoordinate(0,0)); boat.setBearing(Bearing.fromDegrees(180)); - ahead = new CompoundMark(0, "Ahead", new Mark(0, "Ahead", new GPSCoordinate(-.0001, 0))); - behind = new CompoundMark(1, "Behind", new Mark(0, "Behind", new GPSCoordinate(.0001, 0))); + near = new CompoundMark(0, "Near", new Mark(0, "Near", new GPSCoordinate(-.0001, 0))); + far = new CompoundMark(1, "Far", new Mark(0, "Far", new GPSCoordinate(.001, 0))); } @Test - public void markAheadOfBoat0() { - assertTrue(ahead.rayCast(boat, new Collision(Bearing.fromDegrees(0), 100))); + public void nearMarkWithin100m() { + assertTrue(near.rayCast(boat, 100)); } @Test - public void markBehindBoat180() { - assertTrue(behind.rayCast(boat, new Collision(Bearing.fromDegrees(180), 100))); + public void farMarkBeyond100m() { + assertFalse(far.rayCast(boat, 100)); } } From d63641c1e28216f89d0b5aaa32e1b21186418146 Mon Sep 17 00:00:00 2001 From: cbt24 Date: Wed, 16 Aug 2017 14:54:55 +1200 Subject: [PATCH 05/14] Cherry-picked multiple changes from master --- .../src/main/java/mock/model/MockBoat.java | 110 +++++++++++++++++- .../src/main/java/mock/model/MockRace.java | 30 ++--- .../src/main/java/shared/model/Race.java | 55 +++------ 3 files changed, 130 insertions(+), 65 deletions(-) diff --git a/racevisionGame/src/main/java/mock/model/MockBoat.java b/racevisionGame/src/main/java/mock/model/MockBoat.java index 6ab43cf3..86570c75 100644 --- a/racevisionGame/src/main/java/mock/model/MockBoat.java +++ b/racevisionGame/src/main/java/mock/model/MockBoat.java @@ -24,10 +24,18 @@ public class MockBoat extends Boat implements Collider { */ private long timeSinceTackChange = 0; + /** + * This stores the boats current status of rounding a mark + * 0: not started rounding + * 1: passed only first check + * 2: passed first and second check + */ + private Integer roundingStatus = 0; + /** * Stores whether the boat is on autoVMG or not */ - private boolean autoVMG = true; + private boolean autoVMG = false; @@ -69,7 +77,15 @@ public class MockBoat extends Boat implements Collider { //Get the start and end points. GPSCoordinate currentPosition = this.getCurrentPosition(); - GPSCoordinate nextMarkerPosition = this.getCurrentLeg().getEndCompoundMark().getAverageGPSCoordinate(); + GPSCoordinate nextMarkerPosition; + + // if boat is at the finish + if (this.getCurrentLeg().getEndCompoundMark() == null) { + nextMarkerPosition = currentPosition; + } + else { + nextMarkerPosition = this.getCurrentLeg().getEndCompoundMark().getAverageGPSCoordinate(); + } //Calculate bearing. Bearing bearing = GPSCoordinate.calculateBearing(currentPosition, nextMarkerPosition); @@ -96,9 +112,7 @@ public class MockBoat extends Boat implements Collider { //Calculate distance. - double distanceNauticalMiles = GPSCoordinate.calculateDistanceNauticalMiles(startPosition, endMarker); - - return distanceNauticalMiles; + return GPSCoordinate.calculateDistanceNauticalMiles(startPosition, endMarker); } @@ -198,7 +212,91 @@ public class MockBoat extends Boat implements Collider { return distanceTravelledMeters; } - public boolean isAutoVMG() { + /** + * Check if a mark is on the port side of the boat + * @param mark mark to be passed + * @return true if mark is on port side + */ + public boolean isPortSide(Mark mark){ + Bearing towardsMark = GPSCoordinate.calculateBearing(this.getCurrentPosition(), mark.getPosition()); + if (towardsMark.degrees() > 315 || towardsMark.degrees() <= 45){ + //south quadrant + return this.getBearing().degrees() <= 180; + } else if(towardsMark.degrees() > 45 && towardsMark.degrees() <= 135){ + //west quadrant + return (this.getBearing().degrees() <= 270 && this.getBearing().degrees() >= 90); + }else if(towardsMark.degrees() > 135 && towardsMark.degrees() <= 225){ + //north quadrant + return this.getBearing().degrees() >= 180; + }else if(towardsMark.degrees() > 225 && towardsMark.degrees() <= 315){ + //east quadrant + return (this.getBearing().degrees() <= 90 || this.getBearing().degrees() >= 270); + }else{ + //should not reach here + return false; + } + } + + /** + * Check if a mark is on the starboard side of the boat + * @param mark mark to be passed + * @return true if mark is on starboard side + */ + public boolean isStarboardSide(Mark mark){ + //if this boat is lower than the mark check which way it is facing + Bearing towardsMark = GPSCoordinate.calculateBearing(this.getCurrentPosition(), mark.getPosition()); + if (towardsMark.degrees() > 315 || towardsMark.degrees() <= 45){ + //south quadrant + return !(this.getBearing().degrees() <= 180); + } else if(towardsMark.degrees() > 45 && towardsMark.degrees() <= 135){ + //west quadrant + return !(this.getBearing().degrees() <= 270 && this.getBearing().degrees() >= 90); + }else if(towardsMark.degrees() > 135 && towardsMark.degrees() <= 225){ + //north quadrant + return !(this.getBearing().degrees() >= 180); + }else if(towardsMark.degrees() > 225 && towardsMark.degrees() <= 315){ + //east quadrant + return !(this.getBearing().degrees() <= 90 || this.getBearing().degrees() >= 270); + }else{ + //should not reach here + return false; + } + } + + /** + * Used to check if this boat is between a gate + * @param gate the gate to be checked + * @return true if the boat is between two marks that make up a gate + */ + public boolean isBetweenGate(CompoundMark gate){ + return (this.isPortSide(gate.getMark1()) && this.isStarboardSide(gate.getMark2())) || + (this.isStarboardSide(gate.getMark1()) && this.isPortSide(gate.getMark2())); + } + + /** + * Used to check if this boat is between a two marks + * @param mark1 the first mark + * @param mark2 the second mark + * @return true if the boat is between two marks + */ + public boolean isBetweenGate(Mark mark1, Mark mark2){ + return (this.isPortSide(mark1) && this.isStarboardSide(mark2)) || + (this.isStarboardSide(mark1) && this.isPortSide(mark2)); + } + + public Integer getRoundingStatus() { + return Integer.valueOf(roundingStatus); + } + + public void increaseRoundingStatus() { + this.roundingStatus++; + } + + public void resetRoundingStatus() { + this.roundingStatus = 0; + } + + public boolean getAutoVMG(){ return autoVMG; } diff --git a/racevisionGame/src/main/java/mock/model/MockRace.java b/racevisionGame/src/main/java/mock/model/MockRace.java index 9d03ff14..63ebf278 100644 --- a/racevisionGame/src/main/java/mock/model/MockRace.java +++ b/racevisionGame/src/main/java/mock/model/MockRace.java @@ -1,19 +1,15 @@ package mock.model; -import mock.model.collider.ColliderRegistry; import network.Messages.Enums.BoatStatusEnum; +import network.Messages.Enums.RaceStatusEnum; import network.Messages.LatestMessages; -import org.opengis.geometry.primitive.*; import shared.dataInput.BoatDataSource; import shared.dataInput.RaceDataSource; -import network.Messages.Enums.RaceStatusEnum; import shared.dataInput.RegattaDataSource; import shared.model.*; -import shared.model.Bearing; import java.time.ZonedDateTime; import java.time.temporal.ChronoUnit; -import java.time.temporal.TemporalUnit; import java.util.*; import static java.lang.Math.cos; @@ -53,13 +49,13 @@ public class MockRace extends Race { * @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...). - * @param latestMessages The LatestMessages to send events to. * @param polars The polars table to be used for boat simulation. * @param timeScale The timeScale for the race. See {@link Constants#RaceTimeScale}. + * @param windGenerator The wind generator used for the race. */ - public MockRace(BoatDataSource boatDataSource, RaceDataSource raceDataSource, RegattaDataSource regattaDataSource, LatestMessages latestMessages, Polars polars, int timeScale) { + public MockRace(BoatDataSource boatDataSource, RaceDataSource raceDataSource, RegattaDataSource regattaDataSource, Polars polars, int timeScale, WindGenerator windGenerator) { - super(boatDataSource, raceDataSource, regattaDataSource, latestMessages); + super(boatDataSource, raceDataSource, regattaDataSource); this.scaleFactor = timeScale; @@ -67,14 +63,8 @@ public class MockRace extends Race { this.shrinkBoundary = GPSCoordinate.getShrinkBoundary(this.boundary); - //Set up wind generator. It may be tidier to create this outside the race (with the values sourced from a data file maybe?) and pass it in. - this.windGenerator = new WindGenerator( - Bearing.fromDegrees(225), - Bearing.fromDegrees(215), - Bearing.fromDegrees(235), - 12d, - 8d, - 16d ); + + this.windGenerator = windGenerator; //Wind. this.setWind(windGenerator.generateBaselineWind()); @@ -341,7 +331,7 @@ public class MockRace extends Race { boat.moveForwards(distanceTravelledMeters); boat.setTimeSinceTackChange(boat.getTimeSinceTackChange() + updatePeriodMilliseconds); - if (boat.isAutoVMG()) { + if (boat.getAutoVMG()) { newOptimalVMG(boat); } @@ -351,7 +341,7 @@ public class MockRace extends Race { } private void newOptimalVMG(MockBoat boat) { - long tackPeriod = 15000; + long tackPeriod = 1000; if (boat.getTimeSinceTackChange() > tackPeriod) { //Calculate the new VMG. @@ -375,8 +365,8 @@ public class MockRace extends Race { this.getWindDirection(), this.getWindSpeed(), boat.getBearing(), - boat.getBearing(), - boat.getBearing()); + Bearing.fromDegrees(boat.getBearing().degrees() - 1), + Bearing.fromDegrees(boat.getBearing().degrees() + 1)); if (vmg.getSpeed() > 0) { boat.setCurrentSpeed(vmg.getSpeed()); } diff --git a/racevisionGame/src/main/java/shared/model/Race.java b/racevisionGame/src/main/java/shared/model/Race.java index 00b6eaf0..6df5ebbc 100644 --- a/racevisionGame/src/main/java/shared/model/Race.java +++ b/racevisionGame/src/main/java/shared/model/Race.java @@ -7,7 +7,6 @@ import javafx.beans.property.SimpleObjectProperty; import mock.model.collider.ColliderRegistry; import network.Messages.Enums.RaceStatusEnum; import network.Messages.Enums.RaceTypeEnum; -import network.Messages.LatestMessages; import shared.dataInput.BoatDataSource; import shared.dataInput.RaceDataSource; import shared.dataInput.RegattaDataSource; @@ -33,11 +32,6 @@ public abstract class Race { * The source of regatta related data. */ protected RegattaDataSource regattaDataSource; - /** - * The collection of latest race messages. - * Can be either read from or written to. - */ - protected LatestMessages latestMessages; /** * A list of compound marks in the race. */ @@ -80,7 +74,7 @@ public abstract class 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, {@link #currentFps} is reset. + * 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; /** @@ -92,53 +86,38 @@ public abstract class Race { */ 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...). - * @param latestMessages The collection of latest messages, which can be written to, or read from. */ - public Race(BoatDataSource boatDataSource, RaceDataSource raceDataSource, RegattaDataSource regattaDataSource, LatestMessages latestMessages) { + public Race(BoatDataSource boatDataSource, RaceDataSource raceDataSource, RegattaDataSource regattaDataSource) { //Keep a reference to data sources. this.raceDataSource = raceDataSource; this.boatDataSource = boatDataSource; this.regattaDataSource = regattaDataSource; - this.latestMessages = latestMessages; - - //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(); this.colliderRegistry.addAllColliders(compoundMarks); } @@ -153,7 +132,6 @@ public abstract class Race { */ 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. @@ -185,10 +163,6 @@ public abstract class Race { return legID == lastLegID; } - - - - /** * Returns the current race status. * @return The current race status. @@ -205,7 +179,6 @@ public abstract class Race { this.raceStatusEnum = raceStatusEnum; } - /** * Returns the type of race this is. * @return The type of race this is. @@ -222,7 +195,6 @@ public abstract class Race { return regattaName; } - /** * Updates the race to have a specified wind bearing and speed. * @param windBearing New wind bearing. @@ -241,7 +213,6 @@ public abstract class Race { this.raceWind.setValue(wind); } - /** * Returns the wind bearing. * @return The wind bearing. @@ -268,7 +239,6 @@ public abstract class Race { return raceClock; } - /** * Returns the RaceDataSource used for the race. * @return The RaceDataSource used for the race. @@ -286,7 +256,6 @@ public abstract class Race { return legs.size() - 1; } - /** * Returns the race boundary. * @return The race boundary. @@ -295,12 +264,21 @@ public abstract class Race { return boundary; } + + /** + * Returns the marks of the race. + * @return Marks of the race. + */ + public List getCompoundMarks() { + return compoundMarks; + } + /** - * Returns the number of frames generated per second. - * @return Frames per second. + * Returns the legs of the race. + * @return Legs of the race. */ - public int getFps() { - return lastFps.getValue(); + public List getLegs() { + return legs; } /** @@ -311,7 +289,6 @@ public abstract class Race { 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}. From ce14e934043d946501e5f852cc5a08d9181f6be4 Mon Sep 17 00:00:00 2001 From: cbt24 Date: Wed, 16 Aug 2017 15:17:15 +1200 Subject: [PATCH 06/14] Removed CI-breaking docstring --- racevisionGame/src/main/java/mock/model/RaceLogic.java | 2 +- racevisionGame/src/main/java/shared/model/Race.java | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/racevisionGame/src/main/java/mock/model/RaceLogic.java b/racevisionGame/src/main/java/mock/model/RaceLogic.java index 418ade17..7c2e6dd3 100644 --- a/racevisionGame/src/main/java/mock/model/RaceLogic.java +++ b/racevisionGame/src/main/java/mock/model/RaceLogic.java @@ -116,7 +116,7 @@ public class RaceLogic implements RunnableWithFramePeriod { //If it is still racing, update its position. if (boat.getStatus() == BoatStatusEnum.RACING) { race.updatePosition(boat, framePeriod, race.getRaceClock().getDurationMilli()); - + race.getColliderRegistry().rayCast(boat); } } diff --git a/racevisionGame/src/main/java/shared/model/Race.java b/racevisionGame/src/main/java/shared/model/Race.java index 6df5ebbc..685af9e0 100644 --- a/racevisionGame/src/main/java/shared/model/Race.java +++ b/racevisionGame/src/main/java/shared/model/Race.java @@ -16,7 +16,6 @@ import java.util.List; /** * Represents a yacht race. - * This is a base class inherited by {@link mock.model.MockRace} and {@link visualiser.model.VisualiserRace}. * 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 { From f44929f376032a6eec902a0275308a2948dce697 Mon Sep 17 00:00:00 2001 From: cbt24 Date: Wed, 16 Aug 2017 16:05:25 +1200 Subject: [PATCH 07/14] Spun off Locatable interface to make collision code more reusable #story[1100] --- .../src/main/java/mock/model/MockBoat.java | 16 +- .../src/main/java/mock/model/MockRace.java | 13 +- .../src/main/java/mock/model/RaceServer.java | 6 +- .../src/main/java/mock/model/SplitTODO.java | 555 ------------------ .../src/main/java/shared/model/Boat.java | 35 +- .../main/java/shared/model/CompoundMark.java | 39 +- .../src/main/java/shared/model/Locatable.java | 9 + .../src/main/java/shared/model/Mark.java | 33 +- .../src/main/java/shared/model/Race.java | 6 +- .../BoatLocationCommand.java | 5 +- .../Controllers/FinishController.java | 2 +- .../Controllers/RaceController.java | 3 +- .../visualiser/model/ResizableRaceCanvas.java | 8 +- .../java/visualiser/model/VisualiserBoat.java | 4 +- .../visualiser/model/VisualiserRaceState.java | 7 +- .../test/java/mock/model/MockBoatTest.java | 11 +- .../src/test/java/shared/model/BoatTest.java | 10 +- 17 files changed, 98 insertions(+), 664 deletions(-) delete mode 100644 racevisionGame/src/main/java/mock/model/SplitTODO.java create mode 100644 racevisionGame/src/main/java/shared/model/Locatable.java diff --git a/racevisionGame/src/main/java/mock/model/MockBoat.java b/racevisionGame/src/main/java/mock/model/MockBoat.java index 86570c75..227dfe54 100644 --- a/racevisionGame/src/main/java/mock/model/MockBoat.java +++ b/racevisionGame/src/main/java/mock/model/MockBoat.java @@ -76,7 +76,7 @@ public class MockBoat extends Boat implements Collider { public Bearing calculateBearingToNextMarker() { //Get the start and end points. - GPSCoordinate currentPosition = this.getCurrentPosition(); + GPSCoordinate currentPosition = this.getPosition(); GPSCoordinate nextMarkerPosition; // if boat is at the finish @@ -101,7 +101,7 @@ public class MockBoat extends Boat implements Collider { public double calculateDistanceToNextMarker() { //Get start and end markers. - GPSCoordinate startPosition = this.getCurrentPosition(); + GPSCoordinate startPosition = this.getPosition(); //When boats finish, their "current leg" doesn't have an end marker. if (this.getCurrentLeg().getEndCompoundMark() == null) { @@ -159,8 +159,8 @@ public class MockBoat extends Boat implements Collider { */ public void moveForwards(double meters) { //Updates the current position of the boat. - GPSCoordinate newPosition = GPSCoordinate.calculateNewPosition(this.getCurrentPosition(), meters, Azimuth.fromBearing(this.getBearing())); - this.setCurrentPosition(newPosition); + GPSCoordinate newPosition = GPSCoordinate.calculateNewPosition(this.getPosition(), meters, Azimuth.fromBearing(this.getBearing())); + this.setPosition(newPosition); } @@ -218,7 +218,7 @@ public class MockBoat extends Boat implements Collider { * @return true if mark is on port side */ public boolean isPortSide(Mark mark){ - Bearing towardsMark = GPSCoordinate.calculateBearing(this.getCurrentPosition(), mark.getPosition()); + Bearing towardsMark = GPSCoordinate.calculateBearing(this.getPosition(), mark.getPosition()); if (towardsMark.degrees() > 315 || towardsMark.degrees() <= 45){ //south quadrant return this.getBearing().degrees() <= 180; @@ -244,7 +244,7 @@ public class MockBoat extends Boat implements Collider { */ public boolean isStarboardSide(Mark mark){ //if this boat is lower than the mark check which way it is facing - Bearing towardsMark = GPSCoordinate.calculateBearing(this.getCurrentPosition(), mark.getPosition()); + Bearing towardsMark = GPSCoordinate.calculateBearing(this.getPosition(), mark.getPosition()); if (towardsMark.degrees() > 315 || towardsMark.degrees() <= 45){ //south quadrant return !(this.getBearing().degrees() <= 180); @@ -306,8 +306,8 @@ public class MockBoat extends Boat implements Collider { @Override public boolean rayCast(MockBoat boat, double distance) { - double actualDistance = GPSCoordinate.calculateDistanceMeters(boat.getCurrentPosition(), this.getCurrentPosition()); - Bearing absolute = GPSCoordinate.calculateBearing(boat.getCurrentPosition(), this.getCurrentPosition()); + double actualDistance = GPSCoordinate.calculateDistanceMeters(boat.getPosition(), this.getPosition()); + Bearing absolute = GPSCoordinate.calculateBearing(boat.getPosition(), this.getPosition()); Bearing relative = Bearing.fromDegrees(absolute.degrees() - boat.getBearing().degrees()); if(actualDistance <= distance) { diff --git a/racevisionGame/src/main/java/mock/model/MockRace.java b/racevisionGame/src/main/java/mock/model/MockRace.java index 7df41b1f..e25c0909 100644 --- a/racevisionGame/src/main/java/mock/model/MockRace.java +++ b/racevisionGame/src/main/java/mock/model/MockRace.java @@ -2,7 +2,6 @@ package mock.model; import network.Messages.Enums.BoatStatusEnum; import network.Messages.Enums.RaceStatusEnum; -import network.Messages.LatestMessages; import shared.dataInput.BoatDataSource; import shared.dataInput.RaceDataSource; import shared.dataInput.RegattaDataSource; @@ -195,7 +194,7 @@ public class MockRace extends Race { boat.setCurrentSpeed(0d); //Place the boat at its starting position. - boat.setCurrentPosition(startPosition); + boat.setPosition(startPosition); //Boats start facing their next marker. boat.setBearing(boat.calculateBearingToNextMarker()); @@ -400,7 +399,7 @@ public class MockRace extends Race { Bearing bearing = Bearing.fromDegrees(angle); //Check that if it is acceptable. - boolean bearingIsGood = this.checkBearingInsideCourse(bearing, boat.getCurrentPosition()); + boolean bearingIsGood = this.checkBearingInsideCourse(bearing, boat.getPosition()); if (lastAngle != -1) { @@ -475,7 +474,7 @@ public class MockRace extends Race { case 0://hasn't started rounding if (boat.isPortSide(roundingMark) && GPSCoordinate.passesLine(roundingMark.getPosition(), - roundingChecks.get(0), boat.getCurrentPosition(), legBearing) && + roundingChecks.get(0), boat.getPosition(), legBearing) && gateCheck && boat.isBetweenGate(roundingMark, Mark.tempMark(roundingChecks.get(0)))) { boat.increaseRoundingStatus(); if (boat.getCurrentLeg().getLegNumber() + 2 >= legs.size()){ @@ -487,7 +486,7 @@ public class MockRace extends Race { case 1://has been parallel to the mark; if (boat.isPortSide(roundingMark) && GPSCoordinate.passesLine(roundingMark.getPosition(), - roundingChecks.get(1), boat.getCurrentPosition(), + roundingChecks.get(1), boat.getPosition(), Bearing.fromDegrees(legBearing.degrees() - 90)) &&//negative 90 from bearing because of port rounding boat.isBetweenGate(roundingMark, Mark.tempMark(roundingChecks.get(1)))) { boat.increaseRoundingStatus(); @@ -519,7 +518,7 @@ public class MockRace extends Race { case 0://hasn't started rounding if (boat.isStarboardSide(roundingMark) && GPSCoordinate.passesLine(roundingMark.getPosition(), - roundingChecks.get(0), boat.getCurrentPosition(), legBearing) && + roundingChecks.get(0), boat.getPosition(), legBearing) && gateCheck && boat.isBetweenGate(roundingMark, Mark.tempMark(roundingChecks.get(0)))) { boat.increaseRoundingStatus(); @@ -532,7 +531,7 @@ public class MockRace extends Race { case 1://has been parallel to the mark if (boat.isStarboardSide(roundingMark) && GPSCoordinate.passesLine(roundingMark.getPosition(), - roundingChecks.get(1), boat.getCurrentPosition(), Bearing.fromDegrees(legBearing.degrees() + 90)) && //positive 90 from bearing because of starboard rounding + roundingChecks.get(1), boat.getPosition(), Bearing.fromDegrees(legBearing.degrees() + 90)) && //positive 90 from bearing because of starboard rounding boat.isBetweenGate(roundingMark, Mark.tempMark(roundingChecks.get(1)))) { boat.increaseRoundingStatus(); } diff --git a/racevisionGame/src/main/java/mock/model/RaceServer.java b/racevisionGame/src/main/java/mock/model/RaceServer.java index 969a4c71..af343666 100644 --- a/racevisionGame/src/main/java/mock/model/RaceServer.java +++ b/racevisionGame/src/main/java/mock/model/RaceServer.java @@ -2,10 +2,8 @@ package mock.model; import network.Messages.*; import network.Messages.Enums.BoatLocationDeviceEnum; -import network.Utils.AC35UnitConverter; import shared.model.Bearing; import shared.model.CompoundMark; -import shared.model.Constants; import shared.model.Mark; import java.util.ArrayList; @@ -127,8 +125,8 @@ public class RaceServer { BoatLocation boatLocation = new BoatLocation( boat.getSourceID(), - boat.getCurrentPosition().getLatitude(), - boat.getCurrentPosition().getLongitude(), + boat.getPosition().getLatitude(), + boat.getPosition().getLongitude(), this.boatLocationSequenceNumber, BoatLocationDeviceEnum.RacingYacht, boat.getBearing(), diff --git a/racevisionGame/src/main/java/mock/model/SplitTODO.java b/racevisionGame/src/main/java/mock/model/SplitTODO.java deleted file mode 100644 index 20f14973..00000000 --- a/racevisionGame/src/main/java/mock/model/SplitTODO.java +++ /dev/null @@ -1,555 +0,0 @@ -//package mock.model; -// -//import javafx.animation.AnimationTimer; -//import network.Messages.BoatLocation; -//import network.Messages.BoatStatus; -//import network.Messages.Enums.BoatStatusEnum; -//import network.Messages.Enums.RaceStatusEnum; -//import network.Messages.LatestMessages; -//import network.Messages.RaceStatus; -//import network.Utils.AC35UnitConverter; -//import shared.dataInput.BoatDataSource; -//import shared.dataInput.RaceDataSource; -//import shared.dataInput.RegattaDataSource; -//import shared.model.*; -// -//import java.time.ZonedDateTime; -//import java.time.temporal.ChronoUnit; -//import java.util.ArrayList; -//import java.util.Iterator; -//import java.util.List; -//import java.util.Map; -// -//import static java.lang.Math.cos; -// -///** -// * Unused class, copy of MockRace so methods can be deleted once they are moved (more of a checklist) -// */ -//public class SplitTODO { -// -// -// /** -// * Represents a yacht race. -// * Has a course, boats, boundaries, etc... -// * Is responsible for simulating the race, and sending messages to a MockOutput instance. -// */ -// public class MockRace extends Race { -// -// /** -// * Constructs a race object with a given RaceDataSource, BoatDataSource, and RegattaDataSource and sends events to the given mockOutput. -// * @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...). -// * @param latestMessages The LatestMessages to send events to. -// * @param polars The polars table to be used for boat simulation. -// * @param timeScale The timeScale for the race. See {@link Constants#RaceTimeScale}. -// */ -// public MockRace(BoatDataSource boatDataSource, RaceDataSource raceDataSource, RegattaDataSource regattaDataSource, LatestMessages latestMessages, Polars polars, int timeScale) { -// -// super(boatDataSource, raceDataSource, regattaDataSource, latestMessages); -// -// this.scaleFactor = timeScale; -// } -// -// -// -// /** -// * Parse the compound marker boats through mock output. -// */ -// private void parseMarks() { -// for (CompoundMark compoundMark : this.compoundMarks) { -// -// //Get the individual marks from the compound mark. -// Mark mark1 = compoundMark.getMark1(); -// Mark mark2 = compoundMark.getMark2(); -// -// //If they aren't null, parse them (some compound marks only have one mark). -// if (mark1 != null) { -// this.parseIndividualMark(mark1); -// } -// -// if (mark2 != null) { -// this.parseIndividualMark(mark2); -// } -// -// } -// } -// -// /** -// * Parses an individual marker boat, and sends it to mockOutput. -// * @param mark The marker boat to parse. -// */ -// private void parseIndividualMark(Mark mark) { -// -// //Create message. -// BoatLocation boatLocation = new BoatLocation( -// mark.getSourceID(), -// mark.getPosition().getLatitude(), -// mark.getPosition().getLongitude(), -// this.boatLocationSequenceNumber, -// 0, 0, -// this.raceClock.getCurrentTimeMilli()); -// -// //Iterates the sequence number. -// this.boatLocationSequenceNumber++; -// -// this.latestMessages.setBoatLocation(boatLocation); -// -// -// } -// -// /** -// * Parse the boats in the race, and send it to mockOutput. -// */ -// private void parseBoatLocations() { -// -// //Parse each boat. -// for (MockBoat boat : this.boats) { -// -// this.parseIndividualBoatLocation(boat); -// -// } -// -// } -// -// /** -// * Parses an individual boat, and sends it to mockOutput. -// * @param boat The boat to parse. -// */ -// private void parseIndividualBoatLocation(MockBoat boat) { -// -// BoatLocation boatLocation = new BoatLocation( -// boat.getSourceID(), -// boat.getCurrentPosition().getLatitude(), -// boat.getCurrentPosition().getLongitude(), -// this.boatLocationSequenceNumber, -// boat.getBearing().degrees(), -// boat.getCurrentSpeed(), -// this.raceClock.getCurrentTimeMilli()); -// -// //Iterates the sequence number. -// this.boatLocationSequenceNumber++; -// -// this.latestMessages.setBoatLocation(boatLocation); -// -// } -// -// -// /** -// * Updates the race time to a specified value, in milliseconds since the unix epoch. -// * @param currentTime Milliseconds since unix epoch. -// */ -// private void updateRaceTime(long currentTime) { -// this.raceClock.setUTCTime(currentTime); -// } -// -// -// /** -// * Updates the race status enumeration based on the current time. -// */ -// private void updateRaceStatusEnum() { -// -// //The millisecond duration of the race. Negative means it hasn't started, so we flip sign. -// long timeToStart = - this.raceClock.getDurationMilli(); -// -// -// if (timeToStart > Constants.RacePreStartTime) { -// //Time > 3 minutes is the prestart period. -// this.setRaceStatusEnum(RaceStatusEnum.PRESTART); -// -// } else if ((timeToStart <= Constants.RacePreStartTime) && (timeToStart >= Constants.RacePreparatoryTime)) { -// //Time between [1, 3] minutes is the warning period. -// this.setRaceStatusEnum(RaceStatusEnum.WARNING); -// -// } else if ((timeToStart <= Constants.RacePreparatoryTime) && (timeToStart > 0)) { -// //Time between (0, 1] minutes is the preparatory period. -// this.setRaceStatusEnum(RaceStatusEnum.PREPARATORY); -// -// } else { -// //Otherwise, the race has started! -// this.setRaceStatusEnum(RaceStatusEnum.STARTED); -// -// } -// -// -// } -// -// /** -// * Parses the race status, and sends it to mockOutput. -// */ -// private void parseRaceStatus() { -// -// //A race status message contains a list of boat statuses. -// List boatStatuses = new ArrayList<>(); -// -// //Add each boat status to the status list. -// for (MockBoat boat : this.boats) { -// -// BoatStatus boatStatus = new BoatStatus( -// boat.getSourceID(), -// boat.getStatus(), -// boat.getCurrentLeg().getLegNumber(), -// boat.getEstimatedTimeAtNextMark().toInstant().toEpochMilli() ); -// -// boatStatuses.add(boatStatus); -// } -// -// -// //Convert wind direction and speed to ints. //TODO this conversion should be done inside the racestatus class. -// int windDirectionInt = AC35UnitConverter.encodeHeading(this.getWindDirection().degrees()); -// int windSpeedInt = (int) (this.getWindSpeed() * Constants.KnotsToMMPerSecond); -// -// //Create race status object, and send it. -// RaceStatus raceStatus = new RaceStatus( -// System.currentTimeMillis(), -// this.raceId, -// this.getRaceStatusEnum().getValue(), -// this.raceClock.getStartingTimeMilli(), -// windDirectionInt, -// windSpeedInt, -// this.getRaceType().getValue(), -// boatStatuses); -// -// -// this.latestMessages.setRaceStatus(raceStatus); -// -// -// } -// -// -// /** -// * Sets the status of all boats in the race to RACING. -// */ -// private void setBoatsStatusToRacing() { -// -// for (MockBoat boat : this.boats) { -// boat.setStatus(BoatStatusEnum.RACING); -// } -// } -// -// -// /** -// * Sets the estimated time at next mark for each boat to a specified time. This is used during the countdown timer to provide this value to boat before the race starts. -// * @param time The time to provide to each boat. -// */ -// private void setBoatsTimeNextMark(ZonedDateTime time) { -// -// for (MockBoat boat : this.boats) { -// boat.setEstimatedTimeAtNextMark(time); -// } -// } -// -// -// /** -// * Countdown timer until race starts. -// */ -// protected AnimationTimer countdownTimer = new AnimationTimer() { -// -// -// long currentTime = System.currentTimeMillis(); -// -// @Override -// public void handle(long arg0) { -// -// //Update race time. -// updateRaceTime(currentTime); -// -// //Update the race status based on the current time. -// updateRaceStatusEnum(); -// -// //Provide boat's with an estimated time at next mark until the race starts. -// setBoatsTimeNextMark(raceClock.getCurrentTime()); -// -// //Parse the boat locations. -// parseBoatLocations(); -// -// //Parse the marks. -// parseMarks(); -// -// // Change wind direction -// changeWindDirection(); -// -// //Parse the race status. -// parseRaceStatus(); -// -// -// if (getRaceStatusEnum() == RaceStatusEnum.STARTED) { -// setBoatsStatusToRacing(); -// raceTimer.start(); -// this.stop(); -// } -// -// //Update the animations timer's time. -// currentTime = System.currentTimeMillis(); -// } -// }; -// -// -// /** -// * Timer that runs for the duration of the race, until all boats finish. -// */ -// private AnimationTimer raceTimer = new AnimationTimer() { -// -// /** -// * Start time of loop, in milliseconds. -// */ -// long timeRaceStarted = System.currentTimeMillis(); -// -// /** -// * Current time during a loop iteration. -// */ -// long currentTime = System.currentTimeMillis(); -// -// /** -// * The time of the previous frame, in milliseconds. -// */ -// long lastFrameTime = timeRaceStarted; -// -// @Override -// public void handle(long arg0) { -// -// //Get the current time. -// currentTime = System.currentTimeMillis(); -// -// //Update race time. -// updateRaceTime(currentTime); -// -// -// //As long as there is at least one boat racing, we still simulate the race. -// if (getNumberOfActiveBoats() != 0) { -// -// //Get the time period of this frame. -// long framePeriod = currentTime - lastFrameTime; -// -// //For each boat, we update its position, and generate a BoatLocationMessage. -// for (MockBoat boat : boats) { -// -// //If it is still racing, update its position. -// if (boat.getStatus() == BoatStatusEnum.RACING) { -// -// updatePosition(boat, framePeriod, raceClock.getDurationMilli()); -// -// } -// -// } -// -// } else { -// //Otherwise, the race is over! -// raceFinished.start(); -// setRaceStatusEnum(RaceStatusEnum.FINISHED); -// this.stop(); -// } -// -// if (getNumberOfActiveBoats() != 0) { -// // Change wind direction -// changeWindDirection(); -// -// //Parse the boat locations. -// parseBoatLocations(); -// -// //Parse the marks. -// parseMarks(); -// -// //Parse the race status. -// parseRaceStatus(); -// -// -// //Update the last frame time. -// this.lastFrameTime = currentTime; -// } -// } -// }; -// -// /** -// * Broadcast that the race has finished. -// */ -// protected AnimationTimer raceFinished = new AnimationTimer(){ -// int iters = 0; -// @Override -// public void handle(long now) { -// -// parseRaceStatus(); -// -// if (iters > 500) { -// stop(); -// } -// iters++; -// } -// }; -// -// -// /** -// * Calculates a boat's VMG. -// * @param boat The boat to calculate VMG for. -// * @return VMG for the specified boat. -// */ -// private VMG calculateVMG(MockBoat boat) { -// -// -// //Find the VMG inside these bounds. -// VMG bestVMG = boat.getPolars().calculateVMG(this.getWindDirection(), this.getWindSpeed(), boat.calculateBearingToNextMarker(), Bearing.fromDegrees(0d), Bearing.fromDegrees(359.99999d)); -// -// -// return bestVMG; -// -// } -// -// -// /** -// * Determines whether or not a given VMG improves the velocity of a boat, if it were currently using currentVMG. -// * @param currentVMG The current VMG of the boat. -// * @param potentialVMG The new VMG to test. -// * @param bearingToDestination The bearing between the boat and its destination. -// * @return True if the new VMG is improves velocity, false otherwise. -// */ -// private boolean improvesVelocity(VMG currentVMG, VMG potentialVMG, Bearing bearingToDestination) { -// -// //Calculates the angle between the boat and its destination. -// Angle angleBetweenDestAndHeading = Angle.fromDegrees(currentVMG.getBearing().degrees() - bearingToDestination.degrees()); -// -// //Calculates the angle between the new VMG and the boat's destination. -// Angle angleBetweenDestAndNewVMG = Angle.fromDegrees(potentialVMG.getBearing().degrees() - bearingToDestination.degrees()); -// -// -// //Calculate the boat's current velocity. -// double currentVelocity = Math.cos(angleBetweenDestAndHeading.radians()) * currentVMG.getSpeed(); -// -// //Calculate the potential velocity with the new VMG. -// double vmgVelocity = Math.cos(angleBetweenDestAndNewVMG.radians()) * potentialVMG.getSpeed(); -// -// //Return whether or not the new VMG gives better velocity. -// return vmgVelocity > currentVelocity; -// -// } -// -// /** -// * Determines whether or not a given VMG improves the velocity of a boat. -// * @param boat The boat to test. -// * @param vmg The new VMG to test. -// * @return True if the new VMG is improves velocity, false otherwise. -// */ -// private boolean improvesVelocity(MockBoat boat, VMG vmg) { -// -// //Get the boats "current" VMG. -// VMG boatVMG = new VMG(boat.getCurrentSpeed(), boat.getBearing()); -// -// //Check if the new VMG is better than the boat's current VMG. -// return this.improvesVelocity(boatVMG, vmg, boat.calculateBearingToNextMarker()); -// -// } -// -// -// /** -// * Calculates the distance a boat has travelled and updates its current position according to this value. -// * -// * @param boat The boat to be updated. -// * @param updatePeriodMilliseconds The time, in milliseconds, since the last update. -// * @param totalElapsedMilliseconds The total number of milliseconds that have elapsed since the start of the race. -// */ -// protected void updatePosition(MockBoat boat, long updatePeriodMilliseconds, long totalElapsedMilliseconds) { -// -// //Checks if the current boat has finished the race or not. -// boolean finish = this.isLastLeg(boat.getCurrentLeg()); -// -// if (!finish) { -// -// -// //Calculates the distance travelled, in meters, in the current timeslice. -// double distanceTravelledMeters = boat.calculateMetersTravelled(updatePeriodMilliseconds); -// -// //Scale it. -// distanceTravelledMeters = distanceTravelledMeters * this.scaleFactor; -// -// -// //Move the boat forwards that many meters, and advances its time counters by enough milliseconds. -// boat.moveForwards(distanceTravelledMeters, updatePeriodMilliseconds * this.scaleFactor); -// -// long tackPeriod = 15000; -// if (boat.getTimeSinceTackChange() > tackPeriod) { -// //Calculate the new VMG. -// VMG newVMG = this.calculateVMG(boat); -// -// -// //If the new vmg improves velocity, use it. -// if (improvesVelocity(boat, newVMG)) { -// boat.setVMG(newVMG); -// -// } -// } -// -// this.updateEstimatedTime(boat); -// -// -// //Check the boats position (update leg and stuff). -// this.checkPosition(boat, totalElapsedMilliseconds); -// -// } -// -// } -// -// -// /** -// * Checks if a boat has finished any legs, or has pulled out of race (DNF). -// * @param boat The boat to check. -// * @param timeElapsed The total time, in milliseconds, that has elapsed since the race started. -// */ -// protected void checkPosition(MockBoat boat, long timeElapsed) { -// -// //The distance, in nautical miles, within which the boat needs to get in order to consider that it has reached the marker. -// double epsilonNauticalMiles = 100.0 / Constants.NMToMetersConversion; //100 meters. TODO should be more like 5-10. -// -// if (boat.calculateDistanceToNextMarker() < epsilonNauticalMiles) { -// //Boat has reached its target marker, and has moved on to a new leg. -// -// -// -// //Calculate how much the boat overshot the marker by. -// double overshootMeters = boat.calculateDistanceToNextMarker(); -// -// -// //Move boat on to next leg. -// Leg nextLeg = this.legs.get(boat.getCurrentLeg().getLegNumber() + 1); -// boat.setCurrentLeg(nextLeg); -// -// //Add overshoot distance into the distance travelled for the next leg. -// boat.setDistanceTravelledInLeg(overshootMeters); -// -// //Setting a high value for this allows the boat to immediately do a large turn, as it needs to in order to get to the next mark. -// boat.setTimeSinceTackChange(999999); -// -// -// //Check if the boat has finished or stopped racing. -// -// if (this.isLastLeg(boat.getCurrentLeg())) { -// //Boat has finished. -// boat.setTimeFinished(timeElapsed); -// boat.setCurrentSpeed(0); -// boat.setStatus(BoatStatusEnum.FINISHED); -// -// } -// -// } -// -// } -// -// /** -// * Updates the boat's estimated time to next mark if positive -// * @param boat to estimate time given its velocity -// */ -// private void updateEstimatedTime(MockBoat boat) { -// -// double velocityToMark = boat.getCurrentSpeed() * cos(boat.getBearing().radians() - boat.calculateBearingToNextMarker().radians()) / Constants.KnotsToMMPerSecond; -// -// if (velocityToMark > 0) { -// -// //Calculate milliseconds until boat reaches mark. -// long timeFromNow = (long) (1000 * boat.calculateDistanceToNextMarker() / velocityToMark); -// -// //Calculate time at which it will reach mark. -// ZonedDateTime timeAtMark = this.raceClock.getCurrentTime().plus(timeFromNow, ChronoUnit.MILLIS); -// boat.setEstimatedTimeAtNextMark(timeAtMark); -// } -// -// } -// } -//} diff --git a/racevisionGame/src/main/java/shared/model/Boat.java b/racevisionGame/src/main/java/shared/model/Boat.java index 385c4f3b..9d1d0c40 100644 --- a/racevisionGame/src/main/java/shared/model/Boat.java +++ b/racevisionGame/src/main/java/shared/model/Boat.java @@ -10,7 +10,7 @@ import java.time.ZonedDateTime; /** * Boat Model that is used to store information on the boats that are running in the race. */ -public class Boat { +public class Boat implements Locatable { /** * The name of the boat/team. */ @@ -30,7 +30,7 @@ public class Boat { /** * The current position of the boat. */ - private GPSCoordinate currentPosition; + private GPSCoordinate position; /** * The country or team abbreviation of the boat. @@ -57,7 +57,7 @@ public class Boat { /** * The boat's position within the race (e.g., 5th). */ - private StringProperty positionInRace = new SimpleStringProperty(); + private StringProperty placing = new SimpleStringProperty(); /** @@ -107,7 +107,7 @@ public class Boat { this.bearing = Bearing.fromDegrees(0d); - setCurrentPosition(new GPSCoordinate(0, 0)); + setPosition(new GPSCoordinate(0, 0)); this.status = BoatStatusEnum.UNDEFINED; } @@ -256,41 +256,32 @@ public class Boat { * Returns the position within the race the boat has (e.g., 5th). * @return The boat's position in race. */ - public StringProperty positionProperty() { - return positionInRace; + public StringProperty placingProperty() { + return placing; } /** * Sets the position within the race the boat has (e.g., 5th). * @param position The boat's position in race. */ - public void setPosition(String position) { - this.positionInRace.set(position); + public void setPlacing(String position) { + this.placing.set(position); } - /** - * Returns the position within the race the boat has (e.g., 5th). - * @return The boat's position in race. - */ - public String getPosition() { - return this.positionInRace.get(); - } - - /** * Returns the current position of the boat. * @return The current position of the boat. */ - public GPSCoordinate getCurrentPosition() { - return currentPosition; + public GPSCoordinate getPosition() { + return position; } /** * Sets the current position of the boat. - * @param currentPosition The new position for the boat. + * @param position The new position for the boat. */ - public void setCurrentPosition(GPSCoordinate currentPosition) { - this.currentPosition = currentPosition; + public void setPosition(GPSCoordinate position) { + this.position = position; } diff --git a/racevisionGame/src/main/java/shared/model/CompoundMark.java b/racevisionGame/src/main/java/shared/model/CompoundMark.java index 66e682e5..cabf3a02 100644 --- a/racevisionGame/src/main/java/shared/model/CompoundMark.java +++ b/racevisionGame/src/main/java/shared/model/CompoundMark.java @@ -1,16 +1,11 @@ package shared.model; - -import mock.model.MockBoat; -import mock.model.collider.Collider; -import mock.model.collider.Collision; - import shared.enums.RoundingType; /** * Represents a compound mark - that is, either one or two individual marks which form a single compound mark. */ -public class CompoundMark implements Collider { +public class CompoundMark { /** * The ID of the compound mark. @@ -146,38 +141,6 @@ public class CompoundMark implements Collider { } - private Mark closestMark(GPSCoordinate coordinate) { - double mark1distance = GPSCoordinate.calculateDistanceMeters(getMark1Position(), coordinate); - double mark2distance = GPSCoordinate.calculateDistanceMeters(getMark2Position(), coordinate); - return mark1distance <= mark2distance? mark1 : mark2; - } - - @Override - public boolean rayCast(MockBoat boat, double distance) { - GPSCoordinate position = boat.getCurrentPosition(); - double actualDistance = GPSCoordinate.calculateDistanceMeters(position, closestMark(position).getPosition()); - // Compass direction of collider - Bearing absolute = Bearing.fromAzimuth(GPSCoordinate.calculateAzimuth(position, closestMark(position).getPosition())); - // Direction of collider from heading - Bearing relative = Bearing.fromDegrees(absolute.degrees() - boat.getBearing().degrees()); - - if(actualDistance <= distance) { - onCollisionEnter(new Collision(relative, distance)); - return true; - } else return false; - } - - @Override - public boolean rayCast(MockBoat boat) { - return rayCast(boat, 100); - } - - @Override - public void onCollisionEnter(Collision e) { - if(e.getBearing().degrees() < 90) System.out.println("Starboard"); - else if(e.getBearing().degrees() > 270) System.out.println("Port"); - } - /** * Used to find how far apart the marks that make up this gate are * If this compound mark is only one point return base length of 250m diff --git a/racevisionGame/src/main/java/shared/model/Locatable.java b/racevisionGame/src/main/java/shared/model/Locatable.java new file mode 100644 index 00000000..4655563d --- /dev/null +++ b/racevisionGame/src/main/java/shared/model/Locatable.java @@ -0,0 +1,9 @@ +package shared.model; + +/** + * Created by cbt24 on 16/08/17. + */ +public interface Locatable { + GPSCoordinate getPosition(); + void setPosition(GPSCoordinate position); +} diff --git a/racevisionGame/src/main/java/shared/model/Mark.java b/racevisionGame/src/main/java/shared/model/Mark.java index 2b01184a..1dddeea8 100644 --- a/racevisionGame/src/main/java/shared/model/Mark.java +++ b/racevisionGame/src/main/java/shared/model/Mark.java @@ -1,10 +1,14 @@ package shared.model; +import mock.model.MockBoat; +import mock.model.collider.Collider; +import mock.model.collider.Collision; + /** * Represents an individual mark. * Has a source ID, name, and position. */ -public class Mark { +public class Mark implements Locatable, Collider { /** * The source ID of the mark. @@ -75,4 +79,31 @@ public class Mark { public void setPosition(GPSCoordinate position) { this.position = position; } + + @Override + public boolean rayCast(MockBoat boat, double distance) { + double actualDistance = GPSCoordinate.calculateDistanceMeters(boat.getPosition(), this.position); + // Compass direction of collider + Bearing absolute = Bearing.fromAzimuth(GPSCoordinate.calculateAzimuth(boat.getPosition(), this.position)); + // Direction of collider from heading + Bearing relative = Bearing.fromDegrees(absolute.degrees() - boat.getBearing().degrees()); + + if(actualDistance <= distance) { + onCollisionEnter(new Collision(relative, distance)); + return true; + } else return false; + } + + @Override + public boolean rayCast(MockBoat boat) { + return rayCast(boat, 100); + } + + @Override + public void onCollisionEnter(Collision e) { + if(e.getBearing().degrees() == 0) System.out.println("Ahead"); + 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"); + } } diff --git a/racevisionGame/src/main/java/shared/model/Race.java b/racevisionGame/src/main/java/shared/model/Race.java index 685af9e0..a15e2edd 100644 --- a/racevisionGame/src/main/java/shared/model/Race.java +++ b/racevisionGame/src/main/java/shared/model/Race.java @@ -118,7 +118,11 @@ public abstract class Race { this.setWind(Bearing.fromDegrees(0), 0); // Set up colliders this.colliderRegistry = new ColliderRegistry(); - this.colliderRegistry.addAllColliders(compoundMarks); + + for(CompoundMark mark: compoundMarks) { + colliderRegistry.addCollider(mark.getMark1()); + if(mark.getMark2() != null) colliderRegistry.addCollider(mark.getMark2()); + } } public ColliderRegistry getColliderRegistry() { diff --git a/racevisionGame/src/main/java/visualiser/Commands/VisualiserRaceCommands/BoatLocationCommand.java b/racevisionGame/src/main/java/visualiser/Commands/VisualiserRaceCommands/BoatLocationCommand.java index d2c60bd7..160955bc 100644 --- a/racevisionGame/src/main/java/visualiser/Commands/VisualiserRaceCommands/BoatLocationCommand.java +++ b/racevisionGame/src/main/java/visualiser/Commands/VisualiserRaceCommands/BoatLocationCommand.java @@ -8,7 +8,6 @@ import shared.exceptions.MarkNotFoundException; import shared.model.GPSCoordinate; import shared.model.Mark; import visualiser.model.VisualiserBoat; -import visualiser.model.VisualiserRaceEvent; import visualiser.model.VisualiserRaceState; import java.util.logging.Level; @@ -68,7 +67,7 @@ public class BoatLocationCommand implements Command { boatLocation.getLatitude(), boatLocation.getLongitude()); - boat.setCurrentPosition(gpsCoordinate); + boat.setPosition(gpsCoordinate); //Bearing. boat.setBearing(boatLocation.getHeading()); @@ -96,7 +95,7 @@ public class BoatLocationCommand implements Command { */ private void attemptAddTrackPoint(VisualiserBoat boat) { if (boat.getStatus() == BoatStatusEnum.RACING) { - boat.addTrackPoint(boat.getCurrentPosition(), visualiserRace.getRaceClock().getCurrentTime()); + boat.addTrackPoint(boat.getPosition(), visualiserRace.getRaceClock().getCurrentTime()); } } diff --git a/racevisionGame/src/main/java/visualiser/Controllers/FinishController.java b/racevisionGame/src/main/java/visualiser/Controllers/FinishController.java index b6f7dff8..c5356495 100644 --- a/racevisionGame/src/main/java/visualiser/Controllers/FinishController.java +++ b/racevisionGame/src/main/java/visualiser/Controllers/FinishController.java @@ -67,7 +67,7 @@ public class FinishController extends Controller { boatNameColumn.setCellValueFactory(cellData -> cellData.getValue().nameProperty()); //Rank/position. - boatRankColumn.setCellValueFactory(cellData -> cellData.getValue().positionProperty()); + boatRankColumn.setCellValueFactory(cellData -> cellData.getValue().placingProperty()); //Winner label. diff --git a/racevisionGame/src/main/java/visualiser/Controllers/RaceController.java b/racevisionGame/src/main/java/visualiser/Controllers/RaceController.java index 3e4c1398..7b495411 100644 --- a/racevisionGame/src/main/java/visualiser/Controllers/RaceController.java +++ b/racevisionGame/src/main/java/visualiser/Controllers/RaceController.java @@ -23,7 +23,6 @@ import visualiser.gameController.ControllerClient; import visualiser.gameController.Keys.ControlKey; import visualiser.gameController.Keys.KeyFactory; import visualiser.model.*; -import visualiser.network.ServerConnection; import java.net.URL; import java.util.ResourceBundle; @@ -293,7 +292,7 @@ public class RaceController extends Controller { //Current place within race. boatPlacingColumn.setCellValueFactory( - cellData -> cellData.getValue().positionProperty() ); + cellData -> cellData.getValue().placingProperty() ); } diff --git a/racevisionGame/src/main/java/visualiser/model/ResizableRaceCanvas.java b/racevisionGame/src/main/java/visualiser/model/ResizableRaceCanvas.java index d58e2afd..57c864b5 100644 --- a/racevisionGame/src/main/java/visualiser/model/ResizableRaceCanvas.java +++ b/racevisionGame/src/main/java/visualiser/model/ResizableRaceCanvas.java @@ -269,7 +269,7 @@ public class ResizableRaceCanvas extends ResizableCanvas { boat.getName(), boat.getCountry(), boat.getCurrentSpeed(), - this.map.convertGPS(boat.getCurrentPosition()), + this.map.convertGPS(boat.getPosition()), boat.getTimeToNextMarkFormatted(this.visualiserRace.getVisualiserRaceState().getRaceClock().getCurrentTime()), boat.getTimeSinceLastMarkFormatted(this.visualiserRace.getVisualiserRaceState().getRaceClock().getCurrentTime()) ); @@ -322,7 +322,7 @@ public class ResizableRaceCanvas extends ResizableCanvas { } //Convert position to graph coordinate. - GraphCoordinate pos = this.map.convertGPS(boat.getCurrentPosition()); + GraphCoordinate pos = this.map.convertGPS(boat.getPosition()); //The x coordinates of each vertex of the boat. double[] x = { @@ -356,7 +356,7 @@ public class ResizableRaceCanvas extends ResizableCanvas { private void drawClientBoat(VisualiserBoat boat) { //Convert position to graph coordinate. - GraphCoordinate pos = this.map.convertGPS(boat.getCurrentPosition()); + GraphCoordinate pos = this.map.convertGPS(boat.getPosition()); //The x coordinates of each vertex of the boat. double[] x = { @@ -390,7 +390,7 @@ public class ResizableRaceCanvas extends ResizableCanvas { private void drawWake(VisualiserBoat boat) { //Calculate either end of wake line. - GraphCoordinate wakeFrom = this.map.convertGPS(boat.getCurrentPosition()); + GraphCoordinate wakeFrom = this.map.convertGPS(boat.getPosition()); GraphCoordinate wakeTo = this.map.convertGPS(boat.getWake()); //Draw. diff --git a/racevisionGame/src/main/java/visualiser/model/VisualiserBoat.java b/racevisionGame/src/main/java/visualiser/model/VisualiserBoat.java index ce966b02..a02706a6 100644 --- a/racevisionGame/src/main/java/visualiser/model/VisualiserBoat.java +++ b/racevisionGame/src/main/java/visualiser/model/VisualiserBoat.java @@ -1,7 +1,5 @@ package visualiser.model; -import javafx.beans.property.SimpleStringProperty; -import javafx.beans.property.StringProperty; import javafx.scene.paint.Color; import network.Messages.Enums.BoatStatusEnum; import shared.model.Azimuth; @@ -102,7 +100,7 @@ public class VisualiserBoat extends Boat { //Calculate the new coordinate. - GPSCoordinate wakeCoordinate = GPSCoordinate.calculateNewPosition(getCurrentPosition(), wakeDistanceMeters, reverseAzimuth); + GPSCoordinate wakeCoordinate = GPSCoordinate.calculateNewPosition(getPosition(), wakeDistanceMeters, reverseAzimuth); return wakeCoordinate; } diff --git a/racevisionGame/src/main/java/visualiser/model/VisualiserRaceState.java b/racevisionGame/src/main/java/visualiser/model/VisualiserRaceState.java index b1767cd5..3315cbfa 100644 --- a/racevisionGame/src/main/java/visualiser/model/VisualiserRaceState.java +++ b/racevisionGame/src/main/java/visualiser/model/VisualiserRaceState.java @@ -1,7 +1,6 @@ package visualiser.model; -import javafx.application.Platform; import javafx.collections.FXCollections; import javafx.collections.ObservableList; import javafx.scene.paint.Color; @@ -228,7 +227,7 @@ public class VisualiserRaceState extends RaceState { boat.setCurrentLeg(startingLeg); boat.setTimeAtLastMark(getRaceClock().getCurrentTime()); - boat.setCurrentPosition(new GPSCoordinate(0, 0)); + boat.setPosition(new GPSCoordinate(0, 0)); } @@ -253,10 +252,10 @@ public class VisualiserRaceState extends RaceState { if ((boat.getStatus() == BoatStatusEnum.DNF) || (boat.getStatus() == BoatStatusEnum.PRESTART) || (boat.getCurrentLeg().getLegNumber() < 0)) { - boat.setPosition("-"); + boat.setPlacing("-"); } else { - boat.setPosition(Integer.toString(i + 1)); + boat.setPlacing(Integer.toString(i + 1)); } } diff --git a/racevisionGame/src/test/java/mock/model/MockBoatTest.java b/racevisionGame/src/test/java/mock/model/MockBoatTest.java index 10792a12..dcc17f1b 100644 --- a/racevisionGame/src/test/java/mock/model/MockBoatTest.java +++ b/racevisionGame/src/test/java/mock/model/MockBoatTest.java @@ -1,6 +1,5 @@ package mock.model; -import mock.model.collider.Collision; import org.junit.Before; import org.junit.Test; import shared.model.Bearing; @@ -12,17 +11,17 @@ import static org.junit.Assert.*; public class MockBoatTest { private MockBoat boat; - private CompoundMark near; - private CompoundMark far; + private Mark near; + private Mark far; @Before public void setUp() { boat = new MockBoat(0, "Bob", "NZ", null); - boat.setCurrentPosition(new GPSCoordinate(0,0)); + boat.setPosition(new GPSCoordinate(0,0)); boat.setBearing(Bearing.fromDegrees(180)); - near = new CompoundMark(0, "Near", new Mark(0, "Near", new GPSCoordinate(-.0001, 0))); - far = new CompoundMark(1, "Far", new Mark(0, "Far", new GPSCoordinate(.001, 0))); + near = new Mark(0, "Near", new GPSCoordinate(-.0001, 0)); + far = new Mark(0, "Far", new GPSCoordinate(.001, 0)); } @Test diff --git a/racevisionGame/src/test/java/shared/model/BoatTest.java b/racevisionGame/src/test/java/shared/model/BoatTest.java index c087708c..babfbb45 100644 --- a/racevisionGame/src/test/java/shared/model/BoatTest.java +++ b/racevisionGame/src/test/java/shared/model/BoatTest.java @@ -19,7 +19,7 @@ public class BoatTest { public void setUp() { ORIGIN_COORDS = new GPSCoordinate(0, 0); TEST_BOAT = new Boat(1, "Test", "tt"); - TEST_BOAT.setCurrentPosition(ORIGIN_COORDS); + TEST_BOAT.setPosition(ORIGIN_COORDS); } //TODO these bearing tests could be tidied up to reduce code repetition. @@ -113,7 +113,7 @@ public class BoatTest { Leg start = new Leg("Start", startMarker, endMarker, 0); TEST_BOAT.setCurrentLeg(start); - assertEquals(GPSCoordinate.calculateAzimuth(TEST_BOAT.getCurrentPosition(), endMarker.getAverageGPSCoordinate()).degrees(), 0, 1e-8); + assertEquals(GPSCoordinate.calculateAzimuth(TEST_BOAT.getPosition(), endMarker.getAverageGPSCoordinate()).degrees(), 0, 1e-8); } @@ -131,7 +131,7 @@ public class BoatTest { Leg start = new Leg("Start", startMarker, endMarker, 0); TEST_BOAT.setCurrentLeg(start); - assertEquals(GPSCoordinate.calculateAzimuth(TEST_BOAT.getCurrentPosition(), endMarker.getAverageGPSCoordinate()).degrees(), 90, 1e-8); + assertEquals(GPSCoordinate.calculateAzimuth(TEST_BOAT.getPosition(), endMarker.getAverageGPSCoordinate()).degrees(), 90, 1e-8); } @Test @@ -148,7 +148,7 @@ public class BoatTest { Leg start = new Leg("Start", startMarker, endMarker, 0); TEST_BOAT.setCurrentLeg(start); - assertEquals(GPSCoordinate.calculateAzimuth(TEST_BOAT.getCurrentPosition(), endMarker.getAverageGPSCoordinate()).degrees(), -180, 1e-8); + assertEquals(GPSCoordinate.calculateAzimuth(TEST_BOAT.getPosition(), endMarker.getAverageGPSCoordinate()).degrees(), -180, 1e-8); } @Test @@ -165,7 +165,7 @@ public class BoatTest { Leg start = new Leg("Start", startMarker, endMarker, 0); TEST_BOAT.setCurrentLeg(start); - assertEquals(GPSCoordinate.calculateBearing(TEST_BOAT.getCurrentPosition(), endMarker.getAverageGPSCoordinate()).degrees(), 270, 1e-8); + assertEquals(GPSCoordinate.calculateBearing(TEST_BOAT.getPosition(), endMarker.getAverageGPSCoordinate()).degrees(), 270, 1e-8); } From 79f3c41d45d004097e6daad39fa87c66fb4d7239 Mon Sep 17 00:00:00 2001 From: cbt24 Date: Wed, 16 Aug 2017 16:21:55 +1200 Subject: [PATCH 08/14] Moved generic ray casting to Collider abstract class - Boat is now collider - Collider subclasses specify their own collision ray and collision handler #story[1100] --- .../src/main/java/mock/model/MockBoat.java | 29 +------------------ .../java/mock/model/collider/Collider.java | 24 +++++++++++---- .../mock/model/collider/ColliderRegistry.java | 26 +++++++++-------- .../src/main/java/shared/model/Boat.java | 15 +++++++++- .../src/main/java/shared/model/Mark.java | 19 ++---------- .../test/java/mock/model/MockBoatTest.java | 1 - 6 files changed, 50 insertions(+), 64 deletions(-) diff --git a/racevisionGame/src/main/java/mock/model/MockBoat.java b/racevisionGame/src/main/java/mock/model/MockBoat.java index 227dfe54..b6cd7a24 100644 --- a/racevisionGame/src/main/java/mock/model/MockBoat.java +++ b/racevisionGame/src/main/java/mock/model/MockBoat.java @@ -1,8 +1,5 @@ package mock.model; - -import mock.model.collider.Collider; -import mock.model.collider.Collision; import shared.model.*; @@ -10,7 +7,7 @@ import shared.model.*; * Represents a Boat on the mock side of a race. * This adds mock specific functionality to a boat. */ -public class MockBoat extends Boat implements Collider { +public class MockBoat extends Boat { /** @@ -303,28 +300,4 @@ public class MockBoat extends Boat implements Collider { public void setAutoVMG(boolean autoVMG) { this.autoVMG = autoVMG; } - - @Override - public boolean rayCast(MockBoat boat, double distance) { - double actualDistance = GPSCoordinate.calculateDistanceMeters(boat.getPosition(), this.getPosition()); - Bearing absolute = GPSCoordinate.calculateBearing(boat.getPosition(), this.getPosition()); - Bearing relative = Bearing.fromDegrees(absolute.degrees() - boat.getBearing().degrees()); - - if(actualDistance <= distance) { - onCollisionEnter(new Collision(relative, actualDistance)); - return true; - } else return false; - } - - @Override - public boolean rayCast(MockBoat boat) { - if(boat != this) { - return rayCast(boat, 100); - } else return false; - } - - @Override - public void onCollisionEnter(Collision e) { - System.out.println(e.getBearing().degrees()); - } } diff --git a/racevisionGame/src/main/java/mock/model/collider/Collider.java b/racevisionGame/src/main/java/mock/model/collider/Collider.java index c7a2fa51..967af804 100644 --- a/racevisionGame/src/main/java/mock/model/collider/Collider.java +++ b/racevisionGame/src/main/java/mock/model/collider/Collider.java @@ -1,29 +1,43 @@ package mock.model.collider; -import mock.model.MockBoat; +import shared.model.Bearing; +import shared.model.Boat; +import shared.model.GPSCoordinate; +import shared.model.Locatable; /** * Interface for all objects sensitive to collision in a race. */ -public interface Collider { +public abstract class Collider implements Locatable { /** * Indicates whether a ray cast from a boat to a target collider is within the specified length. * @param boat potentially colliding with target * @param distance distance for valid collision * @return whether or not a collision has occurred */ - boolean rayCast(MockBoat boat, double distance); + public boolean rayCast(Boat boat, double distance) { + double actualDistance = GPSCoordinate.calculateDistanceMeters(boat.getPosition(), this.getPosition()); + // Compass direction of collider + Bearing absolute = Bearing.fromAzimuth(GPSCoordinate.calculateAzimuth(boat.getPosition(), this.getPosition())); + // Direction of collider from heading + Bearing relative = Bearing.fromDegrees(absolute.degrees() - boat.getBearing().degrees()); + + if(actualDistance <= distance) { + onCollisionEnter(new Collision(relative, distance)); + return true; + } else return false; + } /** * Indicates whether a ray cast from a boat to a target collider triggers a collision. Distance is set by the object. * @param boat potentially colliding with target * @return whether or not a collision has occurred */ - boolean rayCast(MockBoat boat); + public abstract boolean rayCast(Boat boat); /** * Handle a collision event * @param e details of collision */ - void onCollisionEnter(Collision e); + public abstract void onCollisionEnter(Collision e); } diff --git a/racevisionGame/src/main/java/mock/model/collider/ColliderRegistry.java b/racevisionGame/src/main/java/mock/model/collider/ColliderRegistry.java index 7127b75c..efc0caa5 100644 --- a/racevisionGame/src/main/java/mock/model/collider/ColliderRegistry.java +++ b/racevisionGame/src/main/java/mock/model/collider/ColliderRegistry.java @@ -1,6 +1,7 @@ package mock.model.collider; -import mock.model.MockBoat; +import shared.model.Boat; +import shared.model.GPSCoordinate; import java.util.ArrayList; import java.util.Collection; @@ -9,7 +10,7 @@ import java.util.List; /** * Registry for all Collider objects in a MockRace. Wraps the Collider interface as part of a Composite Pattern. */ -public class ColliderRegistry implements Collider { +public class ColliderRegistry extends Collider { /** * List of all registered Colliders */ @@ -26,21 +27,12 @@ public class ColliderRegistry implements Collider { colliders.add(collider); } - public void removeCollider(Collider collider) { - colliders.remove(collider); - } - public void addAllColliders(Collection colliders) { for(Collider collider: colliders) addCollider(collider); } @Override - public boolean rayCast(MockBoat boat, double distance) { - return false; - } - - @Override - public boolean rayCast(MockBoat boat) { + public boolean rayCast(Boat boat) { for(Collider collider: colliders) { if(collider.rayCast(boat)) return true; } @@ -49,4 +41,14 @@ public class ColliderRegistry implements Collider { @Override public void onCollisionEnter(Collision e) {} + + @Override + public GPSCoordinate getPosition() { + return null; + } + + @Override + public void setPosition(GPSCoordinate position) { + + } } diff --git a/racevisionGame/src/main/java/shared/model/Boat.java b/racevisionGame/src/main/java/shared/model/Boat.java index 9d1d0c40..16ec08b9 100644 --- a/racevisionGame/src/main/java/shared/model/Boat.java +++ b/racevisionGame/src/main/java/shared/model/Boat.java @@ -2,6 +2,8 @@ package shared.model; import javafx.beans.property.*; +import mock.model.collider.Collider; +import mock.model.collider.Collision; import network.Messages.Enums.BoatStatusEnum; import org.jetbrains.annotations.Nullable; @@ -10,7 +12,7 @@ import java.time.ZonedDateTime; /** * Boat Model that is used to store information on the boats that are running in the race. */ -public class Boat implements Locatable { +public class Boat extends Collider { /** * The name of the boat/team. */ @@ -390,4 +392,15 @@ public class Boat implements Locatable { this.timeAtLastMark = timeAtLastMark; } + @Override + public boolean rayCast(Boat boat) { + if(boat != this) { + return rayCast(boat, 100); + } else return false; + } + + @Override + public void onCollisionEnter(Collision e) { + System.out.println(e.getBearing().degrees()); + } } diff --git a/racevisionGame/src/main/java/shared/model/Mark.java b/racevisionGame/src/main/java/shared/model/Mark.java index 1dddeea8..149713be 100644 --- a/racevisionGame/src/main/java/shared/model/Mark.java +++ b/racevisionGame/src/main/java/shared/model/Mark.java @@ -1,6 +1,5 @@ package shared.model; -import mock.model.MockBoat; import mock.model.collider.Collider; import mock.model.collider.Collision; @@ -8,7 +7,7 @@ import mock.model.collider.Collision; * Represents an individual mark. * Has a source ID, name, and position. */ -public class Mark implements Locatable, Collider { +public class Mark extends Collider { /** * The source ID of the mark. @@ -81,21 +80,7 @@ public class Mark implements Locatable, Collider { } @Override - public boolean rayCast(MockBoat boat, double distance) { - double actualDistance = GPSCoordinate.calculateDistanceMeters(boat.getPosition(), this.position); - // Compass direction of collider - Bearing absolute = Bearing.fromAzimuth(GPSCoordinate.calculateAzimuth(boat.getPosition(), this.position)); - // Direction of collider from heading - Bearing relative = Bearing.fromDegrees(absolute.degrees() - boat.getBearing().degrees()); - - if(actualDistance <= distance) { - onCollisionEnter(new Collision(relative, distance)); - return true; - } else return false; - } - - @Override - public boolean rayCast(MockBoat boat) { + public boolean rayCast(Boat boat) { return rayCast(boat, 100); } diff --git a/racevisionGame/src/test/java/mock/model/MockBoatTest.java b/racevisionGame/src/test/java/mock/model/MockBoatTest.java index dcc17f1b..8d1f45ee 100644 --- a/racevisionGame/src/test/java/mock/model/MockBoatTest.java +++ b/racevisionGame/src/test/java/mock/model/MockBoatTest.java @@ -3,7 +3,6 @@ package mock.model; import org.junit.Before; import org.junit.Test; import shared.model.Bearing; -import shared.model.CompoundMark; import shared.model.GPSCoordinate; import shared.model.Mark; From 8113867576305010edcfd3418cf9fd8b70188f8a Mon Sep 17 00:00:00 2001 From: cbt24 Date: Wed, 16 Aug 2017 16:56:20 +1200 Subject: [PATCH 09/14] Bubbles collision events to RaceLogic - ColliderRegistry collects and forwards all Collision events - RaceLogic observes the ColliderRegistry of its single Race instance #story[1100] --- .../src/main/java/mock/model/RaceLogic.java | 19 +++++++++++++++++- .../java/mock/model/collider/Collider.java | 12 +++++++++-- .../mock/model/collider/ColliderRegistry.java | 20 +++++++++++++++---- .../src/main/java/shared/model/Boat.java | 1 - .../src/main/java/shared/model/Mark.java | 4 ---- 5 files changed, 44 insertions(+), 12 deletions(-) diff --git a/racevisionGame/src/main/java/mock/model/RaceLogic.java b/racevisionGame/src/main/java/mock/model/RaceLogic.java index 7c2e6dd3..a3560bbd 100644 --- a/racevisionGame/src/main/java/mock/model/RaceLogic.java +++ b/racevisionGame/src/main/java/mock/model/RaceLogic.java @@ -1,6 +1,8 @@ package mock.model; import javafx.animation.AnimationTimer; +import mock.model.collider.Collision; +import mock.model.commandFactory.Command; import mock.model.commandFactory.CompositeCommand; import mock.model.commandFactory.CommandFactory; import network.Messages.Enums.BoatActionEnum; @@ -9,8 +11,11 @@ import network.Messages.Enums.RaceStatusEnum; import network.Messages.LatestMessages; import shared.model.RunnableWithFramePeriod; +import java.util.Observable; +import java.util.Observer; -public class RaceLogic implements RunnableWithFramePeriod { + +public class RaceLogic implements RunnableWithFramePeriod, Observer { /** * State of current race modified by this object */ @@ -32,6 +37,8 @@ public class RaceLogic implements RunnableWithFramePeriod { this.race = race; this.server = new RaceServer(race, messages); this.commands = compositeCommand; + + race.getColliderRegistry().addObserver(this); } /** @@ -168,4 +175,14 @@ public class RaceLogic implements RunnableWithFramePeriod { public MockRace getRace() { return race; } + + @Override + public void update(Observable o, Object arg) { + Collision e = (Collision)arg; + + if(e.getBearing().degrees() == 0) System.out.println("Ahead"); + 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"); + } } diff --git a/racevisionGame/src/main/java/mock/model/collider/Collider.java b/racevisionGame/src/main/java/mock/model/collider/Collider.java index 967af804..32fb25eb 100644 --- a/racevisionGame/src/main/java/mock/model/collider/Collider.java +++ b/racevisionGame/src/main/java/mock/model/collider/Collider.java @@ -5,10 +5,12 @@ import shared.model.Boat; import shared.model.GPSCoordinate; import shared.model.Locatable; +import java.util.Observable; + /** * Interface for all objects sensitive to collision in a race. */ -public abstract class Collider implements Locatable { +public abstract class Collider extends Observable implements Locatable { /** * Indicates whether a ray cast from a boat to a target collider is within the specified length. * @param boat potentially colliding with target @@ -23,7 +25,13 @@ public abstract class Collider implements Locatable { Bearing relative = Bearing.fromDegrees(absolute.degrees() - boat.getBearing().degrees()); if(actualDistance <= distance) { - onCollisionEnter(new Collision(relative, distance)); + Collision collision = new Collision(relative, distance); + // Notify object of collision + onCollisionEnter(collision); + // Notify observers of collision + notifyObservers(collision); + this.setChanged(); + return true; } else return false; } diff --git a/racevisionGame/src/main/java/mock/model/collider/ColliderRegistry.java b/racevisionGame/src/main/java/mock/model/collider/ColliderRegistry.java index efc0caa5..746b9fa4 100644 --- a/racevisionGame/src/main/java/mock/model/collider/ColliderRegistry.java +++ b/racevisionGame/src/main/java/mock/model/collider/ColliderRegistry.java @@ -3,14 +3,12 @@ package mock.model.collider; import shared.model.Boat; import shared.model.GPSCoordinate; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; +import java.util.*; /** * Registry for all Collider objects in a MockRace. Wraps the Collider interface as part of a Composite Pattern. */ -public class ColliderRegistry extends Collider { +public class ColliderRegistry extends Collider implements Observer { /** * List of all registered Colliders */ @@ -24,6 +22,7 @@ public class ColliderRegistry extends Collider { } public void addCollider(Collider collider) { + collider.addObserver(this); colliders.add(collider); } @@ -51,4 +50,17 @@ public class ColliderRegistry extends Collider { public void setPosition(GPSCoordinate position) { } + + /** + * Fire onCollisionEnter when collision bubbles up from registered colliders. + * @param o object collided with + * @param arg parameters of the collision + */ + @Override + public void update(Observable o, Object arg) { + Collision collision = (Collision)arg; + + notifyObservers(collision); + this.setChanged(); + } } diff --git a/racevisionGame/src/main/java/shared/model/Boat.java b/racevisionGame/src/main/java/shared/model/Boat.java index 16ec08b9..7aff1222 100644 --- a/racevisionGame/src/main/java/shared/model/Boat.java +++ b/racevisionGame/src/main/java/shared/model/Boat.java @@ -401,6 +401,5 @@ public class Boat extends Collider { @Override public void onCollisionEnter(Collision e) { - System.out.println(e.getBearing().degrees()); } } diff --git a/racevisionGame/src/main/java/shared/model/Mark.java b/racevisionGame/src/main/java/shared/model/Mark.java index 149713be..aa123aff 100644 --- a/racevisionGame/src/main/java/shared/model/Mark.java +++ b/racevisionGame/src/main/java/shared/model/Mark.java @@ -86,9 +86,5 @@ public class Mark extends Collider { @Override public void onCollisionEnter(Collision e) { - if(e.getBearing().degrees() == 0) System.out.println("Ahead"); - 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"); } } From eaa0d2e82bf4f073cfbf0cfb0ff5f8d746390fa8 Mon Sep 17 00:00:00 2001 From: cbt24 Date: Wed, 16 Aug 2017 17:22:08 +1200 Subject: [PATCH 10/14] Boats bounce away from marks. - Changed onCollisionEnter signature to pass boat info #story[1100] --- .../src/main/java/mock/model/collider/Collider.java | 5 +++-- .../java/mock/model/collider/ColliderRegistry.java | 2 +- racevisionGame/src/main/java/shared/model/Boat.java | 2 +- racevisionGame/src/main/java/shared/model/Mark.java | 10 ++++++++-- 4 files changed, 13 insertions(+), 6 deletions(-) diff --git a/racevisionGame/src/main/java/mock/model/collider/Collider.java b/racevisionGame/src/main/java/mock/model/collider/Collider.java index 32fb25eb..93a2a7e0 100644 --- a/racevisionGame/src/main/java/mock/model/collider/Collider.java +++ b/racevisionGame/src/main/java/mock/model/collider/Collider.java @@ -27,7 +27,7 @@ public abstract class Collider extends Observable implements Locatable { if(actualDistance <= distance) { Collision collision = new Collision(relative, distance); // Notify object of collision - onCollisionEnter(collision); + onCollisionEnter(boat, collision); // Notify observers of collision notifyObservers(collision); this.setChanged(); @@ -45,7 +45,8 @@ public abstract class Collider extends Observable implements Locatable { /** * Handle a collision event + * @param collider * @param e details of collision */ - public abstract void onCollisionEnter(Collision e); + public abstract void onCollisionEnter(Boat collider, Collision e); } diff --git a/racevisionGame/src/main/java/mock/model/collider/ColliderRegistry.java b/racevisionGame/src/main/java/mock/model/collider/ColliderRegistry.java index 746b9fa4..69eac91a 100644 --- a/racevisionGame/src/main/java/mock/model/collider/ColliderRegistry.java +++ b/racevisionGame/src/main/java/mock/model/collider/ColliderRegistry.java @@ -39,7 +39,7 @@ public class ColliderRegistry extends Collider implements Observer { } @Override - public void onCollisionEnter(Collision e) {} + public void onCollisionEnter(Boat collider, Collision e) {} @Override public GPSCoordinate getPosition() { diff --git a/racevisionGame/src/main/java/shared/model/Boat.java b/racevisionGame/src/main/java/shared/model/Boat.java index 7aff1222..38128f4b 100644 --- a/racevisionGame/src/main/java/shared/model/Boat.java +++ b/racevisionGame/src/main/java/shared/model/Boat.java @@ -400,6 +400,6 @@ public class Boat extends Collider { } @Override - public void onCollisionEnter(Collision e) { + public void onCollisionEnter(Boat collider, Collision e) { } } diff --git a/racevisionGame/src/main/java/shared/model/Mark.java b/racevisionGame/src/main/java/shared/model/Mark.java index aa123aff..fcf76521 100644 --- a/racevisionGame/src/main/java/shared/model/Mark.java +++ b/racevisionGame/src/main/java/shared/model/Mark.java @@ -24,6 +24,10 @@ public class Mark extends Collider { */ private GPSCoordinate position; + /** + * Repulsion radius of the mark + */ + private double repulsionRadius = 50; /** * Constructs a mark with a given source ID, name, and position. @@ -81,10 +85,12 @@ public class Mark extends Collider { @Override public boolean rayCast(Boat boat) { - return rayCast(boat, 100); + return rayCast(boat, repulsionRadius); } @Override - public void onCollisionEnter(Collision e) { + public void onCollisionEnter(Boat collider, Collision e) { + Azimuth reverseAzimuth = Azimuth.fromDegrees(collider.getBearing().degrees() - 180d); + collider.setPosition(GPSCoordinate.calculateNewPosition(collider.getPosition(), 2 * repulsionRadius, reverseAzimuth)); } } From f7d0e9d46648cf73847acf12535476b67c705079 Mon Sep 17 00:00:00 2001 From: cbt24 Date: Wed, 16 Aug 2017 17:55:33 +1200 Subject: [PATCH 11/14] Boats bounce during collision if pointing into collision #story[1100] --- racevisionGame/src/main/java/shared/model/Boat.java | 8 ++++++++ racevisionGame/src/main/java/shared/model/Mark.java | 3 +-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/racevisionGame/src/main/java/shared/model/Boat.java b/racevisionGame/src/main/java/shared/model/Boat.java index 38128f4b..7d86afbf 100644 --- a/racevisionGame/src/main/java/shared/model/Boat.java +++ b/racevisionGame/src/main/java/shared/model/Boat.java @@ -392,6 +392,11 @@ public class Boat extends Collider { this.timeAtLastMark = timeAtLastMark; } + public void bounce(double repulsionRadius) { + Azimuth reverseAzimuth = Azimuth.fromDegrees(getBearing().degrees() - 180d); + setPosition(GPSCoordinate.calculateNewPosition(getPosition(), 2 * repulsionRadius, reverseAzimuth)); + } + @Override public boolean rayCast(Boat boat) { if(boat != this) { @@ -401,5 +406,8 @@ public class Boat extends Collider { @Override public void onCollisionEnter(Boat collider, Collision e) { + if(e.getBearing().degrees() > 270 || e.getBearing().degrees() < 90) { + collider.bounce(100); + } } } diff --git a/racevisionGame/src/main/java/shared/model/Mark.java b/racevisionGame/src/main/java/shared/model/Mark.java index fcf76521..77a59ede 100644 --- a/racevisionGame/src/main/java/shared/model/Mark.java +++ b/racevisionGame/src/main/java/shared/model/Mark.java @@ -90,7 +90,6 @@ public class Mark extends Collider { @Override public void onCollisionEnter(Boat collider, Collision e) { - Azimuth reverseAzimuth = Azimuth.fromDegrees(collider.getBearing().degrees() - 180d); - collider.setPosition(GPSCoordinate.calculateNewPosition(collider.getPosition(), 2 * repulsionRadius, reverseAzimuth)); + collider.bounce(repulsionRadius); } } From f8150ef449b447e6fbb73e8fffa73a62d927be37 Mon Sep 17 00:00:00 2001 From: Connor Taylor-Brown Date: Thu, 17 Aug 2017 01:10:55 +1200 Subject: [PATCH 12/14] Added YachtEvent message with encoder and decoder - Updated Encoder and Decoder factories for the new message type - Added an enum for handling yacht event types #story[1100] --- .../MessageDecoders/DecoderFactory.java | 2 +- .../YachtEventCodeDecoder.java | 47 +++++++++++++++++ .../MessageEncoders/EncoderFactory.java | 2 +- .../YachtEventCodeEncoder.java | 43 ++++++++++++++++ .../Messages/Enums/YachtEventEnum.java | 24 +++++++++ .../java/network/Messages/YachtEvent.java | 51 +++++++++++++++++++ .../YachtEventCodeDecoderTest.java | 47 +++++++++++++++++ 7 files changed, 214 insertions(+), 2 deletions(-) create mode 100644 racevisionGame/src/main/java/network/MessageDecoders/YachtEventCodeDecoder.java create mode 100644 racevisionGame/src/main/java/network/MessageEncoders/YachtEventCodeEncoder.java create mode 100644 racevisionGame/src/main/java/network/Messages/Enums/YachtEventEnum.java create mode 100644 racevisionGame/src/main/java/network/Messages/YachtEvent.java create mode 100644 racevisionGame/src/test/java/network/MessageDecoders/YachtEventCodeDecoderTest.java diff --git a/racevisionGame/src/main/java/network/MessageDecoders/DecoderFactory.java b/racevisionGame/src/main/java/network/MessageDecoders/DecoderFactory.java index 09ea4b95..24caf97c 100644 --- a/racevisionGame/src/main/java/network/MessageDecoders/DecoderFactory.java +++ b/racevisionGame/src/main/java/network/MessageDecoders/DecoderFactory.java @@ -39,7 +39,7 @@ public class DecoderFactory { case RACESTARTSTATUS: return new RaceStartStatusDecoder(); - //case YACHTEVENTCODE: return new YachtEventCodeDecoder();//TODO + case YACHTEVENTCODE: return new YachtEventCodeDecoder(); //case YACHTACTIONCODE: return new YachtActionCodeDecoder();//TODO diff --git a/racevisionGame/src/main/java/network/MessageDecoders/YachtEventCodeDecoder.java b/racevisionGame/src/main/java/network/MessageDecoders/YachtEventCodeDecoder.java new file mode 100644 index 00000000..fb601c24 --- /dev/null +++ b/racevisionGame/src/main/java/network/MessageDecoders/YachtEventCodeDecoder.java @@ -0,0 +1,47 @@ +package network.MessageDecoders; + +import network.Exceptions.InvalidMessageException; +import network.Messages.AC35Data; +import network.Messages.Enums.YachtEventEnum; +import network.Messages.YachtEvent; + +import java.util.Arrays; + +import static network.Utils.ByteConverter.bytesToInt; +import static network.Utils.ByteConverter.bytesToLong; +import static network.Utils.ByteConverter.bytesToShort; + +/** + * Decodes {@link YachtEvent} messages. + */ +public class YachtEventCodeDecoder implements MessageDecoder { + private YachtEvent message; + + @Override + public AC35Data decode(byte[] encodedMessage) throws InvalidMessageException { + // Deserialise message + byte[] timestamp = Arrays.copyOfRange(encodedMessage, 1, 7); + byte[] ackNum = Arrays.copyOfRange(encodedMessage, 7, 9); + byte[] raceID = Arrays.copyOfRange(encodedMessage, 9, 13); + byte[] sourceID = Arrays.copyOfRange(encodedMessage, 13, 17); + byte[] incidentID = Arrays.copyOfRange(encodedMessage, 17, 21); + byte eventID = encodedMessage[21]; + + // Unpack bytes into YachtEvent + this.message = new YachtEvent( + bytesToLong(timestamp), + bytesToShort(ackNum), + bytesToInt(raceID), + bytesToInt(sourceID), + bytesToInt(incidentID), + YachtEventEnum.fromByte(eventID) + ); + + // Return YachtEvent + return message; + } + + public YachtEvent getMessage() { + return message; + } +} diff --git a/racevisionGame/src/main/java/network/MessageEncoders/EncoderFactory.java b/racevisionGame/src/main/java/network/MessageEncoders/EncoderFactory.java index b59150e4..d274f435 100644 --- a/racevisionGame/src/main/java/network/MessageEncoders/EncoderFactory.java +++ b/racevisionGame/src/main/java/network/MessageEncoders/EncoderFactory.java @@ -39,7 +39,7 @@ public class EncoderFactory { case RACESTARTSTATUS: return new RaceStartStatusEncoder(); - //case YACHTEVENTCODE: return new YachtEventCodeEncoder();//TODO + case YACHTEVENTCODE: return new YachtEventCodeEncoder(); //case YACHTACTIONCODE: return new YachtActionCodeEncoder();//TODO diff --git a/racevisionGame/src/main/java/network/MessageEncoders/YachtEventCodeEncoder.java b/racevisionGame/src/main/java/network/MessageEncoders/YachtEventCodeEncoder.java new file mode 100644 index 00000000..505761f1 --- /dev/null +++ b/racevisionGame/src/main/java/network/MessageEncoders/YachtEventCodeEncoder.java @@ -0,0 +1,43 @@ +package network.MessageEncoders; + +import network.Exceptions.InvalidMessageException; +import network.Messages.AC35Data; +import network.Messages.YachtEvent; + +import java.nio.ByteBuffer; + +import static network.Utils.ByteConverter.intToBytes; +import static network.Utils.ByteConverter.longToBytes; + +/** + * Encodes a {@link YachtEvent} message. + */ +public class YachtEventCodeEncoder implements MessageEncoder { + @Override + public byte[] encode(AC35Data message) throws InvalidMessageException { + // Downcast message + YachtEvent yachtEvent = (YachtEvent)message; + + // Serialise message + byte messageVersion = 0b10; + byte[] timestamp = longToBytes(yachtEvent.getCurrentTime(), 6); + byte[] ackNum = intToBytes(yachtEvent.getAckNum(), 2); + byte[] raceID = intToBytes(yachtEvent.getRaceID()); + byte[] sourceID = intToBytes(yachtEvent.getSourceID()); + byte[] incidentID = intToBytes(yachtEvent.getIncidentID()); + byte eventID = yachtEvent.getYachtEvent().getValue(); + + // Pack bytes into string + ByteBuffer yachtEventMessage = ByteBuffer.allocate(22); + yachtEventMessage.put(messageVersion); + yachtEventMessage.put(timestamp); + yachtEventMessage.put(ackNum); + yachtEventMessage.put(raceID); + yachtEventMessage.put(sourceID); + yachtEventMessage.put(incidentID); + yachtEventMessage.put(eventID); + + // Return byte string + return yachtEventMessage.array(); + } +} diff --git a/racevisionGame/src/main/java/network/Messages/Enums/YachtEventEnum.java b/racevisionGame/src/main/java/network/Messages/Enums/YachtEventEnum.java new file mode 100644 index 00000000..73be05b5 --- /dev/null +++ b/racevisionGame/src/main/java/network/Messages/Enums/YachtEventEnum.java @@ -0,0 +1,24 @@ +package network.Messages.Enums; + +/** + * Yacht event codes + */ +public enum YachtEventEnum { + NOT_AN_EVENT(-1), + COLLISION(1); + + private byte value; + + YachtEventEnum(int value) { this.value = (byte)value; } + + public byte getValue() { + return value; + } + + public static YachtEventEnum fromByte(byte value) { + switch(value) { + case 1: return COLLISION; + default: return NOT_AN_EVENT; + } + } +} diff --git a/racevisionGame/src/main/java/network/Messages/YachtEvent.java b/racevisionGame/src/main/java/network/Messages/YachtEvent.java new file mode 100644 index 00000000..db2ff931 --- /dev/null +++ b/racevisionGame/src/main/java/network/Messages/YachtEvent.java @@ -0,0 +1,51 @@ +package network.Messages; + +import network.Messages.Enums.MessageType; +import network.Messages.Enums.YachtEventEnum; + +/** + * Represents a Yacht Event Code message defined in the AC35 spec, with Event IDs amended for the purposes of + * a game. + */ +public class YachtEvent extends AC35Data { + private long currentTime; + private int ackNum; + private int raceID; + private int sourceID; + private int incidentID; + private YachtEventEnum yachtEvent; + + public YachtEvent(long currentTime, int ackNum, int raceID, int sourceID, int incidentID, YachtEventEnum yachtEvent) { + super(MessageType.YACHTEVENTCODE); + this.currentTime = currentTime; + this.ackNum = ackNum; + this.raceID = raceID; + this.sourceID = sourceID; + this.incidentID = incidentID; + this.yachtEvent = yachtEvent; + } + + public YachtEventEnum getYachtEvent() { + return yachtEvent; + } + + public int getSourceID() { + return sourceID; + } + + public int getIncidentID() { + return incidentID; + } + + public long getCurrentTime() { + return currentTime; + } + + public int getAckNum() { + return ackNum; + } + + public int getRaceID() { + return raceID; + } +} diff --git a/racevisionGame/src/test/java/network/MessageDecoders/YachtEventCodeDecoderTest.java b/racevisionGame/src/test/java/network/MessageDecoders/YachtEventCodeDecoderTest.java new file mode 100644 index 00000000..3f3aadac --- /dev/null +++ b/racevisionGame/src/test/java/network/MessageDecoders/YachtEventCodeDecoderTest.java @@ -0,0 +1,47 @@ +package network.MessageDecoders; + +import network.MessageEncoders.RaceVisionByteEncoder; +import network.Messages.Enums.YachtEventEnum; +import network.Messages.YachtEvent; +import org.junit.Before; +import org.junit.Test; + +import static org.testng.Assert.*; + +/** + * Tests for the YachtEvent decoder and encoder + */ +public class YachtEventCodeDecoderTest { + private YachtEvent decodedMessage; + private YachtEvent originalMessage; + + @Before + public void setUp() throws Exception { + long timestamp = System.currentTimeMillis(); + + originalMessage = new YachtEvent( + timestamp, + 55, + 35, + 0, + 1, + YachtEventEnum.COLLISION + ); + + byte[] encodedMessage = RaceVisionByteEncoder.encode(originalMessage); + + YachtEventCodeDecoder testDecoder = new YachtEventCodeDecoder(); + testDecoder.decode(encodedMessage); + decodedMessage = testDecoder.getMessage(); + } + + @Test + public void decodingEqualsOriginal() { + assertEquals(originalMessage.getCurrentTime(), decodedMessage.getCurrentTime()); + assertEquals(originalMessage.getAckNum(), decodedMessage.getAckNum()); + assertEquals(originalMessage.getRaceID(), decodedMessage.getRaceID()); + assertEquals(originalMessage.getSourceID(), decodedMessage.getSourceID()); + assertEquals(originalMessage.getIncidentID(), decodedMessage.getIncidentID()); + assertEquals(originalMessage.getYachtEvent(), decodedMessage.getYachtEvent()); + } +} \ No newline at end of file From 4b3cc8e126dc12b188ca7af8600a0ca02d4484fe Mon Sep 17 00:00:00 2001 From: Connor Taylor-Brown Date: Thu, 17 Aug 2017 11:47:54 +1200 Subject: [PATCH 13/14] Created ack number generator for use by multiple services #story[1100] --- .../java/mock/app/ConnectionAcceptor.java | 19 ++--------------- .../src/main/java/mock/model/RaceServer.java | 1 - .../src/main/java/network/AckSequencer.java | 21 +++++++++++++++++++ 3 files changed, 23 insertions(+), 18 deletions(-) create mode 100644 racevisionGame/src/main/java/network/AckSequencer.java diff --git a/racevisionGame/src/main/java/mock/app/ConnectionAcceptor.java b/racevisionGame/src/main/java/mock/app/ConnectionAcceptor.java index d399210d..da5c50f8 100644 --- a/racevisionGame/src/main/java/mock/app/ConnectionAcceptor.java +++ b/racevisionGame/src/main/java/mock/app/ConnectionAcceptor.java @@ -4,6 +4,7 @@ import mock.model.RaceLogic; import mock.model.ClientConnection; import mock.model.SourceIdAllocator; import mock.model.commandFactory.CompositeCommand; +import network.AckSequencer; import network.Messages.Enums.XMLMessageType; import network.Messages.LatestMessages; import network.Messages.XMLMessage; @@ -58,11 +59,6 @@ public class ConnectionAcceptor implements Runnable { */ private SourceIdAllocator sourceIdAllocator; - - - - //Acknowledgement number for packets - private int ackNumber = 0; //race xml sequence number private short raceXMLSequenceNumber; //boat xml sequence number @@ -263,7 +259,7 @@ public class ConnectionAcceptor implements Runnable { //Create the message. XMLMessage message = new XMLMessage( XMLMessage.currentVersionNumber, - getNextAckNumber(), + AckSequencer.getNextAckNum(), System.currentTimeMillis(), messageType, sequenceNumber, @@ -272,15 +268,4 @@ public class ConnectionAcceptor implements Runnable { return message; } - - /** - * Increments the ackNumber value, and returns it. - * @return Incremented ackNumber. - */ - private int getNextAckNumber(){ - this.ackNumber++; - - return this.ackNumber; - } - } diff --git a/racevisionGame/src/main/java/mock/model/RaceServer.java b/racevisionGame/src/main/java/mock/model/RaceServer.java index af343666..cbbe1971 100644 --- a/racevisionGame/src/main/java/mock/model/RaceServer.java +++ b/racevisionGame/src/main/java/mock/model/RaceServer.java @@ -28,7 +28,6 @@ public class RaceServer { this.latestMessages = latestMessages; } - /** * Parses the race to create a snapshot, and places it in latestMessages. */ diff --git a/racevisionGame/src/main/java/network/AckSequencer.java b/racevisionGame/src/main/java/network/AckSequencer.java new file mode 100644 index 00000000..bed59664 --- /dev/null +++ b/racevisionGame/src/main/java/network/AckSequencer.java @@ -0,0 +1,21 @@ +package network; + +import java.util.concurrent.atomic.AtomicInteger; + +/** + * Common source of ack numbers for all messages + */ +public class AckSequencer { + /** + * Generator for ack numbers + */ + private static AtomicInteger ackNum = new AtomicInteger(0); + + /** + * Retrieve next ack number + * @return next ack number + */ + public static int getNextAckNum() { + return ackNum.getAndIncrement(); + } +} From 86d94ef27e8f1693adf4f5c8b40feb7ef1a2d8e5 Mon Sep 17 00:00:00 2001 From: hwball Date: Thu, 17 Aug 2017 11:58:13 +1200 Subject: [PATCH 14/14] javadoc fix --- racevisionGame/src/main/java/mock/model/collider/Collider.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/racevisionGame/src/main/java/mock/model/collider/Collider.java b/racevisionGame/src/main/java/mock/model/collider/Collider.java index 93a2a7e0..029fee57 100644 --- a/racevisionGame/src/main/java/mock/model/collider/Collider.java +++ b/racevisionGame/src/main/java/mock/model/collider/Collider.java @@ -45,7 +45,7 @@ public abstract class Collider extends Observable implements Locatable { /** * Handle a collision event - * @param collider + * @param collider Boat that is colliding * @param e details of collision */ public abstract void onCollisionEnter(Boat collider, Collision e);