You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
379 lines
13 KiB
379 lines
13 KiB
package visualiser.Controllers;
|
|
|
|
import com.interactivemesh.jfx.importer.stl.StlMeshImporter;
|
|
import javafx.animation.AnimationTimer;
|
|
import javafx.application.Platform;
|
|
import javafx.collections.FXCollections;
|
|
import javafx.collections.ListChangeListener;
|
|
import javafx.collections.ObservableList;
|
|
import javafx.fxml.FXML;
|
|
import javafx.geometry.Insets;
|
|
import javafx.scene.Node;
|
|
import javafx.scene.control.Alert;
|
|
import javafx.scene.control.ButtonType;
|
|
import javafx.scene.control.Label;
|
|
import javafx.scene.image.ImageView;
|
|
import javafx.scene.layout.AnchorPane;
|
|
import javafx.scene.layout.GridPane;
|
|
import javafx.scene.paint.Color;
|
|
import javafx.scene.paint.PhongMaterial;
|
|
import javafx.scene.shape.MeshView;
|
|
import mock.app.Event;
|
|
import network.Messages.Enums.RaceStatusEnum;
|
|
import network.Messages.Enums.RequestToJoinEnum;
|
|
import visualiser.app.App;
|
|
import visualiser.gameController.ControllerClient;
|
|
import visualiser.layout.BoatHighlight;
|
|
import visualiser.layout.SeaSurface;
|
|
import visualiser.layout.Subject3D;
|
|
import visualiser.layout.View3D;
|
|
import visualiser.model.VisualiserBoat;
|
|
import visualiser.model.VisualiserRaceEvent;
|
|
import visualiser.model.VisualiserRaceState;
|
|
|
|
import java.io.IOException;
|
|
import java.net.Socket;
|
|
import java.net.URL;
|
|
import java.time.temporal.ChronoUnit;
|
|
import java.util.*;
|
|
import java.util.logging.Level;
|
|
import java.util.logging.Logger;
|
|
|
|
/**
|
|
* Controller for Hosting a game.
|
|
*/
|
|
public class InGameLobbyController extends Controller {
|
|
@FXML
|
|
private ImageView imageView;
|
|
|
|
@FXML
|
|
GridPane playerContainer;
|
|
|
|
|
|
@FXML
|
|
private Label playerLabel;
|
|
|
|
@FXML
|
|
private Label playerLabel2;
|
|
|
|
@FXML
|
|
private Label playerLabel3;
|
|
|
|
@FXML
|
|
private Label playerLabel4;
|
|
|
|
@FXML
|
|
private Label playerLabel5;
|
|
|
|
@FXML
|
|
private Label playerLabel6;
|
|
|
|
@FXML
|
|
private Label countdownLabel;
|
|
|
|
@FXML
|
|
private AnchorPane countdownTenPane;
|
|
|
|
@FXML
|
|
private Label countdownTenText;
|
|
|
|
private Event game;
|
|
|
|
private View3D playerBoat;
|
|
|
|
private VisualiserRaceEvent visualiserRaceEvent;
|
|
|
|
private boolean isHost;
|
|
|
|
private ControllerClient controllerClient;
|
|
|
|
private ArrayList<Label> allPlayerLabels;
|
|
|
|
private ObservableList<Subject3D> subjects = FXCollections.observableArrayList();
|
|
|
|
private StlMeshImporter importer;
|
|
|
|
private PopulatePlayers lobbyUpdateListener;
|
|
|
|
|
|
public void initialize() {
|
|
allPlayerLabels = new ArrayList(Arrays.asList(playerLabel, playerLabel2,
|
|
playerLabel3,
|
|
playerLabel4,
|
|
playerLabel5,
|
|
playerLabel6));
|
|
|
|
URL asset = HostGameController.class.getClassLoader().getResource("assets/V1.2 Complete Boat.stl");
|
|
importer = new StlMeshImporter();
|
|
importer.read(asset);
|
|
lobbyUpdateListener = new PopulatePlayers();
|
|
|
|
}
|
|
|
|
private void resetLobby(){
|
|
for (Label label: allPlayerLabels){
|
|
label.setText("No Player");
|
|
}
|
|
List<Node> nodeCopy = new ArrayList(playerContainer.getChildren());
|
|
for (Node node: nodeCopy){
|
|
if (node instanceof View3D){
|
|
playerContainer.getChildren().remove(node);
|
|
}
|
|
}
|
|
}
|
|
|
|
public class PopulatePlayers implements ListChangeListener {
|
|
|
|
@Override
|
|
public void onChanged(Change change) {
|
|
Platform.runLater(
|
|
() -> {
|
|
while (change.next()){
|
|
if (change.wasAdded() || change.wasRemoved() || change.wasUpdated()){
|
|
try{
|
|
resetLobby();
|
|
int count = 0;
|
|
int row = 0;
|
|
for (VisualiserBoat boat :visualiserRaceEvent.getVisualiserRaceState().getBoats()) {
|
|
View3D playerBoatToSet = new View3D();
|
|
playerBoatToSet.setItems(subjects);
|
|
|
|
playerContainer.add(playerBoatToSet, (count % 3) , row);
|
|
playerContainer.setMargin(playerBoatToSet, new Insets(10, 10, 10, 10));
|
|
|
|
SeaSurface sea = new SeaSurface(750, 200);
|
|
sea.setX(250);
|
|
sea.setZ(210);
|
|
subjects.add(sea);
|
|
|
|
MeshView mesh = new MeshView(importer.getImport());
|
|
PhongMaterial boatColorMat = new PhongMaterial(boat.getColor());
|
|
mesh.setMaterial(boatColorMat);
|
|
Subject3D subject = new Subject3D(mesh,0);
|
|
subjects.add(subject);
|
|
|
|
playerBoatToSet.setDistance(50);
|
|
playerBoatToSet.setYaw(45);
|
|
playerBoatToSet.setPitch(20);
|
|
|
|
|
|
if (boat.isClientBoat()) {
|
|
BoatHighlight boatHighlight = new BoatHighlight(10, new Color(1, 1, 0, 0.1));
|
|
boatHighlight.setX(subject.getPosition().getX());
|
|
boatHighlight.setY(subject.getPosition().getY());
|
|
boatHighlight.setZ(subject.getPosition().getZ());
|
|
subjects.add(boatHighlight);
|
|
subject.getMesh().toFront();
|
|
}
|
|
|
|
AnimationTimer rotate = new AnimationTimer() {
|
|
@Override
|
|
public void handle(long now) {
|
|
subject.setHeading(subject.getHeading().getAngle() + 0.1);
|
|
}
|
|
};
|
|
rotate.start();
|
|
|
|
allPlayerLabels.get(count).setText(boat.getName());
|
|
allPlayerLabels.get(count).toFront();
|
|
count += 1;
|
|
if (count > 2){
|
|
row = 1;
|
|
}
|
|
}
|
|
}
|
|
catch(ConcurrentModificationException e){
|
|
}
|
|
}
|
|
}
|
|
}
|
|
);
|
|
}
|
|
}
|
|
/*
|
|
private void populatePlayers(ListChangeListener.Change change){
|
|
}*/
|
|
|
|
/**
|
|
* Starts the race.
|
|
*/
|
|
private void startRace() {
|
|
//Initialises the race clock.
|
|
initialiseRaceClock(this.visualiserRaceEvent.getVisualiserRaceState());
|
|
|
|
|
|
//Starts the race countdown timer.
|
|
countdownTimer();
|
|
}
|
|
|
|
/**
|
|
* Initialises the race clock/timer labels for the start time, current time, and remaining time.
|
|
* @param visualiserRace The race to get data from.
|
|
*/
|
|
private void initialiseRaceClock(VisualiserRaceState visualiserRace) {
|
|
//Remaining time.
|
|
initialiseRaceClockDuration(visualiserRace);
|
|
|
|
}
|
|
|
|
|
|
/**
|
|
* Initialises the race duration label.
|
|
* @param visualiserRace The race to get data from.
|
|
*/
|
|
private void initialiseRaceClockDuration(VisualiserRaceState visualiserRace) {
|
|
|
|
visualiserRace.getRaceClock().durationProperty().addListener((observable, oldValue, newValue) -> {
|
|
Platform.runLater(() -> {
|
|
countdownLabel.setText(newValue);
|
|
});
|
|
});
|
|
|
|
}
|
|
/**
|
|
* Countdown timer until race starts.
|
|
*/
|
|
private void countdownTimer() {
|
|
new AnimationTimer() {
|
|
@Override
|
|
public void handle(long arg0) {
|
|
|
|
//Get the current race status.
|
|
RaceStatusEnum raceStatus = visualiserRaceEvent.getVisualiserRaceState().getRaceStatusEnum();
|
|
|
|
//Try catch for getting interval times
|
|
try {
|
|
long interval = ChronoUnit.MILLIS.between(visualiserRaceEvent.getVisualiserRaceState().getRaceClock().getCurrentTime(), visualiserRaceEvent.getVisualiserRaceState().getRaceClock().getStartingTime());
|
|
if(interval<=10000){
|
|
countdownLabel.setVisible(false);
|
|
countdownTenPane.setVisible(true);
|
|
countdownTenText.setVisible(true);
|
|
}
|
|
countdownText(interval);
|
|
} catch (Exception e){
|
|
|
|
}
|
|
|
|
|
|
//If the race has reached the preparatory phase, or has started...
|
|
if (raceStatus == RaceStatusEnum.PREPARATORY || raceStatus == RaceStatusEnum.STARTED) {
|
|
//Stop this timer.
|
|
stop();
|
|
|
|
//Hide this, and display the race controller.
|
|
try {
|
|
visualiserRaceEvent.getVisualiserRaceState().getBoats().removeListener(lobbyUpdateListener);
|
|
|
|
RaceViewController rvc = (RaceViewController)
|
|
loadScene("newRaceView.fxml");
|
|
rvc.startRace(visualiserRaceEvent, controllerClient,
|
|
isHost);
|
|
} catch (IOException e) {
|
|
e.printStackTrace();
|
|
}
|
|
|
|
}
|
|
}
|
|
}.start();
|
|
}
|
|
|
|
public void enterGameLobby(Socket socket, boolean isHost){
|
|
try {
|
|
|
|
this.visualiserRaceEvent = new VisualiserRaceEvent(socket, RequestToJoinEnum.PARTICIPANT);
|
|
this.isHost = isHost;
|
|
this.controllerClient = visualiserRaceEvent.getControllerClient();
|
|
|
|
this.visualiserRaceEvent.getVisualiserRaceState().getBoats().addListener(this.lobbyUpdateListener);
|
|
|
|
startRace();
|
|
} catch (IOException e) {
|
|
//TODO should probably let this propagate, so that we only enter this scene if everything works
|
|
Logger.getGlobal().log(Level.WARNING, "Could not connect to server.", e);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Menu button pressed. Prompt alert then return to menu
|
|
* @throws IOException socket erro
|
|
*/
|
|
public void menuBtnPressed() throws IOException {
|
|
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){
|
|
visualiserRaceEvent.terminate();
|
|
|
|
try{
|
|
if(isHost) {
|
|
App.game.endEvent();
|
|
}
|
|
loadScene("title.fxml");
|
|
|
|
}catch (IOException ignore){};
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 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");
|
|
}
|
|
|
|
public void joinSpecPressed(){
|
|
//System.out.println("Spectator list pressed. Joining spectators");
|
|
}
|
|
|
|
public void joinRacePressed(){
|
|
//System.out.println("Empty race user pane pressed. Joining racers");
|
|
}
|
|
|
|
/**
|
|
* Countdown interval checker that updates the countdown text
|
|
* @param interval Countdown interval to check
|
|
*/
|
|
private void countdownText(long interval){
|
|
countdownTenPane.setVisible(false);
|
|
//Do nothing if 5 seconds or less to go
|
|
if (interval <=5000){
|
|
countdownTenPane.setVisible(false);
|
|
//countdownTenText.setText("5");
|
|
return;
|
|
}
|
|
|
|
//6 seconds left. Display 1 second for countdown
|
|
if (interval <=6000){
|
|
countdownTenText.setText("1");
|
|
return;
|
|
}
|
|
|
|
//7 seconds left. Display 2 seconds for countdown
|
|
if (interval <=7000){
|
|
countdownTenText.setText("2");
|
|
return;
|
|
}
|
|
|
|
//8 seconds left. Display 3 seconds for countdown
|
|
if (interval <=8000){
|
|
countdownTenText.setText("3");
|
|
return;
|
|
}
|
|
|
|
//9 seconds left. Display 4 seconds for countdown
|
|
if (interval <=9000){
|
|
countdownTenText.setText("4");
|
|
return;
|
|
}
|
|
|
|
//10 seconds left. Display 5 seconds for countdown
|
|
if (interval <=10000){
|
|
countdownTenText.setText("5");
|
|
return;
|
|
}
|
|
}
|
|
|
|
}
|