Merge branch 'raceLength' into 'master'

Race length

AC's:
- Scale map to selected duration of user

See merge request !64
main
Joseph Gardner 8 years ago
commit 5eeb65ad41

@ -21,7 +21,7 @@ public class App extends Application {
public void start(Stage primaryStage) { public void start(Stage primaryStage) {
try { try {
//TODO should read a configuration file to configure server? //TODO should read a configuration file to configure server?
Event raceEvent = new Event(false, 0); Event raceEvent = new Event(false, 0, 5);
} catch (Exception e) { } catch (Exception e) {

@ -40,24 +40,17 @@ public class Event {
private String raceXML; private String raceXML;
private String regattaXML; private String regattaXML;
private String boatXML; private String boatXML;
private XMLFileType xmlFileType; private XMLFileType xmlFileType;
private Polars boatPolars; private Polars boatPolars;
/** /**
* Data sources containing data from the xml files. * Data sources containing data from the xml files.
*/ */
RaceDataSource raceDataSource; private RaceDataSource raceDataSource;
BoatDataSource boatDataSource; private BoatDataSource boatDataSource;
RegattaDataSource regattaDataSource; private RegattaDataSource regattaDataSource;
private ConnectionAcceptor connectionAcceptor; private ConnectionAcceptor connectionAcceptor;
private LatestMessages latestMessages; private LatestMessages latestMessages;
private CompositeCommand compositeCommand; private CompositeCommand compositeCommand;
/** /**
* This is used to allocate source IDs. * This is used to allocate source IDs.
*/ */
@ -66,22 +59,17 @@ public class Event {
private RaceLogic raceLogic; private RaceLogic raceLogic;
private Thread raceThread; private Thread raceThread;
private Thread connectionThread; private Thread connectionThread;
private int mapIndex; private int mapIndex;
/** /**
* Constructs an event, using various XML files. * Constructs an event, using various XML files.
* @param singlePlayer Whether or not to create a single player event. * @param singlePlayer Whether or not to create a single player event.
* @param mapIndex Specifies which map to use. * @param mapIndex Specifies which map to use.
* @throws EventConstructionException Thrown if we cannot create an Event for any reason. * @throws EventConstructionException Thrown if we cannot create an Event for any reason.
*/ */
public Event(boolean singlePlayer, int mapIndex) throws EventConstructionException { public Event(boolean singlePlayer, int mapIndex, int raceLength) throws
EventConstructionException {
PolarParser.parseNewPolars("mock/polars/acc_polars.csv"); PolarParser.parseNewPolars("mock/polars/acc_polars.csv");
this.mapIndex = mapIndex; this.mapIndex = mapIndex;
String raceXMLFile; String raceXMLFile;
@ -125,8 +113,8 @@ public class Event {
} else { } else {
this.raceXML = Event.setRaceXMLAtCurrentTimeToNow(XMLReader.readXMLFileToString(raceXMLFile, StandardCharsets.UTF_8)); this.raceXML = Event.setRaceXMLAtCurrentTimeToNow(XMLReader.readXMLFileToString(raceXMLFile, StandardCharsets.UTF_8));
this.raceXML = RaceXMLCreator.alterRaceToWind(this.raceXML, XMLFileType.Contents, windAngle); this.raceXML = RaceXMLCreator.alterRaceToWind(this.raceXML, XMLFileType.Contents, windAngle);
this.raceXML = RaceXMLCreator.scaleRaceSize(raceXML, windSpeed, 15 * 60 * 1000); this.raceXML = RaceXMLCreator.scaleRaceSize(raceXML,
windSpeed, raceLength);
} }
this.boatXML = XMLReader.readXMLFileToString(boatsXMLFile, StandardCharsets.UTF_8); this.boatXML = XMLReader.readXMLFileToString(boatsXMLFile, StandardCharsets.UTF_8);

@ -21,6 +21,8 @@ import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatter;
import java.util.Collections; import java.util.Collections;
import java.util.Comparator; import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;
/** /**
* Helper Class for creating a Race XML * Helper Class for creating a Race XML
@ -212,13 +214,17 @@ public class RaceXMLCreator {
double averageSpeed = (bestDownWindSpeed + bestUpWindSpeed) / 2; double averageSpeed = (bestDownWindSpeed + bestUpWindSpeed) / 2;
double raceApproximateTime = getRaceLength(race, averageSpeed); double raceApproximateTime = getRaceLength(race, averageSpeed);
double scale = milliseconds / raceApproximateTime; double scale = milliseconds / raceApproximateTime;
Map<XMLCompoundMark, Boolean> hasBeenScaled = new HashMap<>();
for (XMLCorner cm: race.getCompoundMarkSequence().getCorner()){ for (XMLCorner cm: race.getCompoundMarkSequence().getCorner()){
int index = cm.getCompoundMarkID() - 1; int index = cm.getCompoundMarkID() - 1;
XMLCompoundMark mark = race.getCourse().getCompoundMark().get(index); XMLCompoundMark mark = race.getCourse().getCompoundMark().get(index);
if (!hasBeenScaled.containsKey(mark)) {
for (XMLMark m : mark.getMark()) { for (XMLMark m : mark.getMark()) {
scalePoint(m, center, scale); scalePoint(m, center, scale);
} }
} }
hasBeenScaled.put(mark, true);
}
for (XMLLimit limit: race.getCourseLimit().getLimit()){ for (XMLLimit limit: race.getCourseLimit().getLimit()){
scalePoint(limit, center, scale); scalePoint(limit, center, scale);
} }
@ -319,8 +325,13 @@ public class RaceXMLCreator {
} }
/**
* sets the current race time of the xml
* @param raceXML race xml to alter
* @param racePrestartTime prestart time
* @param racePreparatoryTime preparatory time
* @deprecated this should be used from the RaceXMLCreator not from this function
*/
public static void setRaceXMLAtCurrentTimeToNow(XMLRace raceXML, long racePrestartTime, long racePreparatoryTime){ public static void setRaceXMLAtCurrentTimeToNow(XMLRace raceXML, long racePrestartTime, long racePreparatoryTime){
//The start time is current time + 4 minutes. prestart is 3 minutes, and we add another minute. //The start time is current time + 4 minutes. prestart is 3 minutes, and we add another minute.
long millisecondsToAdd = racePrestartTime + racePreparatoryTime; long millisecondsToAdd = racePrestartTime + racePreparatoryTime;

@ -4,6 +4,8 @@ import javafx.application.Platform;
import javafx.fxml.FXML; import javafx.fxml.FXML;
import javafx.scene.control.Alert; import javafx.scene.control.Alert;
import javafx.scene.control.ButtonType; import javafx.scene.control.ButtonType;
import javafx.scene.control.Label;
import javafx.scene.control.Slider;
import javafx.scene.image.Image; import javafx.scene.image.Image;
import javafx.scene.image.ImageView; import javafx.scene.image.ImageView;
import mock.app.Event; import mock.app.Event;
@ -28,8 +30,12 @@ import java.util.logging.Logger;
*/ */
public class HostGameController extends Controller { public class HostGameController extends Controller {
private @FXML ImageView mapImage; private @FXML ImageView mapImage;
private @FXML Slider sliderLength;
private @FXML Label lblLength;
private ArrayList<Image> listOfMaps; private ArrayList<Image> listOfMaps;
private int currentMapIndex = 0; private int currentMapIndex = 0;
private int selectedRaceLength; // in minutes
private final int MAX_RACE_LENGTH = 30; // in minutes
private DatagramSocket udpSocket; private DatagramSocket udpSocket;
private MatchBrowserInterface matchBrowserInterface; private MatchBrowserInterface matchBrowserInterface;
@ -37,8 +43,33 @@ public class HostGameController extends Controller {
loadMaps(); loadMaps();
this.udpSocket = MatchBrowserSingleton.getInstance().getUdpSocket(); this.udpSocket = MatchBrowserSingleton.getInstance().getUdpSocket();
this.matchBrowserInterface = MatchBrowserSingleton.getInstance().getMatchBrowserInterface(); this.matchBrowserInterface = MatchBrowserSingleton.getInstance().getMatchBrowserInterface();
setRaceLengthSlider();
} }
/**
* Sets up the values and display for a slider object which allows a user
* to select how many minutes long they would like their race to be.
*/
private void setRaceLengthSlider(){
// set the listener to update the label
sliderLength.valueProperty().addListener((ov, old_val, new_val) -> {
selectedRaceLength = new_val.intValue();
if (selectedRaceLength == 1){
lblLength.setText(selectedRaceLength + " minute.");
} else {
lblLength.setText(selectedRaceLength + " minutes.");
}
});
// set values and marks to be displayed
sliderLength.setMin(2);
sliderLength.setMax(MAX_RACE_LENGTH);
sliderLength.setShowTickLabels(true);
sliderLength.setMajorTickUnit(MAX_RACE_LENGTH-1);
sliderLength.setBlockIncrement(1);
sliderLength.getStylesheets().add("/css/slider.css");
}
/** /**
@ -64,7 +95,8 @@ public class HostGameController extends Controller {
*/ */
public void hostGamePressed() { public void hostGamePressed() {
try { try {
App.game = new Event(false, currentMapIndex); App.game = new Event(false, currentMapIndex,
selectedRaceLength*60*1000);
App.gameType = currentMapIndex; App.gameType = currentMapIndex;
HttpMatchBrowserHost matchBrowserHost = new HttpMatchBrowserHost(); HttpMatchBrowserHost matchBrowserHost = new HttpMatchBrowserHost();

@ -0,0 +1,16 @@
.slider .thumb {
-fx-background-image: url("/visualiser/images/sun.png");
-fx-background-size: 25px;
-fx-pref-height: 25px;
-fx-pref-width: 25px;
-fx-background-position: top;
-fx-background-repeat: no-repeat;
-fx-focus-color: transparent;
-fx-background-color: transparent;
}
.slider .track {
-fx-control-inner-background: dodgerblue;
-fx-border-color: rgba(30, 144, 255, 0.44);
-fx-border-radius: 0.25em, 0.25em, 0.166667em;
}

@ -3,6 +3,7 @@
<?import javafx.geometry.Insets?> <?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?> <?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?> <?import javafx.scene.control.Label?>
<?import javafx.scene.control.Slider?>
<?import javafx.scene.image.ImageView?> <?import javafx.scene.image.ImageView?>
<?import javafx.scene.layout.AnchorPane?> <?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.ColumnConstraints?> <?import javafx.scene.layout.ColumnConstraints?>
@ -12,19 +13,20 @@
<AnchorPane fx:id="hostWrapper" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="600.0" prefWidth="780.0" xmlns="http://javafx.com/javafx/8.0.111" xmlns:fx="http://javafx.com/fxml/1" fx:controller="visualiser.Controllers.HostGameController"> <AnchorPane fx:id="hostWrapper" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="600.0" prefWidth="780.0" xmlns="http://javafx.com/javafx/8.0.111" xmlns:fx="http://javafx.com/fxml/1" fx:controller="visualiser.Controllers.HostGameController">
<children> <children>
<GridPane layoutY="14.0" AnchorPane.bottomAnchor="-14.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="14.0"> <GridPane layoutY="14.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<columnConstraints> <columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" maxWidth="170.0" minWidth="10.0" prefWidth="170.0" /> <ColumnConstraints hgrow="NEVER" prefWidth="170.0" />
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" /> <ColumnConstraints hgrow="NEVER" prefWidth="100.0" />
<ColumnConstraints hgrow="SOMETIMES" maxWidth="170.0" minWidth="10.0" prefWidth="170.0" /> <ColumnConstraints hgrow="NEVER" prefWidth="170.0" />
</columnConstraints> </columnConstraints>
<rowConstraints> <rowConstraints>
<RowConstraints maxHeight="60.0" minHeight="60.0" prefHeight="30.0" vgrow="SOMETIMES" /> <RowConstraints prefHeight="50.0" vgrow="NEVER" />
<RowConstraints minHeight="10.0" prefHeight="435.0" vgrow="SOMETIMES" /> <RowConstraints prefHeight="419.5" vgrow="NEVER" />
<RowConstraints maxHeight="80.0" minHeight="80.0" prefHeight="80.0" vgrow="SOMETIMES" /> <RowConstraints prefHeight="50.0" vgrow="NEVER" />
<RowConstraints prefHeight="80.0" vgrow="NEVER" />
</rowConstraints> </rowConstraints>
<children> <children>
<Button fx:id="hostGameBtn" mnemonicParsing="false" onAction="#hostGamePressed" text="Start Game" GridPane.columnIndex="1" GridPane.halignment="CENTER" GridPane.rowIndex="2" GridPane.valignment="CENTER"> <Button fx:id="hostGameBtn" mnemonicParsing="false" onAction="#hostGamePressed" text="Start Game" GridPane.columnIndex="1" GridPane.halignment="CENTER" GridPane.rowIndex="3" GridPane.valignment="CENTER">
<font> <font>
<Font size="20.0" /> <Font size="20.0" />
</font> </font>
@ -50,6 +52,16 @@
<ImageView fx:id="mapImage" pickOnBounds="true" preserveRatio="true" GridPane.columnIndex="1" GridPane.halignment="CENTER" GridPane.hgrow="ALWAYS" GridPane.rowIndex="1" GridPane.valignment="CENTER" GridPane.vgrow="ALWAYS" /> <ImageView fx:id="mapImage" pickOnBounds="true" preserveRatio="true" GridPane.columnIndex="1" GridPane.halignment="CENTER" GridPane.hgrow="ALWAYS" GridPane.rowIndex="1" GridPane.valignment="CENTER" GridPane.vgrow="ALWAYS" />
<Button fx:id="previousButton" maxHeight="80.0" maxWidth="80.0" mnemonicParsing="false" onAction="#previousImage" GridPane.halignment="CENTER" GridPane.rowIndex="1" GridPane.valignment="CENTER" /> <Button fx:id="previousButton" maxHeight="80.0" maxWidth="80.0" mnemonicParsing="false" onAction="#previousImage" GridPane.halignment="CENTER" GridPane.rowIndex="1" GridPane.valignment="CENTER" />
<Button fx:id="nextButton" maxHeight="80.0" maxWidth="80.0" mnemonicParsing="false" onAction="#nextImage" GridPane.columnIndex="2" GridPane.halignment="CENTER" GridPane.rowIndex="1" GridPane.valignment="CENTER" /> <Button fx:id="nextButton" maxHeight="80.0" maxWidth="80.0" mnemonicParsing="false" onAction="#nextImage" GridPane.columnIndex="2" GridPane.halignment="CENTER" GridPane.rowIndex="1" GridPane.valignment="CENTER" />
<Slider fx:id="sliderLength" prefHeight="14.0" prefWidth="100.0" GridPane.columnIndex="1" GridPane.halignment="CENTER" GridPane.rowIndex="2">
<GridPane.margin>
<Insets left="50.0" right="50.0" />
</GridPane.margin>
</Slider>
<Label fx:id="lblLength" GridPane.columnIndex="1" GridPane.halignment="CENTER" GridPane.rowIndex="2" GridPane.valignment="BOTTOM">
<GridPane.margin>
<Insets />
</GridPane.margin>
</Label>
</children> </children>
</GridPane> </GridPane>
</children> </children>

Loading…
Cancel
Save