Refactored launcher class

launcher.Config functionality merged with launcher.Settings.
launcher.Config has been deleted.

Added Javadoc to every method of the launcher package.

Commented most methods to improve code readability.

Added authorship of most methods.

Fixed regression of commit c5ac0e9297d7aabc2e7eed52fd1f952cc77087a4:
launcher now properly saves to game.set file and does not default to
failsafe anymore.
This commit is contained in:
François Autin 2021-06-24 02:12:52 +02:00
parent 62fb41a3a2
commit 6bbf302a80
4 changed files with 389 additions and 248 deletions

View File

@ -1,118 +0,0 @@
package launcher;
import java.io.*;
import org.json.simple.*;
import org.json.simple.parser.*;
public class Config {
public int width, height, rounds;
public boolean fullscreen, hitboxes;
public String stage;
public String p1, p2;
public Config() throws FileNotFoundException {
parse();
}
public void parse() throws FileNotFoundException {
// initialize the parser
JSONParser jsonP = new JSONParser();
try {
// read the json document
JSONObject jsonO = (JSONObject) jsonP.parse(new FileReader("game.set"));
// to print all values
// System.out.println(jsonO.values());
// isolate the "test" part and print it
// String test = (String) jsonO.get("test");
// System.out.println("ceci est un test :" + test);
JSONArray game = (JSONArray) jsonO.get("game");
JSONObject settings = (JSONObject) game.get(0);
// print a case of this element
stage = (String) settings.get("stage");
// rounds
rounds = Integer.parseInt((String) settings.get("rounds"));
// character selection
p1 = (String) settings.get("character1");
p2 = (String) settings.get("character2");
height = Integer.parseInt((String) settings.get("height")); // String to int
width = Integer.parseInt((String) settings.get("width"));
// fullscreen
String fs = (String) settings.get("fullscreen");
if (fs.equals("true")) {
fullscreen = true;
} else fullscreen = false;
String hb = (String) settings.get("hitboxes");
if (hb == null) hb = "false";
if (hb.equals("true")) {
hitboxes = true;
} else hitboxes = false;
// rounds
String temprounds = (String) settings.get("rounds");
switch (temprounds) {
case "1": rounds = 1;
case "3": rounds = 3;
case "5": rounds = 5;
default: rounds = 1;
}
} catch (FileNotFoundException e) {
File f = new File("game.set");
try {
f.createNewFile();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
System.exit(1);
}
parse();
} catch (IOException e) {
e.printStackTrace();
} catch (ParseException e) {
System.out.println("Empty config file");
}
}
@SuppressWarnings("unchecked")
public void write(int width, int height, int rounds, boolean fullscreen, boolean hitboxes, String character1, String character2, String stage) throws Exception {
JSONObject metafile = new JSONObject();
JSONArray array = new JSONArray();
JSONObject set = new JSONObject();
set.put("width", Integer.toString(width));
set.put("height", Integer.toString(height));
set.put("rounds", Integer.toString(rounds));
set.put("fullscreen", Boolean.toString(fullscreen));
set.put("hitboxes", Boolean.toString(hitboxes));
set.put("character1", character1);
set.put("character2", character2);
set.put("stage", stage);
array.add(set);
metafile.put("game", array);
try (FileWriter file = new FileWriter("game.set", false)) {
file.write(metafile.toJSONString());
file.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}

View File

@ -1,12 +1,3 @@
/**
* CLASS LAUNCHER
*
* Fenêtre de configuration du jeu préalablement au lancement d'une partie
*
* @author François Autin
*
*/
package launcher;
import gameplay.match.*;
@ -23,19 +14,27 @@ import javafx.scene.control.CheckBox;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
import javafx.fxml.*;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
/**
* <p>Game configuration window and engine launcher</p>
* @author François Autin
*/
@SuppressWarnings("unchecked")
public class Launcher extends Application {
public static Launcher pointer;
private static Settings setter;
private HashMap<String, Object> arraysettings;
private static Map<String, Object> namespace;
//public static Launcher pointer; // Self pointer, required to regain context if ever exited
private static Settings setter; // Settings class allows manipulation of settings
protected static HashMap<String, Object> arraysettings; // Array that allows passing values of UI elements to setter
private static Map<String, Object> namespace; // Namespace containing all elements from UI
/**
* Starts the Launcher thread
*/
public Launcher() {
pointer = this;
try {
setter = new Settings();
} catch (Exception e) {
@ -45,189 +44,265 @@ public class Launcher extends Application {
arraysettings = new HashMap<String, Object>();
}
/*
/**
* Start method is used by Launcher as an implementation of the Application class to create a JavaFX thread to display the GUI window
* @param primaryStage the base Stage on which to place UI elements
* @throws IOException if the FXMLLoader fails to find or parse the launcher.fxml file
* @author François Autin
*/
public void start(Stage primaryStage) throws Exception {
public void start(Stage primaryStage) throws IOException {
// Loading UI from FXML file
FXMLLoader loader = new FXMLLoader(getClass().getResource("launcher.fxml"));
Parent root = loader.load();
Scene main = new Scene(root);
// Assigning pointer to namespace
namespace = loader.getNamespace();
/******************/
/* Resolution box */
/******************/
// Getting resolution ChoiceBox object from namespace
ChoiceBox<String> cb = (ChoiceBox<String>) namespace.get("resolution");
// Assigning list of possible choices to ChoiceBox
ObservableList<String> availableres = FXCollections.observableArrayList("640x480", "800x600", "1024x768", "1280x720", "1366x768", "1600x900", "1920x1080");
cb.setItems(availableres);
// Setting default ChoiceBox value to the one already in the config file
if (!availableres.contains(setter.getResolution())) {
cb.setValue("640x480");
} else {
cb.setValue(setter.getResolution());
}
/******************/
/* Fullscreen box */
/******************/
// Getting fullscreen CheckBox object from namespace
CheckBox fs = (CheckBox) namespace.get("fullscreen");
// Setting default CheckBox value to the one already in the config file
if(setter.getFullscreen()) {
fs.setSelected(true);
} else {
fs.setSelected(false);
}
/**************/
/* Rounds box */
/**************/
// Getting rounds ChoiceBox object from namespace
ChoiceBox<String> cbr = (ChoiceBox<String>) namespace.get("rounds");
// Assigning list of possible choices to ChoiceBox
ObservableList<String> nbrounds = FXCollections.observableArrayList("1", "3", "5", "7", "9");
cbr.setItems(nbrounds);
// Setting default ChoiceBox value to the one already in the config file
if (!nbrounds.contains(setter.getRounds())) {
cb.setValue("3");
cbr.setValue("3");
} else {
cb.setValue(setter.getRounds());
cbr.setValue(setter.getRounds());
}
/****************/
/* Hitboxes box */
/****************/
// Getting hitboxes CheckBox from namespace
CheckBox hb = (CheckBox) namespace.get("hitboxes");
// Setting default CheckBox value to the one already in the config file
if (setter.getHitboxes()) {
hb.setSelected(true);
} else {
hb.setSelected(false);
}
/********************/
/* Character select */
/********************/
// Getting character 1 ChoiceBox from namespace
VBox v1 = (VBox) namespace.get("p1");
ChoiceBox<String> b1 = (ChoiceBox<String>) v1.getChildren().get(1);
// Getting character 2 ChoiceBox from namespace
VBox v2 = (VBox) namespace.get("p2");
ChoiceBox<String> b2 = (ChoiceBox<String>) v2.getChildren().get(1);
// Assigning list of possible choices to ChoiceBoxes
ObservableList<String> availablechar = FXCollections.observableArrayList("Blue");
b1.setItems(availablechar);
b2.setItems(availablechar);
// Setting default ChoiceBoxes values to the ones already in the config file
if(setter.getChar1().equals("blue")) {
b1.setValue("Blue");
}
if(setter.getChar2().equals("blue")) {
b2.setValue("Blue");
}
/*******************/
/* Window settings */
/*******************/
// Removing window decorations
primaryStage.initStyle(StageStyle.UNDECORATED);
// Setting window title
primaryStage.setTitle("Boulevard Combattant");
// Assinging main scene to primaryStage
primaryStage.setScene(main);
// Showing the stage to the user
primaryStage.show();
}
/**
* saves all settings to game.set and then launches the Engine thread
* @author François Autin
*/
@FXML
public void runGame() {
private void runGame() {
try {
int width, height;
ChoiceBox<String> cb = (ChoiceBox<String>) namespace.get("resolution");
switch (cb.getValue()) {
case "640x480":
width = 640;
height = 480;
break;
case "800x600":
width = 800;
height = 600;
break;
case "1024x768":
width = 1024;
height = 768;
break;
case "1280x720":
width = 1280;
height = 720;
break;
case "1366x768":
width = 1366;
height = 768;
break;
case "1600x900":
width = 1600;
height = 900;
break;
case "1920x1080":
width = 1920;
height = 1080;
break;
default:
width = 640;
height = 480;
break;
}
pointer.arraysettings.put("width", width);
pointer.arraysettings.put("height", height);
CheckBox fs = (CheckBox) namespace.get("fullscreen");
pointer.arraysettings.put("fullscreen", fs.isSelected());
CheckBox hb = (CheckBox) namespace.get("hitboxes");
pointer.arraysettings.put("hitboxes", hb.isSelected());
ChoiceBox<String> rnd = (ChoiceBox<String>) namespace.get("rounds");
pointer.arraysettings.put("rounds", rnd.getValue());
VBox vp1 = (VBox) namespace.get("p1");
ChoiceBox<String> p1 = (ChoiceBox<String>) vp1.getChildren().get(1);
pointer.arraysettings.put("character1", p1.getValue().toLowerCase());
VBox vp2 = (VBox) namespace.get("p2");
ChoiceBox<String> p2 = (ChoiceBox<String>) vp2.getChildren().get(1);
pointer.arraysettings.put("character2", p2.getValue().toLowerCase());
pointer.arraysettings.put("stage", "default");
fillArraySettings();
setter.setSettings();
match.main(null);
} catch (Exception e) {
e.printStackTrace();
System.exit(1);
}
}
@FXML
public void launch() {
this.runGame();
/**
* fills the array bridging between the launcher and the setter class
* @throws NullPointerException if namespace does not contain required classes
* @author François Autin
*/
private void fillArraySettings() throws NullPointerException {
// Converting the choice of resolution to two workable variables
int width, height;
ChoiceBox<String> cb = (ChoiceBox<String>) namespace.get("resolution");
switch (cb.getValue()) {
case "800x600":
width = 800;
height = 600;
break;
case "1024x768":
width = 1024;
height = 768;
break;
case "1280x720":
width = 1280;
height = 720;
break;
case "1366x768":
width = 1366;
height = 768;
break;
case "1600x900":
width = 1600;
height = 900;
break;
case "1920x1080":
width = 1920;
height = 1080;
break;
default:
width = 640;
height = 480;
break;
}
arraysettings.put("width", width);
arraysettings.put("height", height);
// Fullscreen
CheckBox fs = (CheckBox) namespace.get("fullscreen");
arraysettings.put("fullscreen", fs.isSelected());
// Hitboxes
CheckBox hb = (CheckBox) namespace.get("hitboxes");
arraysettings.put("hitboxes", hb.isSelected());
// Number of rounds
ChoiceBox<String> rnd = (ChoiceBox<String>) namespace.get("rounds");
arraysettings.put("rounds", rnd.getValue());
// Character 1
VBox vp1 = (VBox) namespace.get("p1");
ChoiceBox<String> p1 = (ChoiceBox<String>) vp1.getChildren().get(1);
arraysettings.put("character1", p1.getValue().toLowerCase());
// Character 2
VBox vp2 = (VBox) namespace.get("p2");
ChoiceBox<String> p2 = (ChoiceBox<String>) vp2.getChildren().get(1);
arraysettings.put("character2", p2.getValue().toLowerCase());
// Stage
arraysettings.put("stage", "default");
}
/**
* quits the launcher and the game
*/
@FXML
public void quit() {
private void quit() {
System.exit(0);
}
/**
* links to the gitlab project page
*/
@FXML
public void website() {
private void website() {
getHostServices().showDocument("https://gitlab.istic.univ-rennes1.fr/fautin/jeu-de-combat");
}
/**
* changes the character image of the player 1 depending on its character selection
*/
@FXML
public void chp1() {
VBox v1 = (VBox) namespace.get("p1");
ImageView iv1 = (ImageView) v1.getChildren().get(0);
ChoiceBox<String> b1 = (ChoiceBox<String>) v1.getChildren().get(1);
switch (b1.getValue()) {
case "Blue":
iv1.setImage(new Image("/launcher/charfaces/blue.png"));
break;
default:
iv1.setImage(new Image("/launcher/default.png"));
break;
}
private void chp1() {
chp(1);
}
/**
* changes the character image of the player 1 depending on its character selection
*/
@FXML
public void chp2() {
VBox v1 = (VBox) namespace.get("p2");
ImageView iv1 = (ImageView) v1.getChildren().get(0);
ChoiceBox<String> b1 = (ChoiceBox<String>) v1.getChildren().get(1);
switch (b1.getValue()) {
private void chp2() {
chp(2);
}
/**
* changes the character image of the player n depending on its character selection
*/
@FXML
private void chp(int n) {
// if we try to change the character image of a player who does not exist, we simply return without doing anything
if(n > 2 || n < 1) {
return;
}
// getting the corresponding VBox
VBox v = (VBox) namespace.get("p" + Integer.toString(n));
// getting the first child of the VBox (the imageview containing the character image
ImageView iv = (ImageView) v.getChildren().get(0);
// Evaluating the new character choice in order to change the image accordingly
ChoiceBox<String> b = (ChoiceBox<String>) v.getChildren().get(1);
switch (b.getValue()) {
case "Blue":
iv1.setImage(new Image("/launcher/charfaces/blue.png"));
iv.setImage(new Image("/launcher/charfaces/blue.png"));
break;
default:
iv1.setImage(new Image("/launcher/default.png"));
iv.setImage(new Image("/launcher/default.png"));
break;
}
}
public HashMap<String, Object> getArraysettings() {
/**
* Returns the hashmap containing all settings inputed in the launcher by the user
* @return the hashmap containing all settings inputed in the launcher by the user
*/
protected static HashMap<String, Object> getArraysettings() {
return arraysettings;
}

View File

@ -1,60 +1,239 @@
package launcher;
import java.io.*;
import java.util.HashMap;
import org.json.simple.*;
import org.json.simple.parser.*;
/**
* <p>Allows the launcher to modify the game.set json file</p>
* @author François Autin
* @author Indy Boyeau
*/
public class Settings {
private Config config;
private int width, height, rounds;
private boolean fullscreen, hitboxes;
private String stage, p1, p2;
/**
* <p>Settings allows manipulating the JSON game.set file.</p>
* <p>The constructor parses the game.set file.</p>
* @author François Autin
*/
public Settings() {
try {
config = new Config();
parse();
} catch (Exception e) {
e.printStackTrace();
System.exit(1);
}
}
public void setSettings() throws Exception {
HashMap<String, Object> set = Launcher.pointer.getArraysettings();
/**
* <p>Parses the game.set file (creates it if it does not exist).</p>
* <p>Isolates the relevant settings from the game.set JSONFile and puts them in the correct global variables of the Settings class</p>
* @throws FileNotFoundException if the game.set file does not exist
* @throws IOException in case of IO error
* @throws ParseException if the JSON file is invalid
* @throws Exception for any other unaccounted for exception
* @author François Autin
* @author Indy Boyeau
*/
private void parse() throws Exception {
// Initializing the parser
JSONParser jsonP = new JSONParser();
try {
int width = (Integer) set.get("width");
int height = (Integer) set.get("height");
int rounds = (Integer) set.get("rounds");
boolean fullscreen = (Boolean) set.get("fullscreen");
boolean hitboxes = (Boolean) set.get("hitboxes");
String character1 = (String) set.get("character1");
String character2 = (String) set.get("character2");
String stage = (String) set.get("stage");
config.write(width, height, rounds, fullscreen, hitboxes, character1, character2, stage);
} catch (Exception e) {
config.write(800, 600, 3, false, false, "blue", "blue", "default");
System.out.println("Incorrect config file");
// Loading the json document into memory
JSONObject jsonO = (JSONObject) jsonP.parse(new FileReader("game.set"));
// Getting the primary node (game)
JSONArray root = (JSONArray) jsonO.get("game");
JSONObject settings = (JSONObject) root.get(0);
// Rounds
rounds = Integer.parseInt((String) settings.get("rounds"));
// Character selection
p1 = (String) settings.get("character1");
p2 = (String) settings.get("character2");
// Resolution
height = Integer.parseInt((String) settings.get("height"));
width = Integer.parseInt((String) settings.get("width"));
// Fullscreen
String fs = (String) settings.get("fullscreen");
if (fs.equals("true")) {
fullscreen = true;
} else fullscreen = false;
// Hitboxes
String hb = (String) settings.get("hitboxes");
if (hb.equals("true")) {
hitboxes = true;
} else hitboxes = false;
// Stage
stage = (String) settings.get("stage");
} catch (FileNotFoundException e) {
// If the file does not exist, we create it
File f = new File("game.set");
try {
f.createNewFile();
parse();
} catch (IOException e1) {
e1.printStackTrace();
System.exit(1);
}
} catch (IOException e) {
e.printStackTrace();
System.exit(1);
} catch (ParseException e) {
System.out.println("Invalid config file");
}
}
/**
* <p>Converts user inputed data to settings passable to the write() method</p>
* @throws Exception any exception caused by write(...)
* @author François Autin
*/
protected void setSettings() throws Exception {
// Getting the HashMap arraysettings containing all user inputed settings
HashMap<String, Object> arraysettings = Launcher.getArraysettings();
try {
// Putting arraysettings content in global variables
width = (Integer) arraysettings.get("width");
height = (Integer) arraysettings.get("height");
rounds = Integer.parseInt((String) arraysettings.get("rounds"));
fullscreen = (Boolean) arraysettings.get("fullscreen");
hitboxes = (Boolean) arraysettings.get("hitboxes");
p1 = (String) arraysettings.get("character1");
p2 = (String) arraysettings.get("character2");
stage = (String) arraysettings.get("stage");
// Writing to file
write();
} catch (Exception e) {
// Failsafe in case of Exception
write(800, 600, 3, false, false, "blue", "blue", "default");
e.printStackTrace();
}
}
/**
* <p>This version of the write method without parameters simply passes the global variables of the Settings class instance to the full write method.</p>
* @throws Exception any exception caused by write(...)
* @author François Autin
*/
private void write() throws Exception {
write(width, height, rounds, fullscreen, hitboxes, p1, p2, stage);
}
/**
* <p>Write echoes all user settings to the game.set JSON File</p>
* @param width the width of the game window
* @param height the height of the game window
* @param rounds the number of rounds to be played
* @param fullscreen whether or not to show the window fullscreen
* @param hitboxes whether or not to display the hitboxes
* @param character1 the name of the character chosen by player 1
* @param character2 the name of the character chosen by player 2
* @param stage the name of the stage
* @throws FileNotFoundException if the game.set file does not exist
* @throws IOException in case of IO error
* @throws Exception for any other unaccounted for exception
* @author François Autin
*/
@SuppressWarnings("unchecked")
private void write(int width, int height, int rounds, boolean fullscreen, boolean hitboxes, String character1, String character2, String stage) throws Exception {
JSONObject metafile = new JSONObject();
JSONArray array = new JSONArray();
JSONObject set = new JSONObject();
set.put("width", Integer.toString(width));
set.put("height", Integer.toString(height));
set.put("rounds", Integer.toString(rounds));
set.put("fullscreen", Boolean.toString(fullscreen));
set.put("hitboxes", Boolean.toString(hitboxes));
set.put("character1", character1);
set.put("character2", character2);
set.put("stage", stage);
array.add(set);
metafile.put("game", array);
try (FileWriter file = new FileWriter("game.set", false)) {
file.write(metafile.toJSONString());
file.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* Returns the current resolution setting
* @return a string of the (width)x(height) format
* @author François Autin
*/
public String getResolution() {
return "" + Integer.toString(config.width) + "x" + Integer.toString(config.height);
return "" + Integer.toString(width) + "x" + Integer.toString(height);
}
/**
* Returns the current fullscreen setting
* @return <p>A boolean:<ul><li>true if fullscreen mode</li><li>false if windowed mode</li></ul></p>
* @author François Autin
*/
public boolean getFullscreen() {
return config.fullscreen;
return fullscreen;
}
/**
* Returns the current hitbox setting
* @return <p>A boolean:<ul><li>true if hitboxes are to be showed</li><li>false if hitboxes are to be hidden</li></ul></p>
* @author François Autin
*/
public boolean getHitboxes() {
return config.hitboxes;
return hitboxes;
}
/**
* Returns the current rounds setting
* @return The number of rounds to be played
* @author François Autin
*/
public String getRounds() {
return Integer.toString(config.rounds);
return Integer.toString(rounds);
}
/**
* Returns the current fullscreen setting
* @return the name of the character chosen by player 1
* @author François Autin
*/
public String getChar1() {
return config.p1;
return p1;
}
/**
* Returns the current fullscreen setting
* @return the name of the character chosen by player 2
* @author François Autin
*/
public String getChar2() {
return config.p2;
return p2;
}
}

View File

@ -1,5 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Launcher FXML
@author François AUTIN
-->
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.ChoiceBox?>
<?import javafx.scene.control.CheckBox?>
@ -50,7 +55,7 @@
<CheckBox fx:id="hitboxes"/>
</children>
</HBox>
<Button text="Play" fx:id="btn_launch" onAction="#launch"
<Button text="Play" fx:id="btn_launch" onAction="#runGame"
prefWidth="110" prefHeight="15"/>
<Button text="Quit" fx:id="btn_quit" onAction="#quit"
prefWidth="110" prefHeight="15"/>