diff --git a/dedicatedServer/src/main/java/app/App.java b/dedicatedServer/src/main/java/app/App.java index 34ee2c5b..3b36c43e 100644 --- a/dedicatedServer/src/main/java/app/App.java +++ b/dedicatedServer/src/main/java/app/App.java @@ -21,7 +21,7 @@ public class App extends Application { public void start(Stage primaryStage) { try { //TODO should read a configuration file to configure server? - Event raceEvent = new Event(false); + Event raceEvent = new Event(false, 0); } catch (Exception e) { diff --git a/racevisionGame/src/main/java/mock/app/Event.java b/racevisionGame/src/main/java/mock/app/Event.java index 1ff92196..2c9785f1 100644 --- a/racevisionGame/src/main/java/mock/app/Event.java +++ b/racevisionGame/src/main/java/mock/app/Event.java @@ -18,6 +18,7 @@ import shared.exceptions.InvalidRegattaDataException; import shared.exceptions.XMLReaderException; import shared.model.Bearing; import shared.model.Constants; +import shared.xml.XMLUtilities; import javax.xml.bind.JAXBException; import javax.xml.parsers.ParserConfigurationException; @@ -70,6 +71,8 @@ public class Event { private Thread connectionThread; + private int mapIndex; + @@ -79,11 +82,29 @@ public class Event { * @param singlePlayer Whether or not to create a single player event. * @throws EventConstructionException Thrown if we cannot create an Event for any reason. */ - public Event(boolean singlePlayer) throws EventConstructionException { - - String raceXMLFile = "mock/mockXML/raceThreePlayers.xml"; + public Event(boolean singlePlayer, int mapIndex) throws EventConstructionException { + this.mapIndex = mapIndex; + String raceXMLFile; String boatsXMLFile = "mock/mockXML/boatTest.xml"; String regattaXMLFile = "mock/mockXML/regattaTest.xml"; + switch (mapIndex){ + case 0:raceXMLFile = "mock/mockXML/raceSixPlayers.xml"; + break; + case 1:raceXMLFile = "mock/mockXML/oMapLayout.xml"; + break; + case 2: raceXMLFile = "mock/mockXML/iMapLayout.xml"; + break; + case 3: raceXMLFile = "mock/mockXML/mMapLayout.xml"; + break; + case 4: + raceXMLFile = "mock/mockXML/raceTutorial.xml"; + boatsXMLFile = "mock/mockXML/boatTutorial.xml"; + regattaXMLFile = "mock/mockXML/regattaTutorial.xml"; + break; + default: raceXMLFile = "mock/mockXML/raceSixPlayers.xml"; + + } + if (singlePlayer) { raceXMLFile = "mock/mockXML/raceSinglePlayer.xml"; @@ -95,7 +116,9 @@ public class Event { //this.raceXML = RaceXMLCreator.alterRaceToWind(raceXMLFile, 90); this.raceXML = XMLReader.readXMLFileToString(raceXMLFile, StandardCharsets.UTF_8); this.raceXML = Event.setRaceXMLAtCurrentTimeToNow(XMLReader.readXMLFileToString(raceXMLFile, StandardCharsets.UTF_8)); - + if(mapIndex==4){ + this.raceXML = Event.setRaceXMLAtCurrentTimeToNow(XMLReader.readXMLFileToString(raceXMLFile, StandardCharsets.UTF_8), 1000, 5000); + } this.boatXML = XMLReader.readXMLFileToString(boatsXMLFile, StandardCharsets.UTF_8); this.regattaXML = XMLReader.readXMLFileToString(regattaXMLFile, StandardCharsets.UTF_8); @@ -178,9 +201,14 @@ public class Event { * @return String containing edited xml */ public static String setRaceXMLAtCurrentTimeToNow(String raceXML) { + return setRaceXMLAtCurrentTimeToNow(raceXML, Constants.RacePreStartTime, Constants.RacePreparatoryTime); + } + public static String setRaceXMLAtCurrentTimeToNow(String raceXML, long racePreStartTime, long racePreparatoryTime){ //The start time is current time + 4 minutes. prestart is 3 minutes, and we add another minute. - long millisecondsToAdd = Constants.RacePreStartTime + 1 * 60 * 1000; + + long millisecondsToAdd = racePreStartTime + racePreparatoryTime; + long secondsToAdd = millisecondsToAdd / 1000; //Scale the time using our time scalar. secondsToAdd = secondsToAdd / Constants.RaceTimeScale; @@ -190,7 +218,6 @@ public class Event { raceXML = raceXML.replace("RACE_CREATION_TIME", dateFormat.format(creationTime)); raceXML = raceXML.replace("RACE_START_TIME", dateFormat.format(creationTime.plusSeconds(secondsToAdd))); - return raceXML; } diff --git a/racevisionGame/src/main/java/mock/model/RaceLogic.java b/racevisionGame/src/main/java/mock/model/RaceLogic.java index d1ef39e0..0b3dffb2 100644 --- a/racevisionGame/src/main/java/mock/model/RaceLogic.java +++ b/racevisionGame/src/main/java/mock/model/RaceLogic.java @@ -11,6 +11,7 @@ import network.Messages.Enums.RaceStatusEnum; import network.Messages.LatestMessages; import shared.model.RunnableWithFramePeriod; +import java.util.ArrayList; import java.util.Observable; import java.util.Observer; @@ -138,6 +139,8 @@ public class RaceLogic implements RunnableWithFramePeriod, Observer { */ private void raceLoop() { + ArrayList collisionBoats = new ArrayList<>(); + long previousFrameTime = System.currentTimeMillis(); while (race.getRaceStatusEnum() != RaceStatusEnum.FINISHED && loopBool) { @@ -163,9 +166,17 @@ public class RaceLogic implements RunnableWithFramePeriod, Observer { //If it is still racing, update its position. if (boat.getStatus() == BoatStatusEnum.RACING) { race.updatePosition(boat, framePeriod, race.getRaceClock().getDurationMilli()); - race.getColliderRegistry().rayCast(boat); + + if(race.getColliderRegistry().rayCast(boat)){ + System.out.println("Collision!"); + //Add boat to list + collisionBoats.add(boat); + } + + //System.out.println(race.getColliderRegistry().rayCast(boat)); } + } } else { @@ -178,9 +189,14 @@ public class RaceLogic implements RunnableWithFramePeriod, Observer { // Change wind direction race.changeWindDirection(); + //Pass collision boats in + server.parseBoatCollisions(collisionBoats); + //Parse the race snapshot. server.parseSnapshot(); + collisionBoats.clear(); + //Update the last frame time. previousFrameTime = currentTime; } diff --git a/racevisionGame/src/main/java/mock/model/RaceServer.java b/racevisionGame/src/main/java/mock/model/RaceServer.java index b7ccef12..80ec5e8b 100644 --- a/racevisionGame/src/main/java/mock/model/RaceServer.java +++ b/racevisionGame/src/main/java/mock/model/RaceServer.java @@ -3,6 +3,7 @@ package mock.model; import network.AckSequencer; import network.Messages.*; import network.Messages.Enums.BoatLocationDeviceEnum; +import network.Messages.Enums.YachtEventEnum; import network.Messages.Enums.XMLMessageType; import shared.model.Bearing; import shared.model.CompoundMark; @@ -23,6 +24,7 @@ import java.util.logging.Logger; public class RaceServer { private MockRace race; private LatestMessages latestMessages; + private List collisionEvents = new ArrayList<>(); /** @@ -67,9 +69,19 @@ public class RaceServer { //Parse the race status. snapshotMessages.add(parseRaceStatus()); + //Parse collisions + if(collisionEvents.size()>0){ + snapshotMessages.addAll(collisionEvents); + } + latestMessages.setSnapshot(snapshotMessages); updateXMLFiles(); + + //Reset collision list + collisionEvents.clear(); + //System.out.println(collisionEvents.size()); + } @@ -307,4 +319,28 @@ public class RaceServer { return message; } + + /** + * Parse the yacht event and return it + * @param boat yacht with event + * @param event event that happened + * @return yacht event + */ + private YachtEvent parseYachtEvent(MockBoat boat, YachtEventEnum event){ + YachtEvent yachtEvent = new YachtEvent( + System.currentTimeMillis(), + this.boatLocationSequenceNumber, + race.getRaceId(), + boat.getSourceID(), + 1337, + event); + return yachtEvent; + } + + public void parseBoatCollisions(ArrayList boats){ + for (MockBoat boat : boats){ + collisionEvents.add(parseYachtEvent(boat, YachtEventEnum.COLLISION)); + } + } + } diff --git a/racevisionGame/src/main/java/mock/model/SourceIdAllocator.java b/racevisionGame/src/main/java/mock/model/SourceIdAllocator.java index fb0cfd5a..f590d9b7 100644 --- a/racevisionGame/src/main/java/mock/model/SourceIdAllocator.java +++ b/racevisionGame/src/main/java/mock/model/SourceIdAllocator.java @@ -42,14 +42,12 @@ public class SourceIdAllocator { } List allocatedIDs = mockRace.getRaceDataSource().getParticipants(); - System.out.println(allocatedIDs); + List allIDs = new ArrayList<>(mockRace.getBoatDataSource().getBoats().keySet()); - System.out.println(allIDs); //Get list of unallocated ids. List unallocatedIDs = new ArrayList<>(allIDs); unallocatedIDs.removeAll(allocatedIDs); - System.out.println(unallocatedIDs.isEmpty()); if (!unallocatedIDs.isEmpty()) { diff --git a/racevisionGame/src/main/java/mock/model/collider/Collider.java b/racevisionGame/src/main/java/mock/model/collider/Collider.java index 029fee57..81b2ed62 100644 --- a/racevisionGame/src/main/java/mock/model/collider/Collider.java +++ b/racevisionGame/src/main/java/mock/model/collider/Collider.java @@ -32,6 +32,8 @@ public abstract class Collider extends Observable implements Locatable { notifyObservers(collision); this.setChanged(); + //Send out packet to all boats + return true; } else return false; } diff --git a/racevisionGame/src/main/java/mock/model/commandFactory/CompositeCommand.java b/racevisionGame/src/main/java/mock/model/commandFactory/CompositeCommand.java index 74c5e95b..a931a85a 100644 --- a/racevisionGame/src/main/java/mock/model/commandFactory/CompositeCommand.java +++ b/racevisionGame/src/main/java/mock/model/commandFactory/CompositeCommand.java @@ -1,7 +1,7 @@ package mock.model.commandFactory; -import java.util.ArrayDeque; import java.util.Queue; +import java.util.concurrent.ConcurrentLinkedDeque; /** * Wraps multiple commands into a composite to execute queued commands during a frame. @@ -10,15 +10,15 @@ public class CompositeCommand implements Command { private Queue commands; public CompositeCommand() { - this.commands = new ArrayDeque<>(); + this.commands = new ConcurrentLinkedDeque<>(); } public void addCommand(Command command) { - commands.add(command); + commands.offer(command); } @Override public void execute() { - while(!commands.isEmpty()) commands.remove().execute(); + while(commands.peek() != null) commands.poll().execute(); } } diff --git a/racevisionGame/src/main/java/shared/model/Constants.java b/racevisionGame/src/main/java/shared/model/Constants.java index 26c56d11..7a5e2820 100644 --- a/racevisionGame/src/main/java/shared/model/Constants.java +++ b/racevisionGame/src/main/java/shared/model/Constants.java @@ -39,14 +39,14 @@ public class Constants { * The race pre-start time, in milliseconds. 3 minutes (30 seconds for development). */ // public static final long RacePreStartTime = 30 * 1000; - public static final long RacePreStartTime = 6 * 1000; + public static final long RacePreStartTime = 1000; /** * The race preparatory time, in milliseconds. 1 minute. */ // public static final long RacePreparatoryTime = 60 * 1000; - public static final long RacePreparatoryTime = 6 * 1000; + public static final long RacePreparatoryTime = 1 * 60 * 1000; diff --git a/racevisionGame/src/main/java/visualiser/Commands/VisualiserRaceCommands/BoatCollisionCommand.java b/racevisionGame/src/main/java/visualiser/Commands/VisualiserRaceCommands/BoatCollisionCommand.java new file mode 100644 index 00000000..c3046d18 --- /dev/null +++ b/racevisionGame/src/main/java/visualiser/Commands/VisualiserRaceCommands/BoatCollisionCommand.java @@ -0,0 +1,39 @@ +package visualiser.Commands.VisualiserRaceCommands; + +import javafx.scene.media.AudioClip; +import mock.model.commandFactory.Command; +import network.Messages.YachtEvent; +import visualiser.model.VisualiserRaceState; + +/** + * Created by zwu18 on 4/09/17. + */ +public class BoatCollisionCommand implements Command { + + YachtEvent yachtEvent; + + VisualiserRaceState visualiserRace; + + public BoatCollisionCommand(YachtEvent yachtEvent, VisualiserRaceState visualiserRace){ + this.yachtEvent = yachtEvent; + this.visualiserRace = visualiserRace; + + } + + @Override + public void execute() { + + if(visualiserRace.getPlayerBoatID()==yachtEvent.getSourceID()){ + System.out.println("I crashed!"); + AudioClip sound = new AudioClip(this.getClass().getResource("/visualiser/sounds/collision.wav").toExternalForm()); + sound.play(); + + } else { + System.out.println("Someone else crashed!"); + AudioClip sound = new AudioClip(this.getClass().getResource("/visualiser/sounds/quietcollision.wav").toExternalForm()); + sound.play(); + } + + //System.out.println("Collision command executed!"); + } +} diff --git a/racevisionGame/src/main/java/visualiser/Commands/VisualiserRaceCommands/RaceStatusCommand.java b/racevisionGame/src/main/java/visualiser/Commands/VisualiserRaceCommands/RaceStatusCommand.java index 825cd274..add1a3dd 100644 --- a/racevisionGame/src/main/java/visualiser/Commands/VisualiserRaceCommands/RaceStatusCommand.java +++ b/racevisionGame/src/main/java/visualiser/Commands/VisualiserRaceCommands/RaceStatusCommand.java @@ -1,5 +1,6 @@ package visualiser.Commands.VisualiserRaceCommands; +import javafx.scene.media.AudioClip; import mock.model.commandFactory.Command; import network.Messages.BoatStatus; import network.Messages.Enums.BoatStatusEnum; @@ -176,6 +177,10 @@ public class RaceStatusCommand implements Command { //Record order in which boat finished leg. visualiserRace.getLegCompletionOrder().get(boat.getCurrentLeg()).add(boat); + //play sound + AudioClip sound = new AudioClip(getClass().getResource("/visualiser/sounds/passmark.wav").toExternalForm()); + sound.play(); + //Update boat. boat.setCurrentLeg(leg); boat.setTimeAtLastMark(visualiserRace.getRaceClock().getCurrentTime()); diff --git a/racevisionGame/src/main/java/visualiser/Commands/VisualiserRaceCommands/VisualiserRaceCommandFactory.java b/racevisionGame/src/main/java/visualiser/Commands/VisualiserRaceCommands/VisualiserRaceCommandFactory.java index 37755e91..0e2f3d15 100644 --- a/racevisionGame/src/main/java/visualiser/Commands/VisualiserRaceCommands/VisualiserRaceCommandFactory.java +++ b/racevisionGame/src/main/java/visualiser/Commands/VisualiserRaceCommands/VisualiserRaceCommandFactory.java @@ -23,7 +23,9 @@ public class VisualiserRaceCommandFactory { switch (message.getType()) { - case BOATLOCATION: return new BoatLocationCommand((BoatLocation) message, visualiserRace); + case BOATLOCATION: + //System.out.println("Boat location received"); + return new BoatLocationCommand((BoatLocation) message, visualiserRace); case RACESTATUS: return new RaceStatusCommand((RaceStatus) message, visualiserRace); @@ -31,6 +33,11 @@ public class VisualiserRaceCommandFactory { case ASSIGN_PLAYER_BOAT: return new AssignPlayerBoatCommand((AssignPlayerBoat) message, visualiserRace); + case YACHTEVENTCODE: + return new BoatCollisionCommand((YachtEvent) message, visualiserRace); + + + default: throw new CommandConstructionException("Could not create VisualiserRaceCommand. Unrecognised or unsupported MessageType: " + message.getType()); } diff --git a/racevisionGame/src/main/java/visualiser/Controllers/HostController.java b/racevisionGame/src/main/java/visualiser/Controllers/HostController.java index 46acb405..4f07647c 100644 --- a/racevisionGame/src/main/java/visualiser/Controllers/HostController.java +++ b/racevisionGame/src/main/java/visualiser/Controllers/HostController.java @@ -1,28 +1,29 @@ package visualiser.Controllers; -import com.interactivemesh.jfx.importer.stl.StlMeshImporter; -import javafx.animation.AnimationTimer; -import javafx.collections.FXCollections; -import javafx.collections.ObservableList; import javafx.fxml.FXML; -import javafx.scene.control.Alert; -import javafx.scene.control.ButtonType; -import javafx.scene.control.SplitPane; +import javafx.scene.control.Button; +import javafx.scene.control.TextField; +import javafx.scene.image.Image; import javafx.scene.image.ImageView; import javafx.scene.layout.AnchorPane; import javafx.scene.layout.GridPane; -import javafx.scene.shape.MeshView; +import javafx.stage.Stage; +import javafx.scene.media.AudioClip; import mock.app.Event; +import org.xml.sax.SAXException; import mock.exceptions.EventConstructionException; -import visualiser.layout.Plane3D; -import visualiser.layout.SeaSurface; -import visualiser.layout.Subject3D; -import visualiser.layout.View3D; +import shared.exceptions.InvalidBoatDataException; +import shared.exceptions.InvalidRaceDataException; +import shared.exceptions.InvalidRegattaDataException; +import shared.exceptions.XMLReaderException; +import javax.xml.bind.JAXBException; +import javax.xml.parsers.ParserConfigurationException; import java.io.IOException; import java.net.Socket; import java.net.URL; -import java.util.Optional; +import java.util.ArrayList; +import java.util.Arrays; import java.util.ResourceBundle; import java.util.logging.Level; import java.util.logging.Logger; @@ -33,69 +34,48 @@ import java.util.logging.Logger; public class HostController extends Controller { -// @FXML -// TextField gameNameField; -// -// @FXML -// TextField hostNameField; - @FXML - private ImageView imageView; + TextField gameNameField; @FXML - AnchorPane hostWrapper; + TextField hostNameField; @FXML - AnchorPane imagePane; + AnchorPane hostWrapper; @FXML - SplitPane splitPane; + Button previousButton; @FXML - AnchorPane specPane; + Button nextButton; @FXML - GridPane playerContainer; + ImageView mapImage; private Event game; - private View3D view3D; - - @Override - public void initialize(URL location, ResourceBundle resources) { - ObservableList subjects = FXCollections.observableArrayList(); - - view3D = new View3D(); - view3D.setItems(subjects); - playerContainer.add(view3D, 0,0); + private ArrayList listOfMaps; + private int currentMapIndex = 0; - URL asset = HostController.class.getClassLoader().getResource("assets/V1.2 Complete Boat.stl"); - StlMeshImporter importer = new StlMeshImporter(); - importer.read(asset); - Subject3D subject = new Subject3D(new MeshView(importer.getImport())); - - subjects.add(subject); - - view3D.setDistance(50); - view3D.setYaw(45); - view3D.setPitch(20); - - AnimationTimer rotate = new AnimationTimer() { - @Override - public void handle(long now) { - subject.setHeading(subject.getHeading().getAngle() + 0.1); - } - }; - rotate.start(); + @Override + public void initialize(URL location, ResourceBundle resources){ + Image ac35Map = new Image(getClass().getClassLoader().getResourceAsStream("images/AC35_Racecourse_MAP.png")); + Image oMap = new Image(getClass().getClassLoader().getResourceAsStream("images/oMapLayout.png")); + Image iMap = new Image(getClass().getClassLoader().getResourceAsStream("images/iMapLayout.png")); + Image mMap = new Image(getClass().getClassLoader().getResourceAsStream("images/mMapLayout.png")); + + listOfMaps = new ArrayList(Arrays.asList(ac35Map, oMap, iMap, mMap)); + mapImage.setImage(listOfMaps.get(currentMapIndex)); } /** * Hosts a game + * @throws IOException if socket cannot be connected to */ - public void hostGamePressed() { + public void hostGamePressed() throws IOException{ try { - this.game = new Event(false); + this.game = new Event(false, currentMapIndex); connectSocket("localhost", 4942); } catch (EventConstructionException e) { Logger.getGlobal().log(Level.SEVERE, "Could not create Event.", e); @@ -128,10 +108,7 @@ public class HostController extends Controller { * Hosts a game. */ public void hostGame(){ - splitPane.setResizableWithParent(specPane, false); - splitPane.lookupAll(".split-pane-divider").stream().forEach(div -> div.setMouseTransparent(true)); - imageView.fitWidthProperty().bind(imagePane.widthProperty()); - imageView.fitHeightProperty().bind(imagePane.heightProperty()); + mapImage.fitWidthProperty().bind(((Stage) mapImage.getScene().getWindow()).widthProperty().multiply(0.6)); hostWrapper.setVisible(true); } @@ -139,23 +116,33 @@ public class HostController extends Controller { * Menu button pressed. Prompt alert then return to menu */ public void menuBtnPressed(){ - Alert alert = new Alert(Alert.AlertType.CONFIRMATION); - alert.setTitle("Quitting race"); - alert.setContentText("Do you wish to quit the race?"); - alert.setHeaderText("You are about to quit the race"); - Optional result = alert.showAndWait(); - if(result.get() == ButtonType.OK){ - hostWrapper.setVisible(false); - parent.enterTitle(); - } + AudioClip sound = new AudioClip(this.getClass().getResource("/visualiser/sounds/buttonpress.wav").toExternalForm()); + sound.play(); + hostWrapper.setVisible(false); + parent.enterTitle(); } - /** - * Start button pressed. Currently only prints out start - */ - public void startBtnPressed(){ - //System.out.println("Should start the race. This button is only visible for the host"); - hostGamePressed(); + public void nextImage(){ + increaseIndex(); + mapImage.setImage(listOfMaps.get(currentMapIndex)); + } + + public void previousImage(){ + decreaseIndex(); + mapImage.setImage(listOfMaps.get(currentMapIndex)); + } + private void increaseIndex(){ + currentMapIndex = (currentMapIndex + 1)%listOfMaps.size(); } + private void decreaseIndex(){ + currentMapIndex = ((((currentMapIndex - 1)%listOfMaps.size())+listOfMaps.size())%listOfMaps.size()); + } + + public void setGameType(int gameType){ + this.currentMapIndex = gameType; + } + + public int getGameType(){ return this.currentMapIndex; } + } diff --git a/racevisionGame/src/main/java/visualiser/Controllers/LobbyController.java b/racevisionGame/src/main/java/visualiser/Controllers/LobbyController.java index d541c531..8b3f523f 100644 --- a/racevisionGame/src/main/java/visualiser/Controllers/LobbyController.java +++ b/racevisionGame/src/main/java/visualiser/Controllers/LobbyController.java @@ -8,6 +8,7 @@ import javafx.scene.control.TableColumn; import javafx.scene.control.TableView; import javafx.scene.control.TextField; import javafx.scene.layout.AnchorPane; +import javafx.scene.media.AudioClip; import visualiser.model.RaceConnection; import java.io.IOException; @@ -39,6 +40,8 @@ public class LobbyController extends Controller { private ObservableList connections; + private AudioClip sound; + @Override public void initialize(URL location, ResourceBundle resources) { @@ -66,6 +69,8 @@ public class LobbyController extends Controller { * Refreshes the connections in the lobby */ public void refreshBtnPressed(){ + sound = new AudioClip(this.getClass().getResource("/visualiser/sounds/buttonpress.wav").toExternalForm()); + sound.play(); for(RaceConnection connection: connections) { connection.check(); } @@ -93,6 +98,8 @@ public class LobbyController extends Controller { } public void menuBtnPressed(){ + sound = new AudioClip(this.getClass().getResource("/visualiser/sounds/buttonpress.wav").toExternalForm()); + sound.play(); lobbyWrapper.setVisible(false); parent.enterTitle(); } @@ -101,6 +108,8 @@ public class LobbyController extends Controller { * adds a new connection */ public void addConnectionPressed(){ + sound = new AudioClip(this.getClass().getResource("/visualiser/sounds/buttonpress.wav").toExternalForm()); + sound.play(); String hostName = addressFld.getText(); String portString = portFld.getText(); try{ diff --git a/racevisionGame/src/main/java/visualiser/Controllers/MainController.java b/racevisionGame/src/main/java/visualiser/Controllers/MainController.java index e1aa1ede..2f9817d7 100644 --- a/racevisionGame/src/main/java/visualiser/Controllers/MainController.java +++ b/racevisionGame/src/main/java/visualiser/Controllers/MainController.java @@ -3,6 +3,8 @@ package visualiser.Controllers; import javafx.collections.ObservableList; import javafx.fxml.FXML; import javafx.scene.layout.AnchorPane; +import javafx.scene.media.AudioClip; +import visualiser.app.App; import visualiser.gameController.ControllerClient; import visualiser.model.VisualiserBoat; import visualiser.model.VisualiserRaceEvent; @@ -26,6 +28,8 @@ public class MainController extends Controller { @FXML private HostController hostController; @FXML private LobbyController lobbyController; + private AudioClip sound; + /** * Ctor. @@ -53,6 +57,8 @@ public class MainController extends Controller { * @param isHost is connection a host */ public void enterLobby(Socket socket, Boolean isHost) { + sound = new AudioClip(this.getClass().getResource("/visualiser/sounds/buttonpress.wav").toExternalForm()); + sound.play(); startController.enterLobby(socket, isHost); } @@ -74,18 +80,38 @@ public class MainController extends Controller { /** * Transitions into lobby screen */ - public void enterLobby(){ lobbyController.enterLobby(); } + public void enterLobby(){ + sound = new AudioClip(this.getClass().getResource("/visualiser/sounds/buttonpress.wav").toExternalForm()); + sound.play(); + lobbyController.enterLobby(); } /** * Transitions into host game screen */ - public void hostGame(){ hostController.hostGame(); } + public void hostGame(){ + sound = new AudioClip(this.getClass().getResource("/visualiser/sounds/buttonpress.wav").toExternalForm()); + sound.play(); + hostController.hostGame(); } /** * Sets up the css for the start of the program */ public void startCss(){titleController.setDayMode();} + /** + * host controller host a game + * @throws IOException throws exception + */ + public void beginGame() throws IOException { + hostController.hostGamePressed(); + } + + public void setGameType(int gameType){ + hostController.setGameType(gameType); + } + + public int getGameType(){ return hostController.getGameType(); } + /** * Main Controller for the applications will house the menu and the displayed pane. * diff --git a/racevisionGame/src/main/java/visualiser/Controllers/RaceController.java b/racevisionGame/src/main/java/visualiser/Controllers/RaceController.java index 3872ac37..05a922e3 100644 --- a/racevisionGame/src/main/java/visualiser/Controllers/RaceController.java +++ b/racevisionGame/src/main/java/visualiser/Controllers/RaceController.java @@ -3,6 +3,7 @@ package visualiser.Controllers; import com.interactivemesh.jfx.importer.stl.StlMeshImporter; import javafx.animation.AnimationTimer; import javafx.application.Platform; +import javafx.beans.value.ChangeListener; import javafx.collections.FXCollections; import javafx.collections.ListChangeListener; import javafx.collections.ObservableList; @@ -18,14 +19,20 @@ import javafx.scene.input.KeyEvent; import javafx.scene.layout.GridPane; import javafx.scene.layout.StackPane; import javafx.scene.paint.Color; +import javafx.scene.paint.Material; +import javafx.scene.paint.PhongMaterial; +import javafx.scene.shape.Box; import javafx.scene.shape.MeshView; +import javafx.scene.shape.Shape3D; +import javafx.scene.shape.Sphere; import javafx.scene.transform.Translate; import javafx.util.Callback; import network.Messages.Enums.RaceStatusEnum; import shared.dataInput.RaceDataSource; -import shared.model.Leg; -import shared.model.Mark; +import shared.exceptions.BoatNotFoundException; +import shared.model.*; import visualiser.app.App; +import visualiser.enums.TutorialState; import visualiser.gameController.ControllerClient; import visualiser.gameController.Keys.ControlKey; import visualiser.layout.*; @@ -34,8 +41,7 @@ import visualiser.utils.GPSConverter; import java.io.IOException; import java.net.URL; -import java.util.Optional; -import java.util.ResourceBundle; +import java.util.*; import java.util.logging.Level; import java.util.logging.Logger; @@ -58,6 +64,15 @@ public class RaceController extends Controller { private boolean isHost; + private TutorialState currentState; + + private ArrayList tutorialStates; + + private boolean isTutorial = false; + + private String keyToPress; + + /** * state of the info table */ @@ -66,6 +81,9 @@ public class RaceController extends Controller { private View3D view3D; private ObservableList viewSubjects; + private Subject3D nextMarkArrow; + private ChangeListener pointToMark; + /** * The arrow controller. */ @@ -75,6 +93,9 @@ public class RaceController extends Controller { @FXML private SplitPane racePane; + @FXML private Label tutorialText; + + /** * This is the pane we place the actual arrow control inside of. */ @@ -94,6 +115,7 @@ public class RaceController extends Controller { * Ctor. */ public RaceController() { + this.nextMarkArrow = new Annotation3D(new Box(1,3,0)); } @Override @@ -110,13 +132,27 @@ public class RaceController extends Controller { if(controlKey != null) { try { controlKey.onAction(); // Change key state if applicable + + //Check if current race is a tutorial + if (isTutorial){ + //Check if current tutorial state has the same boat protocol code as key press + if (controlKey.getProtocolCode().equals(currentState.getAction())){ + //Update tutorial + checkTutorialState(); + } + } + controllerClient.sendKey(controlKey); event.consume(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); Logger.getGlobal().log(Level.WARNING, "RaceController was interrupted on thread: " + Thread.currentThread() + "while sending: " + controlKey, e); + } catch (Exception e) { + e.printStackTrace(); } } + + if(event.getCode() == KeyCode.ESCAPE) { try { @@ -237,7 +273,7 @@ public class RaceController extends Controller { // Position and add each mark to view for(Mark mark: race.getVisualiserRaceState().getMarks()) { MeshView mesh = new MeshView(importerMark.getImport()); - Subject3D markModel = new Subject3D(mesh); + Subject3D markModel = new Subject3D(mesh, mark.getSourceID()); markModel.setX(gpsConverter.convertGPS(mark.getPosition()).getX()); markModel.setZ(gpsConverter.convertGPS(mark.getPosition()).getY()); @@ -252,7 +288,7 @@ public class RaceController extends Controller { } else { mesh = new MeshView(importerBurgerBoat.getImport()); } - Subject3D boatModel = new Subject3D(mesh); + Subject3D boatModel = new Subject3D(mesh, boat.getSourceID()); viewSubjects.add(boatModel); @@ -266,10 +302,27 @@ public class RaceController extends Controller { } }; trackBoat.start(); + + Material markColor = new PhongMaterial(new Color(0.15,0.9,0.2,1)); + CompoundMark nextMark = boat.getCurrentLeg().getEndCompoundMark(); + view3D.getShape(nextMark.getMark1().getSourceID()).setMaterial(markColor); + if(nextMark.getMark2() != null) { + view3D.getShape(nextMark.getMark2().getSourceID()).setMaterial(markColor); + } + + boat.legProperty().addListener((o, prev, curr) -> swapColours(curr)); } // Fix initial bird's-eye position view3D.updatePivot(new Translate(250, 0, 210)); + view3D.targetProperty().addListener((o, prev, curr)-> { + if(curr != null && visualiserRace.getVisualiserRaceState().isVisualiserBoat(curr.getSourceID())) { + addThirdPersonAnnotations(curr); + } else { + removeThirdPersonAnnotations(prev); + } + }); + // Bind zooming to scrolling view3D.setOnScroll(e -> { view3D.updateDistance(e.getDeltaY()); @@ -281,9 +334,33 @@ public class RaceController extends Controller { if(key != null) { switch (key.toString()) { case "Zoom In": + //Check if race is a tutorial + if (isTutorial) { + //Check if the current tutorial state is zoom-in + if (currentState.equals(TutorialState.ZOOMIN)) { + try { + //Update tutorial + checkTutorialState(); + } catch (Exception e1) { + e1.printStackTrace(); + } + } + } view3D.updateDistance(-10); break; case "Zoom Out": + //Check if race is a tutorial + if(isTutorial) { + //Check if current tutorial state is zoom-out + if (currentState.equals(TutorialState.ZOOMOUT)) { + try { + //Update tutorial + checkTutorialState(); + } catch (Exception e1) { + e1.printStackTrace(); + } + } + } view3D.updateDistance(10); break; } @@ -291,6 +368,64 @@ public class RaceController extends Controller { }); } + private void addThirdPersonAnnotations(Subject3D subject3D) { + viewSubjects.add(nextMarkArrow); + + try { + VisualiserBoat boat = visualiserRace.getVisualiserRaceState().getBoat(subject3D.getSourceID()); + this.pointToMark = (o, prev, curr) -> { + CompoundMark target = boat.getCurrentLeg().getEndCompoundMark(); + Bearing headingToMark = GPSCoordinate.calculateBearing(boat.getPosition(), target.getAverageGPSCoordinate()); + + nextMarkArrow.setX(view3D.getPivot().getX()); + nextMarkArrow.setY(view3D.getPivot().getY()); + nextMarkArrow.setZ(view3D.getPivot().getZ() + 10); + nextMarkArrow.setHeading(headingToMark.degrees()); + }; + + boat.positionProperty().addListener(pointToMark); + } catch (BoatNotFoundException e) { + e.printStackTrace(); + } + } + + private void removeThirdPersonAnnotations(Subject3D subject3D) { + viewSubjects.remove(nextMarkArrow); + + try { + VisualiserBoat boat = visualiserRace.getVisualiserRaceState().getBoat(subject3D.getSourceID()); + boat.positionProperty().removeListener(pointToMark); + } catch (BoatNotFoundException e) { + e.printStackTrace(); + } + } + + /** + * Swap the colour of the next mark to pass with the last mark passed + * @param leg boat has started on + */ + private void swapColours(Leg leg) { + CompoundMark start = leg.getStartCompoundMark(); + CompoundMark end = leg.getEndCompoundMark(); + + Shape3D start1 = view3D.getShape(start.getMark1().getSourceID()); + Shape3D end1 = view3D.getShape(end.getMark1().getSourceID()); + + Material nextMark = start1.getMaterial(); + Material lastMark = end1.getMaterial(); + + start1.setMaterial(lastMark); + if(start.getMark2() != null) { + Shape3D start2 = view3D.getShape(start.getMark2().getSourceID()); + start2.setMaterial(lastMark); + } + + end1.setMaterial(nextMark); + if(end.getMark2() != null) { + Shape3D end2 = view3D.getShape(end.getMark2().getSourceID()); + end2.setMaterial(nextMark); + } + } /** * Initialises the frame rate functionality. This allows for toggling the frame rate, and connect the fps label to the race's fps property. @@ -468,6 +603,25 @@ public class RaceController extends Controller { this.controllerClient = controllerClient; this.isHost = isHost; + + //Check if the game is a tutorial + if (parent.getGameType()==4){ + isTutorial = true; + tutorialText.setVisible(true); + tutorialStates = new ArrayList<>(Arrays.asList(TutorialState.values())); + + currentState = tutorialStates.get(0); + tutorialStates.remove(0); + + searchMapForKey("Upwind"); + + tutorialText.setText("Welcome to the tutorial! Exit at anytime with ESC. \nWe will first learn how to turn upwind. Press " + keyToPress + " to turn upwind."); + + } else { + isTutorial = false; + tutorialText.setVisible(false); + } + initialiseRace(); //Display this controller. @@ -565,4 +719,108 @@ public class RaceController extends Controller { infoTableShow = !infoTableShow; } + /** + * Get the next tutorial state + */ + private void updateTutorialState(){ + //Next tutorial state is popped from list + currentState = tutorialStates.get(0); + tutorialStates.remove(0); + } + + /** + * Search key map for key given string of command + * @param command the command of the key + */ + private void searchMapForKey(String command){ + //For loop through keyFactory + for (Map.Entry entry: keyFactory.getKeyState().entrySet()){ + if(entry.getValue().toString().equals(command)){ + + //Found next key required to press + keyToPress = entry.getKey(); + } + } + } + + /** + * Updates tutorial state and gui display for tutorial text + * @throws Exception Exception thrown + */ + private void checkTutorialState() throws Exception { + //Switch statement to check what the current tutorial state is + switch (currentState){ + case UPWIND: + //Set next key to press as the downwind key + searchMapForKey("Downwind"); + //Update tutorial text + tutorialText.setText("Nice! To turn downwind press " + keyToPress + "."); + updateTutorialState(); + break; + case DOWNWIND: + //Set next key to press as the tack/gybe key + searchMapForKey("Tack/Gybe"); + //Update tutorial text + tutorialText.setText("Nice! To tack or gybe press " + keyToPress + "."); + updateTutorialState(); + break; + case TACKGYBE: + //Set next key to press as the VMG key + searchMapForKey("VMG"); + //Update tutorial text + tutorialText.setText("Nice! To use VMG press " + keyToPress + ". This will turn the boat."); + updateTutorialState(); + break; + case VMG: + //Set next key to press as the sails-in key + searchMapForKey("Toggle Sails"); + //Update tutorial text + tutorialText.setText("Nice! To sails in press " + keyToPress + ". This will stop the boat."); + updateTutorialState(); + break; + case SAILSIN: + //Set next key to press as the sails-out key + searchMapForKey("Toggle Sails"); + //Update tutorial text + tutorialText.setText("Nice! To sails out press " + keyToPress + " again. The will start moving again."); + updateTutorialState(); + break; + case SAILSOUT: + //Set next key to press as the zoom-in key + searchMapForKey("Zoom In"); + //Update tutorial text + tutorialText.setText("Nice! To zoom in press " + keyToPress + "."); + updateTutorialState(); + break; + case ZOOMIN: + //Set next key to press as the zoom-out key + searchMapForKey("Zoom Out"); + //Update tutorial text + tutorialText.setText("Nice! You will also be able to zoom into boats and marks by clicking them. To zoom out press " + keyToPress + "."); + updateTutorialState(); + break; + case ZOOMOUT: + //Finished tutorial. Display pop-up for exiting the tutorial + tutorialText.setText("Congratulations! You're done!"); + Alert alert = new Alert(Alert.AlertType.INFORMATION); + alert.setTitle("Finished Tutorial"); + alert.setHeaderText("You have finished the tutorial."); + alert.setContentText("Now you know the controls you are ready to race!"); + Optional result = alert.showAndWait(); + if (result.get() == ButtonType.OK) { + parent.endEvent(); + racePane.setVisible(false); + App.app.showMainStage(App.getStage()); + } + break; + default: + //State not found. Exit tutorial to title menu + parent.endEvent(); + racePane.setVisible(false); + App.app.showMainStage(App.getStage()); + break; + } + + } + } diff --git a/racevisionGame/src/main/java/visualiser/Controllers/StartController.java b/racevisionGame/src/main/java/visualiser/Controllers/StartController.java index b46bf79f..290837ae 100644 --- a/racevisionGame/src/main/java/visualiser/Controllers/StartController.java +++ b/racevisionGame/src/main/java/visualiser/Controllers/StartController.java @@ -86,9 +86,6 @@ public class StartController extends Controller { - - - /** * Ctor. */ @@ -218,29 +215,30 @@ public class StartController extends Controller { * Countdown timer until race starts. */ private void countdownTimer() { - new AnimationTimer() { - @Override - public void handle(long arg0) { + new AnimationTimer() { + @Override + public void handle(long arg0) { - //Get the current race status. - RaceStatusEnum raceStatus = visualiserRaceEvent.getVisualiserRaceState().getRaceStatusEnum(); + //Get the current race status. + RaceStatusEnum raceStatus = visualiserRaceEvent.getVisualiserRaceState().getRaceStatusEnum(); - //If the race has reached the preparatory phase, or has started... - if (raceStatus == RaceStatusEnum.WARNING - || raceStatus == RaceStatusEnum.PREPARATORY - || raceStatus == RaceStatusEnum.STARTED) { - //Stop this timer. - stop(); + //If the race has reached the preparatory phase, or has started... + if (raceStatus == RaceStatusEnum.WARNING + || raceStatus == RaceStatusEnum.PREPARATORY + || raceStatus == RaceStatusEnum.STARTED) { + //Stop this timer. + stop(); - //Hide this, and display the race controller. - startWrapper.setVisible(false); - //start.setVisible(false);//TODO is this needed? + //Hide this, and display the race controller. + startWrapper.setVisible(false); + //start.setVisible(false);//TODO is this needed? - parent.beginRace(visualiserRaceEvent, controllerClient, isHost); + parent.beginRace(visualiserRaceEvent, controllerClient, isHost); + } } - } - }.start(); + }.start(); + } diff --git a/racevisionGame/src/main/java/visualiser/Controllers/TitleController.java b/racevisionGame/src/main/java/visualiser/Controllers/TitleController.java index aa2edf13..e5c4975b 100644 --- a/racevisionGame/src/main/java/visualiser/Controllers/TitleController.java +++ b/racevisionGame/src/main/java/visualiser/Controllers/TitleController.java @@ -6,16 +6,29 @@ import javafx.fxml.FXMLLoader; import javafx.scene.Parent; import javafx.scene.Scene; import javafx.scene.control.Button; +import javafx.scene.control.Label; import javafx.scene.control.RadioButton; +import javafx.scene.image.Image; +import javafx.scene.image.ImageView; import javafx.scene.layout.AnchorPane; +import javafx.scene.layout.Pane; +import javafx.scene.media.AudioClip; +import javafx.scene.media.Media; +import javafx.scene.media.MediaPlayer; import javafx.stage.Modality; import javafx.stage.Stage; +import mock.app.Event; +import mock.exceptions.EventConstructionException; import javafx.stage.WindowEvent; import visualiser.app.App; +import java.io.File; import java.io.IOException; +import java.net.URISyntaxException; import java.net.URL; import java.util.ResourceBundle; +import java.util.logging.Level; +import java.util.logging.Logger; /** * Controller for the opening title window. @@ -33,6 +46,12 @@ public class TitleController extends Controller { RadioButton dayModeRD; @FXML RadioButton nightModeRD; + @FXML + Label tutorialLabel; + @FXML + Pane menuPane; + @FXML + ImageView imgSun; /** * Method called when the 'host a game' button is pressed. @@ -40,8 +59,9 @@ public class TitleController extends Controller { * Currently used to run the RaceVision mock. * @throws IOException if main has problems */ - public void hostAGame() throws IOException { + public void hostAGame() throws IOException, URISyntaxException { titleWrapper.setVisible(false); + parent.setGameType(0); parent.hostGame(); App.getStage().setResizable(true); } @@ -68,7 +88,10 @@ public class TitleController extends Controller { */ public void setDayMode(){ dayModeRD.getScene().getStylesheets().clear(); + menuPane.getStylesheets().clear(); + imgSun.setImage(new Image(getClass().getResource("/visualiser/images/sun.png").toExternalForm())); dayModeRD.getScene().getStylesheets().add("/css/dayMode.css"); + menuPane.setStyle("-fx-background-color: #6be6ff;"); nightModeRD.setSelected(false); } @@ -77,12 +100,17 @@ public class TitleController extends Controller { */ public void setNightMode(){ nightModeRD.getScene().getStylesheets().clear(); + menuPane.getStylesheets().clear(); + imgSun.setImage(new Image(getClass().getResource("/visualiser/images/sunsleep.png").toExternalForm())); nightModeRD.getScene().getStylesheets().add("/css/nightMode.css"); + menuPane.setStyle("-fx-background-color: #1f2c60;"); dayModeRD.setSelected(false); } @Override public void initialize(URL location, ResourceBundle resources) { + tutorialLabel.setWrapText(true); + } /** @@ -90,6 +118,8 @@ public class TitleController extends Controller { */ public void controlBtnPressed(){ try { + AudioClip sound = new AudioClip(this.getClass().getResource("/visualiser/sounds/buttonpress.wav").toExternalForm()); + sound.play(); FXMLLoader loader = new FXMLLoader(); loader.setLocation(getClass().getResource("/visualiser/scenes/keyBindings.fxml")); Parent layout = loader.load(); @@ -114,4 +144,12 @@ public class TitleController extends Controller { } } + + public void tutorialStartPressed() throws IOException { + titleWrapper.setVisible(false); + parent.setGameType(4); + parent.beginGame(); + + } + } diff --git a/racevisionGame/src/main/java/visualiser/app/App.java b/racevisionGame/src/main/java/visualiser/app/App.java index e095e04e..d33fd2b4 100644 --- a/racevisionGame/src/main/java/visualiser/app/App.java +++ b/racevisionGame/src/main/java/visualiser/app/App.java @@ -3,6 +3,7 @@ package visualiser.app; import javafx.animation.FadeTransition; import javafx.application.Application; import javafx.application.Platform; +import javafx.beans.property.ReadOnlyObjectProperty; import javafx.collections.FXCollections; import javafx.collections.ObservableList; import javafx.concurrent.Task; @@ -14,6 +15,7 @@ import javafx.geometry.Rectangle2D; import javafx.scene.Parent; import javafx.scene.Scene; import javafx.scene.control.Label; +import javafx.scene.control.ListView; import javafx.scene.control.ProgressBar; import javafx.scene.effect.DropShadow; import javafx.scene.image.Image; @@ -95,7 +97,7 @@ public class App extends Application { ); updateMessage("Preparing ingredients . . ."); - Thread.sleep(200); + Thread.sleep(100); for (int i = 0; i < burgerFilling.size(); i++) { Thread.sleep(100); updateProgress(i + 1, burgerFilling.size()); diff --git a/racevisionGame/src/main/java/visualiser/enums/TutorialState.java b/racevisionGame/src/main/java/visualiser/enums/TutorialState.java new file mode 100644 index 00000000..ab811a43 --- /dev/null +++ b/racevisionGame/src/main/java/visualiser/enums/TutorialState.java @@ -0,0 +1,66 @@ +package visualiser.enums; + +import javafx.scene.input.KeyCode; +import network.Messages.BoatAction; +import network.Messages.Enums.BoatActionEnum; +import visualiser.gameController.Keys.ControlKey; +import static visualiser.app.App.keyFactory; + +import java.util.ArrayList; + +/** + * State of which stage the tutorial is currently in + */ +public enum TutorialState { + + /** + * State for upwind in tutorial + */ + UPWIND(BoatActionEnum.UPWIND), + + /** + * State for downwind in tutorial + */ + DOWNWIND(BoatActionEnum.DOWNWIND), + + /** + * State for tacking/gybing in tutorial + */ + TACKGYBE(BoatActionEnum.TACK_GYBE), + + /** + * State for vmg in tutorial + */ + VMG(BoatActionEnum.AUTO_PILOT), + + /** + * State for sails-in in tutorial + */ + SAILSIN(BoatActionEnum.SAILS_IN), + + /** + * State for sails-out in tutorial + */ + SAILSOUT(BoatActionEnum.SAILS_OUT), + + /** + * State for zoom-in in tutorial + */ + ZOOMIN(null), + + /** + * State for zoom-out in tutorial + */ + ZOOMOUT(null); + + private BoatActionEnum action; + + TutorialState(BoatActionEnum action){ + this.action = action; + } + + public BoatActionEnum getAction(){ + return action; + } + +} diff --git a/racevisionGame/src/main/java/visualiser/layout/Annotation3D.java b/racevisionGame/src/main/java/visualiser/layout/Annotation3D.java new file mode 100644 index 00000000..eae706da --- /dev/null +++ b/racevisionGame/src/main/java/visualiser/layout/Annotation3D.java @@ -0,0 +1,24 @@ +package visualiser.layout; + +import javafx.scene.shape.Shape3D; + +/** + * Created by connortaylorbrown on 13/09/17. + */ +public class Annotation3D extends Subject3D { + /** + * Constructor for view subject wrapper + * + * @param mesh to be rendered + */ + public Annotation3D(Shape3D mesh) { + super(mesh, 0); + } + + /** + * Prevent rescaling of this subject + * @param scale ignored + */ + @Override + public void setScale(double scale) {} +} diff --git a/racevisionGame/src/main/java/visualiser/layout/Boundary3D.java b/racevisionGame/src/main/java/visualiser/layout/Boundary3D.java index beb59914..6af7918b 100644 --- a/racevisionGame/src/main/java/visualiser/layout/Boundary3D.java +++ b/racevisionGame/src/main/java/visualiser/layout/Boundary3D.java @@ -62,12 +62,12 @@ public class Boundary3D { double c = Math.sqrt(a * a + b * b); - Subject3D bound1 = new Subject3D(new Sphere(thickness * 2)); + Subject3D bound1 = new Subject3D(new Sphere(thickness * 2),0); bound1.setX(graphCoord1.getX()); bound1.setZ(graphCoord1.getY()); boundaryNodes.add(bound1); - Subject3D connector = new Subject3D(new Box(c, thickness, thickness)); + Subject3D connector = new Subject3D(new Box(c, thickness, thickness),0); connector.setX(avgCoord.getX()); connector.setZ(avgCoord.getY()); double angle = 90 + Math.toDegrees(GPSConverter.getAngle(graphCoord2, graphCoord1)); diff --git a/racevisionGame/src/main/java/visualiser/layout/SeaSurface.java b/racevisionGame/src/main/java/visualiser/layout/SeaSurface.java index e12898f9..9fb2d755 100644 --- a/racevisionGame/src/main/java/visualiser/layout/SeaSurface.java +++ b/racevisionGame/src/main/java/visualiser/layout/SeaSurface.java @@ -24,7 +24,7 @@ public class SeaSurface extends Subject3D { * @param freq frequency the perlin noise is to be generated at */ public SeaSurface(int size, double freq){ - super(createSurface(size, freq)); + super(createSurface(size, freq),0); image = new Image(getClass().getClassLoader().getResourceAsStream("images/skybox/ThickCloudsWaterDown2048.png")); } diff --git a/racevisionGame/src/main/java/visualiser/layout/SkyBox.java b/racevisionGame/src/main/java/visualiser/layout/SkyBox.java index 27943b2c..09492510 100644 --- a/racevisionGame/src/main/java/visualiser/layout/SkyBox.java +++ b/racevisionGame/src/main/java/visualiser/layout/SkyBox.java @@ -50,10 +50,10 @@ public class SkyBox { surface.setRotate(180); surface.setTranslateX(x); - surface.setTranslateY(y - size/2 + yshift + clipOverlap); + surface.setTranslateY(y - size + 1); surface.setTranslateZ(z); - Subject3D top = new SkyBoxPlane(surface); + Subject3D top = new Subject3D(surface,0); skyBoxPlanes.add(top); } @@ -72,7 +72,7 @@ public class SkyBox { surface.setTranslateZ(z + size/2 - clipOverlap); - Subject3D right = new SkyBoxPlane(surface); + Subject3D right = new Subject3D(surface,0); skyBoxPlanes.add(right); } @@ -94,7 +94,7 @@ public class SkyBox { surface.setTranslateZ(z - size/2 + clipOverlap); - Subject3D left = new SkyBoxPlane(surface); + Subject3D left = new Subject3D(surface,0); skyBoxPlanes.add(left); } @@ -112,7 +112,7 @@ public class SkyBox { surface.setTranslateY(y + yshift); surface.setTranslateZ(z); - Subject3D back = new SkyBoxPlane(surface); + Subject3D back = new Subject3D(surface,0); skyBoxPlanes.add(back); } @@ -130,7 +130,7 @@ public class SkyBox { surface.setTranslateY(y + yshift); surface.setTranslateZ(z); - Subject3D front = new SkyBoxPlane(surface); + Subject3D front = new Subject3D(surface,0); skyBoxPlanes.add(front); } diff --git a/racevisionGame/src/main/java/visualiser/layout/Subject3D.java b/racevisionGame/src/main/java/visualiser/layout/Subject3D.java index cf9c13d7..4b18fec4 100644 --- a/racevisionGame/src/main/java/visualiser/layout/Subject3D.java +++ b/racevisionGame/src/main/java/visualiser/layout/Subject3D.java @@ -13,6 +13,10 @@ public class Subject3D { * Rendered mesh */ private Shape3D mesh; + /** + * Source ID of subject in game model + */ + private int sourceID; /** * Position translation updated by state listeners @@ -30,8 +34,9 @@ public class Subject3D { * Constructor for view subject wrapper * @param mesh to be rendered */ - public Subject3D(Shape3D mesh) { + public Subject3D(Shape3D mesh, int sourceID) { this.mesh = mesh; + this.sourceID = sourceID; this.scale = new Scale(); this.position = new Translate(); this.heading = new Rotate(0, Rotate.Y_AXIS); @@ -43,6 +48,10 @@ public class Subject3D { return mesh; } + public int getSourceID() { + return sourceID; + } + public Translate getPosition() { return this.position; } diff --git a/racevisionGame/src/main/java/visualiser/layout/View3D.java b/racevisionGame/src/main/java/visualiser/layout/View3D.java index bf4ee555..c62fe22e 100644 --- a/racevisionGame/src/main/java/visualiser/layout/View3D.java +++ b/racevisionGame/src/main/java/visualiser/layout/View3D.java @@ -1,5 +1,7 @@ package visualiser.layout; +import javafx.beans.property.ObjectProperty; +import javafx.beans.property.SimpleObjectProperty; import javafx.beans.value.ChangeListener; import javafx.collections.ListChangeListener; import javafx.collections.ObservableList; @@ -31,11 +33,15 @@ public class View3D extends Pane { /** * Map for selecting Subject3D from Shape3D */ - private Map selectionMap; + private Map shapeMap; + /** + * Map for selecting Shape3D from source ID + */ + private Map sourceMap; /** * Subject tracked by camera */ - private Subject3D target; + private ObjectProperty target; /** * Rendering container for shapes */ @@ -95,8 +101,9 @@ public class View3D extends Pane { */ public View3D(boolean fill) { this.world = new Group(); - this.selectionMap = new HashMap<>(); - this.target = null; + this.shapeMap = new HashMap<>(); + this.sourceMap = new HashMap<>(); + this.target = new SimpleObjectProperty<>(null); this.scene = new SubScene(world, 300, 300); scene.widthProperty().bind(this.widthProperty()); @@ -148,17 +155,23 @@ public class View3D extends Pane { if (c.wasRemoved() || c.wasAdded()) { for (Subject3D shape : c.getRemoved()) { world.getChildren().remove(shape.getMesh()); - selectionMap.remove(shape.getMesh()); + shapeMap.remove(shape.getMesh()); + sourceMap.remove(shape.getSourceID()); } for (Subject3D shape : c.getAddedSubList()) { world.getChildren().add(shape.getMesh()); - selectionMap.put(shape.getMesh(), shape); + shapeMap.put(shape.getMesh(), shape); + sourceMap.put(shape.getSourceID(), shape.getMesh()); } } } }); } + public Shape3D getShape(int sourceID) { + return sourceMap.get(sourceID); + } + /** * Intercept mouse clicks on subjects in view. The applied listener cannot be removed. */ @@ -167,12 +180,16 @@ public class View3D extends Pane { PickResult result = e.getPickResult(); if(result != null && result.getIntersectedNode() != null && result.getIntersectedNode() instanceof Shape3D) { untrackSubject(); - trackSubject(selectionMap.get(result.getIntersectedNode())); + trackSubject(shapeMap.get(result.getIntersectedNode())); setThirdPerson(); } }); } + public ObjectProperty targetProperty() { + return target; + } + /** * Configures camera to third person view */ @@ -201,11 +218,12 @@ public class View3D extends Pane { * Stop camera from following the last selected subject */ private void untrackSubject() { - if(target != null) { - target.getPosition().xProperty().removeListener(pivotX); - target.getPosition().yProperty().removeListener(pivotY); - target.getPosition().zProperty().removeListener(pivotZ); - target.getHeading().angleProperty().removeListener(pivotHeading); + if(target.get() != null) { + target.get().getPosition().xProperty().removeListener(pivotX); + target.get().getPosition().yProperty().removeListener(pivotY); + target.get().getPosition().zProperty().removeListener(pivotZ); + target.get().getHeading().angleProperty().removeListener(pivotHeading); + target.setValue(null); } } @@ -214,15 +232,15 @@ public class View3D extends Pane { * @param subject to track */ private void trackSubject(Subject3D subject) { - target = subject; + target.set(subject); - updatePivot(target.getPosition()); - setYaw(target.getHeading().getAngle()); + updatePivot(target.get().getPosition()); + setYaw(target.get().getHeading().getAngle()); - target.getPosition().xProperty().addListener(pivotX); - target.getPosition().yProperty().addListener(pivotY); - target.getPosition().zProperty().addListener(pivotZ); - target.getHeading().angleProperty().addListener(pivotHeading); + target.get().getPosition().xProperty().addListener(pivotX); + target.get().getPosition().yProperty().addListener(pivotY); + target.get().getPosition().zProperty().addListener(pivotZ); + target.get().getHeading().angleProperty().addListener(pivotHeading); } public void setNearClip(double nearClip) { @@ -233,6 +251,10 @@ public class View3D extends Pane { this.farClip = farClip; } + public Translate getPivot() { + return pivot; + } + /** * Sets the coordinates of the camera pivot once. * @param pivot source of coordinates diff --git a/racevisionGame/src/main/java/visualiser/model/VisualiserRaceController.java b/racevisionGame/src/main/java/visualiser/model/VisualiserRaceController.java index 748808b3..47382b74 100644 --- a/racevisionGame/src/main/java/visualiser/model/VisualiserRaceController.java +++ b/racevisionGame/src/main/java/visualiser/model/VisualiserRaceController.java @@ -65,7 +65,7 @@ public class VisualiserRaceController implements RunnableWithFramePeriod { compositeRaceCommand.addCommand(command); } catch (CommandConstructionException e) { - Logger.getGlobal().log(Level.WARNING, "VisualiserRaceController could not create a command for incoming message."); + //Logger.getGlobal().log(Level.WARNING, "VisualiserRaceController could not create a command for incoming message."); } catch (InterruptedException e) { Logger.getGlobal().log(Level.SEVERE, "VisualiserRaceController was interrupted on thread: " + Thread.currentThread() + " while waiting for messages."); diff --git a/racevisionGame/src/main/resources/css/dayMode.css b/racevisionGame/src/main/resources/css/dayMode.css index aa14c68b..b62f8391 100644 --- a/racevisionGame/src/main/resources/css/dayMode.css +++ b/racevisionGame/src/main/resources/css/dayMode.css @@ -53,5 +53,39 @@ } #arrowImage { - -fx-image: url("/visualiser/images/arrow.png"); + -fx-graphic: url("/visualiser/images/arrow.png"); +} + +#nextButton { + -fx-background-image: url("/visualiser/images/ArrowRoundRight.png"); + -fx-background-size: 60px; + -fx-background-repeat: no-repeat; + -fx-background-position: center center; + -fx-focus-color: transparent; + -fx-background-color: transparent; +} +#nextButton:pressed { + -fx-background-image: url("/visualiser/images/ArrowRoundRightClicked.png"); + -fx-background-size: 60px; + -fx-background-repeat: no-repeat; + -fx-background-position: center center; + -fx-focus-color: transparent; + -fx-background-color: transparent; +} + +#previousButton { + -fx-background-image: url("/visualiser/images/ArrowRoundLeft.png"); + -fx-background-size: 60px; + -fx-background-repeat: no-repeat; + -fx-background-position: center center; + -fx-focus-color: transparent; + -fx-background-color: transparent; +} +#previousButton:pressed { + -fx-background-image: url("/visualiser/images/ArrowRoundLeftClicked.png"); + -fx-background-size: 60px; + -fx-background-repeat: no-repeat; + -fx-background-position: center center; + -fx-focus-color: transparent; + -fx-background-color: transparent; } diff --git a/racevisionGame/src/main/resources/css/nightMode.css b/racevisionGame/src/main/resources/css/nightMode.css index 7fe6a67b..deefa51a 100644 --- a/racevisionGame/src/main/resources/css/nightMode.css +++ b/racevisionGame/src/main/resources/css/nightMode.css @@ -57,3 +57,37 @@ #arrowImage { -fx-image: url("/visualiser/images/arrowLight.png"); } + +#nextButton { + -fx-background-image: url("/visualiser/images/ArrowRoundRight.png"); + -fx-background-size: 60px; + -fx-background-repeat: no-repeat; + -fx-background-position: center center; + -fx-focus-color: transparent; + -fx-background-color: transparent; +} +#nextButton:pressed { + -fx-background-image: url("/visualiser/images/ArrowRoundRightClicked.png"); + -fx-background-size: 60px; + -fx-background-repeat: no-repeat; + -fx-background-position: center center; + -fx-focus-color: transparent; + -fx-background-color: transparent; +} + +#previousButton { + -fx-background-image: url("/visualiser/images/ArrowRoundLeft.png"); + -fx-background-size: 60px; + -fx-background-repeat: no-repeat; + -fx-background-position: center center; + -fx-focus-color: transparent; + -fx-background-color: transparent; +} +#previousButton:pressed { + -fx-background-image: url("/visualiser/images/ArrowRoundLeftClicked.png"); + -fx-background-size: 60px; + -fx-background-repeat: no-repeat; + -fx-background-position: center center; + -fx-focus-color: transparent; + -fx-background-color: transparent; +} diff --git a/racevisionGame/src/main/resources/images/AC35_Racecourse_MAP.png b/racevisionGame/src/main/resources/images/AC35_Racecourse_MAP.png new file mode 100644 index 00000000..1b5e39ca Binary files /dev/null and b/racevisionGame/src/main/resources/images/AC35_Racecourse_MAP.png differ diff --git a/racevisionGame/src/main/resources/images/iMapLayout.png b/racevisionGame/src/main/resources/images/iMapLayout.png new file mode 100644 index 00000000..5932a60d Binary files /dev/null and b/racevisionGame/src/main/resources/images/iMapLayout.png differ diff --git a/racevisionGame/src/main/resources/images/mMapLayout.png b/racevisionGame/src/main/resources/images/mMapLayout.png new file mode 100644 index 00000000..fa0af51f Binary files /dev/null and b/racevisionGame/src/main/resources/images/mMapLayout.png differ diff --git a/racevisionGame/src/main/resources/images/oMapLayout.png b/racevisionGame/src/main/resources/images/oMapLayout.png new file mode 100644 index 00000000..ca520959 Binary files /dev/null and b/racevisionGame/src/main/resources/images/oMapLayout.png differ diff --git a/racevisionGame/src/main/resources/mock/mockXML/boatTutorial.xml b/racevisionGame/src/main/resources/mock/mockXML/boatTutorial.xml new file mode 100644 index 00000000..023c5090 --- /dev/null +++ b/racevisionGame/src/main/resources/mock/mockXML/boatTutorial.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/racevisionGame/src/main/resources/mock/mockXML/iMapLayout.xml b/racevisionGame/src/main/resources/mock/mockXML/iMapLayout.xml new file mode 100644 index 00000000..ca914b12 --- /dev/null +++ b/racevisionGame/src/main/resources/mock/mockXML/iMapLayout.xml @@ -0,0 +1,53 @@ + + + 5326 + FLEET + RACE_CREATION_TIME + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/racevisionGame/src/main/resources/mock/mockXML/mMapLayout.xml b/racevisionGame/src/main/resources/mock/mockXML/mMapLayout.xml new file mode 100644 index 00000000..ce715ba6 --- /dev/null +++ b/racevisionGame/src/main/resources/mock/mockXML/mMapLayout.xml @@ -0,0 +1,43 @@ + + + 5326 + FLEET + RACE_CREATION_TIME + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/racevisionGame/src/main/resources/mock/mockXML/oMapLayout.xml b/racevisionGame/src/main/resources/mock/mockXML/oMapLayout.xml new file mode 100644 index 00000000..5021bbba --- /dev/null +++ b/racevisionGame/src/main/resources/mock/mockXML/oMapLayout.xml @@ -0,0 +1,49 @@ + + + 5326 + FLEET + RACE_CREATION_TIME + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/racevisionGame/src/main/resources/mock/mockXML/raceTest.xml b/racevisionGame/src/main/resources/mock/mockXML/raceSixPlayers.xml similarity index 100% rename from racevisionGame/src/main/resources/mock/mockXML/raceTest.xml rename to racevisionGame/src/main/resources/mock/mockXML/raceSixPlayers.xml diff --git a/racevisionGame/src/main/resources/mock/mockXML/raceTutorial.xml b/racevisionGame/src/main/resources/mock/mockXML/raceTutorial.xml new file mode 100644 index 00000000..47519d00 --- /dev/null +++ b/racevisionGame/src/main/resources/mock/mockXML/raceTutorial.xml @@ -0,0 +1,43 @@ + + + 9999 + FLEET + RACE_CREATION_TIME + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/racevisionGame/src/main/resources/mock/mockXML/regattaTutorial.xml b/racevisionGame/src/main/resources/mock/mockXML/regattaTutorial.xml new file mode 100644 index 00000000..d7f6b9e7 --- /dev/null +++ b/racevisionGame/src/main/resources/mock/mockXML/regattaTutorial.xml @@ -0,0 +1,10 @@ + + 0 + Race Tutorial + Tutorial + -36.82791529 + 174.81218919 + 0.00 + 12 + 14.1 + \ No newline at end of file diff --git a/racevisionGame/src/main/resources/visualiser/images/ArrowRoundLeft.png b/racevisionGame/src/main/resources/visualiser/images/ArrowRoundLeft.png new file mode 100644 index 00000000..ea4f4d64 Binary files /dev/null and b/racevisionGame/src/main/resources/visualiser/images/ArrowRoundLeft.png differ diff --git a/racevisionGame/src/main/resources/visualiser/images/ArrowRoundLeftClicked.png b/racevisionGame/src/main/resources/visualiser/images/ArrowRoundLeftClicked.png new file mode 100644 index 00000000..794ba57c Binary files /dev/null and b/racevisionGame/src/main/resources/visualiser/images/ArrowRoundLeftClicked.png differ diff --git a/racevisionGame/src/main/resources/visualiser/images/ArrowRoundRight.png b/racevisionGame/src/main/resources/visualiser/images/ArrowRoundRight.png new file mode 100644 index 00000000..751698cb Binary files /dev/null and b/racevisionGame/src/main/resources/visualiser/images/ArrowRoundRight.png differ diff --git a/racevisionGame/src/main/resources/visualiser/images/ArrowRoundRightClicked.png b/racevisionGame/src/main/resources/visualiser/images/ArrowRoundRightClicked.png new file mode 100644 index 00000000..10c1b53b Binary files /dev/null and b/racevisionGame/src/main/resources/visualiser/images/ArrowRoundRightClicked.png differ diff --git a/racevisionGame/src/main/resources/visualiser/images/sunsleep.png b/racevisionGame/src/main/resources/visualiser/images/sunsleep.png new file mode 100644 index 00000000..e52b2674 Binary files /dev/null and b/racevisionGame/src/main/resources/visualiser/images/sunsleep.png differ diff --git a/racevisionGame/src/main/resources/visualiser/mock/mockXML/raceXML/raceTutorial.xml b/racevisionGame/src/main/resources/visualiser/mock/mockXML/raceXML/raceTutorial.xml new file mode 100644 index 00000000..db7a6978 --- /dev/null +++ b/racevisionGame/src/main/resources/visualiser/mock/mockXML/raceXML/raceTutorial.xml @@ -0,0 +1,91 @@ + + + + + 99999999 + + Match + + 2011-08-06T13:25:00-0000 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/racevisionGame/src/main/resources/visualiser/scenes/hostgame.fxml b/racevisionGame/src/main/resources/visualiser/scenes/hostgame.fxml index ab14abaf..0767dd44 100644 --- a/racevisionGame/src/main/resources/visualiser/scenes/hostgame.fxml +++ b/racevisionGame/src/main/resources/visualiser/scenes/hostgame.fxml @@ -1,44 +1,61 @@ - + - - - - - - - + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/racevisionGame/src/main/resources/visualiser/scenes/main.fxml b/racevisionGame/src/main/resources/visualiser/scenes/main.fxml index 7aff44c0..074a9b31 100644 --- a/racevisionGame/src/main/resources/visualiser/scenes/main.fxml +++ b/racevisionGame/src/main/resources/visualiser/scenes/main.fxml @@ -7,7 +7,7 @@ - + diff --git a/racevisionGame/src/main/resources/visualiser/scenes/race.fxml b/racevisionGame/src/main/resources/visualiser/scenes/race.fxml index b6496743..af2bf8a3 100644 --- a/racevisionGame/src/main/resources/visualiser/scenes/race.fxml +++ b/racevisionGame/src/main/resources/visualiser/scenes/race.fxml @@ -1,5 +1,11 @@ + + + + + + @@ -22,83 +28,91 @@ - + - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/racevisionGame/src/main/resources/visualiser/sounds/buttonpress.wav b/racevisionGame/src/main/resources/visualiser/sounds/buttonpress.wav new file mode 100644 index 00000000..a32482e0 Binary files /dev/null and b/racevisionGame/src/main/resources/visualiser/sounds/buttonpress.wav differ diff --git a/racevisionGame/src/main/resources/visualiser/sounds/collision.wav b/racevisionGame/src/main/resources/visualiser/sounds/collision.wav new file mode 100644 index 00000000..0195375d Binary files /dev/null and b/racevisionGame/src/main/resources/visualiser/sounds/collision.wav differ diff --git a/racevisionGame/src/main/resources/visualiser/sounds/collision2.wav b/racevisionGame/src/main/resources/visualiser/sounds/collision2.wav new file mode 100644 index 00000000..9e295636 Binary files /dev/null and b/racevisionGame/src/main/resources/visualiser/sounds/collision2.wav differ diff --git a/racevisionGame/src/main/resources/visualiser/sounds/passmark.wav b/racevisionGame/src/main/resources/visualiser/sounds/passmark.wav new file mode 100644 index 00000000..be0be83b Binary files /dev/null and b/racevisionGame/src/main/resources/visualiser/sounds/passmark.wav differ diff --git a/racevisionGame/src/main/resources/visualiser/sounds/quietcollision.wav b/racevisionGame/src/main/resources/visualiser/sounds/quietcollision.wav new file mode 100644 index 00000000..d1c8a01e Binary files /dev/null and b/racevisionGame/src/main/resources/visualiser/sounds/quietcollision.wav differ diff --git a/racevisionGame/src/test/java/shared/dataInput/BoatsXMLTest.java b/racevisionGame/src/test/java/shared/dataInput/BoatsXMLTest.java deleted file mode 100644 index 35e21a0e..00000000 --- a/racevisionGame/src/test/java/shared/dataInput/BoatsXMLTest.java +++ /dev/null @@ -1,47 +0,0 @@ -//package seng302.Mock; -// -//import org.junit.Before; -//import org.junit.Test; -// -//import java.util.HashMap; -//import java.util.Map; -// -//import static org.junit.Assert.assertEquals; -// -///** -// * Created by jjg64 on 21/04/17. -// */ -//public class BoatsXMLTest { -// private BoatXMLReader boatXMLReader; -// -// @Before -// public void setup() { -// try { -// boatXMLReader = new BoatXMLReader("mockXML/boatXML/boatTest.xml", false); -// } catch (Exception e) { -// e.printStackTrace(); -// //fail("Cannot find mockXML/raceXML/raceTest.xml in the resources folder"); -// } -// } -// -// @Test -// public void testInvalidParticipant() { -// Map inputParticipants = new HashMap<>(); -// inputParticipants.put(420, new StreamedBoat(420)); -// boatXMLReader.setParticipants(inputParticipants); -// boatXMLReader.read(); -// assertEquals(boatXMLReader.getBoats().size(), 0); -// } -// -// @Test -// public void testValidParticipant() { -// Map inputParticipants = new HashMap<>(); -// inputParticipants.put(101, new StreamedBoat(101)); -// boatXMLReader.setParticipants(inputParticipants); -// boatXMLReader.read(); -// assertEquals(boatXMLReader.getBoats().size(), 1); -// StreamedBoat boat = (StreamedBoat) boatXMLReader.getBoats().get(0); -// assertEquals(boat.getSourceID(), 101); -// } -// -//} diff --git a/racevisionGame/src/test/java/shared/dataInput/FailBoatXMLTest.java b/racevisionGame/src/test/java/shared/dataInput/FailBoatXMLTest.java deleted file mode 100644 index a299c2bf..00000000 --- a/racevisionGame/src/test/java/shared/dataInput/FailBoatXMLTest.java +++ /dev/null @@ -1,26 +0,0 @@ -//package seng302.Mock; -// -//import org.junit.Test; -//import org.xml.sax.SAXException; -// -//import javax.xml.parsers.ParserConfigurationException; -//import java.io.IOException; -//import java.text.ParseException; -// -///** -// * Created by jjg64 on 1/05/17. -// */ -//public class FailBoatXMLTest { -// private final String path = "mockXML/boatXML/"; -// -// @Test(expected = NumberFormatException.class) -// public void invalidSourceID() throws SAXException, ParserConfigurationException, ParseException, IOException { -// new BoatXMLReader(path + "invalidSourceID.xml"); -// } -// -// @Test(expected = NullPointerException.class) -// public void insufficientInformation() throws SAXException, ParserConfigurationException, ParseException, IOException { -// new BoatXMLReader(path + "insufficientInformation.xml"); -// } -// -//} diff --git a/racevisionGame/src/test/java/shared/model/RaceTest.java b/racevisionGame/src/test/java/shared/model/RaceTest.java deleted file mode 100644 index 3334aefd..00000000 --- a/racevisionGame/src/test/java/shared/model/RaceTest.java +++ /dev/null @@ -1,345 +0,0 @@ -//package shared.model; -// -// -//import mock.model.Polars; -//import org.junit.Before; -//import org.junit.Ignore; -//import org.junit.Test; -//import org.mockito.Mockito; -//import org.xml.sax.SAXException; -// -//import javax.xml.parsers.ParserConfigurationException; -//import java.io.IOException; -//import java.text.ParseException; -//import java.util.ArrayList; -// -//import static org.junit.Assert.*; -//import static org.mockito.Mockito.*; -// -///** -// * Created by esa46 on 15/03/17. -// */ -//public class RaceTest{ -// -// -// private CompoundMark ORIGIN; -// -// private CompoundMark THREE_NM_FROM_ORIGIN; -// -// private CompoundMark FIFTEEN_NM_FROM_ORIGIN; -// -// private ArrayList TEST_LEGS = new ArrayList<>(); -// -// private int START_LEG_DISTANCE = 3; -// private int MIDDLE_LEG_DISTANCE = 12; -// -// private Leg START_LEG; -// -// private Leg MIDDLE_LEG; -// -// private Leg FINISH_LEG; -// -// -// @Before -// public void setUp() { -// -// ORIGIN = new CompoundMark( -// 1, -// "origin compound", -// new Mark(1, "test origin 1", new GPSCoordinate(0, 0)) ); -// -// -// THREE_NM_FROM_ORIGIN = new CompoundMark( -// 2, -// "3 NM from origin compound", -// new Mark(2, "test mark 2", new GPSCoordinate(0.050246769, 0)) ); -// -// -// FIFTEEN_NM_FROM_ORIGIN = new CompoundMark( -// 3, -// "15 NM from origin compound", -// new Mark(3, "test mark 3", new GPSCoordinate(0.251233845, 0)) ); -// -// -// START_LEG = new Leg("Start", ORIGIN, THREE_NM_FROM_ORIGIN, 0); -// -// -// MIDDLE_LEG = new Leg("Middle", THREE_NM_FROM_ORIGIN, FIFTEEN_NM_FROM_ORIGIN, 1); -// -// -// FINISH_LEG = new Leg("Finish", FIFTEEN_NM_FROM_ORIGIN, FIFTEEN_NM_FROM_ORIGIN, 2); -// -// -// TEST_LEGS.add(START_LEG); -// TEST_LEGS.add(MIDDLE_LEG); -// TEST_LEGS.add(FINISH_LEG); -// } -// -// @Ignore -// @Test -// public void countdownTimerSendsBoatLocations() { -// -// try { -// MockOutput mockOutput = Mockito.mock(MockOutput.class); -// BoatDataSource boatDataSource = new BoatXMLReader("mockXML/boatTest.xml", new Polars()); -// RaceDataSource raceDataSource = new RaceXMLReader("mockXML/raceTest.xml", boatDataSource); -// Race testRace = new Race(raceDataSource, mockOutput); -// testRace.initialiseBoats(); -// testRace.countdownTimer.handle(1); -// verify(mockOutput, atLeast(boatDataSource.getBoats().size())).parseBoatLocation(anyInt(), anyDouble(), anyDouble(), anyDouble(), anyDouble(), anyLong()); -// -// } catch (ParserConfigurationException | IOException | SAXException | ParseException | StreamedCourseXMLException e) { -// e.printStackTrace(); -// fail(); -// } -// } -// -// @Ignore -// @Test -// public void countdownTimerSendsRaceStatusMessages() { -// -// try { -// MockOutput mockOutput = Mockito.mock(MockOutput.class); -// RaceDataSource dataSource = new RaceXMLReader("mockXML/raceTest.xml", new BoatXMLReader("mockXML/boatTest.xml", new Polars())); -// Race testRace = new Race(dataSource, mockOutput); -// testRace.initialiseBoats(); -// testRace.countdownTimer.handle(1); -// verify(mockOutput, atLeast(1)).parseRaceStatus(any()); -// -// } catch (ParserConfigurationException | IOException | SAXException | ParseException | StreamedCourseXMLException e) { -// e.printStackTrace(); -// fail(); -// } -// } -// -// @Ignore -// @Test -// public void checkPositionFinishedUpdatesNumberFinishedBoats() { -// -// try { -// MockOutput mockOutput = Mockito.mock(MockOutput.class); -// RaceDataSource dataSource = new RaceXMLReader("mockXML/raceTest.xml", new BoatXMLReader("mockXML/boatTest.xml", new Polars())); -// Race testRace = new Race(dataSource, mockOutput); -// testRace.initialiseBoats(); -// Boat testBoat = testRace.getBoats().get(0); -// testBoat.setCurrentLeg(FINISH_LEG); -// testBoat.setDistanceTravelledInLeg(1); -// testRace.checkPosition(testBoat, 1); -// -// assertEquals(testRace.getNumberOfActiveBoats(), 0); -// -// } catch (ParserConfigurationException | IOException | SAXException | ParseException | StreamedCourseXMLException e) { -// e.printStackTrace(); -// fail(); -// } -// } -// -// @Ignore -// @Test -// public void checkPositionSetFinishedBoatVelocityTo0() { -// -// try { -// MockOutput mockOutput = Mockito.mock(MockOutput.class); -// RaceDataSource dataSource = new RaceXMLReader("mockXML/raceTest.xml", new BoatXMLReader("mockXML/boatTest.xml", new Polars())); -// Race testRace = new Race(dataSource, mockOutput); -// testRace.initialiseBoats(); -// Boat testBoat = testRace.getBoats().get(0); -// testBoat.setCurrentLeg(FINISH_LEG); -// testBoat.setDistanceTravelledInLeg(1); -// testRace.checkPosition(testBoat, 1); -// -// assertEquals(testBoat.getCurrentSpeed(), 0, 1e-8); -// -// } catch (ParserConfigurationException | IOException | SAXException | ParseException | StreamedCourseXMLException e) { -// e.printStackTrace(); -// fail(); -// } -// } -// -// @Ignore -// @Test -// public void checkPositionSetsFinishTime() { -// -// try { -// MockOutput mockOutput = Mockito.mock(MockOutput.class); -// RaceDataSource dataSource = new RaceXMLReader("mockXML/raceTest.xml", new BoatXMLReader("mockXML/boatTest.xml", new Polars())); -// Race testRace = new Race(dataSource, mockOutput); -// testRace.initialiseBoats(); -// Boat testBoat = testRace.getBoats().get(0); -// testBoat.setCurrentLeg(FINISH_LEG); -// testBoat.setDistanceTravelledInLeg(1); -// testRace.checkPosition(testBoat, 1); -// -// assertEquals(testBoat.getTimeFinished(), 1, 1e-8); -// -// } catch (ParserConfigurationException | IOException | SAXException | ParseException | StreamedCourseXMLException e) { -// e.printStackTrace(); -// fail(); -// } -// } -// -// @Ignore -// @Test -// public void checkPositionUnfinishedDoesntUpdateNumberFinishedBoats() { -// -// try { -// MockOutput mockOutput = Mockito.mock(MockOutput.class); -// RaceDataSource dataSource = new RaceXMLReader("mockXML/raceTest.xml", new BoatXMLReader("mockXML/boatTest.xml", new Polars())); -// Race testRace = new Race(dataSource, mockOutput); -// testRace.initialiseBoats(); -// Boat testBoat = testRace.getBoats().get(0); -// testBoat.setCurrentLeg(START_LEG); -// testBoat.setDistanceTravelledInLeg(START_LEG_DISTANCE); -// testRace.checkPosition(testBoat, 1); -// -// assertEquals(testRace.getNumberOfActiveBoats(), 1); -// -// } catch (ParserConfigurationException | IOException | SAXException | ParseException | StreamedCourseXMLException e) { -// e.printStackTrace(); -// fail(); -// } -// } -// -// -// @Ignore -// @Test -// public void distanceTravelledBeforeUpdatingLegIsRetained() { -// -// try { -// MockOutput mockOutput = Mockito.mock(MockOutput.class); -// RaceDataSource dataSource = new RaceXMLReader("mockXML/raceTest.xml", new BoatXMLReader("mockXML/boatTest.xml", new Polars())); -// Race testRace = new Race(dataSource, mockOutput); -// testRace.initialiseBoats(); -// Boat testBoat = testRace.getBoats().get(0); -// testBoat.setCurrentLeg(START_LEG); -// testBoat.setDistanceTravelledInLeg(START_LEG_DISTANCE + 1); -// testRace.checkPosition(testBoat, 0); -// -// assertEquals(testBoat.getDistanceTravelledInLeg(), 1, 1e-7); -// -// } catch (ParserConfigurationException | IOException | SAXException | ParseException | StreamedCourseXMLException e) { -// e.printStackTrace(); -// fail(); -// } -// } -// -// @Ignore -// @Test -// public void doNotFinishAnswersYesIf100PercentChance() { -// -// try { -// MockOutput mockOutput = Mockito.mock(MockOutput.class); -// BoatDataSource boatDataSource = new BoatXMLReader("mockXML/boatTest.xml", new Polars()); -// RaceDataSource raceDataSource = new RaceXMLReader("mockXML/raceTest.xml", boatDataSource); -// Race testRace = new Race(raceDataSource, mockOutput); -// -// testRace.setDnfChance(100); -// assertTrue(testRace.doNotFinish()); -// -// } catch (ParserConfigurationException | IOException | SAXException | ParseException | StreamedCourseXMLException e) { -// e.printStackTrace(); -// fail(); -// } -// } -// -// @Ignore -// @Test -// public void doNotFinishAnswersNoIf0PercentChance() { -// -// try { -// MockOutput mockOutput = Mockito.mock(MockOutput.class); -// BoatDataSource boatDataSource = new BoatXMLReader("mockXML/boatTest.xml", new Polars()); -// RaceDataSource raceDataSource = new RaceXMLReader("mockXML/raceTest.xml", boatDataSource); -// Race testRace = new Race(raceDataSource, mockOutput); -// testRace.setDnfChance(0); -// assertFalse(testRace.doNotFinish()); -// -// } catch (ParserConfigurationException | IOException | SAXException | ParseException | StreamedCourseXMLException e) { -// e.printStackTrace(); -// fail(); -// } -// } -// -// @Ignore -// @Test -// public void boatsAreSetToDNF() { -// try { -// MockOutput mockOutput = Mockito.mock(MockOutput.class); -// BoatDataSource boatDataSource = new BoatXMLReader("mockXML/boatTest.xml", new Polars()); -// RaceDataSource raceDataSource = new RaceXMLReader("mockXML/raceTest.xml", boatDataSource); -// Race testRace = new Race(raceDataSource, mockOutput); -// testRace.setDnfChance(100); -// Boat testBoat = testRace.getBoats().get(0); -// testBoat.setCurrentLeg(START_LEG); -// testBoat.setDistanceTravelledInLeg(START_LEG_DISTANCE + 1); -// testRace.checkPosition(testBoat, 1); -// assertEquals(testBoat.getCurrentLeg().getName(), "DNF"); -// -// } catch (ParserConfigurationException | IOException | SAXException | ParseException | StreamedCourseXMLException e) { -// e.printStackTrace(); -// fail(); -// } -// -// } -// -// @Ignore -// @Test -// public void updatePositionIgnoresFinishedBoats() { -// try { -// MockOutput mockOutput = Mockito.mock(MockOutput.class); -// BoatDataSource boatDataSource = new BoatXMLReader("mockXML/boatTest.xml", new Polars()); -// RaceDataSource raceDataSource = new RaceXMLReader("mockXML/raceTest.xml", boatDataSource); -// Race testRace = new Race(raceDataSource, mockOutput); -// Boat testBoat = testRace.getBoats().get(0); -// testBoat.setCurrentLeg(FINISH_LEG); -// testBoat.setCurrentPosition(ORIGIN.getAverageGPSCoordinate()); -// testRace.updatePosition(testBoat, 1, 1); -// assertEquals(testBoat.getCurrentPosition(), ORIGIN.getAverageGPSCoordinate()); -// -// } catch (ParserConfigurationException | IOException | SAXException | ParseException | StreamedCourseXMLException e) { -// e.printStackTrace(); -// fail(); -// } -// } -// -// @Ignore -// @Test -// public void updatePositionChangesBoatPosition() { -// try { -// MockOutput mockOutput = Mockito.mock(MockOutput.class); -// BoatDataSource boatDataSource = new BoatXMLReader("mockXML/boatTest.xml", new Polars()); -// RaceDataSource raceDataSource = new RaceXMLReader("mockXML/raceTest.xml", boatDataSource); -// Race testRace = new Race(raceDataSource, mockOutput); -// testRace.initialiseBoats(); -// Boat testBoat = testRace.getBoats().get(0); -// testBoat.setCurrentLeg(START_LEG); -// testBoat.setDistanceTravelledInLeg(START_LEG_DISTANCE - 1); -// testBoat.setCurrentPosition(ORIGIN.getAverageGPSCoordinate()); -// testRace.updatePosition(testBoat, 100, 100); -// assertFalse(testBoat.getCurrentPosition() == ORIGIN.getAverageGPSCoordinate()); -// } catch (ParserConfigurationException | IOException | SAXException | ParseException | StreamedCourseXMLException e) { -// e.printStackTrace(); -// fail(); -// } -// } -// -// @Ignore -// @Test -// public void windDirectionCorrectValues(){ -//// try { -//// MockOutput mockOutput = Mockito.mock(MockOutput.class); -//// BoatDataSource boatDataSource = new BoatXMLReader("mockXML/boatTest.xml"); -//// RaceDataSource raceDataSource = new RaceXMLReader("mockXML/raceTest.xml", boatDataSource); -//// Race testRace = new Race(raceDataSource, mockOutput); -//// testRace.setChangeWind(1); -//// testRace.setWindDir(65535); -//// testRace.changeWindDir(); -//// assertEquals(100, testRace.getWind()); -//// } catch (ParserConfigurationException | IOException | SAXException | ParseException | StreamedCourseXMLException e) { -//// e.printStackTrace(); -//// fail(); -//// } -// } -// -// -//} diff --git a/racevisionGame/src/test/java/visualiser/model/VisualiserRaceTest.java b/racevisionGame/src/test/java/visualiser/model/VisualiserRaceTest.java deleted file mode 100644 index ef5e691a..00000000 --- a/racevisionGame/src/test/java/visualiser/model/VisualiserRaceTest.java +++ /dev/null @@ -1,100 +0,0 @@ -//package visualiser.model; -// -// -//import org.junit.Before; -//import org.junit.Test; -//import shared.dataInput.RaceXMLReader; -//import shared.dataInput.XMLReader; -//import shared.exceptions.InvalidRaceDataException; -//import shared.model.GPSCoordinate; -// -//import java.nio.charset.StandardCharsets; -//import java.util.List; -// -//import static org.junit.Assert.assertEquals; -//import static org.junit.Assert.fail; -// -///** -// * Tests only work on the current version of mockXML/raceXML/raceTest.xml -// */ -//public class VisualiserRaceTest { -// private RaceXMLReader streamedCourseXMLReader; -// private List boundary; -// -// @Before -// public void setup() { -// try { -// streamedCourseXMLReader = new RaceXMLReader(XMLReader.readXMLFileToString("mockXML/raceXML/raceTest.xml", StandardCharsets.UTF_8)); -// boundary = streamedCourseXMLReader.getBoundary(); -// } catch (InvalidRaceDataException e) { -// e.printStackTrace(); -// fail("Cannot find mockXML/raceXML/raceTest.xml in the resources folder"); -// } -// } -// -// @Test -// public void testAllBoundaryPointsRead() { -// assertEquals(boundary.size(), 10); -// } -// -// @Test -// public void testBoundaryPointData() { -// // First point -// assertEquals(boundary.get(0).getLatitude(), -36.8325, 1e-6); -// assertEquals(boundary.get(0).getLongitude(), 174.8325, 1e-6); -// -// // Last point -// assertEquals(boundary.get(boundary.size() - 1).getLatitude(), -36.83417, 1e-6); -// assertEquals(boundary.get(boundary.size() - 1).getLongitude(), 174.84767, 1e-6); -// } -// -// @Test -// public void testMapEdges() { -// double maxLatitude = streamedCourseXMLReader.getMapBottomRight().getLatitude() - streamedCourseXMLReader.getPadding(); -// double maxLongitude = streamedCourseXMLReader.getMapBottomRight().getLongitude() - streamedCourseXMLReader.getPadding(); -// double minLatitude = streamedCourseXMLReader.getMapTopLeft().getLatitude() - streamedCourseXMLReader.getPadding(); -// double minLongitude = streamedCourseXMLReader.getMapTopLeft().getLongitude() - streamedCourseXMLReader.getPadding(); -// -// assertEquals(maxLatitude, -36.81033, 1e-6); -// assertEquals(maxLongitude, 174.88217, 1e-6); -// assertEquals(minLatitude, -36.83417, 1e-6); -// assertEquals(minLongitude, 174.81983, 1e-6); -// } -// -// @Test -// public void testRaceSettings() { -// -// } -// -// @Test -// public void correctLegSequence() { -// List legs = streamedCourseXMLReader.getLegs(); -// String[] expectedNames = { -// "StartLine", -// "M1", -// "M2", -// "Gate" -// }; -// for(int i = 0; i < legs.size(); i++) { -// assertEquals(expectedNames[i], legs.get(i).getName()); -// } -// } -// -// /** -// * raceTest.xml is not compliant with this test. Markers are positioned far out of bounds. -// */ -// @Test -// @Ignore -// public void markersWithinRaceBoundaries() { -// GPSCoordinate topLeft = streamedCourseXMLReader.getMapTopLeft(); -// GPSCoordinate bottomRight = streamedCourseXMLReader.getMapBottomRight(); -// -// for(Marker compoundMark : streamedCourseXMLReader.getMarkers()) { -// GPSCoordinate centre = compoundMark.getAverageGPSCoordinate(); -// assertTrue(centre.getLatitude() < bottomRight.getLatitude()); -// assertTrue(centre.getLatitude() > topLeft.getLatitude()); -// assertTrue(centre.getLongitude() > bottomRight.getLongitude()); -// assertTrue(centre.getLongitude() < topLeft.getLongitude()); -// } -// } -//} diff --git a/settings/keyBindings.xml b/settings/keyBindings.xml index 2b807e17..8aa46d6c 100644 --- a/settings/keyBindings.xml +++ b/settings/keyBindings.xml @@ -1,5 +1,5 @@ - + SPACE @@ -10,8 +10,8 @@ - DOWN - + LEFT + X @@ -22,12 +22,12 @@ - Z - + RIGHT + - UP - + Z +