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/MockBoat.java b/racevisionGame/src/main/java/mock/model/MockBoat.java index f15ec2f2..b6cd7a24 100644 --- a/racevisionGame/src/main/java/mock/model/MockBoat.java +++ b/racevisionGame/src/main/java/mock/model/MockBoat.java @@ -1,6 +1,5 @@ package mock.model; - import shared.model.*; @@ -74,7 +73,7 @@ public class MockBoat extends Boat { 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 @@ -87,7 +86,6 @@ public class MockBoat extends Boat { //Calculate bearing. Bearing bearing = GPSCoordinate.calculateBearing(currentPosition, nextMarkerPosition); - return bearing; } @@ -100,7 +98,7 @@ public class MockBoat extends Boat { 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) { @@ -111,9 +109,7 @@ public class MockBoat extends Boat { //Calculate distance. - double distanceNauticalMiles = GPSCoordinate.calculateDistanceNauticalMiles(startPosition, endMarker); - - return distanceNauticalMiles; + return GPSCoordinate.calculateDistanceNauticalMiles(startPosition, endMarker); } @@ -160,8 +156,8 @@ public class MockBoat extends Boat { */ 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); } @@ -219,7 +215,7 @@ public class MockBoat extends Boat { * @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; @@ -245,7 +241,7 @@ public class MockBoat extends Boat { */ 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); @@ -297,12 +293,11 @@ public class MockBoat extends Boat { this.roundingStatus = 0; } + public boolean getAutoVMG(){ + return autoVMG; + } public void setAutoVMG(boolean autoVMG) { this.autoVMG = autoVMG; } - - 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 3879e3fc..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; @@ -29,8 +28,6 @@ public class MockRace extends Race { */ private List boats; - - /** * A copy of the boundary list, except "shrunk" inwards by 50m. */ @@ -72,6 +69,8 @@ public class MockRace extends Race { //Wind. this.setWind(windGenerator.generateBaselineWind()); + + this.colliderRegistry.addAllColliders(boats); } /** @@ -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/RaceLogic.java b/racevisionGame/src/main/java/mock/model/RaceLogic.java index 418ade17..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); } /** @@ -116,7 +123,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); } } @@ -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/RaceServer.java b/racevisionGame/src/main/java/mock/model/RaceServer.java index 969a4c71..cbbe1971 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; @@ -30,7 +28,6 @@ public class RaceServer { this.latestMessages = latestMessages; } - /** * Parses the race to create a snapshot, and places it in latestMessages. */ @@ -127,8 +124,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/collider/Collider.java b/racevisionGame/src/main/java/mock/model/collider/Collider.java new file mode 100644 index 00000000..029fee57 --- /dev/null +++ b/racevisionGame/src/main/java/mock/model/collider/Collider.java @@ -0,0 +1,52 @@ +package mock.model.collider; + +import shared.model.Bearing; +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 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 + * @param distance distance for valid collision + * @return whether or not a collision has occurred + */ + 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) { + Collision collision = new Collision(relative, distance); + // Notify object of collision + onCollisionEnter(boat, collision); + // Notify observers of collision + notifyObservers(collision); + this.setChanged(); + + 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 + */ + public abstract boolean rayCast(Boat boat); + + /** + * Handle a collision event + * @param collider Boat that is colliding + * @param e details of collision + */ + 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 new file mode 100644 index 00000000..69eac91a --- /dev/null +++ b/racevisionGame/src/main/java/mock/model/collider/ColliderRegistry.java @@ -0,0 +1,66 @@ +package mock.model.collider; + +import shared.model.Boat; +import shared.model.GPSCoordinate; + +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 implements Observer { + /** + * List of all registered Colliders + */ + private List colliders; + + /** + * Default constructor for ColliderRegistry + */ + public ColliderRegistry() { + this.colliders = new ArrayList<>(); + } + + public void addCollider(Collider collider) { + collider.addObserver(this); + colliders.add(collider); + } + + public void addAllColliders(Collection colliders) { + for(Collider collider: colliders) addCollider(collider); + } + + @Override + public boolean rayCast(Boat boat) { + for(Collider collider: colliders) { + if(collider.rayCast(boat)) return true; + } + return false; + } + + @Override + public void onCollisionEnter(Boat collider, Collision e) {} + + @Override + public GPSCoordinate getPosition() { + return null; + } + + @Override + 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/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; + } +} 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(); + } +} 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/main/java/shared/model/Boat.java b/racevisionGame/src/main/java/shared/model/Boat.java index 385c4f3b..7d86afbf 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 { +public class Boat extends Collider { /** * The name of the boat/team. */ @@ -30,7 +32,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 +59,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 +109,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 +258,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; } @@ -399,4 +392,22 @@ public class Boat { 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) { + return rayCast(boat, 100); + } else return false; + } + + @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/CompoundMark.java b/racevisionGame/src/main/java/shared/model/CompoundMark.java index 12d88cfc..cabf3a02 100644 --- a/racevisionGame/src/main/java/shared/model/CompoundMark.java +++ b/racevisionGame/src/main/java/shared/model/CompoundMark.java @@ -1,6 +1,5 @@ package shared.model; - import shared.enums.RoundingType; /** @@ -117,7 +116,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(); } @@ -135,13 +134,6 @@ 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()); 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..77a59ede 100644 --- a/racevisionGame/src/main/java/shared/model/Mark.java +++ b/racevisionGame/src/main/java/shared/model/Mark.java @@ -1,10 +1,13 @@ package shared.model; +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 extends Collider { /** * The source ID of the mark. @@ -21,6 +24,10 @@ public class Mark { */ private GPSCoordinate position; + /** + * Repulsion radius of the mark + */ + private double repulsionRadius = 50; /** * Constructs a mark with a given source ID, name, and position. @@ -75,4 +82,14 @@ public class Mark { public void setPosition(GPSCoordinate position) { this.position = position; } + + @Override + public boolean rayCast(Boat boat) { + return rayCast(boat, repulsionRadius); + } + + @Override + public void onCollisionEnter(Boat collider, Collision e) { + collider.bounce(repulsionRadius); + } } diff --git a/racevisionGame/src/main/java/shared/model/Race.java b/racevisionGame/src/main/java/shared/model/Race.java index b8902d84..a15e2edd 100644 --- a/racevisionGame/src/main/java/shared/model/Race.java +++ b/racevisionGame/src/main/java/shared/model/Race.java @@ -4,108 +4,87 @@ import javafx.beans.property.IntegerProperty; import javafx.beans.property.Property; import javafx.beans.property.SimpleIntegerProperty; import javafx.beans.property.SimpleObjectProperty; +import mock.model.collider.ColliderRegistry; import network.Messages.Enums.RaceStatusEnum; import network.Messages.Enums.RaceTypeEnum; import shared.dataInput.BoatDataSource; import shared.dataInput.RaceDataSource; import shared.dataInput.RegattaDataSource; -import visualiser.model.VisualiserRaceEvent; import java.util.List; /** * Represents a yacht race. - * This is a base class inherited by {@link mock.model.MockRace} and {@link VisualiserRaceEvent}. * Has a course, state, wind, boundaries, etc.... Boats are added by inheriting classes (see {@link Boat}, {@link mock.model.MockBoat}, {@link visualiser.model.VisualiserBoat}. */ public abstract class Race { - - /** * The source of race related data. */ protected RaceDataSource raceDataSource; - /** * The source of boat related data. */ protected BoatDataSource boatDataSource; - /** * The source of regatta related data. */ protected RegattaDataSource regattaDataSource; - - /** * A list of compound marks in the race. */ protected List 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. + * We essentially track the number of frames generated per second, over a one second period. When {@link #lastFpsResetTime} reaches 1 second, currentFps is reset. */ private int currentFps = 0; - /** * The number of frames per second we generated over the last 1 second period. */ private IntegerProperty lastFps = new SimpleIntegerProperty(0); - /** * The time, in milliseconds, since we last reset our {@link #currentFps} counter. */ private long lastFpsResetTime; - - /** * Constructs a race object with a given BoatDataSource, RaceDataSource, and RegattaDataSource. * @param boatDataSource Data source for boat related data (yachts and marker boats). @@ -119,39 +98,36 @@ public abstract class Race { this.boatDataSource = boatDataSource; this.regattaDataSource = regattaDataSource; - - //Marks. this.compoundMarks = raceDataSource.getCompoundMarks(); - //Boundaries. this.boundary = raceDataSource.getBoundary(); - - //Legs. this.useLegsList(raceDataSource.getLegs()); - - //Race ID. this.raceId = raceDataSource.getRaceId(); - //Regatta name. this.regattaName = regattaDataSource.getRegattaName(); - //Race clock. this.raceClock = new RaceClock(this.raceDataSource.getStartDateTime()); - //Race status. this.setRaceStatusEnum(RaceStatusEnum.NOT_ACTIVE); //Race type. this.raceType = raceDataSource.getRaceType(); - //Wind. this.setWind(Bearing.fromDegrees(0), 0); + // Set up colliders + this.colliderRegistry = new ColliderRegistry(); + for(CompoundMark mark: compoundMarks) { + colliderRegistry.addCollider(mark.getMark1()); + if(mark.getMark2() != null) colliderRegistry.addCollider(mark.getMark2()); + } } - + public ColliderRegistry getColliderRegistry() { + return colliderRegistry; + } /** * Initialise the boats in the race. @@ -159,7 +135,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. @@ -191,10 +166,6 @@ public abstract class Race { return legID == lastLegID; } - - - - /** * Returns the current race status. * @return The current race status. @@ -211,7 +182,6 @@ public abstract class Race { this.raceStatusEnum = raceStatusEnum; } - /** * Returns the type of race this is. * @return The type of race this is. @@ -228,13 +198,12 @@ public abstract class Race { return regattaName; } - /** * Updates the race to have a specified wind bearing and speed. * @param windBearing New wind bearing. * @param windSpeedKnots New wind speed, in knots. */ - public void setWind(Bearing windBearing, double windSpeedKnots) { + protected void setWind(Bearing windBearing, double windSpeedKnots) { Wind wind = new Wind(windBearing, windSpeedKnots); setWind(wind); } @@ -243,11 +212,10 @@ public abstract class Race { * Updates the race to have a specified wind (bearing and speed). * @param wind New wind. */ - public void setWind(Wind wind) { + protected void setWind(Wind wind) { this.raceWind.setValue(wind); } - /** * Returns the wind bearing. * @return The wind bearing. @@ -265,14 +233,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. @@ -282,7 +242,6 @@ public abstract class Race { return raceClock; } - /** * Returns the RaceDataSource used for the race. * @return The RaceDataSource used for the race. @@ -300,7 +259,6 @@ public abstract class Race { return legs.size() - 1; } - /** * Returns the race boundary. * @return The race boundary. @@ -326,14 +284,6 @@ public abstract class Race { return legs; } - /** - * Returns the number of frames generated per second. - * @return Frames per second. - */ - public int getFps() { - return lastFps.getValue(); - } - /** * Returns the fps property. * @return The fps property. @@ -342,8 +292,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}. 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 00830c42..f812412e 100644 --- a/racevisionGame/src/main/java/visualiser/model/ResizableRaceCanvas.java +++ b/racevisionGame/src/main/java/visualiser/model/ResizableRaceCanvas.java @@ -272,7 +272,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()), Color.BLACK, @@ -349,7 +349,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 = { @@ -385,7 +385,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 = { @@ -421,7 +421,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()); double lineWidth = 4; diff --git a/racevisionGame/src/main/java/visualiser/model/VisualiserBoat.java b/racevisionGame/src/main/java/visualiser/model/VisualiserBoat.java index 9f0a72e4..6cbfdaa3 100644 --- a/racevisionGame/src/main/java/visualiser/model/VisualiserBoat.java +++ b/racevisionGame/src/main/java/visualiser/model/VisualiserBoat.java @@ -100,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 a1f21844..77db4f7c 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; @@ -249,10 +248,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 489a6c5a..8d1f45ee 100644 --- a/racevisionGame/src/test/java/mock/model/MockBoatTest.java +++ b/racevisionGame/src/test/java/mock/model/MockBoatTest.java @@ -1,174 +1,35 @@ package mock.model; -import mock.dataInput.PolarParser; -import mock.exceptions.InvalidPolarFileException; 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.assertEquals; -import static org.junit.Assert.fail; +import static org.junit.Assert.*; public class MockBoatTest { + private MockBoat boat; + private Mark near; + private Mark far; - /** - * boat made for testing - */ - private MockBoat firstTestBoat; - - private Mark markToTest; - private Mark markToTest2; - - private GPSCoordinate highGPS; - private GPSCoordinate middleGPS; - private GPSCoordinate lowGPS; - - /** - * Creates the Polars object for the tests. - */ @Before public void setUp() { - //Read in polars. - try { - //Parse data file. - Polars polars = PolarParser.parse("mock/polars/acc_polars.csv"); - - firstTestBoat = new MockBoat(1, "test", "NZ", polars); - highGPS = new GPSCoordinate(32.296577, -64.854000); - middleGPS = new GPSCoordinate(32.292500, -64.854000); - lowGPS = new GPSCoordinate(32.290000, -64.854000); - markToTest = new Mark(1, "test MARK", middleGPS); - markToTest2 = new Mark(2, "test MARK2", middleGPS); - } - catch (InvalidPolarFileException e) { - fail("Couldn't parse polar file."); - } - } - - //////////////////////////////Mark Higher//////////////////////////////// - - /** - * Tests if the boat is lower than the mark that the port side method works if - * boat is facing east - */ - @Test - public void testIsPortSide() { - firstTestBoat.setBearing(Bearing.fromDegrees(90)); - firstTestBoat.setCurrentPosition(lowGPS); - markToTest.setPosition(highGPS); - - assertEquals(firstTestBoat.isPortSide(markToTest), true); - } - - /** - * Tests if the boat is lower than the mark that the port side method works if - * boat is facing west - */ - @Test - public void testIsPortSideWrong() { - firstTestBoat.setBearing(Bearing.fromDegrees(270)); - firstTestBoat.setCurrentPosition(lowGPS); - markToTest.setPosition(highGPS); - - assertEquals(firstTestBoat.isPortSide(markToTest), false); - } - - /** - * Tests if the boat is lower than the mark that the starboard side method works if - * boat is facing east - */ - @Test - public void testIsStarboardSideWrong() { - firstTestBoat.setBearing(Bearing.fromDegrees(90)); - firstTestBoat.setCurrentPosition(lowGPS); - markToTest.setPosition(highGPS); - - assertEquals(firstTestBoat.isStarboardSide(markToTest), false); - } - - /** - * Tests if the boat is lower than the mark that the starboard side method works if - * boat is facing west - */ - @Test - public void testIsStarboardSide() { - firstTestBoat.setBearing(Bearing.fromDegrees(270)); - firstTestBoat.setCurrentPosition(lowGPS); - markToTest.setPosition(highGPS); - - assertEquals(firstTestBoat.isStarboardSide(markToTest), true); - } - - - //////////////////////////////Mark Lower//////////////////////////////// + boat = new MockBoat(0, "Bob", "NZ", null); + boat.setPosition(new GPSCoordinate(0,0)); + boat.setBearing(Bearing.fromDegrees(180)); - /** - * Tests if the boat is higher than the mark that the port side method works if - * boat is facing east - */ - @Test - public void testIsPortSideHigherWrong() { - firstTestBoat.setBearing(Bearing.fromDegrees(90)); - firstTestBoat.setCurrentPosition(highGPS); - markToTest.setPosition(lowGPS); - - assertEquals(firstTestBoat.isPortSide(markToTest), false); + near = new Mark(0, "Near", new GPSCoordinate(-.0001, 0)); + far = new Mark(0, "Far", new GPSCoordinate(.001, 0)); } - /** - * Tests if the boat is higher than the mark that the port side method works if - * boat is facing west - */ @Test - public void testIsPortSideHigher() { - firstTestBoat.setBearing(Bearing.fromDegrees(270)); - firstTestBoat.setCurrentPosition(highGPS); - markToTest.setPosition(lowGPS); - - assertEquals(firstTestBoat.isPortSide(markToTest), true); + public void nearMarkWithin100m() { + assertTrue(near.rayCast(boat, 100)); } - /** - * Tests if the boat is higher than the mark that the starboard side method works if - * boat is facing east - */ @Test - public void testIsStarboardSideHigher() { - firstTestBoat.setBearing(Bearing.fromDegrees(90)); - firstTestBoat.setCurrentPosition(highGPS); - markToTest.setPosition(lowGPS); - - assertEquals(firstTestBoat.isStarboardSide(markToTest), true); - } - - /** - * Tests if the boat is higher than the mark that the starboard side method works if - * boat is facing west - */ - @Test - public void testIsStarboardSideHigherWrong() { - firstTestBoat.setBearing(Bearing.fromDegrees(270)); - firstTestBoat.setCurrentPosition(highGPS); - markToTest.setPosition(lowGPS); - - assertEquals(firstTestBoat.isStarboardSide(markToTest), false); - } - - /** - * Tests if a boat is between a gate - */ - @Test - public void testIsBetweenGate(){ - markToTest.setPosition(highGPS); - markToTest2.setPosition(lowGPS); - CompoundMark testGate = new CompoundMark(1, "test GATE", markToTest, markToTest2); - - firstTestBoat.setCurrentPosition(middleGPS); - - assertEquals(firstTestBoat.isBetweenGate(testGate), true); - + public void farMarkBeyond100m() { + assertFalse(far.rayCast(boat, 100)); } } 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 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); }