From ee2229339429d50afa33e2f8b9c0ee0939766290 Mon Sep 17 00:00:00 2001 From: sowgro Date: Mon, 8 Jul 2024 02:41:31 -0400 Subject: Change project structure, embed resources into jar and remove libraries from source control --- src/devmenu/DebugMenu.java | 41 --- src/devmenu/DiffEditor.java | 79 ----- src/devmenu/LevelEditor.java | 148 --------- src/devmenu/LevelList.java | 71 ---- src/devmenu/NotesEditor.java | 101 ------ src/gameplay/Block.java | 27 -- src/gameplay/NoteInfo.java | 28 -- src/gameplay/SongPlayer.java | 361 --------------------- src/gameplay/Target.java | 50 --- src/gameplay/Timer.java | 28 -- src/gui/Driver.java | 123 ------- src/gui/GameOver.java | 123 ------- src/gui/Leaderboard.java | 71 ---- src/gui/LevelDetails.java | 136 -------- src/gui/LevelSelector.java | 96 ------ src/gui/LevelSurround.java | 149 --------- src/gui/MainMenu.java | 68 ---- src/gui/Settings.java | 129 -------- src/gui/style.css | 236 -------------- src/main/Difficulty.java | 272 ---------------- src/main/LeaderboardEntry.java | 28 -- src/main/Level.java | 285 ---------------- src/main/LevelController.java | 95 ------ src/main/ScoreController.java | 117 ------- src/main/SettingsController.java | 62 ---- src/main/SoundController.java | 83 ----- src/main/java/module-info.java | 12 + src/main/java/net/sowgro/npehero/Driver.java | 130 ++++++++ .../java/net/sowgro/npehero/devmenu/DebugMenu.java | 41 +++ .../net/sowgro/npehero/devmenu/DiffEditor.java | 79 +++++ .../net/sowgro/npehero/devmenu/LevelEditor.java | 150 +++++++++ .../java/net/sowgro/npehero/devmenu/LevelList.java | 72 ++++ .../net/sowgro/npehero/devmenu/NotesEditor.java | 101 ++++++ .../java/net/sowgro/npehero/gameplay/Block.java | 27 ++ .../java/net/sowgro/npehero/gameplay/NoteInfo.java | 28 ++ .../net/sowgro/npehero/gameplay/SongPlayer.java | 360 ++++++++++++++++++++ .../java/net/sowgro/npehero/gameplay/Target.java | 50 +++ .../java/net/sowgro/npehero/gameplay/Timer.java | 28 ++ src/main/java/net/sowgro/npehero/gui/GameOver.java | 124 +++++++ .../java/net/sowgro/npehero/gui/Leaderboard.java | 72 ++++ .../java/net/sowgro/npehero/gui/LevelDetails.java | 137 ++++++++ .../java/net/sowgro/npehero/gui/LevelSelector.java | 98 ++++++ .../java/net/sowgro/npehero/gui/LevelSurround.java | 150 +++++++++ src/main/java/net/sowgro/npehero/gui/MainMenu.java | 70 ++++ src/main/java/net/sowgro/npehero/gui/Settings.java | 131 ++++++++ .../java/net/sowgro/npehero/main/Difficulty.java | 272 ++++++++++++++++ .../net/sowgro/npehero/main/LeaderboardEntry.java | 28 ++ src/main/java/net/sowgro/npehero/main/Level.java | 285 ++++++++++++++++ .../net/sowgro/npehero/main/LevelController.java | 95 ++++++ .../net/sowgro/npehero/main/ScoreController.java | 117 +++++++ .../sowgro/npehero/main/SettingsController.java | 62 ++++ .../net/sowgro/npehero/main/SoundController.java | 97 ++++++ src/main/resources/net/sowgro/npehero/backward.wav | Bin 0 -> 34684 bytes .../resources/net/sowgro/npehero/fairyfountain.wav | Bin 0 -> 31539988 bytes src/main/resources/net/sowgro/npehero/forward.wav | Bin 0 -> 54992 bytes src/main/resources/net/sowgro/npehero/hit.wav | Bin 0 -> 34820 bytes src/main/resources/net/sowgro/npehero/miss.wav | Bin 0 -> 44144 bytes .../resources/net/sowgro/npehero/mountains.png | Bin 0 -> 1115601 bytes src/main/resources/net/sowgro/npehero/style.css | 236 ++++++++++++++ 59 files changed, 3052 insertions(+), 3007 deletions(-) delete mode 100644 src/devmenu/DebugMenu.java delete mode 100644 src/devmenu/DiffEditor.java delete mode 100644 src/devmenu/LevelEditor.java delete mode 100644 src/devmenu/LevelList.java delete mode 100644 src/devmenu/NotesEditor.java delete mode 100644 src/gameplay/Block.java delete mode 100644 src/gameplay/NoteInfo.java delete mode 100644 src/gameplay/SongPlayer.java delete mode 100644 src/gameplay/Target.java delete mode 100644 src/gameplay/Timer.java delete mode 100644 src/gui/Driver.java delete mode 100644 src/gui/GameOver.java delete mode 100644 src/gui/Leaderboard.java delete mode 100644 src/gui/LevelDetails.java delete mode 100644 src/gui/LevelSelector.java delete mode 100644 src/gui/LevelSurround.java delete mode 100644 src/gui/MainMenu.java delete mode 100644 src/gui/Settings.java delete mode 100644 src/gui/style.css delete mode 100644 src/main/Difficulty.java delete mode 100644 src/main/LeaderboardEntry.java delete mode 100644 src/main/Level.java delete mode 100644 src/main/LevelController.java delete mode 100644 src/main/ScoreController.java delete mode 100644 src/main/SettingsController.java delete mode 100644 src/main/SoundController.java create mode 100644 src/main/java/module-info.java create mode 100755 src/main/java/net/sowgro/npehero/Driver.java create mode 100755 src/main/java/net/sowgro/npehero/devmenu/DebugMenu.java create mode 100755 src/main/java/net/sowgro/npehero/devmenu/DiffEditor.java create mode 100755 src/main/java/net/sowgro/npehero/devmenu/LevelEditor.java create mode 100755 src/main/java/net/sowgro/npehero/devmenu/LevelList.java create mode 100755 src/main/java/net/sowgro/npehero/devmenu/NotesEditor.java create mode 100755 src/main/java/net/sowgro/npehero/gameplay/Block.java create mode 100755 src/main/java/net/sowgro/npehero/gameplay/NoteInfo.java create mode 100755 src/main/java/net/sowgro/npehero/gameplay/SongPlayer.java create mode 100755 src/main/java/net/sowgro/npehero/gameplay/Target.java create mode 100755 src/main/java/net/sowgro/npehero/gameplay/Timer.java create mode 100755 src/main/java/net/sowgro/npehero/gui/GameOver.java create mode 100755 src/main/java/net/sowgro/npehero/gui/Leaderboard.java create mode 100755 src/main/java/net/sowgro/npehero/gui/LevelDetails.java create mode 100755 src/main/java/net/sowgro/npehero/gui/LevelSelector.java create mode 100755 src/main/java/net/sowgro/npehero/gui/LevelSurround.java create mode 100755 src/main/java/net/sowgro/npehero/gui/MainMenu.java create mode 100755 src/main/java/net/sowgro/npehero/gui/Settings.java create mode 100755 src/main/java/net/sowgro/npehero/main/Difficulty.java create mode 100755 src/main/java/net/sowgro/npehero/main/LeaderboardEntry.java create mode 100755 src/main/java/net/sowgro/npehero/main/Level.java create mode 100755 src/main/java/net/sowgro/npehero/main/LevelController.java create mode 100755 src/main/java/net/sowgro/npehero/main/ScoreController.java create mode 100755 src/main/java/net/sowgro/npehero/main/SettingsController.java create mode 100755 src/main/java/net/sowgro/npehero/main/SoundController.java create mode 100755 src/main/resources/net/sowgro/npehero/backward.wav create mode 100755 src/main/resources/net/sowgro/npehero/fairyfountain.wav create mode 100755 src/main/resources/net/sowgro/npehero/forward.wav create mode 100755 src/main/resources/net/sowgro/npehero/hit.wav create mode 100755 src/main/resources/net/sowgro/npehero/miss.wav create mode 100755 src/main/resources/net/sowgro/npehero/mountains.png create mode 100755 src/main/resources/net/sowgro/npehero/style.css (limited to 'src') diff --git a/src/devmenu/DebugMenu.java b/src/devmenu/DebugMenu.java deleted file mode 100644 index 0d55e69..0000000 --- a/src/devmenu/DebugMenu.java +++ /dev/null @@ -1,41 +0,0 @@ -package devmenu; - -import gui.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/devmenu/DiffEditor.java b/src/devmenu/DiffEditor.java deleted file mode 100644 index 0991fb0..0000000 --- a/src/devmenu/DiffEditor.java +++ /dev/null @@ -1,79 +0,0 @@ -package devmenu; - -import java.io.FileNotFoundException; -import java.io.UnsupportedEncodingException; - -import gui.Driver; -import gui.LevelSurround; -import 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 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/devmenu/LevelEditor.java b/src/devmenu/LevelEditor.java deleted file mode 100644 index b8a6532..0000000 --- a/src/devmenu/LevelEditor.java +++ /dev/null @@ -1,148 +0,0 @@ -package devmenu; - -import java.io.File; -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.control.cell.PropertyValueFactory; -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 main.Difficulty; -import 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 diffList = new TableView(); - - TableColumn diffCol = new TableColumn("Difficulty"); - TableColumn validCol = new TableColumn("Valid?"); - - diffList.getColumns().add(diffCol); - diffList.getColumns().add(validCol); - - diffCol.setCellValueFactory(new PropertyValueFactory("title")); - validCol.setCellValueFactory(new PropertyValueFactory("valid")); - - 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/devmenu/LevelList.java b/src/devmenu/LevelList.java deleted file mode 100644 index f9b4207..0000000 --- a/src/devmenu/LevelList.java +++ /dev/null @@ -1,71 +0,0 @@ -package devmenu; - -import gui.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.control.cell.PropertyValueFactory; -import javafx.scene.layout.HBox; -import javafx.scene.layout.VBox; -import javafx.stage.Stage; -import main.Level; -import 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 levels = new TableView(); - - TableColumn titleCol = new TableColumn("Title"); - TableColumn artistCol = new TableColumn("Artist"); - TableColumn validCol = new TableColumn<>("Valid?"); - - levels.getColumns().add(titleCol); - levels.getColumns().add(artistCol); - levels.getColumns().add(validCol); - - titleCol.setCellValueFactory(new PropertyValueFactory("title")); - artistCol.setCellValueFactory(new PropertyValueFactory("artist")); - validCol.setCellValueFactory(new PropertyValueFactory("valid")); - - 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 -> gui.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/devmenu/NotesEditor.java b/src/devmenu/NotesEditor.java deleted file mode 100644 index 0893446..0000000 --- a/src/devmenu/NotesEditor.java +++ /dev/null @@ -1,101 +0,0 @@ -package devmenu; - -import java.io.FileNotFoundException; -import java.io.PrintWriter; -import java.io.UnsupportedEncodingException; -import gameplay.Timer; -import gui.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 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/gameplay/Block.java b/src/gameplay/Block.java deleted file mode 100644 index 68e52b6..0000000 --- a/src/gameplay/Block.java +++ /dev/null @@ -1,27 +0,0 @@ -//glowing block of color c (jfx node) - -package 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/gameplay/NoteInfo.java b/src/gameplay/NoteInfo.java deleted file mode 100644 index 6428066..0000000 --- a/src/gameplay/NoteInfo.java +++ /dev/null @@ -1,28 +0,0 @@ -/*Name: Guitar Hero Project - *Description: Contains the info for when to send a note - */ -package 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/gameplay/SongPlayer.java b/src/gameplay/SongPlayer.java deleted file mode 100644 index 8df2c1f..0000000 --- a/src/gameplay/SongPlayer.java +++ /dev/null @@ -1,361 +0,0 @@ -package 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 gui.Driver; -import 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 main.Difficulty; -import 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 main.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 - - main.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 dSends = new LinkedList(); //Queue that dictates when to send the notes - ArrayList dLane = new ArrayList(); //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 fSends = new LinkedList(); - ArrayList fLane = new ArrayList(); - - Target sButton = new Target(Color.GREEN, 50, 50, 5, '_'); - Queue spaceSends = new LinkedList(); - ArrayList spaceLane = new ArrayList(); - - Target jButton = new Target(Color.PURPLE, 50, 50, 5, 'j'); - Queue jSends = new LinkedList(); - ArrayList jLane = new ArrayList(); - - Target kButton = new Target(Color.YELLOW, 50, 50, 5, 'k'); - Queue kSends = new LinkedList(); - ArrayList kLane = new ArrayList(); - - /** - * 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(main.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); - - gui.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 - * @param pos the x pos of the note to be sent - * @param c the color of the sent note - */ - public void sendNote(Queue sends, ArrayList 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) { - gui.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(); - gui.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 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 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/gameplay/Target.java b/src/gameplay/Target.java deleted file mode 100644 index 6bfac18..0000000 --- a/src/gameplay/Target.java +++ /dev/null @@ -1,50 +0,0 @@ -//glowing block of color c (jfx node) - -package 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/gameplay/Timer.java b/src/gameplay/Timer.java deleted file mode 100644 index 96a6c30..0000000 --- a/src/gameplay/Timer.java +++ /dev/null @@ -1,28 +0,0 @@ -/*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 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/gui/Driver.java b/src/gui/Driver.java deleted file mode 100644 index b46f4c9..0000000 --- a/src/gui/Driver.java +++ /dev/null @@ -1,123 +0,0 @@ -package gui; - -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 main.LevelController; -import main.SettingsController; -import main.SoundController; -import java.nio.file.Paths; - -import devmenu.DebugMenu; - - -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("gui/style.css"); - - 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 url 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(Paths.get("resources/mountains.png").toUri().toString())); - } - - /** - * quits the application - */ - public static void quit() - { - Platform.exit(); - } -} diff --git a/src/gui/GameOver.java b/src/gui/GameOver.java deleted file mode 100644 index 8571d20..0000000 --- a/src/gui/GameOver.java +++ /dev/null @@ -1,123 +0,0 @@ -package 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 main.Difficulty; -import 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() { //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/gui/Leaderboard.java b/src/gui/Leaderboard.java deleted file mode 100644 index 39df409..0000000 --- a/src/gui/Leaderboard.java +++ /dev/null @@ -1,71 +0,0 @@ -package gui; - -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.control.cell.PropertyValueFactory; -import javafx.scene.layout.HBox; -import javafx.scene.layout.Pane; -import javafx.scene.layout.VBox; -import main.Difficulty; -import main.LeaderboardEntry; -import 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 scores = new TableView(); - - TableColumn nameCol = new TableColumn("Name"); - TableColumn scoreCol = new TableColumn("Score"); - TableColumn dateCol = new TableColumn("Date"); - - scores.getColumns().add(nameCol); - scores.getColumns().add(scoreCol); - scores.getColumns().add(dateCol); - - nameCol.setCellValueFactory(new PropertyValueFactory("name")); - scoreCol.setCellValueFactory(new PropertyValueFactory("score")); - dateCol.setCellValueFactory(new PropertyValueFactory("date")); - - 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/gui/LevelDetails.java b/src/gui/LevelDetails.java deleted file mode 100644 index af55b9c..0000000 --- a/src/gui/LevelDetails.java +++ /dev/null @@ -1,136 +0,0 @@ -package 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 main.Difficulty; -import 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/gui/LevelSelector.java b/src/gui/LevelSelector.java deleted file mode 100644 index 6fd6aca..0000000 --- a/src/gui/LevelSelector.java +++ /dev/null @@ -1,96 +0,0 @@ -package gui; - -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.control.cell.PropertyValueFactory; -import javafx.scene.layout.HBox; -import javafx.scene.layout.Pane; -import javafx.scene.layout.VBox; -import main.Level; -import 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 levels = new TableView(); - - TableColumn titleCol = new TableColumn("Title"); - TableColumn artistCol = new TableColumn("Artist"); - - levels.getColumns().add(titleCol); - levels.getColumns().add(artistCol); - - titleCol.setCellValueFactory(new PropertyValueFactory("title")); - artistCol.setCellValueFactory(new PropertyValueFactory("artist")); - - 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() { //listens for change in selected item of the list - - @Override - public void changed(ObservableValue 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 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/gui/LevelSurround.java b/src/gui/LevelSurround.java deleted file mode 100644 index dcf8a10..0000000 --- a/src/gui/LevelSurround.java +++ /dev/null @@ -1,149 +0,0 @@ -package gui; - -import 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 main.Difficulty; -import main.Level; -import 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/gui/MainMenu.java b/src/gui/MainMenu.java deleted file mode 100644 index 84a7508..0000000 --- a/src/gui/MainMenu.java +++ /dev/null @@ -1,68 +0,0 @@ -package 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; - - -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/gui/Settings.java b/src/gui/Settings.java deleted file mode 100644 index 663353a..0000000 --- a/src/gui/Settings.java +++ /dev/null @@ -1,129 +0,0 @@ -package 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; - -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 devmenu.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/gui/style.css b/src/gui/style.css deleted file mode 100644 index dd1de55..0000000 --- a/src/gui/style.css +++ /dev/null @@ -1,236 +0,0 @@ -@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; */ -} - diff --git a/src/main/Difficulty.java b/src/main/Difficulty.java deleted file mode 100644 index d8587f1..0000000 --- a/src/main/Difficulty.java +++ /dev/null @@ -1,272 +0,0 @@ -package main; - -import java.io.File; -import java.io.FileReader; -import java.io.FileWriter; -import java.io.IOException; -import java.time.LocalDate; -import org.json.simple.JSONArray; -import org.json.simple.JSONObject; -import org.json.simple.parser.JSONParser; -import javafx.collections.FXCollections; -import javafx.collections.ObservableList; - -public class Difficulty implements Comparable -{ - public File thisDir; - public String title = "Unnamed"; - private ObservableList leaderboard = FXCollections.observableArrayList(); - public File notes; - public Double bpm = 0.0; - public int numBeats; - public Level level; - public boolean isValid = false; - public int priority = 0; - - /** - * Creates a new Difficulty and gives it a file path - * @param newDir: The file path of the Difficulty - */ - public Difficulty(File newDir, Level level) - { - thisDir = newDir; - this.level = level; - } - - public void readData() - { - boolean isValid1 = true; - if (new File(thisDir, "metadata.json").exists()) - { - if (!parseMetadata()) - { - isValid1 = false; - } - } - else - { - System.err.println(thisDir+" is missing metadata.json"); - isValid1 = false; - } - - if (new File(thisDir, "leaderboard.json").exists()) - { - if (!parseLeaderboard()) - { - isValid1 = false; - } - } - else - { - System.err.println(thisDir+" is missing leaderboard.json"); - isValid1 = false; - } - - if (new File(thisDir, "notes.txt").exists()) - { - notes = new File(thisDir, "notes.txt"); - } - else - { - System.err.println(thisDir+" is missing notes.txt"); - isValid1 = false; - } - - if (bpm == 0.0) - { - System.err.println(thisDir+" is missing a bpm"); - isValid1 = false; - } - - if (numBeats == 0) - { - System.err.println(thisDir+" is missing the number of beats"); - isValid1 = false; - } - - isValid = isValid1; - } - - /** - * Reads in json metadata and assigns values to variables - */ - public boolean parseMetadata() - { - boolean isValid = true; - File file = new File(thisDir, "metadata.json"); - JSONParser jsonParser = new JSONParser(); //parser to read the file - - try(FileReader reader = new FileReader(file)) - { - Object obj = jsonParser.parse(reader); - JSONObject diffStuff = (JSONObject)(obj); //converts read object to a JSONObject - - if (diffStuff.containsKey("title")) - { - title = (String) diffStuff.get("title"); - } - else - { - System.err.println(file+" is missing properety title"); - isValid = false; - } - - if (diffStuff.containsKey("bpm")) - { - bpm = Double.parseDouble(diffStuff.get("bpm")+""); - } - else - { - System.err.println(file+" is missing properety bpm"); - isValid = false; - } - - if (diffStuff.containsKey("numBeats")) - { - numBeats = Integer.parseInt(diffStuff.get("numBeats")+""); - } - else - { - System.err.println(file+" is missing properety numBeats"); - isValid = false; - } - - if (diffStuff.containsKey("priority")) - { - priority = Integer.parseInt(diffStuff.get("priority")+""); - - } - else - { - System.err.println(file+" is missing properety priority"); - isValid = false; - } - } - catch (Exception e) - { - e.printStackTrace(); - isValid = false; - } - return isValid; - } - - /** - * Writes metadata to json file - */ - public void writeMetadata() - { - FileWriter fileWriter; - try - { - File file = new File(thisDir, "metadata.json"); - fileWriter = new FileWriter(file); - JSONObject obj = new JSONObject(); - obj.put("title", title); - obj.put("bpm", bpm); - obj.put("numBeats", numBeats); - obj.put("priority", priority); - obj.writeJSONString(fileWriter); - fileWriter.flush(); - } - catch (IOException e) - { - e.printStackTrace(); - } - } - - /** - * Reads in json leaderboard and assigns populates list with leaderboardEntries - */ - public boolean parseLeaderboard() - { - boolean isValid = true; - File file = new File(thisDir, "leaderboard.json"); - JSONParser jsonParser = new JSONParser(); //parser to read the file - - try(FileReader reader = new FileReader(file)) - { - Object obj = jsonParser.parse(reader); - - JSONArray leaderboardStuff = (JSONArray)(obj); //converts read object to a JSONArray - - for (Object cur: leaderboardStuff) - { - JSONObject cur2 = (JSONObject) cur; - - String name = (String) cur2.get("name"); - int score = Integer.parseInt(""+cur2.get("score")); - String date = (String) cur2.get("date"); - leaderboard.add(new LeaderboardEntry(name, score, date)); - } - } - catch (Exception e) - { - isValid = false; - e.printStackTrace(); - } - return isValid; - } - - /** - * Writes leaderboard to json file - */ - public void writeLeaderboard() - { - FileWriter fileWriter; - try - { - File file = new File(thisDir, "leaderboard.json"); - fileWriter = new FileWriter(file); - //write the settings JSONObject instance to the file - JSONArray jsonArray = new JSONArray(); - for (LeaderboardEntry cur: leaderboard) - { - JSONObject obj = new JSONObject(); - obj.put("name", cur.getName()); - obj.put("score", cur.getScore()); - obj.put("date",cur.getDate()); - jsonArray.add(obj); - } - jsonArray.writeJSONString(fileWriter); - fileWriter.flush(); - - } - catch (IOException e) { - e.printStackTrace(); - } - } - - /** - * Adds new leaderboardEntry to list and updates json file - * @param name: the players name - * @param score the players score - */ - public void addToLeaderboard(String name, int score) - { - leaderboard.add(new LeaderboardEntry(name, score, ""+LocalDate.now())); //do not delete this tho its not a placeholder - writeLeaderboard(); - } - - public ObservableList getLeaderboard() - { - return leaderboard; - } - - public String toString() - { - return title; - } - - public boolean isValid() { - return isValid; - } - - public String getTitle() { - return title; - } - - @Override - public int compareTo(Difficulty d) { - return priority - d.priority; - } -} diff --git a/src/main/LeaderboardEntry.java b/src/main/LeaderboardEntry.java deleted file mode 100644 index 9a298b6..0000000 --- a/src/main/LeaderboardEntry.java +++ /dev/null @@ -1,28 +0,0 @@ -package main; - -public class LeaderboardEntry -{ - private int score; - private String name; - private String date; - - public LeaderboardEntry(String name, int score, String date) - { - this.name = name; - this.score = score; - this.date = date; - } - - public int getScore() { - return score; - } - - public String getName() { - return name; - } - - public String getDate() - { - return date; - } -} diff --git a/src/main/Level.java b/src/main/Level.java deleted file mode 100644 index 313b1fa..0000000 --- a/src/main/Level.java +++ /dev/null @@ -1,285 +0,0 @@ -package main; - -import java.io.File; -import java.util.Collections; -import java.util.Comparator; - -import javafx.collections.FXCollections; -import javafx.collections.ObservableList; -import javafx.scene.image.Image; -import javafx.scene.paint.Color; -import java.io.FileWriter; -import java.io.FileReader; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.StandardCopyOption; -import org.json.simple.JSONObject; -import org.json.simple.parser.JSONParser; - -public class Level -{ - public File thisDir; - private String title = "Unnamed"; - private String artist = "Unknown"; - private ObservableList diffList; - private ObservableList validDiffList; - private boolean isValid; - - public Image preview; //optional - public String desc; - public Image background; //optional - public Color[] colors = {Color.RED,Color.BLUE,Color.GREEN,Color.PURPLE,Color.YELLOW};//optional, have default colors - public File song; - - /** - * Creates a new level and gives it a file path - * @param newDir: The path of the Level - */ - public Level(File newDir) - { - thisDir = newDir; - } - - public void readData() - { - boolean isValid1 = true; - if (new File(thisDir, "metadata.json").exists()) - { - if (!parseMetadata()) - { - System.err.println(new File(thisDir, "metadata.json")+" contains error(s)"); - isValid1 = false; - } - } - else - { - System.err.println(thisDir+" is missing metadata.json"); - isValid1 = false; - } - - if (new File(thisDir, "song.wav").exists()) - { - song = new File(thisDir,"song.wav"); - } - else - { - System.err.println(thisDir+" is missing song.wav"); - isValid1 = false; - } - - if (new File(thisDir, "background.png").exists()) - { - background = new Image(new File(thisDir,"background.png").toURI().toString()); - } - - if (new File(thisDir, "preview.png").exists()) - { - preview = new Image(new File(thisDir,"preview.png").toURI().toString()); - } - - diffList = FXCollections.observableArrayList(); - validDiffList = FXCollections.observableArrayList(); - for(File cur: thisDir.listFiles()) //iterates through all files/folders in /levels/LEVEL - { - if (cur.isDirectory()) //all subfolders within a level folder are difficulties - { - Difficulty diff = new Difficulty(cur,this); - diff.readData(); - if (diff.isValid) - { - diffList.add(diff); - validDiffList.add(diff); - } - else - { - diffList.add(diff); - } - } - } - if (validDiffList.size() == 0) - { - System.err.println(thisDir+" contains no valid difficulties"); - isValid1 = false; - } - - Collections.sort(validDiffList); - Collections.sort(diffList); - isValid = isValid1; - } - - /** - * Reads in json metadata and assigns values to variables - */ - public boolean parseMetadata() - { - boolean isValid = true; - JSONParser jsonParser = new JSONParser(); //parser to read the file - File file = new File(thisDir, "metadata.json"); - try(FileReader reader = new FileReader(file)) - { - Object obj = jsonParser.parse(reader); - JSONObject levelStuff = new JSONObject(); - levelStuff = (JSONObject)(obj); //converts read object to a JSONObject - - if (levelStuff.containsKey("title")) - { - title = (String) levelStuff.get("title"); - } - else - { - System.err.println(file+" is missing properety title"); - isValid = false; - } - - if (levelStuff.containsKey("artist")) - { - artist = (String)(levelStuff.get("artist")); - } - else - { - System.err.println(file+" is missing properety aritst"); - isValid = false; - } - - if (levelStuff.containsKey("desc")) - { - desc = (String) levelStuff.get("desc"); - } - - if(( levelStuff).containsKey("color1")) //check for custom colors in a hexadecimal format (zach was lazy for not checking all five colors but i will forgive him) - { - colors = new Color[5]; - - colors[0] = Color.web((String)(levelStuff.get("color1"))); //read in all the custom colors - colors[1] = Color.web((String)(levelStuff.get("color2"))); - colors[2] = Color.web((String)(levelStuff.get("color3"))); - colors[3] = Color.web((String)(levelStuff.get("color4"))); - colors[4] = Color.web((String)(levelStuff.get("color5"))); - } - } - catch (Exception e) - { - e.printStackTrace(); - isValid = false; - } - return isValid; - } - - /** - * Writes metadata to json file - */ - public void writeMetadata() - { - FileWriter fileWriter; - try - { - fileWriter = new FileWriter(new File(thisDir, "metadata.json")); - JSONObject obj = new JSONObject(); - obj.put("title", title); - obj.put("artist", artist); - if (desc != null) - { - obj.put("desc", desc); - } - obj.put("color1",colors[0].toString()); - obj.put("color2",colors[1].toString()); - obj.put("color3",colors[2].toString()); - obj.put("color4",colors[3].toString()); - obj.put("color5",colors[4].toString()); - obj.writeJSONString(fileWriter); - fileWriter.flush(); - } - catch (IOException e) { - e.printStackTrace(); - } - } - - /** - * Adds a difficulty by creating a directory and required files - * @param text: the name of the directory and default title - */ - public void addDiff(String text) - { - File diffDir = new File(thisDir, text); - diffDir.mkdirs(); - File metadataDir = new File(diffDir, "metadata.json"); - File leaderboardDir = new File(diffDir, "leaderboard.json"); - File notesDir = new File(diffDir, "notes.txt"); - try { - metadataDir.createNewFile(); - leaderboardDir.createNewFile(); - notesDir.createNewFile(); - } catch (IOException e) { - e.printStackTrace(); - } - Difficulty temp = new Difficulty(diffDir,this); - temp.title = text; - temp.writeMetadata(); - temp.writeLeaderboard(); - readData(); - } - - /** - * Removes the difficaulty from the filesystem then reloads the level - * @param diff: the difficulty to be removed - */ - public void removeDiff(Difficulty diff) - { - File hold = diff.thisDir; - try { - Files.walk(hold.toPath()) - .sorted(Comparator.reverseOrder()) - .map(Path::toFile) - .forEach(File::delete); - } catch (IOException e) { - e.printStackTrace(); - } - readData(); - } - - /** - * Copies a file into the level directory - * @param newFile: the file to be copied - * @param name: the new file name - */ - public void addFile(File newFile, String name) - { - try { - Files.copy(newFile.toPath(), new File(thisDir, name).toPath(), StandardCopyOption.REPLACE_EXISTING); - } catch (IOException e) { - e.printStackTrace(); - } - readData(); - } - - public ObservableList getDiffList() { - return diffList; - } - - public ObservableList getValidDiffList() { - return validDiffList; - } - - public String getTitle() - { - return title; - } - - public void setTitle(String title) { - this.title = title; - } - - public String getArtist() - { - return artist; - } - - public void setArtist(String artist) { - this.artist = artist; - } - - public boolean isValid() { - return isValid; - } -} diff --git a/src/main/LevelController.java b/src/main/LevelController.java deleted file mode 100644 index 07ea3f8..0000000 --- a/src/main/LevelController.java +++ /dev/null @@ -1,95 +0,0 @@ -package main; - -import java.io.File; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.Comparator; - -import javafx.collections.FXCollections; -import javafx.collections.ObservableList; - -public class LevelController -{ - File thisDir = new File("levels"); - private static ObservableList levelList; - private static ObservableList validLevelList; - - /** - * Creates a levelController, which holds all the levels - */ - public LevelController() - { - readData(); - } - - /** - * Reads contents of folder and creates cooresponding levels - */ - public void readData() - { - levelList = FXCollections.observableArrayList(); - validLevelList = FXCollections.observableArrayList(); - for (File cur: thisDir.listFiles()) //iterates through all files/folders in levels - { - Level level = new Level(cur); - level.readData(); - levelList.add(level); - if (level.isValid()) - { - validLevelList.add(level); - } - } - } - - /** - * Adds a level to the list by creating a directory and required files - * @param text: the name of the directory and default title - */ - public void addLevel(String text) - { - File levelDir = new File(thisDir,text); - levelDir.mkdirs(); - File metadataDir = new File(levelDir, "metadata.json"); - try - { - metadataDir.createNewFile(); - } - catch (IOException e) - { - e.printStackTrace(); - } - Level temp = new Level(levelDir); - temp.setTitle(text); - temp.writeMetadata(); - readData(); - } - - /** - * Removes level from the filesystem then reloads this levelController - * @param level: the level to be removed - */ - public void removeLevel(Level level) - { - File hold = level.thisDir; - levelList.remove(level); - - try { - Files.walk(hold.toPath()) - .sorted(Comparator.reverseOrder()) - .map(Path::toFile) - .forEach(File::delete); - } catch (IOException e) { - e.printStackTrace(); - } - readData(); - } - - public static ObservableList getLevelList() { - return levelList; - } - - public static ObservableList getValidLevelList() { - return validLevelList; - } -} \ No newline at end of file diff --git a/src/main/ScoreController.java b/src/main/ScoreController.java deleted file mode 100644 index 066a0d1..0000000 --- a/src/main/ScoreController.java +++ /dev/null @@ -1,117 +0,0 @@ -package main; - -import gui.Driver; -import javafx.beans.property.SimpleStringProperty; -import javafx.beans.property.StringProperty; - -public class ScoreController{ - - private int score = 0; - private int combo = 0; - private int comboMultiplier=1; - public StringProperty scoreProperty = new SimpleStringProperty("0"); - public StringProperty comboProperty = new SimpleStringProperty("0"); - - /** - * Called when the user performs a perfect hit - */ - public void perfect() { - combo(); - score += 300*comboMultiplier; - scoreProperty.setValue(score+""); - comboProperty.setValue(combo +""); - // System.out.println("Perfect!"); - } - - /** - * called when the user performs an okay hit - */ - public void good() { - combo(); - score += 100*comboMultiplier; - scoreProperty.setValue(score+""); - comboProperty.setValue(combo+""); - // System.out.println("Good"); - } - - /** - * Called when the user misses a note - */ - public void miss(boolean muted) { - if (!muted) { - Driver.soundController.playSfx("miss"); - } - combo = 0; - comboMultiplier = 1; - scoreProperty.setValue(score+""); - comboProperty.setValue(combo+""); - // System.out.println("Miss"); - } - - /* - * Increments the combo by one - */ - private void combo() { - Driver.soundController.playSfx("hit"); - combo++; - - if (combo == 2) { - comboMultiplier = 2; - } - - if (combo == 4) { - comboMultiplier = 4; - } - - if (combo == 8) { - comboMultiplier = 8; - } - } - - /** - * @return current score - */ - public int getScore() - { - return score; - } - - /** - * @return current combo - */ - public int getCombo() - { - return combo; - } - - /** - * @param newScore: the score to be set, only used in debug - */ - public void setScore(int newScore) - { - score = newScore; - scoreProperty.setValue(newScore+""); - } - - /** - * @param newCombo: the combo to be set, only used in debug - */ - public void setCombo(int newCombo) - { - combo = newCombo; - comboProperty.setValue(newCombo+""); - } - - /** - * prints values into console - */ - public void print() - { - System.out.println("--"); - System.out.println(combo); - System.out.println(score); - System.out.println(""); - System.out.println(scoreProperty); - System.out.println(comboProperty); - } -} diff --git a/src/main/SettingsController.java b/src/main/SettingsController.java deleted file mode 100644 index 3304dd4..0000000 --- a/src/main/SettingsController.java +++ /dev/null @@ -1,62 +0,0 @@ -package main; - -import java.io.FileWriter; -import java.io.File; -import java.io.FileReader; -import java.io.IOException; -import org.json.simple.JSONObject; -import org.json.simple.parser.JSONParser; -import javafx.beans.property.SimpleDoubleProperty; - -public class SettingsController -{ - public SimpleDoubleProperty effectsVol = new SimpleDoubleProperty(1); - public SimpleDoubleProperty musicVol = new SimpleDoubleProperty(1); - private File file = new File("settings.json"); - - public SettingsController() - { - read(); - } - - /** - * reads json data from settings.json - */ - public void read() - { - JSONParser jsonParser = new JSONParser(); //parser to read the file - try(FileReader reader = new FileReader(file)) - { - Object obj = jsonParser.parse(reader); - JSONObject settings = new JSONObject(); - settings = (JSONObject)(obj); //converts read object to a JSONObject - - effectsVol.set(Double.parseDouble(settings.get("effectsVol")+"")); - musicVol.set(Double.parseDouble(settings.get("musicVol")+"")); - } - catch (Exception e) - { - e.printStackTrace(); - } - } - - /** - * writes json data to settings.json - */ - public void write() - { - FileWriter fileWriter; - try - { - fileWriter = new FileWriter(file); - JSONObject obj = new JSONObject(); - obj.put("musicVol", musicVol.getValue()); - obj.put("effectsVol", effectsVol.getValue()); - obj.writeJSONString(fileWriter); - fileWriter.flush(); - } - catch (IOException e) { - e.printStackTrace(); - } - } -} diff --git a/src/main/SoundController.java b/src/main/SoundController.java deleted file mode 100644 index 0d7527e..0000000 --- a/src/main/SoundController.java +++ /dev/null @@ -1,83 +0,0 @@ -package main; - -import java.io.File; -import java.nio.file.Paths; -import java.util.HashMap; - -import gui.Driver; -import javafx.scene.media.Media; -import javafx.scene.media.MediaPlayer; -import javafx.util.Duration; - -public class SoundController -{ - public MediaPlayer songMediaPlayer; - public MediaPlayer sfxMediaPlayer; - private HashMap effects = new HashMap<>(); - private File mainMenuSong = Paths.get("resources/fairyfountain.wav").toFile(); - - - /** - * 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.forEach((key,value) -> { - value.volumeProperty().bind(Driver.settingsController.effectsVol); - }); - playMenuSong(); - } - - /** - * plays the song that is passed in. - * @param songFile: the song - */ - public void playSong(File songFile) - { - if (songMediaPlayer != null) - { - songMediaPlayer.stop(); - } - Media song = new Media(songFile.toURI().toString()); - songMediaPlayer = new MediaPlayer(song); - songMediaPlayer.volumeProperty().bind(Driver.settingsController.musicVol); - songMediaPlayer.play(); - } - - /** - * plays the main menu song - */ - public void playMenuSong() - { - playSong(mainMenuSong); - songMediaPlayer.setCycleCount(MediaPlayer.INDEFINITE); - songMediaPlayer.play(); - } - - /** - * stops the currently playing song - */ - public void endSong() - { - if (songMediaPlayer != null) - { - songMediaPlayer.stop(); - } - } - - /** - * plays a sound effect - * for the volume slider to take affect each mediaplayer needs to be pre loaded. - * 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 - */ - public void playSfx(String preset) - { - effects.get(preset).seek(new Duration(0)); - effects.get(preset).play(); - } -} \ No newline at end of file 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 diffList = new TableView(); + + TableColumn diffCol = new TableColumn("Difficulty"); + TableColumn validCol = new TableColumn("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 levels = new TableView(); + + TableColumn titleCol = new TableColumn("Title"); + TableColumn artistCol = new TableColumn("Artist"); + TableColumn 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 dSends = new LinkedList(); //Queue that dictates when to send the notes + ArrayList dLane = new ArrayList(); //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 fSends = new LinkedList(); + ArrayList fLane = new ArrayList(); + + Target sButton = new Target(Color.GREEN, 50, 50, 5, '_'); + Queue spaceSends = new LinkedList(); + ArrayList spaceLane = new ArrayList(); + + Target jButton = new Target(Color.PURPLE, 50, 50, 5, 'j'); + Queue jSends = new LinkedList(); + ArrayList jLane = new ArrayList(); + + Target kButton = new Target(Color.YELLOW, 50, 50, 5, 'k'); + Queue kSends = new LinkedList(); + ArrayList kLane = new ArrayList(); + + /** + * 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 sends, ArrayList 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 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 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() { //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 scores = new TableView(); + + TableColumn nameCol = new TableColumn("Name"); + TableColumn scoreCol = new TableColumn("Score"); + TableColumn dateCol = new TableColumn("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 levels = new TableView(); + + TableColumn titleCol = new TableColumn("Title"); + TableColumn artistCol = new TableColumn("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() { //listens for change in selected item of the list + + @Override + public void changed(ObservableValue 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 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/java/net/sowgro/npehero/main/Difficulty.java b/src/main/java/net/sowgro/npehero/main/Difficulty.java new file mode 100755 index 0000000..6bd565a --- /dev/null +++ b/src/main/java/net/sowgro/npehero/main/Difficulty.java @@ -0,0 +1,272 @@ +package net.sowgro.npehero.main; + +import java.io.File; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.time.LocalDate; +import org.json.simple.JSONArray; +import org.json.simple.JSONObject; +import org.json.simple.parser.JSONParser; +import javafx.collections.FXCollections; +import javafx.collections.ObservableList; + +public class Difficulty implements Comparable +{ + public File thisDir; + public String title = "Unnamed"; + private ObservableList leaderboard = FXCollections.observableArrayList(); + public File notes; + public Double bpm = 0.0; + public int numBeats; + public Level level; + public boolean isValid = false; + public int priority = 0; + + /** + * Creates a new Difficulty and gives it a file path + * @param newDir: The file path of the Difficulty + */ + public Difficulty(File newDir, Level level) + { + thisDir = newDir; + this.level = level; + } + + public void readData() + { + boolean isValid1 = true; + if (new File(thisDir, "metadata.json").exists()) + { + if (!parseMetadata()) + { + isValid1 = false; + } + } + else + { + System.err.println(thisDir+" is missing metadata.json"); + isValid1 = false; + } + + if (new File(thisDir, "leaderboard.json").exists()) + { + if (!parseLeaderboard()) + { + isValid1 = false; + } + } + else + { + System.err.println(thisDir+" is missing leaderboard.json"); + isValid1 = false; + } + + if (new File(thisDir, "notes.txt").exists()) + { + notes = new File(thisDir, "notes.txt"); + } + else + { + System.err.println(thisDir+" is missing notes.txt"); + isValid1 = false; + } + + if (bpm == 0.0) + { + System.err.println(thisDir+" is missing a bpm"); + isValid1 = false; + } + + if (numBeats == 0) + { + System.err.println(thisDir+" is missing the number of beats"); + isValid1 = false; + } + + isValid = isValid1; + } + + /** + * Reads in json metadata and assigns values to variables + */ + public boolean parseMetadata() + { + boolean isValid = true; + File file = new File(thisDir, "metadata.json"); + JSONParser jsonParser = new JSONParser(); //parser to read the file + + try(FileReader reader = new FileReader(file)) + { + Object obj = jsonParser.parse(reader); + JSONObject diffStuff = (JSONObject)(obj); //converts read object to a JSONObject + + if (diffStuff.containsKey("title")) + { + title = (String) diffStuff.get("title"); + } + else + { + System.err.println(file+" is missing properety title"); + isValid = false; + } + + if (diffStuff.containsKey("bpm")) + { + bpm = Double.parseDouble(diffStuff.get("bpm")+""); + } + else + { + System.err.println(file+" is missing properety bpm"); + isValid = false; + } + + if (diffStuff.containsKey("numBeats")) + { + numBeats = Integer.parseInt(diffStuff.get("numBeats")+""); + } + else + { + System.err.println(file+" is missing properety numBeats"); + isValid = false; + } + + if (diffStuff.containsKey("priority")) + { + priority = Integer.parseInt(diffStuff.get("priority")+""); + + } + else + { + System.err.println(file+" is missing properety priority"); + isValid = false; + } + } + catch (Exception e) + { + e.printStackTrace(); + isValid = false; + } + return isValid; + } + + /** + * Writes metadata to json file + */ + public void writeMetadata() + { + FileWriter fileWriter; + try + { + File file = new File(thisDir, "metadata.json"); + fileWriter = new FileWriter(file); + JSONObject obj = new JSONObject(); + obj.put("title", title); + obj.put("bpm", bpm); + obj.put("numBeats", numBeats); + obj.put("priority", priority); + obj.writeJSONString(fileWriter); + fileWriter.flush(); + } + catch (IOException e) + { + e.printStackTrace(); + } + } + + /** + * Reads in json leaderboard and assigns populates list with leaderboardEntries + */ + public boolean parseLeaderboard() + { + boolean isValid = true; + File file = new File(thisDir, "leaderboard.json"); + JSONParser jsonParser = new JSONParser(); //parser to read the file + + try(FileReader reader = new FileReader(file)) + { + Object obj = jsonParser.parse(reader); + + JSONArray leaderboardStuff = (JSONArray)(obj); //converts read object to a JSONArray + + for (Object cur: leaderboardStuff) + { + JSONObject cur2 = (JSONObject) cur; + + String name = (String) cur2.get("name"); + int score = Integer.parseInt(""+cur2.get("score")); + String date = (String) cur2.get("date"); + leaderboard.add(new LeaderboardEntry(name, score, date)); + } + } + catch (Exception e) + { + isValid = false; + e.printStackTrace(); + } + return isValid; + } + + /** + * Writes leaderboard to json file + */ + public void writeLeaderboard() + { + FileWriter fileWriter; + try + { + File file = new File(thisDir, "leaderboard.json"); + fileWriter = new FileWriter(file); + //write the settings JSONObject instance to the file + JSONArray jsonArray = new JSONArray(); + for (LeaderboardEntry cur: leaderboard) + { + JSONObject obj = new JSONObject(); + obj.put("name", cur.getName()); + obj.put("score", cur.getScore()); + obj.put("date",cur.getDate()); + jsonArray.add(obj); + } + jsonArray.writeJSONString(fileWriter); + fileWriter.flush(); + + } + catch (IOException e) { + e.printStackTrace(); + } + } + + /** + * Adds new leaderboardEntry to list and updates json file + * @param name: the players name + * @param score the players score + */ + public void addToLeaderboard(String name, int score) + { + leaderboard.add(new LeaderboardEntry(name, score, ""+LocalDate.now())); //do not delete this tho its not a placeholder + writeLeaderboard(); + } + + public ObservableList getLeaderboard() + { + return leaderboard; + } + + public String toString() + { + return title; + } + + public boolean isValid() { + return isValid; + } + + public String getTitle() { + return title; + } + + @Override + public int compareTo(Difficulty d) { + return priority - d.priority; + } +} diff --git a/src/main/java/net/sowgro/npehero/main/LeaderboardEntry.java b/src/main/java/net/sowgro/npehero/main/LeaderboardEntry.java new file mode 100755 index 0000000..18e657c --- /dev/null +++ b/src/main/java/net/sowgro/npehero/main/LeaderboardEntry.java @@ -0,0 +1,28 @@ +package net.sowgro.npehero.main; + +public class LeaderboardEntry +{ + private int score; + private String name; + private String date; + + public LeaderboardEntry(String name, int score, String date) + { + this.name = name; + this.score = score; + this.date = date; + } + + public int getScore() { + return score; + } + + public String getName() { + return name; + } + + public String getDate() + { + return date; + } +} diff --git a/src/main/java/net/sowgro/npehero/main/Level.java b/src/main/java/net/sowgro/npehero/main/Level.java new file mode 100755 index 0000000..ef264ff --- /dev/null +++ b/src/main/java/net/sowgro/npehero/main/Level.java @@ -0,0 +1,285 @@ +package net.sowgro.npehero.main; + +import java.io.File; +import java.util.Collections; +import java.util.Comparator; + +import javafx.collections.FXCollections; +import javafx.collections.ObservableList; +import javafx.scene.image.Image; +import javafx.scene.paint.Color; +import java.io.FileWriter; +import java.io.FileReader; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardCopyOption; +import org.json.simple.JSONObject; +import org.json.simple.parser.JSONParser; + +public class Level +{ + public File thisDir; + private String title = "Unnamed"; + private String artist = "Unknown"; + private ObservableList diffList; + private ObservableList validDiffList; + private boolean isValid; + + public Image preview; //optional + public String desc; + public Image background; //optional + public Color[] colors = {Color.RED,Color.BLUE,Color.GREEN,Color.PURPLE,Color.YELLOW};//optional, have default colors + public File song; + + /** + * Creates a new level and gives it a file path + * @param newDir: The path of the Level + */ + public Level(File newDir) + { + thisDir = newDir; + } + + public void readData() + { + boolean isValid1 = true; + if (new File(thisDir, "metadata.json").exists()) + { + if (!parseMetadata()) + { + System.err.println(new File(thisDir, "metadata.json")+" contains error(s)"); + isValid1 = false; + } + } + else + { + System.err.println(thisDir+" is missing metadata.json"); + isValid1 = false; + } + + if (new File(thisDir, "song.wav").exists()) + { + song = new File(thisDir,"song.wav"); + } + else + { + System.err.println(thisDir+" is missing song.wav"); + isValid1 = false; + } + + if (new File(thisDir, "background.png").exists()) + { + background = new Image(new File(thisDir,"background.png").toURI().toString()); + } + + if (new File(thisDir, "preview.png").exists()) + { + preview = new Image(new File(thisDir,"preview.png").toURI().toString()); + } + + diffList = FXCollections.observableArrayList(); + validDiffList = FXCollections.observableArrayList(); + for(File cur: thisDir.listFiles()) //iterates through all files/folders in /levels/LEVEL + { + if (cur.isDirectory()) //all subfolders within a level folder are difficulties + { + Difficulty diff = new Difficulty(cur,this); + diff.readData(); + if (diff.isValid) + { + diffList.add(diff); + validDiffList.add(diff); + } + else + { + diffList.add(diff); + } + } + } + if (validDiffList.size() == 0) + { + System.err.println(thisDir+" contains no valid difficulties"); + isValid1 = false; + } + + Collections.sort(validDiffList); + Collections.sort(diffList); + isValid = isValid1; + } + + /** + * Reads in json metadata and assigns values to variables + */ + public boolean parseMetadata() + { + boolean isValid = true; + JSONParser jsonParser = new JSONParser(); //parser to read the file + File file = new File(thisDir, "metadata.json"); + try(FileReader reader = new FileReader(file)) + { + Object obj = jsonParser.parse(reader); + JSONObject levelStuff = new JSONObject(); + levelStuff = (JSONObject)(obj); //converts read object to a JSONObject + + if (levelStuff.containsKey("title")) + { + title = (String) levelStuff.get("title"); + } + else + { + System.err.println(file+" is missing properety title"); + isValid = false; + } + + if (levelStuff.containsKey("artist")) + { + artist = (String)(levelStuff.get("artist")); + } + else + { + System.err.println(file+" is missing properety aritst"); + isValid = false; + } + + if (levelStuff.containsKey("desc")) + { + desc = (String) levelStuff.get("desc"); + } + + if(( levelStuff).containsKey("color1")) //check for custom colors in a hexadecimal format (zach was lazy for not checking all five colors but i will forgive him) + { + colors = new Color[5]; + + colors[0] = Color.web((String)(levelStuff.get("color1"))); //read in all the custom colors + colors[1] = Color.web((String)(levelStuff.get("color2"))); + colors[2] = Color.web((String)(levelStuff.get("color3"))); + colors[3] = Color.web((String)(levelStuff.get("color4"))); + colors[4] = Color.web((String)(levelStuff.get("color5"))); + } + } + catch (Exception e) + { + e.printStackTrace(); + isValid = false; + } + return isValid; + } + + /** + * Writes metadata to json file + */ + public void writeMetadata() + { + FileWriter fileWriter; + try + { + fileWriter = new FileWriter(new File(thisDir, "metadata.json")); + JSONObject obj = new JSONObject(); + obj.put("title", title); + obj.put("artist", artist); + if (desc != null) + { + obj.put("desc", desc); + } + obj.put("color1",colors[0].toString()); + obj.put("color2",colors[1].toString()); + obj.put("color3",colors[2].toString()); + obj.put("color4",colors[3].toString()); + obj.put("color5",colors[4].toString()); + obj.writeJSONString(fileWriter); + fileWriter.flush(); + } + catch (IOException e) { + e.printStackTrace(); + } + } + + /** + * Adds a difficulty by creating a directory and required files + * @param text: the name of the directory and default title + */ + public void addDiff(String text) + { + File diffDir = new File(thisDir, text); + diffDir.mkdirs(); + File metadataDir = new File(diffDir, "metadata.json"); + File leaderboardDir = new File(diffDir, "leaderboard.json"); + File notesDir = new File(diffDir, "notes.txt"); + try { + metadataDir.createNewFile(); + leaderboardDir.createNewFile(); + notesDir.createNewFile(); + } catch (IOException e) { + e.printStackTrace(); + } + Difficulty temp = new Difficulty(diffDir,this); + temp.title = text; + temp.writeMetadata(); + temp.writeLeaderboard(); + readData(); + } + + /** + * Removes the difficaulty from the filesystem then reloads the level + * @param diff: the difficulty to be removed + */ + public void removeDiff(Difficulty diff) + { + File hold = diff.thisDir; + try { + Files.walk(hold.toPath()) + .sorted(Comparator.reverseOrder()) + .map(Path::toFile) + .forEach(File::delete); + } catch (IOException e) { + e.printStackTrace(); + } + readData(); + } + + /** + * Copies a file into the level directory + * @param newFile: the file to be copied + * @param name: the new file name + */ + public void addFile(File newFile, String name) + { + try { + Files.copy(newFile.toPath(), new File(thisDir, name).toPath(), StandardCopyOption.REPLACE_EXISTING); + } catch (IOException e) { + e.printStackTrace(); + } + readData(); + } + + public ObservableList getDiffList() { + return diffList; + } + + public ObservableList getValidDiffList() { + return validDiffList; + } + + public String getTitle() + { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getArtist() + { + return artist; + } + + public void setArtist(String artist) { + this.artist = artist; + } + + public boolean isValid() { + return isValid; + } +} diff --git a/src/main/java/net/sowgro/npehero/main/LevelController.java b/src/main/java/net/sowgro/npehero/main/LevelController.java new file mode 100755 index 0000000..68d7450 --- /dev/null +++ b/src/main/java/net/sowgro/npehero/main/LevelController.java @@ -0,0 +1,95 @@ +package net.sowgro.npehero.main; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Comparator; + +import javafx.collections.FXCollections; +import javafx.collections.ObservableList; + +public class LevelController +{ + File thisDir = new File("levels"); + private static ObservableList levelList; + private static ObservableList validLevelList; + + /** + * Creates a levelController, which holds all the levels + */ + public LevelController() + { + readData(); + } + + /** + * Reads contents of folder and creates cooresponding levels + */ + public void readData() + { + levelList = FXCollections.observableArrayList(); + validLevelList = FXCollections.observableArrayList(); + for (File cur: thisDir.listFiles()) //iterates through all files/folders in levels + { + Level level = new Level(cur); + level.readData(); + levelList.add(level); + if (level.isValid()) + { + validLevelList.add(level); + } + } + } + + /** + * Adds a level to the list by creating a directory and required files + * @param text: the name of the directory and default title + */ + public void addLevel(String text) + { + File levelDir = new File(thisDir,text); + levelDir.mkdirs(); + File metadataDir = new File(levelDir, "metadata.json"); + try + { + metadataDir.createNewFile(); + } + catch (IOException e) + { + e.printStackTrace(); + } + Level temp = new Level(levelDir); + temp.setTitle(text); + temp.writeMetadata(); + readData(); + } + + /** + * Removes level from the filesystem then reloads this levelController + * @param level: the level to be removed + */ + public void removeLevel(Level level) + { + File hold = level.thisDir; + levelList.remove(level); + + try { + Files.walk(hold.toPath()) + .sorted(Comparator.reverseOrder()) + .map(Path::toFile) + .forEach(File::delete); + } catch (IOException e) { + e.printStackTrace(); + } + readData(); + } + + public static ObservableList getLevelList() { + return levelList; + } + + public static ObservableList getValidLevelList() { + return validLevelList; + } +} \ No newline at end of file diff --git a/src/main/java/net/sowgro/npehero/main/ScoreController.java b/src/main/java/net/sowgro/npehero/main/ScoreController.java new file mode 100755 index 0000000..ba43171 --- /dev/null +++ b/src/main/java/net/sowgro/npehero/main/ScoreController.java @@ -0,0 +1,117 @@ +package net.sowgro.npehero.main; + +import net.sowgro.npehero.Driver; +import javafx.beans.property.SimpleStringProperty; +import javafx.beans.property.StringProperty; + +public class ScoreController{ + + private int score = 0; + private int combo = 0; + private int comboMultiplier=1; + public StringProperty scoreProperty = new SimpleStringProperty("0"); + public StringProperty comboProperty = new SimpleStringProperty("0"); + + /** + * Called when the user performs a perfect hit + */ + public void perfect() { + combo(); + score += 300*comboMultiplier; + scoreProperty.setValue(score+""); + comboProperty.setValue(combo +""); + // System.out.println("Perfect!"); + } + + /** + * called when the user performs an okay hit + */ + public void good() { + combo(); + score += 100*comboMultiplier; + scoreProperty.setValue(score+""); + comboProperty.setValue(combo+""); + // System.out.println("Good"); + } + + /** + * Called when the user misses a note + */ + public void miss(boolean muted) { + if (!muted) { + Driver.soundController.playSfx("miss"); + } + combo = 0; + comboMultiplier = 1; + scoreProperty.setValue(score+""); + comboProperty.setValue(combo+""); + // System.out.println("Miss"); + } + + /* + * Increments the combo by one + */ + private void combo() { + Driver.soundController.playSfx("hit"); + combo++; + + if (combo == 2) { + comboMultiplier = 2; + } + + if (combo == 4) { + comboMultiplier = 4; + } + + if (combo == 8) { + comboMultiplier = 8; + } + } + + /** + * @return current score + */ + public int getScore() + { + return score; + } + + /** + * @return current combo + */ + public int getCombo() + { + return combo; + } + + /** + * @param newScore: the score to be set, only used in debug + */ + public void setScore(int newScore) + { + score = newScore; + scoreProperty.setValue(newScore+""); + } + + /** + * @param newCombo: the combo to be set, only used in debug + */ + public void setCombo(int newCombo) + { + combo = newCombo; + comboProperty.setValue(newCombo+""); + } + + /** + * prints values into console + */ + public void print() + { + System.out.println("--"); + System.out.println(combo); + System.out.println(score); + System.out.println(""); + System.out.println(scoreProperty); + System.out.println(comboProperty); + } +} diff --git a/src/main/java/net/sowgro/npehero/main/SettingsController.java b/src/main/java/net/sowgro/npehero/main/SettingsController.java new file mode 100755 index 0000000..d5f3e3b --- /dev/null +++ b/src/main/java/net/sowgro/npehero/main/SettingsController.java @@ -0,0 +1,62 @@ +package net.sowgro.npehero.main; + +import java.io.FileWriter; +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import org.json.simple.JSONObject; +import org.json.simple.parser.JSONParser; +import javafx.beans.property.SimpleDoubleProperty; + +public class SettingsController +{ + public SimpleDoubleProperty effectsVol = new SimpleDoubleProperty(1); + public SimpleDoubleProperty musicVol = new SimpleDoubleProperty(1); + private File file = new File("settings.json"); + + public SettingsController() + { + read(); + } + + /** + * reads json data from settings.json + */ + public void read() + { + JSONParser jsonParser = new JSONParser(); //parser to read the file + try(FileReader reader = new FileReader(file)) + { + Object obj = jsonParser.parse(reader); + JSONObject settings = new JSONObject(); + settings = (JSONObject)(obj); //converts read object to a JSONObject + + effectsVol.set(Double.parseDouble(settings.get("effectsVol")+"")); + musicVol.set(Double.parseDouble(settings.get("musicVol")+"")); + } + catch (Exception e) + { + e.printStackTrace(); + } + } + + /** + * writes json data to settings.json + */ + public void write() + { + FileWriter fileWriter; + try + { + fileWriter = new FileWriter(file); + JSONObject obj = new JSONObject(); + obj.put("musicVol", musicVol.getValue()); + obj.put("effectsVol", effectsVol.getValue()); + obj.writeJSONString(fileWriter); + fileWriter.flush(); + } + catch (IOException e) { + e.printStackTrace(); + } + } +} diff --git a/src/main/java/net/sowgro/npehero/main/SoundController.java b/src/main/java/net/sowgro/npehero/main/SoundController.java new file mode 100755 index 0000000..da80ab4 --- /dev/null +++ b/src/main/java/net/sowgro/npehero/main/SoundController.java @@ -0,0 +1,97 @@ +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 net.sowgro.npehero.Driver; +import javafx.scene.media.Media; +import javafx.scene.media.MediaPlayer; +import javafx.util.Duration; + +public class SoundController +{ + public MediaPlayer songMediaPlayer; + public MediaPlayer sfxMediaPlayer; + private final HashMap 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(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); + }); + playMenuSong(); + } + + /** + * plays the song that is passed in. + * @param songFile: the song + */ + public void playSong(File songFile) + { + if (songMediaPlayer != null) + { + songMediaPlayer.stop(); + } + Media song = new Media(songFile.toURI().toString()); + songMediaPlayer = new MediaPlayer(song); + songMediaPlayer.volumeProperty().bind(Driver.settingsController.musicVol); + songMediaPlayer.play(); + } + + /** + * plays the main menu song + */ + public void playMenuSong() + { + if (!mainMenuSong.exists()) { + System.out.println("NOT EXIST " + mainMenuSong.getAbsolutePath()); + return; + } + playSong(mainMenuSong); + songMediaPlayer.setCycleCount(MediaPlayer.INDEFINITE); + songMediaPlayer.play(); + } + + /** + * stops the currently playing song + */ + public void endSong() + { + if (songMediaPlayer != null) + { + songMediaPlayer.stop(); + } + } + + /** + * plays a sound effect + * 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 + */ + public void playSfx(String preset) + { + effects.get(preset).seek(new Duration(0)); + effects.get(preset).play(); + } +} \ No newline at end of file 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 Binary files /dev/null and b/src/main/resources/net/sowgro/npehero/backward.wav 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 Binary files /dev/null and b/src/main/resources/net/sowgro/npehero/fairyfountain.wav 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 Binary files /dev/null and b/src/main/resources/net/sowgro/npehero/forward.wav 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 Binary files /dev/null and b/src/main/resources/net/sowgro/npehero/hit.wav 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 Binary files /dev/null and b/src/main/resources/net/sowgro/npehero/miss.wav 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 Binary files /dev/null and b/src/main/resources/net/sowgro/npehero/mountains.png 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; */ +} + -- cgit v1.2.3