From e026f360ca7777fe72ec1b3bd86045f7d94aa834 Mon Sep 17 00:00:00 2001 From: sowgro Date: Sat, 31 Aug 2024 21:39:29 -0400 Subject: finish SongPlayer rewrite - move from gameloop to timeline - significant code clean up - change design of blocks and targets --- .../java/net/sowgro/npehero/gameplay/NoteInfo.java | 28 -- .../sowgro/npehero/gameplay/ScoreController.java | 8 +- .../net/sowgro/npehero/gameplay/SongPlayer.java | 385 +++++++++------------ .../java/net/sowgro/npehero/gameplay/Target.java | 2 +- .../java/net/sowgro/npehero/gameplay/Timer.java | 28 -- .../java/net/sowgro/npehero/gui/LevelSurround.java | 31 +- .../java/net/sowgro/npehero/levelapi/Note.java | 4 + src/main/java/net/sowgro/npehero/main/Control.java | 54 +-- src/main/java/net/sowgro/npehero/main/Sound.java | 1 + 9 files changed, 217 insertions(+), 324 deletions(-) delete mode 100755 src/main/java/net/sowgro/npehero/gameplay/NoteInfo.java delete mode 100755 src/main/java/net/sowgro/npehero/gameplay/Timer.java diff --git a/src/main/java/net/sowgro/npehero/gameplay/NoteInfo.java b/src/main/java/net/sowgro/npehero/gameplay/NoteInfo.java deleted file mode 100755 index a34e939..0000000 --- a/src/main/java/net/sowgro/npehero/gameplay/NoteInfo.java +++ /dev/null @@ -1,28 +0,0 @@ -/*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/ScoreController.java b/src/main/java/net/sowgro/npehero/gameplay/ScoreController.java index 1865a56..4c603c1 100755 --- a/src/main/java/net/sowgro/npehero/gameplay/ScoreController.java +++ b/src/main/java/net/sowgro/npehero/gameplay/ScoreController.java @@ -37,10 +37,8 @@ public class ScoreController{ /** * Called when the user misses a note */ - public void miss(boolean muted) { - if (!muted) { - Sound.playSfx(Sound.MISS); - } + public void miss() { + Sound.playSfx(Sound.MISS); combo = 0; comboMultiplier = 1; scoreProperty.setValue(score+""); @@ -48,7 +46,7 @@ public class ScoreController{ // System.out.println("Miss"); } - /* + /** * Increments the combo by one */ private void combo() { diff --git a/src/main/java/net/sowgro/npehero/gameplay/SongPlayer.java b/src/main/java/net/sowgro/npehero/gameplay/SongPlayer.java index bf7b8a2..5361b96 100755 --- a/src/main/java/net/sowgro/npehero/gameplay/SongPlayer.java +++ b/src/main/java/net/sowgro/npehero/gameplay/SongPlayer.java @@ -1,20 +1,18 @@ package net.sowgro.npehero.gameplay; -import java.io.FileNotFoundException; -import java.io.IOException; import java.util.ArrayList; -import java.util.LinkedList; -import java.util.Queue; - -import javax.sound.sampled.LineUnavailableException; -import javax.sound.sampled.UnsupportedAudioFileException; import javafx.event.EventHandler; +import javafx.geometry.Insets; import javafx.scene.input.KeyEvent; import javafx.scene.media.Media; +import javafx.scene.shape.Line; +import javafx.scene.shape.Rectangle; import net.sowgro.npehero.Driver; import net.sowgro.npehero.levelapi.Difficulty; import net.sowgro.npehero.levelapi.Level; +import net.sowgro.npehero.levelapi.Note; +import net.sowgro.npehero.levelapi.Notes; import net.sowgro.npehero.main.*; import net.sowgro.npehero.gui.GameOver; import javafx.geometry.Pos; @@ -27,244 +25,180 @@ import javafx.scene.paint.Color; import javafx.animation.*; import javafx.util.*; -class KeyLane { - Target target; //Initializes the button, each parameter is a placeholder that is changed later - Queue sends = new LinkedList<>(); //Queue that dictates when to send the notes - ArrayList lane = new ArrayList<>(); //Array list containing all the notes currently on the field for that lane -} - -public class SongPlayer extends Pane { - private Double bpm; //initializes the bpm of the song, to be read in from a metadata file later - private double songLength; //initializes the length of the song in terms of the song's bpm, to be read in later - - private EventHandler eventHandler; +public class SongPlayer extends HBox { - private Media song; - private boolean songIsPlaying = false; - private boolean missMute = false; - - private Level level; - private Difficulty difficulty; - private Page 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 + static class Lane { + Target target; //Initializes the button, each parameter is a placeholder that is changed later + ArrayList blocks = new ArrayList<>(); //Array list containing all the notes currently on the field for that lane + Pane pane = new Pane(); + } - ScoreController scoreCounter = new ScoreController(); //used to keep track of the user's score + private final int FALL_TIME = 1; // delay for notes falling down the screen (seconds) + private final double START_DELAY = 1; // seconds - HBox buttonBox = new HBox(); //used to align the buttons horizontally - VBox place = new VBox(); //used to place the buttons within the frame + private final Level level; + private final Media song; + private final ScoreController scoreCounter; - KeyLane[] lanes = new KeyLane[5]; + private final EventHandler eventHandler; + private final Timeline timeline; - { - lanes[0] = new KeyLane(); - lanes[0].target = new Target(Color.RED, 50, 50, 5, Control.LANE0.targetString()); - lanes[1] = new KeyLane(); - lanes[1].target = new Target(Color.BLUE, 50, 50, 5, Control.LANE1.targetString()); - lanes[2] = new KeyLane(); - lanes[2].target = new Target(Color.GREEN, 50, 50, 5, Control.LANE2.targetString()); - lanes[3] = new KeyLane(); - lanes[3].target = new Target(Color.PURPLE, 50, 50, 5, Control.LANE3.targetString()); - lanes[4] = new KeyLane(); - lanes[4].target = new Target(Color.YELLOW, 50, 50, 5, Control.LANE4.targetString()); - } + private boolean done = false; + private final Lane[] lanes = new Lane[5]; - /** - * Establishes what the chart for the song is going to look like - * @throws FileNotFoundException - */ - public void loadSong() throws FileNotFoundException { - difficulty.notes.list.forEach(e -> lanes[e.lane].sends.add(new NoteInfo(e.time.get() * (bpm / 60)))); - } + public SongPlayer(Difficulty diff, Page prev, ScoreController scoreController) { + this.level = diff.level; + this.song = diff.level.song; + this.scoreCounter = scoreController; // Uses the song's designated scoreCounter + double songLength = diff.endTime != 0 ? diff.endTime : diff.level.song.getDuration().toSeconds(); + Notes notes = diff.notes; - public SongPlayer(Difficulty diff, Page prev, ScoreController cntrl) { Sound.stopSong(); - song = diff.level.song; - - if (diff.level.background != null) { - Driver.setBackground(diff.level.background); - } - bpm = 60.0; //Reads the song's bpm from a metadata file - level = diff.level; - difficulty = diff; - pane = prev; - - //System.out.println(d.bpm + " " + d.numBeats); - - if (diff.endTime != 0) { - songLength = diff.endTime; - } - else { - songLength = diff.level.song.getDuration().toSeconds(); + if (level.background != null) { + Driver.setBackground(level.background); } - timer = new Timer(bpm); //Sets the timer's bpm to that of the song - scoreCounter = cntrl; //Uses the song's designated scoreCounter - - try { - loadSong(); //Calls the file loading from the song's notes.txt file - } catch (FileNotFoundException e) { + // create targets + for (int i = 0; i < lanes.length; i++) { + lanes[i] = new Lane(); + var tmp = new Target(level.colors[i], 50, 50, 20, Control.lanes[i].targetString()); + bindTarget(tmp); + lanes[i].target = tmp; } - for (int i = 0; i < lanes.length; i++) { - lanes[i].target.setColor(level.colors[i]); - genButton(lanes[i].target); + // create timeline + timeline = new Timeline(); + for (Note note : notes.list) { + // schedule each note to send at its time + KeyFrame kf = new KeyFrame(Duration.seconds(note.getTime() + START_DELAY), _ -> sendNote(note)); + timeline.getKeyFrames().add(kf); } - + // schedule the song to start after the delay + timeline.getKeyFrames().add(new KeyFrame(Duration.seconds(FALL_TIME + START_DELAY), _ -> { + if (!done) { + Sound.playSong(song); + } + })); + // schedule the game over screen to show at the end + timeline.getKeyFrames().add(new KeyFrame(Duration.seconds(songLength + START_DELAY), _ -> { + Driver.setMenu(new GameOver(level, diff, prev, scoreCounter.getScore())); + cancel(); + })); + + // handle keyboard input eventHandler = e -> { - /* - * The keyboard detection for the game: when a key is pressed it - * calls the checkNote() method for the corresponding lane - */ - if (e.getCode() == Control.LANE0.getKey()) { - checkNote(lanes[0].lane, lanes[0].target); - } - if (e.getCode() == Control.LANE1.getKey()) { - checkNote(lanes[1].lane, lanes[1].target); - } - if (e.getCode() == Control.LANE2.getKey()) { - checkNote(lanes[2].lane, lanes[2].target); - } - if (e.getCode() == Control.LANE3.getKey()) { - checkNote(lanes[3].lane, lanes[3].target); - } - if (e.getCode() == Control.LANE4.getKey()) { - checkNote(lanes[4].lane, lanes[4].target); + for (int i = 0; i < lanes.length; i++) { + if (e.getCode() == Control.lanes[i].getKey()) { + checkNote(lanes[i]); + } } if (e.getCode() == Control.LEGACY_PRINT.getKey()) { - System.out.println("" + timer.time()); + System.out.println("" + timeline.getCurrentTime()); } e.consume(); }; Driver.primaryStage.addEventFilter(KeyEvent.KEY_PRESSED, eventHandler); - buttonBox.setAlignment(Pos.CENTER); //puts the buttons in the center of the screen - for (KeyLane lane : lanes) { //places the buttons in the correct row order - buttonBox.getChildren().add(lane.target); + // layout + HBox buttonBox = new HBox(); + buttonBox.setAlignment(Pos.BOTTOM_CENTER); //puts the buttons in the center of the screen + for (Lane lane : lanes) { //places the buttons in the correct row order + Line line = new Line(); + line.setStroke(lane.target.getFillColor()); + line.setStrokeWidth(2); + line.setStartY(0); + line.endYProperty().bind(lane.target.layoutYProperty().subtract(2)); + VBox back = new VBox(line, lane.target); + back.setAlignment(Pos.BOTTOM_CENTER); + StackPane stackPane = new StackPane(back, lane.pane); + buttonBox.getChildren().add(stackPane); } - 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 + buttonBox.spacingProperty().bind(super.heightProperty().multiply(20/1080.0)); + super.getChildren().add(buttonBox); + super.setPadding(new Insets(0, 20, 10, 20)); + super.setAlignment(Pos.BOTTOM_CENTER); } /** * 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)); - } + public void sendNote(Note note) { + Lane lane = lanes[note.lane]; + + Block block = new Block(lane.target.getColor(), 50, 50, 15); + block.setCache(true); + block.setCacheHint(CacheHint.SPEED); + block.xProperty().bind(lane.pane.widthProperty().subtract(block.widthProperty()).divide(2)); + block.yProperty().bind(block.heightProperty().negate()); + bindBlock(block); + + lane.blocks.add(block); + + TranslateTransition anim = new TranslateTransition(Duration.seconds(FALL_TIME + 0.105)); + anim.setInterpolator(Interpolator.LINEAR); + anim.byYProperty().bind(super.heightProperty().add(block.getHeight()).add(75)); + anim.setNode(block); + anim.play(); + anim.setOnFinished(_ -> { + if (lane.pane.getChildren().remove(block) && !done) { + scoreCounter.miss(); + FillTransition ft = new FillTransition(Duration.millis(500), lane.target.rect); + ft.setFromValue(Color.RED); + ft.setToValue(lane.target.getFillColor()); + ft.play(); + } + }); + lane.pane.getChildren().add(block); } /** - * Sets up the given button - * - * @param button + * Binds properties of the target to the screen + * @param target The target to bind */ - 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)); + private void bindTarget(Target target) { + bindBlock(target.rect); +// target.rect.strokeWidthProperty().bind(super.widthProperty().divide(120)); + } + + private void bindBlock(Rectangle block) { + var sizeBind = super.heightProperty().multiply(87/1080.0); + block.heightProperty().bind(sizeBind); + block.widthProperty().bind(sizeBind); + var arcBind = super.heightProperty().multiply(20/1080.0); + block.arcHeightProperty().bind(arcBind); + block.arcWidthProperty().bind(arcBind); } /** - * The background test that is run on every frame of the game + * starts the gameLoop, a periodic background task runner that runs the methods within it 60 times every second */ - AnimationTimer gameLoop = new AnimationTimer() { - - @Override - public void handle(long arg0) { - for (KeyLane lane : lanes) { - sendNote(lane.sends, lane.lane, lane.target); - } - - if (timer.time() > songLength) { - Driver.setMenu(new GameOver(level, difficulty, pane, scoreCounter.getScore())); - cancel(); - } - if (!songIsPlaying && timer.time() > 0.0) { - songIsPlaying = true; - Sound.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(); + public void start() { + timeline.play(); } /** - * Stops the gameloop - * @throws LineUnavailableException - * @throws IOException - * @throws UnsupportedAudioFileException + * Stops the gameLoop */ public void cancel() { Driver.primaryStage.removeEventFilter(KeyEvent.KEY_PRESSED, eventHandler); - missMute = true; + done = true; Sound.stopSong(); Sound.playSong(Sound.MENU_SONG); Driver.setMenuBackground(); - gameLoop.stop(); + timeline.stop(); + timeline.getKeyFrames().clear(); // for some reason other instances of Timeline will have these keyframes if I don't clear. } /** * returns the pos in the lane array of the closest note to the goal - * - * @param searchLane + * @param searchLane The list of blocks to search in * @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))) { + if (distanceToTarget(searchLane.get(i)) < distanceToTarget(searchLane.get(pos))) { pos = i; } } @@ -273,50 +207,49 @@ public class SongPlayer extends Pane { /** * Returns the distance to the goal of the given note - * - * @param note - * @return + * @param note Note to check the distance of + * @return The distance between the note and the target in pixels */ - private double distanceToGoal(Block note) { + private double distanceToTarget(Block note) { return Math.abs((super.getHeight() - note.getTranslateY() + note.getHeight()/2) - lanes[0].target.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; + private int checkNote(Lane lane) { + ArrayList blocks = lane.blocks; + if (blocks.isEmpty() || done) { + return -1; + } + double distance = distanceToTarget(blocks.get(getClosestNote(blocks))); + if (distance < super.getHeight() / 3) { + + FillTransition ft = new FillTransition(Duration.millis(500), lane.target.rect); + ft.setToValue(lane.target.getFillColor()); + + lane.pane.getChildren().removeAll(blocks.get(getClosestNote(blocks))); + blocks.remove(blocks.get(getClosestNote(blocks))); + 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(); + 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 index 229abcb..45907d3 100755 --- a/src/main/java/net/sowgro/npehero/gameplay/Target.java +++ b/src/main/java/net/sowgro/npehero/gameplay/Target.java @@ -30,7 +30,7 @@ public class Target extends StackPane rect.setArcHeight(r); rect.setArcWidth(r); rect.setStroke(col); - rect.setStrokeWidth(5); + rect.setStrokeWidth(4); } public void setColor(Color c) { diff --git a/src/main/java/net/sowgro/npehero/gameplay/Timer.java b/src/main/java/net/sowgro/npehero/gameplay/Timer.java deleted file mode 100755 index eada237..0000000 --- a/src/main/java/net/sowgro/npehero/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 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/LevelSurround.java b/src/main/java/net/sowgro/npehero/gui/LevelSurround.java index 09eeaa0..4b11c15 100755 --- a/src/main/java/net/sowgro/npehero/gui/LevelSurround.java +++ b/src/main/java/net/sowgro/npehero/gui/LevelSurround.java @@ -1,5 +1,6 @@ package net.sowgro.npehero.gui; +import javafx.animation.AnimationTimer; import net.sowgro.npehero.Driver; import net.sowgro.npehero.gameplay.SongPlayer; import javafx.geometry.Insets; @@ -12,7 +13,6 @@ import javafx.scene.layout.StackPane; import javafx.scene.layout.VBox; import javafx.scene.text.Text; import net.sowgro.npehero.levelapi.Difficulty; -import net.sowgro.npehero.levelapi.Level; import net.sowgro.npehero.gameplay.ScoreController; import net.sowgro.npehero.main.Page; import net.sowgro.npehero.main.Sound; @@ -55,10 +55,10 @@ public class LevelSurround extends Page 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); + AnchorPane.setLeftAnchor(buttonBox, 0.0); + AnchorPane.setRightAnchor(titleTextBox, 0.0); + AnchorPane.setTopAnchor(buttonBox, 0.0); + AnchorPane.setTopAnchor(titleTextBox, 0.0); topBar.setPadding(new Insets(10)); @@ -79,8 +79,8 @@ public class LevelSurround extends Page AnchorPane scoreBox = new AnchorPane(); scoreBox.getChildren().add(scoreTextBox); - scoreBox.setLeftAnchor(scoreTextBox, 0.0); - scoreBox.setBottomAnchor(scoreTextBox, 0.0); + AnchorPane.setLeftAnchor(scoreTextBox, 0.0); + AnchorPane.setBottomAnchor(scoreTextBox, 0.0); scoreBox.setPadding(new Insets(10)); Text comboLabel = new Text(); @@ -100,17 +100,17 @@ public class LevelSurround extends Page AnchorPane comboBox = new AnchorPane(); comboBox.getChildren().add(comboTextBox); - comboBox.setRightAnchor(comboTextBox, 0.0); - comboBox.setBottomAnchor(comboTextBox, 0.0); + AnchorPane.setRightAnchor(comboTextBox, 0.0); + AnchorPane.setBottomAnchor(comboTextBox, 0.0); comboBox.setPadding(new Insets(10)); - game.minWidthProperty().bind(content.heightProperty().multiply(0.66)); + game.minWidthProperty().bind(content.heightProperty().multiply(0.55)); game.minHeightProperty().bind(content.heightProperty()); game.getStyleClass().add("box"); - comboBox.minWidthProperty().bind(Driver.primaryPane.widthProperty().subtract(game.minWidthProperty()).divide(2)); - scoreBox.minWidthProperty().bind(Driver.primaryPane.widthProperty().subtract(game.minWidthProperty()).divide(2)); + comboBox.minWidthProperty().bind(Driver.primaryPane.widthProperty().subtract(game.widthProperty()).divide(2)); + scoreBox.minWidthProperty().bind(Driver.primaryPane.widthProperty().subtract(game.widthProperty()).divide(2)); HBox centerBox = new HBox(); centerBox.getChildren().addAll(comboBox, game, scoreBox); @@ -121,7 +121,12 @@ public class LevelSurround extends Page content.getChildren().add(root); - game.start(); + new AnimationTimer() { + @Override + public void handle(long now) { + game.start(); + } + }.start(); } @Override diff --git a/src/main/java/net/sowgro/npehero/levelapi/Note.java b/src/main/java/net/sowgro/npehero/levelapi/Note.java index ab93885..4010867 100644 --- a/src/main/java/net/sowgro/npehero/levelapi/Note.java +++ b/src/main/java/net/sowgro/npehero/levelapi/Note.java @@ -31,4 +31,8 @@ public class Note { this.lane = other.lane; this.time.set(other.time.get()); } + + public double getTime() { + return time.get(); + } } diff --git a/src/main/java/net/sowgro/npehero/main/Control.java b/src/main/java/net/sowgro/npehero/main/Control.java index ece88ac..69bf669 100644 --- a/src/main/java/net/sowgro/npehero/main/Control.java +++ b/src/main/java/net/sowgro/npehero/main/Control.java @@ -28,19 +28,46 @@ public enum Control { LEGACY_PRINT ("Print Time", KeyCode.Q), LEGACY_STOP ("Stop Edit", KeyCode.ESCAPE); - public final String label; - public final KeyCode defaultKey; - public final ObjectProperty keyProperty = new SimpleObjectProperty<>(); - public static final List>> sections = List.of( entry("Gameplay", List.of(LANE0, LANE1, LANE2, LANE3, LANE4)), entry("Editor", List.of(DELETE_NOTE, NOTE_UP, NOTE_DOWN, SCROLL_LOCK, PLAY_PAUSE, CLEAR_SELECTION, SELECT_ALL)), entry("Legacy Editor", List.of(LEGACY_PRINT, LEGACY_STOP)) ); + public static final Control[] lanes = { + LANE0, + LANE1, + LANE2, + LANE3, + LANE4, + }; + private static final File file = new File("controls.json"); private static final Gson json = new GsonBuilder().serializeNulls().setPrettyPrinting().create(); + public static void writeToFile() throws IOException { + Map data = new HashMap<>(); + for (Control control : Control.values()) { + data.put(control.toString(), control.getKey().toString()); + } + FileWriter fileWriter = new FileWriter(file); + json.toJson(data, fileWriter); + fileWriter.close(); + } + + public static void readFromFile() throws Exception { + Map data = json.fromJson(new FileReader(file), Map.class); + for (Control control : Control.values()) { + if (data.containsKey(control.toString())) { + control.setKey(KeyCode.valueOf((String) data.getOrDefault(control.toString(), null))); + } + } + } + + public final String label; + public final KeyCode defaultKey; + public final ObjectProperty keyProperty = new SimpleObjectProperty<>(); + Control(String label, KeyCode key) { this.label = label; this.defaultKey = key; @@ -81,23 +108,4 @@ public enum Control { } }; } - - public static void writeToFile() throws IOException { - Map data = new HashMap<>(); - for (Control control : Control.values()) { - data.put(control.toString(), control.getKey().toString()); - } - FileWriter fileWriter = new FileWriter(file); - json.toJson(data, fileWriter); - fileWriter.close(); - } - - public static void readFromFile() throws Exception { - Map data = json.fromJson(new FileReader(file), Map.class); - for (Control control : Control.values()) { - if (data.containsKey(control.toString())) { - control.setKey(KeyCode.valueOf((String) data.getOrDefault(control.toString(), null))); - } - } - } } diff --git a/src/main/java/net/sowgro/npehero/main/Sound.java b/src/main/java/net/sowgro/npehero/main/Sound.java index 088eab6..cf776a6 100755 --- a/src/main/java/net/sowgro/npehero/main/Sound.java +++ b/src/main/java/net/sowgro/npehero/main/Sound.java @@ -28,6 +28,7 @@ public class Sound songMediaPlayer = new MediaPlayer(song); if (song == MENU_SONG) { songMediaPlayer.muteProperty().bind(Settings.enableMenuMusic.not()); + songMediaPlayer.setCycleCount(MediaPlayer.INDEFINITE); } songMediaPlayer.volumeProperty().bind(Settings.musicVol); songMediaPlayer.play(); -- cgit v1.2.3