Merge remote-tracking branch 'origin/develop' into Story1248_Game_App_Scaling

# Conflicts:
#	src/main/java/seng302/visualiser/GameView.java
#	src/main/java/seng302/visualiser/controllers/RaceViewController.java
#	src/main/resources/views/RaceView.fxml
This commit is contained in:
Zhi You Tan
2017-09-11 15:47:47 +12:00
57 changed files with 1578 additions and 538 deletions
@@ -18,6 +18,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import seng302.gameServer.messages.BoatAction;
import seng302.gameServer.messages.BoatActionMessage;
import seng302.gameServer.messages.ChatterMessage;
import seng302.gameServer.messages.ClientType;
import seng302.gameServer.messages.CustomizeRequestMessage;
import seng302.gameServer.messages.CustomizeRequestType;
@@ -33,8 +34,6 @@ import seng302.model.stream.packets.StreamPacket;
*/
public class ClientToServerThread implements Runnable {
/**
* Functional interface for receiving packets from client socket.
*/
@@ -95,7 +94,7 @@ public class ClientToServerThread implements Runnable {
sendRegistrationRequest();
thread = new Thread(this);
thread = new Thread(this, "ClientToServer");
thread.start();
}
@@ -283,9 +282,17 @@ public class ClientToServerThread implements Runnable {
* @param message The given message type.
*/
private void sendBoatActionMessage(BoatActionMessage message) {
sendByteBuffer(message.getBuffer());
}
public void sendChatterMessage(String message) {
sendByteBuffer(new ChatterMessage(clientId, message).getBuffer());
}
private void sendByteBuffer(byte[] bytes) {
if (clientId != -1) {
try {
os.write(message.getBuffer());
os.write(bytes);
} catch (IOException e) {
logger.warn("IOException on attempting to sendBoatAction from Client");
notifyDisconnectListeners("Cannot communicate with server");
@@ -294,7 +301,7 @@ public class ClientToServerThread implements Runnable {
}
}
private void closeSocket() {
public void closeSocket() {
try {
socket.close();
socketOpen = false;
@@ -1,8 +1,11 @@
package seng302.visualiser;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.util.ArrayList;
import java.util.Date;
import java.util.Map;
import java.util.TimeZone;
import javafx.application.Platform;
@@ -12,12 +15,15 @@ import javafx.fxml.FXMLLoader;
import javafx.scene.Node;
import javafx.scene.control.Alert;
import javafx.scene.control.Alert.AlertType;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.Pane;
import javafx.util.Pair;
import seng302.gameServer.GameState;
import seng302.gameServer.MainServerThread;
import seng302.gameServer.messages.BoatAction;
import seng302.gameServer.messages.BoatStatus;
import seng302.gameServer.messages.YachtEventType;
import seng302.model.ClientYacht;
import seng302.model.RaceState;
import seng302.model.stream.packets.StreamPacket;
@@ -28,6 +34,7 @@ import seng302.model.stream.parser.RaceStatusData;
import seng302.model.stream.parser.YachtEventData;
import seng302.model.stream.xml.parser.RaceXMLData;
import seng302.model.stream.xml.parser.RegattaXMLData;
import seng302.utilities.Sounds;
import seng302.utilities.StreamParser;
import seng302.utilities.XMLParser;
import seng302.visualiser.controllers.FinishScreenViewController;
@@ -53,6 +60,8 @@ public class GameClient {
private RaceState raceState = new RaceState();
private LobbyController lobbyController;
private ArrayList<ClientYacht> finishedBoats = new ArrayList<>();
private ObservableList<String> clientLobbyList = FXCollections.observableArrayList();
/**
@@ -142,11 +151,10 @@ public class GameClient {
}
private void loadStartScreen() {
socketThread.setSocketToClose();
if (server != null) {
server.terminate();
server = null;
if (socketThread != null) {
socketThread.setSocketToClose();
}
FXMLLoader fxmlLoader = new FXMLLoader(
getClass().getResource("/views/StartScreenView.fxml"));
try {
@@ -195,9 +203,19 @@ public class GameClient {
raceView = fxmlLoader.getController();
ClientYacht player = allBoatsMap.get(socketThread.getClientId());
raceView.loadRace(allBoatsMap, courseData, raceState, player);
raceView.getSendPressedProperty().addListener((obs, old, isPressed) -> {
if (isPressed) {
formatAndSendChatMessage(raceView.readChatInput());
}
});
}
private void loadFinishScreenView() {
Sounds.stopMusic();
Sounds.stopSoundEffects();
Sounds.playFinishMusic();
FXMLLoader fxmlLoader = loadFXMLToHolder("/views/FinishScreenView.fxml");
FinishScreenViewController controller = fxmlLoader.getController();
controller.setFinishers(raceState.getPlayerPositions());
@@ -248,6 +266,7 @@ public class GameClient {
courseData = XMLParser.parseRace(
StreamParser.extractXmlMessage(packet)
);
if (raceView != null) {
raceView.updateRaceData(courseData);
}
@@ -278,8 +297,21 @@ public class GameClient {
break;
case YACHT_EVENT_CODE:
showCollisionAlert(StreamParser.extractYachtEventCode(packet));
YachtEventData yachtEventData = StreamParser.extractYachtEventCode(packet);
if (yachtEventData.getEventId() == YachtEventType.COLLISION.getCode()) {
showCollisionAlert(StreamParser.extractYachtEventCode(packet));
} else if (yachtEventData.getEventId() == YachtEventType.TOKEN.getCode()) {
showPickUp();
}
break;
case CHATTER_TEXT:
Pair<Integer, String> playerIdMessagePair = StreamParser
.extractChatterText(packet);
raceView.updateChatHistory(
allBoatsMap.get(playerIdMessagePair.getKey()).getColour(),
playerIdMessagePair.getValue()
);
}
}
}
@@ -320,7 +352,6 @@ public class GameClient {
if (allXMLReceived()) {
ClientYacht clientYacht = allBoatsMap.get(roundingData.getBoatId());
clientYacht.roundMark(
courseData.getCompoundMarks().get(roundingData.getMarkId()),
roundingData.getTimeStamp(),
raceState.getRaceTime() - roundingData.getTimeStamp()
);
@@ -335,6 +366,9 @@ public class GameClient {
for (ClientYacht yacht : allBoatsMap.values()) {
if (yacht.getBoatStatus() != BoatStatus.FINISHED.getCode()) {
raceFinished = false;
} else if (!finishedBoats.contains(yacht)) {
finishedBoats.add(yacht);
Sounds.playFinishSound();
}
}
@@ -350,6 +384,7 @@ public class GameClient {
}
if (raceFinished) {
Sounds.playFinishSound();
close();
loadFinishScreenView();
}
@@ -373,6 +408,12 @@ public class GameClient {
* @param e The key event triggering this call
*/
private void keyPressed(KeyEvent e) {
if (raceView.isChatInputFocused()) {
if (e.getCode() == KeyCode.ENTER) {
formatAndSendChatMessage(raceView.readChatInput());
}
return;
}
switch (e.getCode()) {
case SPACE: // align with vmg
socketThread.sendBoatAction(BoatAction.VMG); break;
@@ -381,12 +422,16 @@ public class GameClient {
case PAGE_DOWN: // downwind
socketThread.sendBoatAction(BoatAction.DOWNWIND); break;
case ENTER: // tack/gybe
// if chat box is active take whatever is in there and send it to server
socketThread.sendBoatAction(BoatAction.TACK_GYBE); break;
}
}
private void keyReleased(KeyEvent e) {
if (raceView.isChatInputFocused()) {
return;
}
switch (e.getCode()) {
//TODO 12/07/17 Determine the sail state and send the appropriate packet (eg. if sails are in, send a sail out packet)
case SHIFT: // sails in/sails out
@@ -407,13 +452,31 @@ public class GameClient {
* Tells race view to show a collision animation.
*/
private void showCollisionAlert(YachtEventData yachtEventData) {
// 33 is the agreed code to show collision
if (yachtEventData.getEventId() == 33) {
raceState.storeCollision(
allBoatsMap.get(
yachtEventData.getSubjectId().intValue()
)
Sounds.playCrashSound();
raceState.storeCollision(
allBoatsMap.get(
yachtEventData.getSubjectId().intValue()
)
);
}
// TODO: 11/09/17 wmu16 - Add in functionality to viually indicate a pickup to a user
private void showPickUp() {
Sounds.playTokenPickupSound();
}
private void formatAndSendChatMessage(String rawChat) {
if (rawChat.length() > 0) {
socketThread.sendChatterMessage(
new SimpleDateFormat("[HH:mm:ss] ").format(new Date()) +
allBoatsMap.get(socketThread.getClientId()).getShortName() + ": " + rawChat
);
}
}
public ClientToServerThread getSocketThread() {
return socketThread;
}
}
+65 -20
View File
@@ -36,7 +36,9 @@ import seng302.model.Limit;
import seng302.model.mark.CompoundMark;
import seng302.model.mark.Corner;
import seng302.model.mark.Mark;
import seng302.model.token.Token;
import seng302.utilities.GeoUtility;
import seng302.utilities.Sounds;
import seng302.visualiser.fxObjects.AnnotationBox;
import seng302.visualiser.fxObjects.BoatObject;
import seng302.visualiser.fxObjects.CourseBoundary;
@@ -64,6 +66,8 @@ public class GameView extends Pane {
private double referencePointX, referencePointY;
private double metersPerPixelX, metersPerPixelY;
private boolean isZoom = false;
private Text fpsDisplay = new Text();
private Polygon raceBorder = new CourseBoundary();
@@ -81,6 +85,7 @@ public class GameView extends Pane {
private Group boatObjectGroup = new Group();
private Group trails = new Group();
private Group markers = new Group();
private Group tokens = new Group();
private List<CompoundMark> course = new ArrayList<>();
private ImageView mapImage = new ImageView();
@@ -100,7 +105,7 @@ public class GameView extends Pane {
private void zoomOut() {
scaleFactor = 0.1;
if (this.getScaleX() > 0.5) {
if (this.isZoom && this.getScaleX() > 0.5) {
this.setScaleX(this.getScaleX() - scaleFactor);
this.setScaleY(this.getScaleY() - scaleFactor);
}
@@ -108,7 +113,7 @@ public class GameView extends Pane {
private void zoomIn() {
scaleFactor = 0.1;
if (this.getScaleX() < 2.5) {
if (this.isZoom && this.getScaleX() < 2.5) {
this.setScaleX(this.getScaleX() + scaleFactor);
this.setScaleY(this.getScaleY() + scaleFactor);
}
@@ -140,7 +145,15 @@ public class GameView extends Pane {
gameObjects.add(mapImage);
gameObjects.add(raceBorder);
gameObjects.add(markers);
gameObjects.add(tokens);
initializeTimer();
this.sceneProperty().addListener(((observable, oldValue, scene) -> {
if (scene != null) {
setupZoom();
} else {
disableZoom();
}
}));
this.widthProperty().addListener(new ChangeListener<Number>() {
@Override
@@ -468,23 +481,51 @@ public class GameView extends Pane {
raceBorder.getPoints().setAll(boundaryPoints);
}
/**
* Replaces all tokens in the course with those passed in
*
* @param newTokens the tokens to be put on the course.
*/
public void updateTokens(List<Token> newTokens) {
List<Marker> mapTokens = new ArrayList<>();
for (Token token : newTokens) {
Point2D location = findScaledXY(token.getLat(), token.getLng());
Marker thisMarker = new Marker(Color.YELLOW);
thisMarker.setLayoutX(location.getX());
thisMarker.setLayoutY(location.getY());
mapTokens.add(thisMarker);
}
Platform.runLater(() -> {
tokens.getChildren().clear();
tokens.getChildren().addAll(mapTokens);
});
}
// TODO: 16/08/17 initialize zooming internal to GameView only
/**
* Enables zoom. Has to be called after this is added to a scene.
*/
public void enableZoom () {
System.out.println("enable zoom");
if (this.getScene() != null) {
System.out.println("can zoom");
this.getScene().addEventHandler(KeyEvent.KEY_PRESSED, (event) -> {
if (event.getCode() == KeyCode.Z) {
zoomIn();
} else if (event.getCode() == KeyCode.X) {
zoomOut();
}
});
}
private void setupZoom() {
this.getScene().addEventHandler(KeyEvent.KEY_PRESSED, (event) -> {
if (event.getCode() == KeyCode.Z) {
zoomIn();
} else if (event.getCode() == KeyCode.X) {
zoomOut();
}
});
enableZoom();
}
public void enableZoom() {
isZoom = true;
}
public void disableZoom() {
isZoom = false;
}
/**
* Rescales the race to the size of the window.
*
@@ -817,15 +858,11 @@ public class GameView extends Pane {
playerYacht.addMarkRoundingListener(this::updateMarkArrows);
}
private void updateMarkArrows (ClientYacht yacht, CompoundMark compoundMark, int legNumber) {
private void updateMarkArrows (ClientYacht yacht, int legNumber) {
//Only show arrows for this and next leg.
if (compoundMark != null) {
for (Mark mark : compoundMark.getMarks()) {
markerObjects.get(mark).showNextExitArrow();
}
}
CompoundMark nextMark = null;
if (legNumber < course.size() - 1) {
Sounds.playMarkRoundingSound();
nextMark = course.get(legNumber);
for (Mark mark : nextMark.getMarks()) {
markerObjects.get(mark).showNextEnterArrow();
@@ -839,6 +876,14 @@ public class GameView extends Pane {
}
}
}
if (legNumber - 1 >= 0) {
CompoundMark thisMark = course.get(Math.max(0, legNumber - 1));
if (thisMark != nextMark) {
for (Mark mark : thisMark.getMarks()) {
markerObjects.get(mark).showNextExitArrow();
}
}
}
}
/**
@@ -7,6 +7,7 @@ import javafx.scene.control.TextField;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
import seng302.gameServer.messages.CustomizeRequestType;
import seng302.utilities.Sounds;
import seng302.visualiser.ClientToServerThread;
public class CustomizationController {
@@ -34,7 +35,8 @@ public class CustomizationController {
@FXML
public void submitCustomization() {
System.out.println("Attempting to send");
Sounds.playButtonClick();
// System.out.println("Attempting to send");
socketThread.sendCustomizationRequest(CustomizeRequestType.NAME, nameField.getText().getBytes());
// TODO: 16/08/17 ajm412: Turn colors into byte array.
Color color = boatColorPicker.getValue();
@@ -15,10 +15,12 @@ import javafx.fxml.Initializable;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Pane;
import seng302.model.ClientYacht;
import seng302.utilities.Sounds;
public class FinishScreenViewController implements Initializable {
@@ -85,6 +87,11 @@ public class FinishScreenViewController implements Initializable {
}
public void switchToStartScreenView() {
Sounds.playButtonClick();
setContentPane("/views/StartScreenView.fxml");
}
public void playButtonHoverSound(MouseEvent mouseEvent) {
Sounds.playHoverSound();
}
}
@@ -16,6 +16,7 @@ import javafx.scene.control.Button;
import javafx.scene.control.TextArea;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.MouseEvent;
import javafx.scene.paint.Color;
import javafx.scene.text.Text;
import javafx.stage.Stage;
@@ -23,6 +24,7 @@ import seng302.gameServer.GameStages;
import seng302.gameServer.GameState;
import seng302.model.Colors;
import seng302.model.RaceState;
import seng302.utilities.Sounds;
import seng302.visualiser.ClientToServerThread;
/**
@@ -31,6 +33,10 @@ import seng302.visualiser.ClientToServerThread;
*/
public class LobbyController {
public void playButtonHoverSound(MouseEvent mouseEvent) {
Sounds.playHoverSound();
}
public enum CloseStatus {
LEAVE,
READY
@@ -153,6 +159,7 @@ public class LobbyController {
@FXML
public void customize() {
Sounds.playButtonClick();
Parent root;
try {
FXMLLoader fxmlLoader = new FXMLLoader(LobbyController.class.getResource("/views/customizeView.fxml"));
@@ -184,6 +191,7 @@ public class LobbyController {
@FXML
public void leaveLobbyButtonPressed() {
Sounds.playButtonClick();
// TODO: 10/07/17 wmu16 - Finish function!
GameState.setCurrentStage(GameStages.CANCELLED);
// TODO: 20/07/17 wmu16 - Implement some way of terminating the game
@@ -193,6 +201,7 @@ public class LobbyController {
@FXML
public void readyButtonPressed() {
Sounds.playButtonClick();
GameState.setCurrentStage(GameStages.PRE_RACE);
// Do countdown logic here
@@ -9,6 +9,7 @@ import java.util.TimerTask;
import java.util.concurrent.TimeUnit;
import javafx.animation.Timeline;
import javafx.application.Platform;
import javafx.beans.property.ReadOnlyBooleanProperty;
import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
@@ -25,6 +26,8 @@ import javafx.scene.control.Button;
import javafx.scene.control.CheckBox;
import javafx.scene.control.ComboBox;
import javafx.scene.control.Slider;
import javafx.scene.control.TextField;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Pane;
import javafx.scene.layout.VBox;
@@ -41,18 +44,31 @@ import seng302.model.RaceState;
import seng302.model.mark.CompoundMark;
import seng302.model.mark.Mark;
import seng302.model.stream.xml.parser.RaceXMLData;
import seng302.model.token.Token;
import seng302.utilities.Sounds;
import seng302.visualiser.GameView;
import seng302.visualiser.controllers.annotations.Annotation;
import seng302.visualiser.controllers.annotations.ImportantAnnotationController;
import seng302.visualiser.controllers.annotations.ImportantAnnotationDelegate;
import seng302.visualiser.controllers.annotations.ImportantAnnotationsState;
import seng302.visualiser.fxObjects.BoatObject;
import seng302.visualiser.fxObjects.ChatHistory;
/**
* Controller class that manages the display of a race
*/
public class RaceViewController extends Thread implements ImportantAnnotationDelegate {
private final int CHAT_LIMIT = 128;
@FXML
private Pane basePane;
@FXML
private Button chatSend;
@FXML
private Pane chatHistoryHolder;
@FXML
private TextField chatInput;
@FXML
private LineChart<String, Double> raceSparkLine;
@FXML
@@ -85,12 +101,17 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
private GameView gameView;
private RaceState raceState;
private ChatHistory chatHistory;
private Timeline timerTimeline;
private Timer timer = new Timer();
private List<Series<String, Double>> sparkLineData = new ArrayList<>();
private ImportantAnnotationsState importantAnnotations;
private ObservableList<ClientYacht> selectionComboBoxList = FXCollections.observableArrayList();
public void initialize() {
Sounds.stopMusic();
Sounds.playRaceMusic();
// Load a default important annotation state
importantAnnotations = new ImportantAnnotationsState();
@@ -101,10 +122,30 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
raceSparkLine.visibleProperty().setValue(false);
raceSparkLine.getYAxis().setAutoRanging(false);
sparklineYAxis.setTickMarkVisible(false);
positionVbox.getStylesheets().add(getClass().getResource("/css/master.css").toString());
selectAnnotationBtn.setOnAction(event -> loadSelectAnnotationView());
chatInput.lengthProperty().addListener((obs, oldLen, newLen) -> {
if (newLen.intValue() > CHAT_LIMIT) {
chatInput.setText(chatInput.getText().substring(0, CHAT_LIMIT));
}
});
chatHistory = new ChatHistory();
chatHistoryHolder.getChildren().addAll(chatHistory);
chatHistory.prefWidthProperty().bind(
chatHistoryHolder.widthProperty()
);
chatHistory.prefHeightProperty().bind(
chatHistoryHolder.heightProperty()
);
// chatHistory.setFitToWidth(true);
// chatHistory.setFitToHeight(true);
// chatHistory.textProperty().addListener((obs, oldValue, newValue) -> {
// chatHistory.setScrollTop(Double.MAX_VALUE);
// });
contentAnchorPane.setOnMouseClicked((event) ->
contentAnchorPane.requestFocus()
);
}
public void loadRace (
@@ -116,12 +157,6 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
this.markers = raceData.getCompoundMarks();
this.raceState = raceState;
initializeUpdateTimer();
initialiseFPSCheckBox();
initialiseAnnotationSlider();
initialiseBoatSelectionComboBox();
initialiseSparkLine();
raceState.getPlayerPositions().addListener((ListChangeListener<ClientYacht>) c -> {
while (c.next()) {
if (c.wasPermutated()) {
@@ -137,10 +172,10 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
Platform.runLater(() -> contentAnchorPane.getChildren().add(0, gameView));
gameView.setBoats(new ArrayList<>(participants.values()));
gameView.updateBorder(raceData.getCourseLimit());
gameView.updateTokens(raceData.getTokens());
gameView.updateCourse(
new ArrayList<>(raceData.getCompoundMarks().values()), raceData.getMarkSequence()
);
gameView.enableZoom();
gameView.setBoatAsPlayer(player);
gameView.startRace();
@@ -155,6 +190,20 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
updateWindDirection(raceState.windDirectionProperty().doubleValue());
updateWindSpeed(raceState.getWindSpeed());
gameView.setWindDir(raceState.windDirectionProperty().doubleValue());
chatInput.focusedProperty().addListener((obs, oldValue, newValue) -> {
if (newValue) {
gameView.disableZoom();
} else {
gameView.enableZoom();
}
});
Platform.runLater(() -> {
initializeUpdateTimer();
initialiseFPSCheckBox();
initialiseAnnotationSlider();
initialiseBoatSelectionComboBox();
initialiseSparkLine();
});
}
/**
@@ -305,13 +354,6 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
)
);
}
// XYChart.Series<String, Double> positionData = sparkLineData.get(yacht.getSourceID());
// positionData.getData().add(
// new XYChart.Data<>(
// Integer.toString(legNumber),
// 1.0 + participants.size() - yacht.getPlacing()
// )
// );
}
@@ -533,10 +575,8 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
* for the combobox to take action upon selection
*/
private void initialiseBoatSelectionComboBox() {
yachtSelectionComboBox.setItems(
FXCollections.observableArrayList(participants.values())
);
//Null check is if the listener is fired but nothing selected
selectionComboBoxList.setAll(participants.values());
yachtSelectionComboBox.setItems(selectionComboBoxList);
yachtSelectionComboBox.valueProperty().addListener((obs, lastSelection, selectedBoat) -> {
if (selectedBoat != null) {
gameView.selectBoat(selectedBoat);
@@ -621,5 +661,26 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
public void updateRaceData (RaceXMLData raceData) {
this.courseData = raceData;
gameView.updateBorder(raceData.getCourseLimit());
gameView.updateTokens(raceData.getTokens());
}
public ReadOnlyBooleanProperty getSendPressedProperty() {
return chatSend.pressedProperty();
}
public boolean isChatInputFocused() {
return chatInput.focusedProperty().getValue();
}
public String readChatInput() {
String chat = chatInput.getText();
chatInput.clear();
basePane.requestFocus();
return chat;
}
public void updateChatHistory(Paint playerColour, String newMessage) {
Platform.runLater(() -> chatHistory.addMessage(playerColour, newMessage));
}
}
@@ -6,12 +6,16 @@ import java.net.NetworkInterface;
import java.net.URL;
import java.util.Enumeration;
import java.util.ResourceBundle;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.TextField;
import javafx.scene.control.ToggleButton;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.GridPane;
import seng302.gameServer.GameState;
import seng302.utilities.Sounds;
import seng302.visualiser.GameClient;
/**
@@ -20,114 +24,56 @@ import seng302.visualiser.GameClient;
*/
public class StartScreenController implements Initializable {
@FXML
private ToggleButton muteMusicButton;
@FXML
private ToggleButton muteSoundsButton;
@FXML
private TextField ipTextField;
@FXML
private TextField portTextField;
@FXML
private GridPane startScreen2;
@FXML
private AnchorPane holder;
GameClient gameClient;
private GameClient gameClient;
public void initialize(URL url, ResourceBundle resourceBundle) {
Sounds.stopMusic();
Sounds.stopSoundEffects();
Sounds.playMenuMusic();
if (Sounds.isMusicMuted()) {
muteMusicButton.setText("UnMute Music");
} else {
muteMusicButton.setText("Mute Music");
}
if (Sounds.isSoundEffectsMuted()) {
muteSoundsButton.setText("UnMute Sounds");
} else {
muteSoundsButton.setText("Mute Sounds");
}
Sounds.setMutes();
// gameClient = new GameClient(holder);
}
//
// /**
// * Loads the fxml content into the parent pane
// * @param jfxUrl
// * @return the controller of the fxml
// */
// private Object setContentPane(String jfxUrl) {
// try {
// AnchorPane contentPane = (AnchorPane) startScreen2.getParent();
// contentPane.getChildren().removeAll();
// contentPane.getChildren().clear();
// contentPane.getStylesheets().add(getClass().getResource("/css/master.css").toString());
// FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource(jfxUrl));
// contentPane.getChildren().addAll((Pane) fxmlLoader.load());
//
// return fxmlLoader.getController();
// } catch (IOException e) {
// e.printStackTrace();
// }
// return null;
// }
/**
* ATTEMPTS TO:
* Sets up a new game state with your IP address as designated as the host.
* Starts a thread to listen for incoming connections.
* Starts a client to server thread and connects to own ip.
* Switches to the lobby screen
* Creates an instance of GameClient and runs it as a host.
*/
@FXML
public void hostButtonPressed() {
// new GameState(getLocalHostIp());
Sounds.playButtonClick();
gameClient = new GameClient(holder);
gameClient.runAsHost(getLocalHostIp(), 4942);
// try {
//// String ipAddress = InetAddress.getLocalHost().getHostAddress();
//// new GameState(ipAddress);
//// new MainServerThread();
//// ClientToServerThread clientToServerThread = new ClientToServerThread("localhost", 4950);
//// controller.setClientToServerThread(clientToServerThread);
// // get the lobby controller so that we can pass the game server thread to it
// new GameState(getLocalHostIp());
// MainServerThread mainServerThread = new MainServerThread();
//// ClientState.setHost(true);
// // host will connect and handshake to itself after setting up the server
// // TODO: 24/07/17 wmu16 - Make port number some static global type constant?
//// ClientToServerThread clientToServerThread = new ClientToServerThread(ClientState.getHostIp(), 4942);
//// ClientState.setConnectedToHost(true);
//// controller.setClientToServerThread(clientToServerThread);
// LobbyController lobbyController = (LobbyController) setContentPane("/views/LobbyView.fxml");
// lobbyController.setMainServerThread(mainServerThread);
// } catch (Exception e) {
// Alert alert = new Alert(AlertType.ERROR);
// alert.setHeaderText("Cannot host");
// alert.setContentText("Oops, failed to host, try to restart.");
// alert.showAndWait();
// e.printStackTrace();
// }
}
/**
* ATTEMPTS TO:
* Connect to an ip address and port using the ip and port specified on start screen.
* Starts a Client To Server Thread to maintain connection to host.
* Switch view to lobby view.
* Creates an instance of GameClient and runs it has a client.
*/
@FXML
public void connectButtonPressed() {
// TODO: 10/07/17 wmu16 - Finish function
Sounds.playButtonClick();
gameClient = new GameClient(holder);
gameClient.runAsClient(ipTextField.getText().trim().toLowerCase(), 4942);
// try {
// String ipAddress = ipTextField.getText().trim().toLowerCase();
// Integer port = Integer.valueOf(portTextField.getText().trim());
//
//// ClientToServerThread clientToServerThread = new ClientToServerThread(ipAddress, port);
//// ClientState.setHost(false);
//// ClientState.setConnectedToHost(true);
//
//// controller.setClientToServerThread(clientToServerThread);
//// setContentPane("/views/LobbyView.fxml");
// } catch (Exception e) {
// Alert alert = new Alert(AlertType.ERROR);
// alert.setHeaderText("Cannot reach the host");
// alert.setContentText("Please check your host IP address.");
// alert.showAndWait();
// }
}
// public void setController(Controller controller) {
// this.controller = controller;
// }
/**
* Gets the local host ip address and sets this ip to ClientState.
@@ -162,7 +108,30 @@ public class StartScreenController implements Initializable {
if (ipAddress == null) {
System.out.println("[HOST] Cannot obtain local host ip address.");
}
// ClientState.setHostIp(ipAddress);
return ipAddress;
}
public void toggleMusic(ActionEvent actionEvent) {
Sounds.toggleMuteMusic();
Sounds.playButtonClick();
if (Sounds.isMusicMuted()) {
muteMusicButton.setText("UnMute Music");
} else {
muteMusicButton.setText("Mute Music");
}
}
public void toggleSounds(ActionEvent actionEvent) {
Sounds.toggleMuteEffects();
Sounds.playButtonClick();
if (Sounds.isSoundEffectsMuted()) {
muteSoundsButton.setText("UnMute Sounds");
} else {
muteSoundsButton.setText("Mute Sounds");
}
}
public void playButtonHoverSound(MouseEvent mouseEvent) {
Sounds.playHoverSound();
}
}
@@ -0,0 +1,75 @@
package seng302.visualiser.fxObjects;
import java.util.Arrays;
import javafx.collections.ListChangeListener;
import javafx.scene.Node;
import javafx.scene.control.ScrollPane;
import javafx.scene.layout.Background;
import javafx.scene.paint.Color;
import javafx.scene.paint.Paint;
import javafx.scene.text.Text;
import javafx.scene.text.TextFlow;
/**
* Extension of a ScrollPane that contains a TextFlow. Has an addMessage() function to parse and
* display chatter text.
*/
public class ChatHistory extends ScrollPane {
private TextFlow textFlow = new TextFlow();
public ChatHistory() {
this.setContent(textFlow);
this.setFitToWidth(true);
this.setFitToHeight(true);
this.setMaxHeight(Double.MAX_VALUE);
this.setMaxWidth(Double.MAX_VALUE);
this.setVbarPolicy(ScrollBarPolicy.AS_NEEDED);
this.setHbarPolicy(ScrollBarPolicy.NEVER);
this.lookup(".scroll-pane").setStyle("-fx-background: rgba(255, 255, 255, 0.1); -fx-background-color: rgba(255, 255, 255, 0.1);");
this.textFlow.setStyle(
"-fx-background: rgba(255, 255, 255, 0.1); -fx-background-color: rgba(255, 255, 255, 0.1);"
);
//This makes the window auto scroll.
textFlow.getChildren().addListener((ListChangeListener<Node>) c ->
this.setVvalue(1.0)
);
//This just makes it so that the ChatHistory is on focus it passes it off to the parent.
this.parentProperty().addListener((obs, old, parent) ->
this.focusedProperty().addListener((obsVal, oldVal, onFocus) -> {
if (onFocus) {
parent.requestFocus();
}
})
);
}
/**
* Adds a message to chat history. Messages should be either of the form:
* "[HH:MM:ss] player_name: message_text" or
* "SERVER: message_text"
* @param colour The colour of the user sending the message
* @param Text The chatter text message to be displayed
*/
public void addMessage (Paint colour, String Text) {
String[] words = Text.split(":");
if (words[0].trim().equals("SERVER")) {
Text text = new Text(Text + "\n\n");
text.setStyle("-fx-font-weight: bolder");
textFlow.getChildren().add(text);
} else {
Text timePlayer = new Text(
String.join(":", Arrays.copyOfRange(words, 0, 3)) + ":"
);
timePlayer.setStyle("-fx-font-weight: bold");
timePlayer.setFill(colour);
Text message = new Text(
String.join(":", Arrays.copyOfRange(words, 3, words.length)) + "\n\n"
);
message.wrappingWidthProperty().bind(this.widthProperty());
textFlow.getChildren().addAll(timePlayer, message);
}
}
}