aboutsummaryrefslogtreecommitdiff
path: root/src/main
diff options
context:
space:
mode:
Diffstat (limited to 'src/main')
-rw-r--r--src/main/java/module-info.java12
-rwxr-xr-xsrc/main/java/net/sowgro/npehero/Driver.java130
-rwxr-xr-xsrc/main/java/net/sowgro/npehero/devmenu/DebugMenu.java41
-rwxr-xr-xsrc/main/java/net/sowgro/npehero/devmenu/DiffEditor.java79
-rwxr-xr-xsrc/main/java/net/sowgro/npehero/devmenu/LevelEditor.java150
-rwxr-xr-xsrc/main/java/net/sowgro/npehero/devmenu/LevelList.java72
-rwxr-xr-xsrc/main/java/net/sowgro/npehero/devmenu/NotesEditor.java101
-rwxr-xr-xsrc/main/java/net/sowgro/npehero/gameplay/Block.java27
-rwxr-xr-xsrc/main/java/net/sowgro/npehero/gameplay/NoteInfo.java28
-rwxr-xr-xsrc/main/java/net/sowgro/npehero/gameplay/SongPlayer.java360
-rwxr-xr-xsrc/main/java/net/sowgro/npehero/gameplay/Target.java50
-rwxr-xr-xsrc/main/java/net/sowgro/npehero/gameplay/Timer.java28
-rwxr-xr-xsrc/main/java/net/sowgro/npehero/gui/GameOver.java124
-rwxr-xr-xsrc/main/java/net/sowgro/npehero/gui/Leaderboard.java72
-rwxr-xr-xsrc/main/java/net/sowgro/npehero/gui/LevelDetails.java137
-rwxr-xr-xsrc/main/java/net/sowgro/npehero/gui/LevelSelector.java98
-rwxr-xr-xsrc/main/java/net/sowgro/npehero/gui/LevelSurround.java150
-rwxr-xr-xsrc/main/java/net/sowgro/npehero/gui/MainMenu.java70
-rwxr-xr-xsrc/main/java/net/sowgro/npehero/gui/Settings.java131
-rwxr-xr-x[-rw-r--r--]src/main/java/net/sowgro/npehero/main/Difficulty.java (renamed from src/main/Difficulty.java)2
-rwxr-xr-x[-rw-r--r--]src/main/java/net/sowgro/npehero/main/LeaderboardEntry.java (renamed from src/main/LeaderboardEntry.java)2
-rwxr-xr-x[-rw-r--r--]src/main/java/net/sowgro/npehero/main/Level.java (renamed from src/main/Level.java)2
-rwxr-xr-x[-rw-r--r--]src/main/java/net/sowgro/npehero/main/LevelController.java (renamed from src/main/LevelController.java)2
-rwxr-xr-x[-rw-r--r--]src/main/java/net/sowgro/npehero/main/ScoreController.java (renamed from src/main/ScoreController.java)4
-rwxr-xr-x[-rw-r--r--]src/main/java/net/sowgro/npehero/main/SettingsController.java (renamed from src/main/SettingsController.java)2
-rwxr-xr-x[-rw-r--r--]src/main/java/net/sowgro/npehero/main/SoundController.java (renamed from src/main/SoundController.java)34
-rwxr-xr-xsrc/main/resources/net/sowgro/npehero/backward.wavbin0 -> 34684 bytes
-rwxr-xr-xsrc/main/resources/net/sowgro/npehero/fairyfountain.wavbin0 -> 31539988 bytes
-rwxr-xr-xsrc/main/resources/net/sowgro/npehero/forward.wavbin0 -> 54992 bytes
-rwxr-xr-xsrc/main/resources/net/sowgro/npehero/hit.wavbin0 -> 34820 bytes
-rwxr-xr-xsrc/main/resources/net/sowgro/npehero/miss.wavbin0 -> 44144 bytes
-rwxr-xr-xsrc/main/resources/net/sowgro/npehero/mountains.pngbin0 -> 1115601 bytes
-rwxr-xr-xsrc/main/resources/net/sowgro/npehero/style.css236
33 files changed, 2127 insertions, 17 deletions
diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java
new file mode 100644
index 0000000..7fc3ef1
--- /dev/null
+++ b/src/main/java/module-info.java
@@ -0,0 +1,12 @@
+module net.sowgro.npehero {
+ requires javafx.controls;
+ requires javafx.fxml;
+ requires javafx.media;
+ requires json.simple;
+ requires java.desktop;
+
+
+ opens net.sowgro.npehero to javafx.fxml;
+ exports net.sowgro.npehero.gui;
+ exports net.sowgro.npehero;
+} \ No newline at end of file
diff --git a/src/main/java/net/sowgro/npehero/Driver.java b/src/main/java/net/sowgro/npehero/Driver.java
new file mode 100755
index 0000000..b5e226e
--- /dev/null
+++ b/src/main/java/net/sowgro/npehero/Driver.java
@@ -0,0 +1,130 @@
+package net.sowgro.npehero;
+
+import javafx.application.Application;
+import javafx.application.Platform;
+import javafx.geometry.Side;
+import javafx.scene.Scene;
+import javafx.scene.image.Image;
+import javafx.scene.input.KeyCode;
+import javafx.scene.input.KeyCombination;
+import javafx.scene.input.KeyEvent;
+import javafx.scene.layout.Background;
+import javafx.scene.layout.BackgroundImage;
+import javafx.scene.layout.BackgroundPosition;
+import javafx.scene.layout.BackgroundRepeat;
+import javafx.scene.layout.BackgroundSize;
+import javafx.scene.layout.Pane;
+import javafx.stage.Stage;
+import net.sowgro.npehero.gui.MainMenu;
+import net.sowgro.npehero.main.LevelController;
+import net.sowgro.npehero.main.SettingsController;
+import net.sowgro.npehero.main.SoundController;
+
+import java.net.URL;
+import java.util.Objects;
+
+
+public class Driver extends Application
+{
+
+ public static Stage primaryStage;
+ static Pane primaryPane = new Pane();
+
+ public static SettingsController settingsController = new SettingsController();
+ public static SoundController soundController = new SoundController();
+ public static LevelController levelController = new LevelController();
+// public static DebugMenu debug = new DebugMenu();
+
+ /*
+ * starts javafx
+ */
+ public static void main(String[] args)
+ {
+ launch(args);
+ }
+
+ /*
+ * sets up game windows and starts controllers
+ * (automatically called by javafx on start)
+ */
+ @Override
+ public void start(Stage newPrimaryStage)
+ {
+ primaryStage = newPrimaryStage;
+
+ Scene primaryScene = new Scene(primaryPane, 800,600);
+
+ primaryScene.getStylesheets().add(getClass().getResource("style.css").toExternalForm());
+
+ primaryStage.setScene(primaryScene);
+ primaryStage.setTitle("NPE Hero");
+
+
+ setMenu(new MainMenu());
+ setMenuBackground();
+
+ primaryStage.addEventHandler(KeyEvent.KEY_PRESSED, event -> { //full screen stuff
+ if (KeyCode.F11.equals(event.getCode())) {
+ primaryStage.setFullScreen(!primaryStage.isFullScreen());
+ }
+ });
+ primaryStage.setFullScreenExitKeyCombination(KeyCombination.NO_MATCH);
+ primaryStage.setFullScreenExitHint("");
+ primaryStage.show();
+ }
+
+ /**
+ * Replaces/adds a new pane to the primaryPane
+ * @param pane the new pane
+ */
+ public static void setMenu(Pane pane)
+ {
+ if (! primaryPane.getChildren().isEmpty())
+ {
+ primaryPane.getChildren().remove(0);
+ }
+ primaryPane.getChildren().add(pane);
+ pane.prefWidthProperty().bind(primaryPane.widthProperty()); //makes pane fill the window
+ pane.prefHeightProperty().bind(primaryPane.heightProperty());
+ primaryPane.requestFocus(); //make the pane itself focused by the keyboard naviagtion so no button is highlighted by default
+ }
+
+ /**
+ * @return the current pane in primaryPane
+ */
+ public static Pane getMenu(){
+ return (Pane) primaryPane.getChildren().get(0);
+ }
+
+ /**
+ * replaces the background image with a new one
+ * @param image the url of the image to set
+ */
+ public static void setBackground(Image image) //replaces background with a new one
+ {
+ primaryPane.setBackground(new Background(
+ new BackgroundImage(
+ image,
+ BackgroundRepeat.REPEAT, BackgroundRepeat.NO_REPEAT,
+ new BackgroundPosition(Side.LEFT, 0, true, Side.BOTTOM, 0, true),
+ new BackgroundSize(BackgroundSize.AUTO, BackgroundSize.AUTO, true, true, false, true)
+ )));
+ }
+
+ public static void setMenuBackground()
+ {
+ setBackground(new Image(Driver.class.getResource("mountains.png").toExternalForm()));
+ }
+
+ /**
+ * quits the application
+ */
+ public static void quit()
+ {
+ Platform.exit();
+ }
+
+ public static URL getResource(String fileName) {
+ return Driver.class.getResource(fileName);
+ }
+}
diff --git a/src/main/java/net/sowgro/npehero/devmenu/DebugMenu.java b/src/main/java/net/sowgro/npehero/devmenu/DebugMenu.java
new file mode 100755
index 0000000..aecd438
--- /dev/null
+++ b/src/main/java/net/sowgro/npehero/devmenu/DebugMenu.java
@@ -0,0 +1,41 @@
+package net.sowgro.npehero.devmenu;
+
+import net.sowgro.npehero.Driver;
+import javafx.scene.Scene;
+import javafx.scene.control.Button;
+import javafx.scene.layout.VBox;
+import javafx.stage.Stage;
+
+public class DebugMenu
+{
+ public Stage primaryStage = new Stage();
+
+ /*
+ * this class is a layout class, most of its purpose is to place UI elements like Buttons within Panes like VBoxes.
+ * the creation of these UI elements are mostly not commented due to their repetitive and self explanatory nature.
+ * style classes are defined in the style.css file.
+ */
+ VBox primaryPane = new VBox();
+ public DebugMenu()
+ {
+ Button testVol = new Button();
+ testVol.setText("print volumes");
+ testVol.setOnAction(e -> System.out.println("setc:"+Driver.settingsController.effectsVol+" sndc:"+Driver.soundController.songMediaPlayer.getVolume()));
+
+ primaryPane.getChildren().addAll(testVol);
+
+ Scene primaryScene = new Scene(primaryPane);
+ primaryStage.setScene(primaryScene);
+ primaryStage.setTitle("debug");
+ }
+
+ public void show()
+ {
+ primaryStage.show();
+ }
+
+ public void addButton(Button b)
+ {
+ primaryPane.getChildren().add(b);
+ }
+}
diff --git a/src/main/java/net/sowgro/npehero/devmenu/DiffEditor.java b/src/main/java/net/sowgro/npehero/devmenu/DiffEditor.java
new file mode 100755
index 0000000..d4ebb02
--- /dev/null
+++ b/src/main/java/net/sowgro/npehero/devmenu/DiffEditor.java
@@ -0,0 +1,79 @@
+package net.sowgro.npehero.devmenu;
+
+import java.io.FileNotFoundException;
+import java.io.UnsupportedEncodingException;
+
+import net.sowgro.npehero.Driver;
+import net.sowgro.npehero.gui.LevelSurround;
+import net.sowgro.npehero.gui.MainMenu;
+import javafx.scene.Scene;
+import javafx.scene.control.Button;
+import javafx.scene.control.TextField;
+import javafx.scene.layout.VBox;
+import javafx.scene.text.Text;
+import javafx.stage.Stage;
+import net.sowgro.npehero.main.Difficulty;
+
+public class DiffEditor
+{
+ /*
+ * this class is a layout class, most of its purpose is to place UI elements like Buttons within Panes like VBoxes.
+ * the creation of these UI elements are mostly not commented due to their repetitive and self explanatory nature.
+ * style classes are defined in the style.css file.
+ */
+ public DiffEditor(Difficulty diff)
+ {
+ Stage primaryStage = new Stage();
+
+ Text folderNameLabel = new Text("Folder name (ordered alphabetically)");
+ TextField folderName = new TextField(diff.thisDir.getName());
+ folderName.setDisable(true);
+
+ Text titleLabel = new Text("Title");
+ TextField title = new TextField(diff.title);
+
+ Text bpmLabel = new Text("BPM");
+ TextField bpm = new TextField(diff.bpm+"");
+
+ Text numBeatsLabel = new Text("Number of beats (set by notes editor)");
+ TextField numBeats = new TextField(diff.numBeats+"");
+
+ Text priorityLabel = new Text("priority (lower first)");
+ TextField priority = new TextField(diff.priority+"");
+
+ Button editNotes = new Button("Edit notes");
+ editNotes.setOnAction(e -> {
+ try {
+ new NotesEditor(diff);
+ } catch (FileNotFoundException | UnsupportedEncodingException e1) {
+ e1.printStackTrace();
+ }
+ });
+
+ Button editScores = new Button("Clear leaderboard");
+ editScores.setOnAction(e -> diff.getLeaderboard().clear());
+
+ Button playLevel = new Button("Launch level");
+ playLevel.setOnAction(e -> Driver.setMenu(new LevelSurround(diff.level, diff, new MainMenu())));
+
+ Button refresh = new Button("Refresh");
+ refresh.setOnAction( e -> {
+ numBeats.setText(diff.numBeats+"");
+ });
+
+ Button save = new Button("Save");
+ save.setOnAction(e -> { //assigns text feilds to values
+ diff.title = title.getText();
+ diff.bpm = Double.parseDouble(bpm.getText());
+ diff.numBeats = Integer.parseInt(numBeats.getText());
+ diff.priority = Integer.parseInt(priority.getText());
+ diff.writeMetadata();
+ });
+
+ VBox main = new VBox();
+ main.getChildren().addAll(folderNameLabel,folderName,titleLabel,title,bpmLabel,bpm,numBeatsLabel,numBeats,refresh,priorityLabel,priority,editNotes,editScores,playLevel,save);
+ Scene scene = new Scene(main);
+ primaryStage.setScene(scene);
+ primaryStage.show();
+ }
+} \ No newline at end of file
diff --git a/src/main/java/net/sowgro/npehero/devmenu/LevelEditor.java b/src/main/java/net/sowgro/npehero/devmenu/LevelEditor.java
new file mode 100755
index 0000000..94fcc16
--- /dev/null
+++ b/src/main/java/net/sowgro/npehero/devmenu/LevelEditor.java
@@ -0,0 +1,150 @@
+package net.sowgro.npehero.devmenu;
+
+import java.io.File;
+
+import javafx.beans.property.ReadOnlyBooleanWrapper;
+import javafx.beans.property.ReadOnlyStringWrapper;
+import javafx.scene.Scene;
+import javafx.scene.control.Button;
+import javafx.scene.control.ColorPicker;
+import javafx.scene.control.TableColumn;
+import javafx.scene.control.TableView;
+import javafx.scene.control.TextField;
+import javafx.scene.layout.HBox;
+import javafx.scene.layout.VBox;
+import javafx.scene.text.Text;
+import javafx.stage.FileChooser;
+import javafx.stage.Stage;
+import javafx.stage.FileChooser.ExtensionFilter;
+import net.sowgro.npehero.main.Difficulty;
+import net.sowgro.npehero.main.Level;
+
+public class LevelEditor
+{
+ private File selectedSong = null;
+ private File selectedPreview = null;
+ private File selectedBackground = null;
+
+ /*
+ * this class is a layout class, most of its purpose is to place UI elements like Buttons within Panes like VBoxes.
+ * the creation of these UI elements are mostly not commented due to their repetitive and self explanatory nature.
+ * style classes are defined in the style.css file.
+ */
+ public LevelEditor(Level level)
+ {
+ Stage primaryStage = new Stage();
+
+ Text folderNameLabel = new Text("Folder name");
+ TextField folderName = new TextField(level.thisDir.getName());
+ folderName.setDisable(true);
+
+ Text titleLabel = new Text("Title");
+ TextField title = new TextField(level.getTitle());
+
+ Text artistLabel = new Text("Artist");
+ TextField artist = new TextField(level.getArtist());
+
+ Text descLabel = new Text("Description");
+ TextField desc = new TextField(level.desc);
+
+ Text colorsLabel = new Text("Colors (Left to right)");
+ ColorPicker c1 = new ColorPicker(level.colors[0]);
+ ColorPicker c2 = new ColorPicker(level.colors[1]);
+ ColorPicker c3 = new ColorPicker(level.colors[2]);
+ ColorPicker c4 = new ColorPicker(level.colors[3]);
+ ColorPicker c5 = new ColorPicker(level.colors[4]);
+
+ Text filesLabel = new Text("Files");
+
+ FileChooser backgroundChooser = new FileChooser();
+ backgroundChooser.getExtensionFilters().add(new ExtensionFilter("PNG", "*.png"));
+ Button backgroundButton = new Button("Import background PNG");
+ backgroundButton.setOnAction(e -> {selectedBackground = backgroundChooser.showOpenDialog(primaryStage);});
+
+ FileChooser previewChooser = new FileChooser();
+ previewChooser.getExtensionFilters().add(new ExtensionFilter("PNG", "*.png"));
+ Button previewButton = new Button("Import preview PNG");
+ previewButton.setOnAction(e -> {selectedPreview = previewChooser.showOpenDialog(primaryStage);});
+
+ FileChooser songChooser = new FileChooser();
+ songChooser.getExtensionFilters().add(new ExtensionFilter("WAV", "*.wav"));
+ Button songButton = new Button("Import song WAV");
+ songButton.setOnAction(e -> selectedSong = songChooser.showOpenDialog(primaryStage));
+
+ Text diffLabel = new Text("Difficulties");
+
+ TableView<Difficulty> diffList = new TableView<Difficulty>();
+
+ TableColumn<Difficulty,String> diffCol = new TableColumn<Difficulty,String>("Difficulty");
+ TableColumn<Difficulty,Boolean> validCol = new TableColumn<Difficulty,Boolean>("Valid?");
+
+ diffList.getColumns().add(diffCol);
+ diffList.getColumns().add(validCol);
+
+ diffCol.setCellValueFactory(data -> new ReadOnlyStringWrapper(data.getValue().title));
+ validCol.setCellValueFactory(data -> new ReadOnlyBooleanWrapper(data.getValue().isValid));
+
+ diffList.setItems(level.getDiffList());
+
+
+ Button edit = new Button("Edit");
+ edit.setOnAction(e -> new DiffEditor(diffList.getSelectionModel().getSelectedItem()));
+
+ Button remove = new Button("Delete");
+ remove.setOnAction(e -> level.removeDiff(diffList.getSelectionModel().getSelectedItem()));
+
+ Button refresh = new Button("Refresh");
+ refresh.setOnAction(e -> {
+ level.readData();
+ diffList.setItems(level.getDiffList());
+ });
+
+ HBox buttons = new HBox();
+ buttons.getChildren().addAll(edit,remove,refresh);
+
+ TextField newDiff = new TextField("new");
+ Button newDiffButton = new Button("add");
+ newDiffButton.setOnAction(e -> level.addDiff(newDiff.getText()));
+ HBox newDiffBox = new HBox();
+ newDiffBox.getChildren().addAll(newDiff,newDiffButton);
+
+ Button save = new Button("Save");
+ save.setOnAction(e -> { //asigns feilds to values
+ level.setTitle(title.getText());
+ level.setArtist(artist.getText());
+ level.desc = desc.getText();
+ level.colors[0] = c1.getValue();
+ level.colors[1] = c2.getValue();
+ level.colors[2] = c3.getValue();
+ level.colors[3] = c4.getValue();
+ level.colors[4] = c5.getValue();
+ if (selectedBackground != null && selectedBackground.exists())
+ {
+ level.addFile(selectedBackground,"background.png");
+ }
+ if (selectedPreview != null && selectedPreview.exists())
+ {
+ level.addFile(selectedPreview,"preview.png");
+ }
+ if (selectedSong != null)
+ {
+ level.addFile(selectedSong,"song.wav");
+ }
+ level.writeMetadata();
+ });
+
+ VBox options = new VBox();
+ options.getChildren().addAll(folderNameLabel,folderName,titleLabel,title,artistLabel,artist,descLabel,desc,colorsLabel,
+ c1,c2,c3,c4,c5,filesLabel,previewButton,backgroundButton,songButton,save);
+
+ VBox diffBox = new VBox();
+ diffBox.getChildren().addAll(diffLabel,diffList,buttons,newDiffBox);
+
+ HBox mainBox = new HBox();
+ mainBox.getChildren().addAll(options,diffBox);
+
+ Scene scene = new Scene(mainBox);
+ primaryStage.setScene(scene);
+ primaryStage.show();
+ }
+} \ No newline at end of file
diff --git a/src/main/java/net/sowgro/npehero/devmenu/LevelList.java b/src/main/java/net/sowgro/npehero/devmenu/LevelList.java
new file mode 100755
index 0000000..8d5e0cb
--- /dev/null
+++ b/src/main/java/net/sowgro/npehero/devmenu/LevelList.java
@@ -0,0 +1,72 @@
+package net.sowgro.npehero.devmenu;
+
+import javafx.beans.property.ReadOnlyBooleanWrapper;
+import javafx.beans.property.ReadOnlyStringWrapper;
+import net.sowgro.npehero.Driver;
+import javafx.scene.Scene;
+import javafx.scene.control.Button;
+import javafx.scene.control.TableColumn;
+import javafx.scene.control.TableView;
+import javafx.scene.control.TextField;
+import javafx.scene.layout.HBox;
+import javafx.scene.layout.VBox;
+import javafx.stage.Stage;
+import net.sowgro.npehero.main.Level;
+import net.sowgro.npehero.main.LevelController;
+
+public class LevelList
+{
+ /*
+ * this class is a layout class, most of its purpose is to place UI elements like Buttons within Panes like VBoxes.
+ * the creation of these UI elements are mostly not commented due to their repetitive and self explanatory nature.
+ * style classes are defined in the style.css file.
+ */
+ public LevelList()
+ {
+ //sets up table view: requires special getters, setters and constructors to work
+ TableView<Level> levels = new TableView<Level>();
+
+ TableColumn<Level,String> titleCol = new TableColumn<Level,String>("Title");
+ TableColumn<Level,String> artistCol = new TableColumn<Level,String>("Artist");
+ TableColumn<Level,Boolean> validCol = new TableColumn<>("Valid?");
+
+ levels.getColumns().add(titleCol);
+ levels.getColumns().add(artistCol);
+ levels.getColumns().add(validCol);
+
+ titleCol.setCellValueFactory(data -> new ReadOnlyStringWrapper(data.getValue().getTitle()));
+ artistCol.setCellValueFactory(data -> new ReadOnlyStringWrapper(data.getValue().getArtist()));
+ validCol.setCellValueFactory(data -> new ReadOnlyBooleanWrapper(data.getValue().isValid()));
+
+ levels.setItems(LevelController.getLevelList());
+
+
+ Button edit = new Button("Edit");
+ edit.setOnAction(e -> new LevelEditor(levels.getSelectionModel().getSelectedItem()));
+
+ Button remove = new Button("Delete");
+ remove.setOnAction(e -> Driver.levelController.removeLevel(levels.getSelectionModel().getSelectedItem()));
+
+ Button refresh = new Button("Refresh");
+ refresh.setOnAction(e -> {
+ Driver.levelController.readData();
+ levels.setItems(LevelController.getLevelList());
+ });
+
+ HBox buttons = new HBox();
+ buttons.getChildren().addAll(edit,remove,refresh);
+
+ TextField newLevel = new TextField("new");
+ Button newLevelButton = new Button("add");
+ newLevelButton.setOnAction(e -> Driver.levelController.addLevel(newLevel.getText()));
+ HBox newLevelBox = new HBox();
+ newLevelBox.getChildren().addAll(newLevel,newLevelButton);
+
+ VBox main = new VBox();
+ main.getChildren().addAll(levels,buttons,newLevelBox);
+ Scene scene = new Scene(main, 400, 400);
+ Stage primaryStage = new Stage();
+ primaryStage.setScene(scene);
+ primaryStage.show();
+ }
+} \ No newline at end of file
diff --git a/src/main/java/net/sowgro/npehero/devmenu/NotesEditor.java b/src/main/java/net/sowgro/npehero/devmenu/NotesEditor.java
new file mode 100755
index 0000000..25b21f1
--- /dev/null
+++ b/src/main/java/net/sowgro/npehero/devmenu/NotesEditor.java
@@ -0,0 +1,101 @@
+package net.sowgro.npehero.devmenu;
+
+import java.io.FileNotFoundException;
+import java.io.PrintWriter;
+import java.io.UnsupportedEncodingException;
+import net.sowgro.npehero.gameplay.Timer;
+import net.sowgro.npehero.Driver;
+import javafx.scene.Scene;
+import javafx.scene.control.Button;
+import javafx.scene.input.KeyCode;
+import javafx.scene.layout.VBox;
+import javafx.scene.text.Text;
+import javafx.stage.Stage;
+import net.sowgro.npehero.main.Difficulty;
+
+public class NotesEditor
+{
+ Text help;
+ String t1 = "Press Start to begin recording. Use the same keys. Note: existing notes will be overwitten.";
+ String t2 = "Now recording. Press Stop or ESC to finish";
+ Difficulty diff;
+ Timer timer;
+ PrintWriter writer;
+ public NotesEditor(Difficulty diff) throws FileNotFoundException, UnsupportedEncodingException
+ {
+ this.diff = diff;
+
+ help = new Text(t1);
+ Text cur = new Text("-----");
+
+ Button start = new Button("Start");
+ start.setOnAction(e -> start());
+ start.setFocusTraversable(false);
+
+ Button stop = new Button("Stop");
+ stop.setOnAction(e -> stop());
+ stop.setFocusTraversable(false);
+
+ VBox main = new VBox();
+ main.getChildren().addAll(help,cur,start,stop);
+
+ Scene scene = new Scene(main);
+ Stage primaryStage = new Stage();
+ primaryStage.setScene(scene);
+ primaryStage.show();
+
+ writer = new PrintWriter(diff.notes, "UTF-8");
+
+ scene.setOnKeyPressed(e -> {
+ if (e.getCode() == KeyCode.D) {
+ writer.println("d"+timer);
+ cur.setText("d"+timer);
+ }
+ if (e.getCode() == KeyCode.F) {
+ writer.println("f"+timer);
+ cur.setText("f"+timer);
+ }
+ if (e.getCode() == KeyCode.SPACE) {
+ writer.println("s"+timer);
+ cur.setText("s"+timer);
+ }
+ if (e.getCode() == KeyCode.J) {
+ writer.println("j"+timer);
+ cur.setText("j"+timer);
+ }
+ if (e.getCode() == KeyCode.K) {
+ writer.println("k"+timer);
+ cur.setText("k"+timer);
+ }
+ if (e.getCode() == KeyCode.ESCAPE)
+ {
+ stop();
+ }
+ });
+
+ primaryStage.setOnCloseRequest(e -> stop());
+ }
+
+ private void start()
+ {
+ Driver.soundController.playSong(diff.level.song);
+ timer = new Timer(diff.bpm);
+ help.setText(t2);
+ }
+
+ private void stop()
+ {
+ try
+ {
+ Driver.soundController.endSong();
+ diff.numBeats = (int)Double.parseDouble(timer.toString());
+ timer = null;
+ writer.close();
+ help.setText(t1);
+ }
+ catch (Exception e)
+ {
+ //System.err.println("tried to stop but already stopped");
+ }
+ }
+} \ No newline at end of file
diff --git a/src/main/java/net/sowgro/npehero/gameplay/Block.java b/src/main/java/net/sowgro/npehero/gameplay/Block.java
new file mode 100755
index 0000000..5bc9d9c
--- /dev/null
+++ b/src/main/java/net/sowgro/npehero/gameplay/Block.java
@@ -0,0 +1,27 @@
+//glowing block of color c (jfx node)
+
+package net.sowgro.npehero.gameplay;
+
+import javafx.scene.effect.BlurType;
+import javafx.scene.effect.DropShadow;
+import javafx.scene.paint.Color;
+import javafx.scene.shape.Rectangle;
+
+public class Block extends Rectangle
+{
+ public Block(Color c, double a, double b, int r)
+ {
+ super();
+ DropShadow dropShadow = new DropShadow();
+ dropShadow.setRadius(200.0);
+ dropShadow.setColor(c);
+ dropShadow.setBlurType(BlurType.GAUSSIAN);
+
+ super.setFill(c);
+ super.setWidth(a);
+ super.setHeight(b);
+ super.setArcHeight(r);
+ super.setArcWidth(r);
+ super.setEffect(dropShadow);
+ }
+} \ No newline at end of file
diff --git a/src/main/java/net/sowgro/npehero/gameplay/NoteInfo.java b/src/main/java/net/sowgro/npehero/gameplay/NoteInfo.java
new file mode 100755
index 0000000..a34e939
--- /dev/null
+++ b/src/main/java/net/sowgro/npehero/gameplay/NoteInfo.java
@@ -0,0 +1,28 @@
+/*Name: Guitar Hero Project
+ *Description: Contains the info for when to send a note
+ */
+package net.sowgro.npehero.gameplay;
+
+import javafx.scene.paint.Color;
+
+public class NoteInfo
+{
+ private double sendTime;
+ private Color col;
+
+ public NoteInfo(double t) {
+ sendTime = t;
+ }
+
+ public double getTime() {
+ return sendTime;
+ }
+
+ public Color getColor() {
+ return col;
+ }
+
+ public double compareTo(NoteInfo other) {
+ return sendTime - other.sendTime;
+ }
+}
diff --git a/src/main/java/net/sowgro/npehero/gameplay/SongPlayer.java b/src/main/java/net/sowgro/npehero/gameplay/SongPlayer.java
new file mode 100755
index 0000000..39932a5
--- /dev/null
+++ b/src/main/java/net/sowgro/npehero/gameplay/SongPlayer.java
@@ -0,0 +1,360 @@
+package net.sowgro.npehero.gameplay;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.Queue;
+import java.util.Scanner;
+
+import javax.sound.sampled.LineUnavailableException;
+import javax.sound.sampled.UnsupportedAudioFileException;
+
+import net.sowgro.npehero.Driver;
+import net.sowgro.npehero.gui.GameOver;
+import javafx.geometry.Pos;
+import javafx.scene.CacheHint;
+import javafx.scene.input.KeyCode;
+import javafx.scene.layout.HBox;
+import javafx.scene.layout.Pane;
+import javafx.scene.layout.StackPane;
+import javafx.scene.layout.VBox;
+import javafx.scene.paint.Color;
+import javafx.animation.*;
+import javafx.util.*;
+import net.sowgro.npehero.main.Difficulty;
+import net.sowgro.npehero.main.Level;
+import net.sowgro.npehero.main.ScoreController;
+
+
+
+//hi aidan here are some objects you can use
+// cntrl.setScore(0) - pass in int
+// cntrl.getScore() - returns int
+// d.bpm - int, defined in difficulty metadata
+// lvl.colors - array of colors (size 5) for the block colors
+// d.notes - File, notes.txt in the difficulty folder
+
+// gui.Driver.setMenu(new GameOver(lvl, d, p, cntrl.getScore()));
+
+//d.numBeats - int
+//d.song - File
+
+
+public class SongPlayer extends Pane {
+ private Double bpm; //initializes the bpm of the song, to be read in from a metadata file later
+ private int songLength; //initializes the length of the song in terms of the song's bpm, to be read in later
+
+ private File song;
+ private boolean songIsPlaying = false;
+ private boolean missMute = false;
+
+ private Level level;
+ private Difficulty difficulty;
+ private Pane pane;
+
+ Timer timer; //the timer that determines when notes will fall, counted in terms of the song's bpm
+ final int TIME = 1000; //delay for notes falling down the screen
+
+ ScoreController scoreCounter = new ScoreController(); //used to keep track of the user's score
+
+ HBox buttonBox = new HBox(); //used to align the buttons horizontally
+ VBox place = new VBox(); //used to place the buttons within the frame
+
+ Target dButton = new Target(Color.RED, 50, 50, 5, 'd'); //Initializes the button, each parameter is a placeholder that is changed later
+ Queue<NoteInfo> dSends = new LinkedList<NoteInfo>(); //Queue that dictates when to send the notes
+ ArrayList<Block> dLane = new ArrayList<Block>(); //Array list containing all the notes currently on the field for that lane
+ //process is repeated for the following four buttons
+ Target fButton = new Target(Color.BLUE, 50, 50, 5, 'f');
+ Queue<NoteInfo> fSends = new LinkedList<NoteInfo>();
+ ArrayList<Block> fLane = new ArrayList<Block>();
+
+ Target sButton = new Target(Color.GREEN, 50, 50, 5, '_');
+ Queue<NoteInfo> spaceSends = new LinkedList<NoteInfo>();
+ ArrayList<Block> spaceLane = new ArrayList<Block>();
+
+ Target jButton = new Target(Color.PURPLE, 50, 50, 5, 'j');
+ Queue<NoteInfo> jSends = new LinkedList<NoteInfo>();
+ ArrayList<Block> jLane = new ArrayList<Block>();
+
+ Target kButton = new Target(Color.YELLOW, 50, 50, 5, 'k');
+ Queue<NoteInfo> kSends = new LinkedList<NoteInfo>();
+ ArrayList<Block> kLane = new ArrayList<Block>();
+
+ /**
+ * Establishes what the chart for the song is going to look like
+ * @throws FileNotFoundException
+ */
+ public void loadSong(File notes) throws FileNotFoundException {
+ Scanner scan = new Scanner(new File(notes.getPath())); //file reader for reading in the notes from a notes.txt file
+ try{
+ while (scan.hasNext()) {
+ String input = scan.next();
+ if (input.charAt(0) == 'd') {
+ dSends.add(new NoteInfo(Double.parseDouble(input.substring(1))));
+ }
+ else if (input.charAt(0) == 'f') {
+ fSends.add(new NoteInfo(Double.parseDouble(input.substring(1))));
+ }
+ else if (input.charAt(0) == 's') {
+ spaceSends.add(new NoteInfo(Double.parseDouble(input.substring(1))));
+ }
+ else if (input.charAt(0) == 'j') {
+ jSends.add(new NoteInfo(Double.parseDouble(input.substring(1))));
+ }
+ else if (input.charAt(0) == 'k') {
+ kSends.add(new NoteInfo(Double.parseDouble(input.substring(1))));
+ }
+ }
+ } catch (NumberFormatException e) {
+ e.printStackTrace();
+ }
+ }
+
+ public SongPlayer(Level lvl, Difficulty d, Pane p, ScoreController cntrl) {
+ Driver.soundController.endSong();
+ song = lvl.song;
+
+ if (lvl.background != null) {
+ Driver.setBackground(lvl.background);
+ }
+ bpm = d.bpm; //Reads the song's bpm from a metadata file
+ level = lvl;
+ difficulty = d;
+ pane = p;
+
+ //System.out.println(d.bpm + " " + d.numBeats);
+
+ songLength = d.numBeats;
+ timer = new Timer(bpm); //Sets the timer's bpm to that of the song
+ scoreCounter = cntrl; //Uses the song's designated scoreCounter
+
+ try {
+ loadSong(d.notes); //Calls the file loading from the song's notes.txt file
+ } catch (FileNotFoundException e) {
+ e.printStackTrace();
+ }
+
+ dButton.setColor(lvl.colors[0]); //sets the color of the five buttons to be
+ fButton.setColor(lvl.colors[1]); //the colors outlined in the songs metadata
+ sButton.setColor(lvl.colors[2]); //file
+ jButton.setColor(lvl.colors[3]);
+ kButton.setColor(lvl.colors[4]);
+ genButton(dButton); //binds the size of each button to the screen, so that
+ genButton(fButton); //they are dynamically resizeable
+ genButton(sButton);
+ genButton(jButton);
+ genButton(kButton);
+
+ Driver.primaryStage.getScene().setOnKeyPressed(e -> {
+ /**
+ * The keyboard detection for the game: when a key is pressed it
+ * calls the checkNote() method for the corresponding lane
+ */
+ //System.out.println(timer.time());
+ if (super.isVisible())
+ {
+ if (e.getCode() == KeyCode.D) {
+ checkNote(dLane, dButton);
+ }
+ if (e.getCode() == KeyCode.F) {
+ checkNote(fLane, fButton);
+ }
+ if (e.getCode() == KeyCode.SPACE) {
+ checkNote(spaceLane, sButton);
+ }
+ if (e.getCode() == KeyCode.J) {
+ checkNote(jLane, jButton);
+ }
+ if (e.getCode() == KeyCode.K) {
+ checkNote(kLane, kButton);
+ }
+ if (e.getCode() == KeyCode.Q) {
+ System.out.println("" + timer.time());
+ }
+ }
+ //prints the user's current score and combo, for debugging purposes
+ //System.out.println("Score: " + scoreCounter.getScore() + "\nCombo: " + scoreCounter.getCombo() + "\n");
+ });
+
+ buttonBox.setAlignment(Pos.CENTER); //puts the buttons in the center of the screen
+ buttonBox.getChildren().addAll(dButton, fButton, sButton, jButton, kButton); //places the buttons in the correct row order
+ buttonBox.setSpacing(10); //sets the space between each button
+
+ place.prefWidthProperty().bind(super.widthProperty()); //Sets the height and with of the scene
+ place.prefHeightProperty().bind(super.heightProperty()); //to natch the window
+ place.getChildren().addAll(buttonBox); //adds the buttonBox to the screen
+ place.setAlignment(Pos.BOTTOM_CENTER); //sets the alignment of the pane
+ place.setSpacing(10);
+
+ StackPane root = new StackPane();
+ root.getChildren().addAll(place); //aligns the components within the pane
+
+ super.getChildren().addAll(root); //puts all of the combonents in the pane to be rendered
+ }
+
+ /**
+ * Checks if a note should be sent at the current time, and sends the note if it
+ * needs to be
+ *
+ * @param sends the queue to check
+ * @param lane the lane to send the note to
+ */
+ public void sendNote(Queue<NoteInfo> sends, ArrayList<Block> lane, Target button) {
+ if (sends.peek() != null && timer.time() > sends.peek().getTime()-(1000*(bpm/60000.0))) {
+ TranslateTransition anim = new TranslateTransition(Duration.millis(TIME+105));
+
+ lane.add(new Block(button.getColor(), 50, 50, 5));
+ int index = lane.size() - 1;
+ sends.remove();
+ lane.get(index).setCache(true); //added by tbone to try to improve performance
+ lane.get(index).setCacheHint(CacheHint.SPEED); //this too
+ lane.get(index).heightProperty().bind(super.widthProperty().divide(8));
+ lane.get(index).widthProperty().bind(super.widthProperty().divide(8));
+ lane.get(index).arcHeightProperty().bind(super.widthProperty().divide(25));
+ lane.get(index).arcWidthProperty().bind(super.widthProperty().divide(25));
+ lane.get(index).setX(button.getLayoutX());
+ lane.get(index).setY(-lane.get(index).getHeight());
+ anim.setInterpolator(Interpolator.LINEAR);
+ anim.setByY(super.getHeight() + lane.get(index).getHeight() + 75);
+ anim.setCycleCount(1);
+ anim.setAutoReverse(false);
+ anim.setNode(lane.get(lane.size() - 1));
+ anim.play();
+
+ anim.setOnFinished(e -> {
+ if (super.getChildren().removeAll(anim.getNode())){
+ scoreCounter.miss(missMute);
+ FillTransition ft = new FillTransition(Duration.millis(500), button.rect);
+ ft.setFromValue(Color.RED);
+ ft.setToValue(button.getFillColor());
+ ft.play();
+ }
+ });
+ super.getChildren().add(lane.get(lane.size() - 1));
+ }
+ }
+
+ /**
+ * Sets up the given button
+ *
+ * @param button
+ */
+ private void genButton(Target button) {
+ button.rect.heightProperty().bind(super.widthProperty().divide(8));
+ button.rect.widthProperty().bind(super.widthProperty().divide(8));
+ button.rect.arcHeightProperty().bind(super.widthProperty().divide(25));
+ button.rect.arcWidthProperty().bind(super.widthProperty().divide(25));
+ button.rect.strokeWidthProperty().bind(super.widthProperty().divide(120));
+ }
+
+ /**
+ * The background test that is run on every frame of the game
+ */
+ AnimationTimer gameLoop = new AnimationTimer() {
+
+ @Override
+ public void handle(long arg0) {
+ sendNote(dSends, dLane, dButton);
+ sendNote(fSends, fLane, fButton);
+ sendNote(spaceSends, spaceLane, sButton);
+ sendNote(jSends, jLane, jButton);
+ sendNote(kSends, kLane, kButton);
+ if (timer.time() > songLength) {
+ Driver.setMenu(new GameOver(level, difficulty, pane, scoreCounter.getScore()));
+ cancel();
+ }
+ if (!songIsPlaying && timer.time() > 0.0) {
+ songIsPlaying = true;
+ Driver.soundController.playSong(song);
+ }
+ }
+ };
+
+ //starts the gameLoop, a periodic backround task runner that runs the methods within it 60 times every second
+ public void start()
+ {
+ gameLoop.start();
+ }
+
+ /**
+ * Stops the gameloop
+ * @throws LineUnavailableException
+ * @throws IOException
+ * @throws UnsupportedAudioFileException
+ */
+ public void cancel() {
+ missMute = true;
+ Driver.soundController.endSong();
+ Driver.soundController.playMenuSong();
+ Driver.setMenuBackground();
+ gameLoop.stop();
+ }
+
+ /**
+ * returns the pos in the lane array of the closest note to the goal
+ *
+ * @param searchLane
+ * @return the position of the note
+ */
+ private int getClosestNote(ArrayList<Block> searchLane) {
+ int pos = 0;
+
+ for (int i = 0; i < searchLane.size(); i++) {
+ if (distanceToGoal(searchLane.get(i)) < distanceToGoal(searchLane.get(pos))) {
+ pos = i;
+ }
+ }
+ return pos;
+ }
+
+ /**
+ * Returns the distance to the goal of the given note
+ *
+ * @param note
+ * @return
+ */
+ private double distanceToGoal(Block note) {
+ return Math.abs((super.getHeight() - note.getTranslateY() + note.getHeight()/2) - dButton.rect.getLayoutY());
+ }
+
+ /**
+ * When the player hits the key, checks the quality of the hit
+ * @param lane the lane checking for a hit
+ * @param button the button checking for a hit
+ * @return 2 for a perfect hit, 1 for a good hit, 0 for a miss, and -1 if there are no notes to hit
+ */
+ private int checkNote(ArrayList<Block> lane, Target button) {
+ if (lane.size() != 0 && super.isVisible())
+ {
+ double distance = distanceToGoal(lane.get(getClosestNote(lane)));
+ if (lane.size() > 0 && distance < super.getHeight() / 3) {
+
+ FillTransition ft = new FillTransition(Duration.millis(500), button.rect);
+ ft.setToValue(button.getFillColor());
+
+ super.getChildren().removeAll(lane.get(getClosestNote(lane)));
+ lane.remove(lane.get(getClosestNote(lane)));
+ if (distance < super.getHeight() / 12) {
+ ft.setFromValue(Color.WHITE);
+ ft.play();
+ scoreCounter.perfect();
+ return 2;
+ }
+ if (distance < super.getHeight() / 4) {
+ ft.setFromValue(Color.CYAN);
+ ft.play();
+ scoreCounter.good();
+ return 1;
+ }
+ ft.setFromValue(Color.RED);
+ ft.play();
+ scoreCounter.miss(false);
+ return 0;
+ }
+ }
+ return -1;
+ }
+
+} \ No newline at end of file
diff --git a/src/main/java/net/sowgro/npehero/gameplay/Target.java b/src/main/java/net/sowgro/npehero/gameplay/Target.java
new file mode 100755
index 0000000..3dc8564
--- /dev/null
+++ b/src/main/java/net/sowgro/npehero/gameplay/Target.java
@@ -0,0 +1,50 @@
+//glowing block of color c (jfx node)
+
+package net.sowgro.npehero.gameplay;
+
+import javafx.scene.layout.StackPane;
+import javafx.scene.paint.Color;
+import javafx.scene.shape.Rectangle;
+import javafx.scene.text.Text;
+
+public class Target extends StackPane
+{
+ private Color col;
+ private Color fill;
+ private Text label;
+ public Rectangle rect = new Rectangle();
+ public Target(Color c, double a, double b, int r, char key)
+ {
+ label = new Text(key+"");
+ label.getStyleClass().add("t3");
+ label.scaleXProperty().bind(super.widthProperty().divide(50));
+ label.scaleYProperty().bind(label.scaleXProperty());
+ super.getChildren().addAll(rect,label);
+
+
+ col = c;
+ fill = new Color(c.darker().getRed(), c.darker().getGreen(), c.darker().getBlue(), 0.45);
+ rect.setFill(fill);
+ rect.setWidth(a);
+ rect.setHeight(b);
+ rect.setArcHeight(r);
+ rect.setArcWidth(r);
+ rect.setStroke(col);
+ rect.setStrokeWidth(5);
+ }
+
+ public void setColor(Color c) {
+ col = c;
+ fill = new Color(c.darker().getRed(), c.darker().getGreen(), c.darker().getBlue(), 0.45);
+ rect.setFill(fill);
+ rect.setStroke(c);
+ }
+
+ public Color getFillColor() {
+ return fill;
+ }
+
+ public Color getColor() {
+ return col;
+ }
+} \ No newline at end of file
diff --git a/src/main/java/net/sowgro/npehero/gameplay/Timer.java b/src/main/java/net/sowgro/npehero/gameplay/Timer.java
new file mode 100755
index 0000000..eada237
--- /dev/null
+++ b/src/main/java/net/sowgro/npehero/gameplay/Timer.java
@@ -0,0 +1,28 @@
+/*Name: Guitar Hero Project
+ *Description: Contains the method used to determine how long the user has been playing,
+ * used to determine when to send notes
+ */
+package net.sowgro.npehero.gameplay;
+
+
+public class Timer
+{
+ private long timeStart = System.currentTimeMillis();
+ private double bpm;
+
+ public Timer(double newBpm) {
+ bpm = newBpm;
+ }
+
+ public Timer() {
+ bpm = 60000;
+ }
+
+ public double time() {
+ return ((double)(System.currentTimeMillis()-timeStart)-2000)*(bpm/60000.0);
+ }
+
+ public String toString() {
+ return ""+((Math.round(10*(((double)(System.currentTimeMillis()-timeStart))*(bpm/60000.0))))/10.0);
+ }
+}
diff --git a/src/main/java/net/sowgro/npehero/gui/GameOver.java b/src/main/java/net/sowgro/npehero/gui/GameOver.java
new file mode 100755
index 0000000..68ce3ea
--- /dev/null
+++ b/src/main/java/net/sowgro/npehero/gui/GameOver.java
@@ -0,0 +1,124 @@
+package net.sowgro.npehero.gui;
+
+import javafx.event.ActionEvent;
+import javafx.event.EventHandler;
+import javafx.geometry.Insets;
+import javafx.geometry.Pos;
+import javafx.scene.control.Button;
+import javafx.scene.control.TextField;
+import javafx.scene.layout.BorderPane;
+import javafx.scene.layout.HBox;
+import javafx.scene.layout.Pane;
+import javafx.scene.layout.VBox;
+import javafx.scene.text.Text;
+import net.sowgro.npehero.Driver;
+import net.sowgro.npehero.main.Difficulty;
+import net.sowgro.npehero.main.Level;
+
+public class GameOver extends Pane
+{
+ /*
+ * this class is a layout class, most of its purpose is to place UI elements like Buttons within Panes like VBoxes.
+ * the creation of these UI elements are mostly not commented due to their repetitive and self explanatory nature.
+ * style classes are defined in the style.css file.
+ */
+ public GameOver(Level level, Difficulty diff, Pane lastMenu, int score2)
+ {
+ Text topText = new Text();
+ topText.setText("Level Complete");
+ topText.getStyleClass().add("t11");
+
+ Text levelName = new Text();
+ levelName.setText(level.getTitle());
+ levelName.getStyleClass().add("t2");
+
+ Text levelArtist = new Text();
+ levelArtist.setText(level.getArtist()+" - "+diff.title);
+ levelArtist.getStyleClass().add("t3");
+
+ VBox levelDetailsBox = new VBox();
+ levelDetailsBox.getChildren().addAll(levelName,levelArtist);
+ levelDetailsBox.getStyleClass().add("box");
+ levelDetailsBox.setPadding(new Insets(5));
+
+
+ Text scoreLabel = new Text();
+ scoreLabel.setText("Final score");
+ scoreLabel.getStyleClass().add("t3");
+
+ Text score = new Text();
+ score.setText(score2+"");
+ score.getStyleClass().add("t2");
+ score.setStyle("-fx-font-size: 30;");
+
+ VBox scoreBox = new VBox();
+ scoreBox.getStyleClass().add("box");
+ scoreBox.getChildren().addAll(scoreLabel,score);
+ scoreBox.setPadding(new Insets(5));
+
+
+ Text nameLabel = new Text();
+ nameLabel.setText("Leaderboard entry");
+ nameLabel.getStyleClass().add("t3");
+
+ TextField name = new TextField();
+ name.getStyleClass().remove("text-feild");
+ name.getStyleClass().add("button");
+ name.setText("name");
+
+ Button save = new Button();
+ save.setText("Add");
+ save.setOnAction(new EventHandler<ActionEvent>() { //this is the same as the "e ->" thing but it allows more than one line to be added
+ @Override
+ public void handle(ActionEvent event) {
+ Driver.soundController.playSfx("forward");
+ save.setDisable(true);
+ name.setDisable(true);
+ diff.addToLeaderboard(name.getText(), score2);
+ }
+ });
+
+ BorderPane b = new BorderPane();
+ b.setRight(save);
+ b.setCenter(name);
+
+ VBox nameBox = new VBox();
+ nameBox.getChildren().addAll(nameLabel,b);
+ nameBox.getStyleClass().add("box");
+ nameBox.setSpacing(5);
+ nameBox.setPadding(new Insets(5));
+
+
+ Button exit = new Button();
+ exit.setText("Back");
+ exit.setOnAction(e -> {
+ Driver.soundController.playSfx("backward");
+ Driver.setMenu(lastMenu);
+ });
+
+ Button replay = new Button();
+ replay.setText("Replay");
+ replay.setOnAction(e -> {
+ Driver.soundController.playSfx("forward");
+ Driver.setMenu(new LevelSurround(level, diff, lastMenu));
+ });
+
+ BorderPane buttonBox = new BorderPane();
+ buttonBox.setLeft(exit);
+ buttonBox.setRight(replay);
+
+
+ VBox centerBox = new VBox();
+ centerBox.getChildren().addAll(topText,levelDetailsBox,scoreBox,nameBox,buttonBox);
+ centerBox.setSpacing(10);
+ centerBox.setAlignment(Pos.CENTER);
+
+ HBox rootBox = new HBox();
+ rootBox.getChildren().add(centerBox);
+ rootBox.setAlignment(Pos.CENTER);
+ rootBox.prefWidthProperty().bind(super.prefWidthProperty());
+ rootBox.prefHeightProperty().bind(super.prefHeightProperty());
+
+ super.getChildren().add(rootBox);
+ }
+}
diff --git a/src/main/java/net/sowgro/npehero/gui/Leaderboard.java b/src/main/java/net/sowgro/npehero/gui/Leaderboard.java
new file mode 100755
index 0000000..a8e54d1
--- /dev/null
+++ b/src/main/java/net/sowgro/npehero/gui/Leaderboard.java
@@ -0,0 +1,72 @@
+package net.sowgro.npehero.gui;
+
+import javafx.beans.property.ReadOnlyStringWrapper;
+import javafx.geometry.Pos;
+import javafx.scene.control.Button;
+import javafx.scene.control.TableColumn;
+import javafx.scene.control.TableView;
+import javafx.scene.control.TableColumn.SortType;
+import javafx.scene.layout.HBox;
+import javafx.scene.layout.Pane;
+import javafx.scene.layout.VBox;
+import net.sowgro.npehero.Driver;
+import net.sowgro.npehero.main.Difficulty;
+import net.sowgro.npehero.main.LeaderboardEntry;
+import net.sowgro.npehero.main.Level;
+
+public class Leaderboard extends Pane
+{
+ /*
+ * this class is a layout class, most of its purpose is to place UI elements like Buttons within Panes like VBoxes.
+ * the creation of these UI elements are mostly not commented due to their repetitive and self explanatory nature.
+ * style classes are defined in the style.css file.
+ */
+ public Leaderboard(Level level, Difficulty diff, Pane prev)
+ {
+ //sets up table view: requires java bean getters, setters and constructors to work
+ TableView<LeaderboardEntry> scores = new TableView<LeaderboardEntry>();
+
+ TableColumn<LeaderboardEntry, String> nameCol = new TableColumn<LeaderboardEntry, String>("Name");
+ TableColumn<LeaderboardEntry, String> scoreCol = new TableColumn<LeaderboardEntry, String>("Score");
+ TableColumn<LeaderboardEntry, String> dateCol = new TableColumn<LeaderboardEntry, String>("Date");
+
+ scores.getColumns().add(nameCol);
+ scores.getColumns().add(scoreCol);
+ scores.getColumns().add(dateCol);
+
+ nameCol.setCellValueFactory(data -> new ReadOnlyStringWrapper(data.getValue().getName()));
+ scoreCol.setCellValueFactory(data -> new ReadOnlyStringWrapper(data.getValue().getScore() + ""));
+ dateCol.setCellValueFactory(data -> new ReadOnlyStringWrapper(data.getValue().getDate()));
+
+ scores.setItems(diff.getLeaderboard());
+
+ scores.getStyleClass().add("unselectable");
+
+ scores.prefWidthProperty().bind(super.prefWidthProperty().multiply(0.25));
+ scores.prefHeightProperty().bind(super.prefHeightProperty().multiply(0.75));
+
+ scoreCol.setSortType(SortType.DESCENDING);
+ scores.getSortOrder().add(scoreCol);
+
+ Button exit = new Button();
+ exit.setText("Back");
+ exit.setOnAction(e -> {
+ Driver.soundController.playSfx("backward");
+ Driver.setMenu(prev);
+ });
+
+ VBox centerBox = new VBox();
+ centerBox.setAlignment(Pos.CENTER);
+ centerBox.setSpacing(10);
+ centerBox.getChildren().addAll(scores,exit);
+ centerBox.setMinWidth(400);
+
+ HBox rootBox = new HBox();
+ rootBox.prefWidthProperty().bind(super.prefWidthProperty());
+ rootBox.prefHeightProperty().bind(super.prefHeightProperty());
+ rootBox.getChildren().add(centerBox);
+ rootBox.setAlignment(Pos.CENTER);
+
+ super.getChildren().add(rootBox);
+ }
+}
diff --git a/src/main/java/net/sowgro/npehero/gui/LevelDetails.java b/src/main/java/net/sowgro/npehero/gui/LevelDetails.java
new file mode 100755
index 0000000..25d96c8
--- /dev/null
+++ b/src/main/java/net/sowgro/npehero/gui/LevelDetails.java
@@ -0,0 +1,137 @@
+package net.sowgro.npehero.gui;
+
+import javafx.geometry.Insets;
+import javafx.geometry.Pos;
+import javafx.scene.control.Button;
+import javafx.scene.control.RadioButton;
+import javafx.scene.control.ScrollPane;
+import javafx.scene.control.ToggleGroup;
+import javafx.scene.image.Image;
+import javafx.scene.image.ImageView;
+import javafx.scene.layout.FlowPane;
+import javafx.scene.layout.HBox;
+import javafx.scene.layout.VBox;
+import javafx.scene.text.Text;
+import javafx.scene.text.TextAlignment;
+import javafx.scene.text.TextFlow;
+import net.sowgro.npehero.Driver;
+import net.sowgro.npehero.main.Difficulty;
+import net.sowgro.npehero.main.Level;
+
+public class LevelDetails extends VBox
+{
+ /**
+ * this class is a layout class, most of its purpose is to place UI elements like Buttons within Panes like VBoxes.
+ * the creation of these UI elements are mostly not commented due to their repetitive and self explanatory nature.
+ * style classes are defined in the style.css file.
+ *
+ * @param level: the selected level on the right side
+ */
+ public LevelDetails(Level level)
+ {
+ VBox rightBox = new VBox();
+ rightBox.prefWidthProperty().bind(super.prefWidthProperty());
+ rightBox.prefHeightProperty().bind(super.prefHeightProperty().multiply(0.75));
+ rightBox.setMinWidth(350);
+ rightBox.getStyleClass().add("box");
+
+ Button play = new Button();
+ play.setDisable(true);
+ play.setText("Play");
+
+ Button leaderboard = new Button();
+ leaderboard.setDisable(true);
+ leaderboard.setText("Leaderboard");
+
+ if (level == null) //if no level is selected from the list on the left
+ {
+ Text desc = new Text();
+ desc.setText("Select a level from the left pane");
+ desc.getStyleClass().add("t3");
+ desc.wrappingWidthProperty().bind(super.prefWidthProperty().subtract(10));
+ desc.setTextAlignment(TextAlignment.CENTER);
+
+ rightBox.setAlignment(Pos.CENTER);
+ rightBox.getChildren().addAll(desc);
+ }
+
+ else
+ {
+ VBox details = new VBox();
+
+ ScrollPane detailsScroll = new ScrollPane(details);
+ detailsScroll.prefHeightProperty().bind(rightBox.prefHeightProperty());
+ detailsScroll.prefWidthProperty().bind(rightBox.prefWidthProperty());
+ detailsScroll.getStyleClass().remove("scroll-pane");
+
+ Text title = new Text();
+ title.setText(level.getTitle());
+ title.getStyleClass().add("t1");
+
+ Text artist = new Text();
+ artist.setText(level.getArtist());
+ artist.getStyleClass().add("t2");
+
+ Text desc = new Text();
+ desc.setText(level.desc);
+ desc.getStyleClass().add("t3");
+
+ ImageView previewView = new ImageView();
+ Image preview = level.preview;
+ previewView.setImage(preview);
+ previewView.fitWidthProperty().bind(super.prefWidthProperty().multiply(0.5));
+ previewView.setPreserveRatio(true);
+
+ FlowPane diffSelector = new FlowPane();
+ diffSelector.setAlignment(Pos.CENTER);
+ ToggleGroup diffToggleGroup = new ToggleGroup(); //allows only one to be selected at a time
+ for (Difficulty diff : level.getValidDiffList()) //adds a button for each diff
+ {
+ RadioButton temp = new RadioButton();
+ temp.getStyleClass().remove("radio-button"); //makes the buttons not look like a radio button and instead a normal button
+ temp.getStyleClass().add("button");
+ temp.setText(diff.title);
+ temp.setUserData(diff); //allows the data and text to be seperate
+ diffToggleGroup.getToggles().add(temp);
+ diffSelector.getChildren().add(temp);
+ }
+ play.disableProperty().bind(diffToggleGroup.selectedToggleProperty().isNull()); //disables play button when no difficulty is selected
+ play.setOnAction(e -> {
+ Driver.soundController.playSfx("forward");
+ Driver.setMenu(new LevelSurround(level, (Difficulty)diffToggleGroup.getSelectedToggle().getUserData(), Driver.getMenu()));
+ });
+
+ leaderboard.disableProperty().bind(diffToggleGroup.selectedToggleProperty().isNull());
+ leaderboard.setOnAction(e -> {
+ Driver.soundController.playSfx("forward");
+ Driver.setMenu(new Leaderboard(level, (Difficulty)diffToggleGroup.getSelectedToggle().getUserData(), Driver.getMenu()));
+ });
+
+
+ HBox diffBox = new HBox();
+ diffSelector.prefWidthProperty().bind(diffBox.widthProperty());
+ diffBox.getChildren().add(diffSelector);
+
+ details.setSpacing(10);
+ details.getChildren().addAll(new TextFlow(title), new TextFlow(artist), new TextFlow(desc), previewView, diffBox);
+ detailsScroll.setFitToWidth(true);
+
+ rightBox.getChildren().add(detailsScroll);
+ rightBox.setPadding(new Insets(5));
+ }
+
+ VBox rightSide = new VBox();
+ rightSide.setAlignment(Pos.CENTER_RIGHT);
+ rightSide.setSpacing(10);
+
+ HBox buttonBox = new HBox();
+ buttonBox.getChildren().addAll(leaderboard,play);
+ buttonBox.setSpacing(5);
+ buttonBox.setAlignment(Pos.CENTER_RIGHT);
+
+ rightSide.getChildren().addAll(rightBox,buttonBox);
+
+ super.setAlignment(Pos.CENTER_RIGHT);
+ super.getChildren().add(rightSide);
+ }
+}
diff --git a/src/main/java/net/sowgro/npehero/gui/LevelSelector.java b/src/main/java/net/sowgro/npehero/gui/LevelSelector.java
new file mode 100755
index 0000000..6d3442e
--- /dev/null
+++ b/src/main/java/net/sowgro/npehero/gui/LevelSelector.java
@@ -0,0 +1,98 @@
+package net.sowgro.npehero.gui;
+
+import javafx.beans.property.ReadOnlyStringWrapper;
+import javafx.beans.value.ChangeListener;
+import javafx.beans.value.ObservableValue;
+import javafx.geometry.Pos;
+import javafx.scene.control.Button;
+import javafx.scene.control.TableColumn;
+import javafx.scene.control.TableView;
+import javafx.scene.layout.HBox;
+import javafx.scene.layout.Pane;
+import javafx.scene.layout.VBox;
+import net.sowgro.npehero.Driver;
+import net.sowgro.npehero.main.Level;
+import net.sowgro.npehero.main.LevelController;
+
+public class LevelSelector extends Pane
+{
+ /*
+ * this class is a layout class, most of its purpose is to place UI elements like Buttons within Panes like VBoxes.
+ * the creation of these UI elements are mostly not commented due to their repetitive and self explanatory nature.
+ * style classes are defined in the style.css file.
+ */
+ public LevelSelector()
+ {
+ //sets up table view: requires special getters, setters and constructors to work
+ TableView<Level> levels = new TableView<Level>();
+
+ TableColumn<Level,String> titleCol = new TableColumn<Level,String>("Title");
+ TableColumn<Level,String> artistCol = new TableColumn<Level,String>("Artist");
+
+ levels.getColumns().add(titleCol);
+ levels.getColumns().add(artistCol);
+
+ titleCol.setCellValueFactory(data -> new ReadOnlyStringWrapper(data.getValue().getTitle()));
+ artistCol.setCellValueFactory(data -> new ReadOnlyStringWrapper(data.getValue().getArtist()));
+
+ levels.setItems(LevelController.getValidLevelList());
+
+ levels.prefWidthProperty().bind(super.prefWidthProperty().multiply(0.25));
+ levels.prefHeightProperty().bind(super.prefHeightProperty().multiply(0.75));
+ levels.setMinWidth(300);
+
+
+ Button exit = new Button();
+ exit.setText("Back");
+ exit.setOnAction(e -> {
+ Driver.setMenu(new MainMenu());
+ Driver.soundController.playSfx("backward");
+ });
+
+ VBox leftBox = new VBox();
+ leftBox.setAlignment(Pos.CENTER_LEFT);
+ leftBox.setSpacing(10);
+ leftBox.getChildren().addAll(levels,exit);
+
+ Pane rightBox = new Pane();
+ addDetails(rightBox, levels);
+
+
+ HBox rootBox = new HBox();
+ rootBox.prefWidthProperty().bind(super.prefWidthProperty());
+ rootBox.prefHeightProperty().bind(super.prefHeightProperty());
+ rootBox.getChildren().addAll(leftBox, rightBox);
+ rootBox.setAlignment(Pos.CENTER);
+ rootBox.setSpacing(10);
+
+ levels.getStyleClass().remove("list-view");
+ levels.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<Level>() { //listens for change in selected item of the list
+
+ @Override
+ public void changed(ObservableValue<? extends Level> arg0, Level arg1, Level arg2) {
+ addDetails(rightBox, levels);
+ }
+ });
+ super.getChildren().add(rootBox);
+ }
+
+ /**
+ * adds corresponding level details pane to the right side
+ * @param rightBox
+ * @param levels
+ */
+ private void addDetails(Pane rightBox, TableView<Level> levels)
+ {
+ VBox details = new LevelDetails(levels.getSelectionModel().getSelectedItem());
+ if (! rightBox.getChildren().isEmpty())
+ {
+ rightBox.getChildren().remove(0);
+ }
+ rightBox.getChildren().add(details);
+ details.prefWidthProperty().bind(super.prefWidthProperty().multiply(0.37));
+ details.prefHeightProperty().bind(super.prefHeightProperty());
+ details.maxWidthProperty().bind(super.prefWidthProperty().multiply(0.37));
+ details.maxHeightProperty().bind(super.prefHeightProperty());
+ }
+
+}
diff --git a/src/main/java/net/sowgro/npehero/gui/LevelSurround.java b/src/main/java/net/sowgro/npehero/gui/LevelSurround.java
new file mode 100755
index 0000000..08baf9e
--- /dev/null
+++ b/src/main/java/net/sowgro/npehero/gui/LevelSurround.java
@@ -0,0 +1,150 @@
+package net.sowgro.npehero.gui;
+
+import net.sowgro.npehero.Driver;
+import net.sowgro.npehero.gameplay.SongPlayer;
+import javafx.geometry.Insets;
+import javafx.geometry.Pos;
+import javafx.scene.control.Button;
+import javafx.scene.layout.AnchorPane;
+import javafx.scene.layout.HBox;
+import javafx.scene.layout.Pane;
+import javafx.scene.layout.StackPane;
+import javafx.scene.layout.VBox;
+import javafx.scene.text.Text;
+import net.sowgro.npehero.main.Difficulty;
+import net.sowgro.npehero.main.Level;
+import net.sowgro.npehero.main.ScoreController;
+
+public class LevelSurround extends Pane
+{
+ /*
+ * this class is a layout class, most of its purpose is to place UI elements like Buttons within Panes like VBoxes.
+ * the creation of these UI elements are mostly not commented due to their repetitive and self explanatory nature.
+ * style classes are defined in the style.css file.
+ */
+ public LevelSurround(Level level, Difficulty difficulty, Pane prev)
+ {
+ ScoreController sc = new ScoreController();
+ SongPlayer game = new SongPlayer(level, difficulty, prev, sc);
+
+ Button exit = new Button();
+ exit.setText("Back");
+ exit.setOnAction(e -> {
+ Driver.setMenu(prev);
+ Driver.soundController.playSfx("backward");
+ game.cancel();
+ });
+
+ HBox buttonBox = new HBox();
+ buttonBox.getChildren().addAll(exit);
+ buttonBox.setAlignment(Pos.TOP_LEFT);
+ buttonBox.setSpacing(10);
+
+ Text title = new Text();
+ title.setText(level.getTitle());
+ title.getStyleClass().add("t2");
+
+ Text artist = new Text();
+ artist.setText(level.getArtist()+" - "+difficulty.title);
+ artist.getStyleClass().add("t3");
+
+ VBox titleTextBox = new VBox();
+ titleTextBox.setAlignment(Pos.TOP_RIGHT);
+ titleTextBox.getChildren().addAll(title, artist);
+ titleTextBox.getStyleClass().add("box");
+ titleTextBox.setPadding(new Insets(10));
+
+ AnchorPane topBar = new AnchorPane();
+ topBar.getChildren().addAll(buttonBox,titleTextBox);
+ topBar.setLeftAnchor(buttonBox, 0.0);
+ topBar.setRightAnchor(titleTextBox, 0.0);
+ topBar.setTopAnchor(buttonBox, 0.0);
+ topBar.setTopAnchor(titleTextBox, 0.0);
+ topBar.setPadding(new Insets(10));
+
+
+ Text scoreLabel = new Text();
+ scoreLabel.setText("Score:");
+ scoreLabel.getStyleClass().add("t3");
+
+ Text scoreDisplay = new Text();
+ scoreDisplay.textProperty().bind(sc.scoreProperty);
+ scoreDisplay.getStyleClass().add("t1");
+
+ VBox scoreTextBox = new VBox();
+ scoreTextBox.setAlignment(Pos.BOTTOM_LEFT);
+ scoreTextBox.getChildren().addAll(scoreLabel,scoreDisplay);
+ scoreTextBox.setPadding(new Insets(10));
+ scoreTextBox.getStyleClass().add("box");
+ scoreTextBox.minWidthProperty().bind(scoreTextBox.heightProperty());
+
+ AnchorPane scoreBox = new AnchorPane();
+ scoreBox.getChildren().add(scoreTextBox);
+ scoreBox.setLeftAnchor(scoreTextBox, 0.0);
+ scoreBox.setBottomAnchor(scoreTextBox, 0.0);
+ scoreBox.setPadding(new Insets(10));
+
+ Text comboLabel = new Text();
+ comboLabel.setText("Combo:");
+ comboLabel.getStyleClass().add("t3");
+
+ Text comboDisplay = new Text();
+ comboDisplay.textProperty().bind(sc.comboProperty);
+ comboDisplay.getStyleClass().add("t1");
+
+ VBox comboTextBox = new VBox();
+ comboTextBox.setAlignment(Pos.BOTTOM_RIGHT);
+ comboTextBox.getChildren().addAll(comboLabel,comboDisplay);
+ comboTextBox.setPadding(new Insets(10));
+ comboTextBox.getStyleClass().add("box");
+ comboTextBox.minWidthProperty().bind(comboTextBox.heightProperty());
+
+ AnchorPane comboBox = new AnchorPane();
+ comboBox.getChildren().add(comboTextBox);
+ comboBox.setRightAnchor(comboTextBox, 0.0);
+ comboBox.setBottomAnchor(comboTextBox, 0.0);
+ comboBox.setPadding(new Insets(10));
+
+ game.minWidthProperty().bind(super.prefHeightProperty().multiply(0.66));
+ game.minHeightProperty().bind(super.prefHeightProperty());
+ game.getStyleClass().add("box");
+
+
+ comboBox.minWidthProperty().bind(super.prefWidthProperty().subtract(game.minWidthProperty()).divide(2));
+ scoreBox.minWidthProperty().bind(super.prefWidthProperty().subtract(game.minWidthProperty()).divide(2));
+
+ HBox centerBox = new HBox();
+ centerBox.getChildren().addAll(comboBox, game, scoreBox);
+ centerBox.setAlignment(Pos.BOTTOM_CENTER);
+
+ StackPane root = new StackPane();
+ root.getChildren().addAll(centerBox, topBar);
+
+ super.getChildren().add(root);
+ root.prefWidthProperty().bind(super.prefWidthProperty());
+ root.prefHeightProperty().bind(super.prefHeightProperty());
+
+ //for debug menu
+ Button addScore = new Button();
+ addScore.setText(level.getTitle() + " addscore");
+ addScore.setOnAction(e -> sc.setScore(sc.getScore()+1));
+// Driver.debug.addButton(addScore);
+
+ Button addCombo = new Button();
+ addCombo.setText(level.getTitle() + " addcombo");
+ addCombo.setOnAction(e -> sc.setCombo(sc.getCombo()+1));
+// Driver.debug.addButton(addCombo);
+
+ Button printD = new Button();
+ printD.setText(level.getTitle() + " print debug");
+ printD.setOnAction(e -> sc.print());
+// Driver.debug.addButton(printD);
+
+ Button testfinish = new Button();
+ testfinish.setText(level.getTitle() + "launch game end");
+ testfinish.setOnAction(e -> Driver.setMenu(new GameOver(level, difficulty, prev, sc.getScore())));
+// Driver.debug.addButton(testfinish);
+
+ game.start();
+ }
+} \ No newline at end of file
diff --git a/src/main/java/net/sowgro/npehero/gui/MainMenu.java b/src/main/java/net/sowgro/npehero/gui/MainMenu.java
new file mode 100755
index 0000000..bb1970f
--- /dev/null
+++ b/src/main/java/net/sowgro/npehero/gui/MainMenu.java
@@ -0,0 +1,70 @@
+package net.sowgro.npehero.gui;
+
+import javafx.geometry.Pos;
+import javafx.scene.control.Button;
+import javafx.scene.effect.BlurType;
+import javafx.scene.effect.DropShadow;
+import javafx.scene.layout.Pane;
+import javafx.scene.layout.VBox;
+import javafx.scene.paint.Color;
+import javafx.scene.text.Text;
+import net.sowgro.npehero.Driver;
+
+
+public class MainMenu extends Pane
+{
+ /*
+ * this class is a layout class, most of its purpose is to place UI elements like Buttons within Panes like VBoxes.
+ * the creation of these UI elements are mostly not commented due to their repetitive and self explanatory nature.
+ * style classes are defined in the style.css file.
+ */
+ public MainMenu()
+ {
+ DropShadow dropShadow = new DropShadow();
+ dropShadow.setRadius(50.0);
+ dropShadow.setColor(Color.WHITE);
+ dropShadow.setBlurType(BlurType.GAUSSIAN);
+
+ Text title = new Text();
+ title.setText("NPE Hero");
+ title.getStyleClass().add("t0");
+ title.setEffect(dropShadow);
+
+ Button play = new Button();
+ play.setText("Play");
+ play.setOnAction(e -> {
+ Driver.setMenu(new LevelSelector());
+ Driver.soundController.playSfx("forward");
+ });
+
+ Button settings = new Button();
+ settings.setText("Settings");
+ settings.setOnAction(e -> {Driver.setMenu(new Settings());
+ Driver.soundController.playSfx("forward");
+ });
+
+ Button exit = new Button();
+ exit.setText("Quit");
+ exit.setOnAction(e -> {Driver.quit();
+ Driver.soundController.playSfx("backward");
+ });
+
+ VBox buttonBox = new VBox();
+ buttonBox.getChildren().addAll(play, settings, exit);
+ buttonBox.setAlignment(Pos.CENTER);
+ buttonBox.setSpacing(10);
+
+ VBox centerBox = new VBox();
+ centerBox.setAlignment(Pos.CENTER);
+ centerBox.getChildren().addAll(title, buttonBox);
+ centerBox.setSpacing(10);
+
+ VBox rootBox = new VBox();
+ rootBox.prefWidthProperty().bind(super.prefWidthProperty());
+ rootBox.prefHeightProperty().bind(super.prefHeightProperty());
+ rootBox.setAlignment(Pos.CENTER);
+ rootBox.getChildren().add(centerBox);
+
+ super.getChildren().add(rootBox);
+ }
+}
diff --git a/src/main/java/net/sowgro/npehero/gui/Settings.java b/src/main/java/net/sowgro/npehero/gui/Settings.java
new file mode 100755
index 0000000..882eb86
--- /dev/null
+++ b/src/main/java/net/sowgro/npehero/gui/Settings.java
@@ -0,0 +1,131 @@
+package net.sowgro.npehero.gui;
+
+import javafx.geometry.Insets;
+import javafx.geometry.Pos;
+import javafx.scene.control.Button;
+import javafx.scene.control.Slider;
+import javafx.scene.control.ToggleButton;
+import javafx.scene.layout.BorderPane;
+import javafx.scene.layout.HBox;
+import javafx.scene.layout.Pane;
+import javafx.scene.layout.VBox;
+import javafx.scene.text.Text;
+import net.sowgro.npehero.Driver;
+import net.sowgro.npehero.devmenu.LevelList;
+
+public class Settings extends Pane
+{
+ /*
+ * this class is a layout class, most of its purpose is to place UI elements like Buttons within Panes like VBoxes.
+ * the creation of these UI elements are mostly not commented due to their repetitive and self explanatory nature.
+ * style classes are defined in the style.css file.
+ */
+ public Settings()
+ {
+ Text musicText = new Text();
+ musicText.setText("Music Volume");
+ musicText.getStyleClass().add("t3");
+
+ Slider musicSlider = new Slider();
+ musicSlider.valueProperty().bindBidirectional(Driver.settingsController.musicVol);
+ musicSlider.setMin(0.0);
+ musicSlider.setMax(1.0);
+
+ VBox musicBox = new VBox();
+ musicBox.getChildren().addAll(musicText, musicSlider);
+ musicBox.getStyleClass().add("box");
+ musicBox.setPadding(new Insets(10));
+
+
+ Text SFXText = new Text();
+ SFXText.setText("Sound Effects Volume");
+ SFXText.getStyleClass().add("t3");
+
+ Slider SFXSlider = new Slider();
+ SFXSlider.valueProperty().bindBidirectional(Driver.settingsController.effectsVol);
+ SFXSlider.setMin(0.0);
+ SFXSlider.setMax(1.0);
+
+ VBox SFXBox = new VBox();
+ SFXBox.getChildren().addAll(SFXText, SFXSlider);
+ SFXBox.getStyleClass().add("box");
+ SFXBox.setPadding(new Insets(10));
+
+
+ Text fullText = new Text();
+ fullText.setText("Fullscreen mode");
+ fullText.getStyleClass().add("t3");
+
+ Button fullscreen = new Button();
+ fullscreen.setText("Toggle (F11)");
+ fullscreen.getStyleClass().remove("toggle-button");
+ fullscreen.getStyleClass().add("button");
+ fullscreen.setOnAction(e -> {
+ Driver.soundController.playSfx("forward");
+ Driver.primaryStage.setFullScreen(!Driver.primaryStage.isFullScreen());
+ });
+
+ VBox fullBox = new VBox();
+ fullBox.getChildren().addAll(fullText,fullscreen);
+ fullBox.getStyleClass().add("box");
+ fullBox.setPadding(new Insets(10));
+
+
+ Text devLabel = new Text("Advanced");
+ devLabel.getStyleClass().add("t3");
+
+ Button levelEdit = new Button("Level Utility");
+ levelEdit.setOnAction(e -> {
+ Driver.soundController.playSfx("forward");
+ new LevelList();
+ });
+
+ Button devMenu = new Button();
+ devMenu.setText("Debug Menu");
+ devMenu.setOnAction(e -> {
+ Driver.soundController.playSfx("forward");
+// Driver.debug.show();
+ });
+
+ VBox devBox = new VBox();
+ devBox.getStyleClass().add("box");
+ devBox.getChildren().addAll(devLabel,levelEdit,devMenu);
+ devBox.setVisible(false);
+ devBox.setManaged(false);
+ devBox.setPadding(new Insets(10));
+
+ ToggleButton advanced = new ToggleButton("Advanced");
+ advanced.getStyleClass().remove("toggle-button");
+ advanced.getStyleClass().add("button");
+ advanced.selectedProperty().bindBidirectional(devBox.managedProperty());
+ advanced.selectedProperty().bindBidirectional(devBox.visibleProperty());
+
+ Button exit = new Button();
+ exit.setText("Back");
+ exit.setOnAction(e -> {
+ Driver.settingsController.write();
+ Driver.soundController.playSfx("backward");
+ Driver.setMenu(new MainMenu());
+ });
+
+ BorderPane buttonBox = new BorderPane();
+ buttonBox.setLeft(exit);
+ buttonBox.setRight(advanced);
+
+
+ VBox options = new VBox();
+ options.setSpacing(10);
+ options.setAlignment(Pos.CENTER);
+ options.getChildren().addAll(musicBox,SFXBox,fullBox,devBox,buttonBox);
+ options.maxWidthProperty().bind(super.prefWidthProperty().multiply(0.25));
+ options.setMinWidth(400);
+ options.prefHeightProperty().bind(super.prefHeightProperty());
+
+ HBox rootBox = new HBox();
+ rootBox.prefWidthProperty().bind(super.prefWidthProperty());
+ rootBox.prefHeightProperty().bind(super.prefHeightProperty());
+ rootBox.getChildren().add(options);
+ rootBox.setAlignment(Pos.CENTER);
+ super.getChildren().add(rootBox);
+ }
+}
diff --git a/src/main/Difficulty.java b/src/main/java/net/sowgro/npehero/main/Difficulty.java
index d8587f1..6bd565a 100644..100755
--- a/src/main/Difficulty.java
+++ b/src/main/java/net/sowgro/npehero/main/Difficulty.java
@@ -1,4 +1,4 @@
-package main;
+package net.sowgro.npehero.main;
import java.io.File;
import java.io.FileReader;
diff --git a/src/main/LeaderboardEntry.java b/src/main/java/net/sowgro/npehero/main/LeaderboardEntry.java
index 9a298b6..18e657c 100644..100755
--- a/src/main/LeaderboardEntry.java
+++ b/src/main/java/net/sowgro/npehero/main/LeaderboardEntry.java
@@ -1,4 +1,4 @@
-package main;
+package net.sowgro.npehero.main;
public class LeaderboardEntry
{
diff --git a/src/main/Level.java b/src/main/java/net/sowgro/npehero/main/Level.java
index 313b1fa..ef264ff 100644..100755
--- a/src/main/Level.java
+++ b/src/main/java/net/sowgro/npehero/main/Level.java
@@ -1,4 +1,4 @@
-package main;
+package net.sowgro.npehero.main;
import java.io.File;
import java.util.Collections;
diff --git a/src/main/LevelController.java b/src/main/java/net/sowgro/npehero/main/LevelController.java
index 07ea3f8..68d7450 100644..100755
--- a/src/main/LevelController.java
+++ b/src/main/java/net/sowgro/npehero/main/LevelController.java
@@ -1,4 +1,4 @@
-package main;
+package net.sowgro.npehero.main;
import java.io.File;
import java.io.IOException;
diff --git a/src/main/ScoreController.java b/src/main/java/net/sowgro/npehero/main/ScoreController.java
index 066a0d1..ba43171 100644..100755
--- a/src/main/ScoreController.java
+++ b/src/main/java/net/sowgro/npehero/main/ScoreController.java
@@ -1,6 +1,6 @@
-package main;
+package net.sowgro.npehero.main;
-import gui.Driver;
+import net.sowgro.npehero.Driver;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
diff --git a/src/main/SettingsController.java b/src/main/java/net/sowgro/npehero/main/SettingsController.java
index 3304dd4..d5f3e3b 100644..100755
--- a/src/main/SettingsController.java
+++ b/src/main/java/net/sowgro/npehero/main/SettingsController.java
@@ -1,4 +1,4 @@
-package main;
+package net.sowgro.npehero.main;
import java.io.FileWriter;
import java.io.File;
diff --git a/src/main/SoundController.java b/src/main/java/net/sowgro/npehero/main/SoundController.java
index 0d7527e..da80ab4 100644..100755
--- a/src/main/SoundController.java
+++ b/src/main/java/net/sowgro/npehero/main/SoundController.java
@@ -1,10 +1,12 @@
-package main;
+package net.sowgro.npehero.main;
import java.io.File;
+import java.net.URISyntaxException;
+import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.HashMap;
-import gui.Driver;
+import net.sowgro.npehero.Driver;
import javafx.scene.media.Media;
import javafx.scene.media.MediaPlayer;
import javafx.util.Duration;
@@ -13,19 +15,27 @@ public class SoundController
{
public MediaPlayer songMediaPlayer;
public MediaPlayer sfxMediaPlayer;
- private HashMap<String,MediaPlayer> effects = new HashMap<>();
- private File mainMenuSong = Paths.get("resources/fairyfountain.wav").toFile();
-
+ private final HashMap<String,MediaPlayer> effects = new HashMap<>();
+ private final File mainMenuSong;
+
+ {
+ try {
+ mainMenuSong = new File(Driver.getResource("fairyfountain.wav").toURI());
+ } catch (URISyntaxException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
/**
* creates a new sound controller and starts playing the main menu music
*/
public SoundController()
{
- effects.put("hit", new MediaPlayer(new Media(Paths.get("resources/hit.wav").toUri().toString())));
- effects.put("miss", new MediaPlayer(new Media(Paths.get("resources/miss.wav").toUri().toString())));
- effects.put("forward", new MediaPlayer(new Media(Paths.get("resources/forward.wav").toUri().toString())));
- effects.put("backward", new MediaPlayer(new Media(Paths.get("resources/backward.wav").toUri().toString())));
+ effects.put("hit", new MediaPlayer(new Media(Driver.getResource("hit.wav").toString())));
+ effects.put("miss", new MediaPlayer(new Media(Driver.getResource("miss.wav").toString())));
+ effects.put("forward", new MediaPlayer(new Media(Driver.getResource("forward.wav").toString())));
+ effects.put("backward", new MediaPlayer(new Media(Driver.getResource("backward.wav").toString())));
effects.forEach((key,value) -> {
value.volumeProperty().bind(Driver.settingsController.effectsVol);
});
@@ -53,6 +63,10 @@ public class SoundController
*/
public void playMenuSong()
{
+ if (!mainMenuSong.exists()) {
+ System.out.println("NOT EXIST " + mainMenuSong.getAbsolutePath());
+ return;
+ }
playSong(mainMenuSong);
songMediaPlayer.setCycleCount(MediaPlayer.INDEFINITE);
songMediaPlayer.play();
@@ -71,7 +85,7 @@ public class SoundController
/**
* plays a sound effect
- * for the volume slider to take affect each mediaplayer needs to be pre loaded.
+ * for the volume slider to take effect each mediaplayer needs to be preloaded.
* this rewinds and played the proper mediaplayer for the sound
* @param preset: a string of the name of the sound. possible sounds assigned in the constructor
*/
diff --git a/src/main/resources/net/sowgro/npehero/backward.wav b/src/main/resources/net/sowgro/npehero/backward.wav
new file mode 100755
index 0000000..e88f58d
--- /dev/null
+++ b/src/main/resources/net/sowgro/npehero/backward.wav
Binary files differ
diff --git a/src/main/resources/net/sowgro/npehero/fairyfountain.wav b/src/main/resources/net/sowgro/npehero/fairyfountain.wav
new file mode 100755
index 0000000..b6fea56
--- /dev/null
+++ b/src/main/resources/net/sowgro/npehero/fairyfountain.wav
Binary files differ
diff --git a/src/main/resources/net/sowgro/npehero/forward.wav b/src/main/resources/net/sowgro/npehero/forward.wav
new file mode 100755
index 0000000..c7b1a77
--- /dev/null
+++ b/src/main/resources/net/sowgro/npehero/forward.wav
Binary files differ
diff --git a/src/main/resources/net/sowgro/npehero/hit.wav b/src/main/resources/net/sowgro/npehero/hit.wav
new file mode 100755
index 0000000..b9463a2
--- /dev/null
+++ b/src/main/resources/net/sowgro/npehero/hit.wav
Binary files differ
diff --git a/src/main/resources/net/sowgro/npehero/miss.wav b/src/main/resources/net/sowgro/npehero/miss.wav
new file mode 100755
index 0000000..d91a987
--- /dev/null
+++ b/src/main/resources/net/sowgro/npehero/miss.wav
Binary files differ
diff --git a/src/main/resources/net/sowgro/npehero/mountains.png b/src/main/resources/net/sowgro/npehero/mountains.png
new file mode 100755
index 0000000..39d560e
--- /dev/null
+++ b/src/main/resources/net/sowgro/npehero/mountains.png
Binary files differ
diff --git a/src/main/resources/net/sowgro/npehero/style.css b/src/main/resources/net/sowgro/npehero/style.css
new file mode 100755
index 0000000..dd1de55
--- /dev/null
+++ b/src/main/resources/net/sowgro/npehero/style.css
@@ -0,0 +1,236 @@
+@import url('https://fonts.googleapis.com/css2?family=Space+Mono&display=swap');
+
+/* global */
+
+.root{
+ -fx-font-family: "space mono";
+}
+
+/* button */
+
+.button {
+ -fx-background-color: rgba(0, 0, 0, 0.5);
+ -fx-text-fill: white;
+ -fx-border-color: transparent;
+ -fx-border-width: 3;
+ -fx-border-radius: 5;
+ -fx-font-size: 25;
+ -fx-background-radius: 5;
+}
+
+.button:hover {
+ -fx-background-color: rgb(50, 50, 50, 0.5);
+}
+
+.button:focused {
+ -fx-background-color: rgb(50, 50, 50, 0.5);
+ -fx-border-color: rgb(255, 255, 255);
+}
+
+.button:selected {
+ -fx-background-color: rgb(255, 255, 255);
+ -fx-text-fill: rgb(0, 0, 0);
+
+}
+
+.button:pressed{
+ -fx-background-color: rgb(231, 231, 231);
+ -fx-border-color: transparent;
+ -fx-text-fill: rgb(0, 0, 0);
+}
+
+/* table */
+
+TableView {
+ -fx-background-color: rgba(0, 0, 0, 0.5);
+ -fx-background-radius: 5;
+ -fx-padding: 5;
+}
+
+.table-view .column-header-background .filler {
+ -fx-background-color: transparent;
+}
+
+.table-view .table-cell{
+ -fx-border-color: transparent;
+}
+
+.table-view .column-header-background{
+ -fx-background-color: transparent;
+}
+
+.table-cell {
+ -fx-padding: .5em;
+}
+
+.table-view .column-header {
+ -fx-text-background-color: rgb(168, 168, 168);
+ -fx-background-color: transparent;
+}
+
+.table-row-cell {
+ -fx-cell-size: 40;
+ -fx-background-color: transparent;
+ -fx-background-radius: 3;
+ -fx-text-background-color: rgb(255, 255, 255);
+ /* -fx-border-width: 3; */
+ /* -fx-border-radius: 5; */
+ /* -fx-border-color: transparent; */
+}
+
+.table-row-cell:hover {
+ -fx-background-color: rgba(100, 100, 100, 0.5);
+
+}
+
+TableView:focused {
+ -fx-effect: null;
+}
+
+TableView:focused .list-cell:focused {
+ -fx-background-color: rgb(50, 50, 50, 0.5);
+ /* -fx-border-color: rgb(255, 255, 255); */
+}
+
+.table-view .corner {
+ -fx-background-color: transparent;
+ -fx-border-color: transparent;
+}
+
+.table-row-cell:selected {
+ -fx-background-color: rgb(255, 255, 255);
+ -fx-text-background-color: rgb(0, 0, 0);
+}
+
+.table-row-cell:pressed {
+ -fx-background-color: rgb(231, 231, 231);
+ /* -fx-border-color: transparent; */
+}
+
+.table-row-cell:empty {
+ -fx-background-color: transparent;
+ /* -fx-border-color: transparent; */
+ -fx-text-background-color: white;
+}
+
+.unselectable .table-row-cell{
+ -fx-background-color: transparent;
+ /* -fx-border-color: transparent; */
+ -fx-text-background-color: white;
+}
+
+/* slider */
+
+Slider {
+ -fx-padding: 1em;
+}
+
+.track {
+
+ -fx-padding: 3;
+ -fx-background-color: rgba(0, 0, 0, 0.5);
+ -fx-background-radius: 5;
+}
+
+.thumb {
+ -fx-pref-height: 30;
+ -fx-prefer-width: 30;
+ -fx-background-color: rgba(0, 0, 0, 0.5);
+ -fx-size: 25;
+ -fx-border-radius: 5;
+ -fx-border-color: rgb(231, 231, 231);
+ -fx-border-width: 3;
+}
+
+.thumb:hover {
+ -fx-background-color: rgb(50, 50, 50, 0.5);
+}
+
+Slider:focused .thumb{
+ -fx-background-color: rgb(255,255,255);
+ -fx-border-color: white;
+}
+
+.thumb:pressed {
+ -fx-background-color: rgb(231, 231, 231);
+ -fx-border-color: rgb(231, 231, 231);
+}
+
+/* scroll bars */
+
+.scroll-bar:horizontal ,
+.scroll-bar:vertical{
+ -fx-font-size: 5px;
+ -fx-background-color :transparent;
+ -fx-border-color :transparent;
+ -fx-background-radius : 0.0em;
+ -fx-border-radius :2.0em;
+}
+
+.increment-button ,.decrement-button {
+ -fx-background-color:transparent;
+ -fx-border-color:transparent;
+}
+
+.scroll-bar:horizontal .track ,
+.scroll-bar:vertical .track{
+ -fx-background-color: rgba(0, 0, 0, 0.5);
+ -fx-background-radius: 5em;
+}
+
+.scroll-bar:horizontal .thumb,
+.scroll-bar:vertical .thumb {
+ -fx-background-color:white;
+ -fx-background-radius: 5em;
+ -fx-border-width: 0;
+
+}
+
+.scroll-bar .thumb:pressed {
+ -fx-background-color: rgb(231, 231, 231);
+}
+
+/* text */
+
+.t0 {
+ -fx-font-size: 125;
+ -fx-fill: black;
+}
+
+.t1 {
+ -fx-font-size: 50;
+ -fx-fill: white;
+}
+
+.t11 {
+ -fx-font-size: 50;
+ -fx-fill: black;
+}
+
+.t2 {
+ -fx-font-size: 30;
+ -fx-fill: white;
+}
+
+.t3 {
+ -fx-fill: white;
+}
+
+/* text box */
+
+.box {
+ -fx-background-radius: 5;
+ -fx-background-color: rgba(0, 0, 0, 0.5);
+ -fx-text-fill: white;
+}
+
+/* debug */
+
+.debug {
+ /* -fx-background-radius: 5; */
+ -fx-background-color: rgb(255, 0, 0);
+ /* -fx-border-color: red; */
+ /* -fx-text-fill: white; */
+ /* -fx-border-width: 20; */
+}
+