Merge branch 'storyA_sounds' into storyD-3D
# Conflicts: # racevisionGame/src/main/java/visualiser/layout/SeaSurface.java # racevisionGame/src/main/java/visualiser/layout/SkyBox.java
This commit is contained in:
@@ -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
|
||||
TextField gameNameField;
|
||||
|
||||
@FXML
|
||||
private ImageView imageView;
|
||||
TextField hostNameField;
|
||||
|
||||
@FXML
|
||||
AnchorPane hostWrapper;
|
||||
|
||||
@FXML
|
||||
AnchorPane imagePane;
|
||||
Button previousButton;
|
||||
|
||||
@FXML
|
||||
SplitPane splitPane;
|
||||
Button nextButton;
|
||||
|
||||
@FXML
|
||||
AnchorPane specPane;
|
||||
|
||||
@FXML
|
||||
GridPane playerContainer;
|
||||
ImageView mapImage;
|
||||
|
||||
private Event game;
|
||||
|
||||
private View3D view3D;
|
||||
private ArrayList<Image> listOfMaps;
|
||||
private int currentMapIndex = 0;
|
||||
|
||||
|
||||
@Override
|
||||
public void initialize(URL location, ResourceBundle resources) {
|
||||
ObservableList<Subject3D> subjects = FXCollections.observableArrayList();
|
||||
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"));
|
||||
|
||||
view3D = new View3D();
|
||||
view3D.setItems(subjects);
|
||||
playerContainer.add(view3D, 0,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();
|
||||
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<ButtonType> 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; }
|
||||
|
||||
}
|
||||
|
||||
@@ -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<RaceConnection> 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{
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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<TutorialState> 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<Subject3D> viewSubjects;
|
||||
|
||||
private Subject3D nextMarkArrow;
|
||||
private ChangeListener<? super GPSCoordinate> 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<String, ControlKey> 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<ButtonType> 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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user