Follow-up to #99: replay seeking improvements.
- Added on/off option for replay seeking in the "custom" menu. - Mute sounds while seeking. - Draw a bar on the left of the screen during replays for seeking (instead of just clicking near the top of the screen). Signed-off-by: Jeffrey Han <itdelatrisu@gmail.com>
This commit is contained in:
parent
495a7e7f8b
commit
2167698740
|
@ -453,7 +453,8 @@ public class Options {
|
||||||
val - TimeUnit.MINUTES.toSeconds(TimeUnit.SECONDS.toMinutes(val)));
|
val - TimeUnit.MINUTES.toSeconds(TimeUnit.SECONDS.toMinutes(val)));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
ENABLE_THEME_SONG ("Enable Theme Song", "MenuMusic", "Whether to play the theme song upon starting opsu!", true);
|
ENABLE_THEME_SONG ("Enable Theme Song", "MenuMusic", "Whether to play the theme song upon starting opsu!", true),
|
||||||
|
REPLAY_SEEKING ("Replay Seeking", "ReplaySeeking", "Enable a seeking bar on the left side of the screen during replays.", false);
|
||||||
|
|
||||||
/** Option name. */
|
/** Option name. */
|
||||||
private String name;
|
private String name;
|
||||||
|
@ -958,6 +959,12 @@ public class Options {
|
||||||
*/
|
*/
|
||||||
public static boolean isThemeSongEnabled() { return GameOption.ENABLE_THEME_SONG.getBooleanValue(); }
|
public static boolean isThemeSongEnabled() { return GameOption.ENABLE_THEME_SONG.getBooleanValue(); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether or not replay seeking is enabled.
|
||||||
|
* @return true if enabled
|
||||||
|
*/
|
||||||
|
public static boolean isReplaySeekingEnabled() { return GameOption.REPLAY_SEEKING.getBooleanValue(); }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the track checkpoint time, if within bounds.
|
* Sets the track checkpoint time, if within bounds.
|
||||||
* @param time the track position (in ms)
|
* @param time the track position (in ms)
|
||||||
|
|
|
@ -59,6 +59,9 @@ public class SoundController {
|
||||||
/** Sample volume multiplier, from timing points [0, 1]. */
|
/** Sample volume multiplier, from timing points [0, 1]. */
|
||||||
private static float sampleVolumeMultiplier = 1f;
|
private static float sampleVolumeMultiplier = 1f;
|
||||||
|
|
||||||
|
/** Whether all sounds are muted. */
|
||||||
|
private static boolean isMuted;
|
||||||
|
|
||||||
/** The name of the current sound file being loaded. */
|
/** The name of the current sound file being loaded. */
|
||||||
private static String currentFileName;
|
private static String currentFileName;
|
||||||
|
|
||||||
|
@ -261,7 +264,7 @@ public class SoundController {
|
||||||
if (clip == null) // clip failed to load properly
|
if (clip == null) // clip failed to load properly
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (volume > 0f) {
|
if (volume > 0f && !isMuted) {
|
||||||
try {
|
try {
|
||||||
clip.start(volume, listener);
|
clip.start(volume, listener);
|
||||||
} catch (LineUnavailableException e) {
|
} catch (LineUnavailableException e) {
|
||||||
|
@ -317,6 +320,12 @@ public class SoundController {
|
||||||
playClip(s.getClip(), Options.getHitSoundVolume() * sampleVolumeMultiplier * Options.getMasterVolume(), null);
|
playClip(s.getClip(), Options.getHitSoundVolume() * sampleVolumeMultiplier * Options.getMasterVolume(), null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mutes or unmutes all sounds (hit sounds and sound effects).
|
||||||
|
* @param mute true to mute, false to unmute
|
||||||
|
*/
|
||||||
|
public static void mute(boolean mute) { isMuted = mute; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the name of the current file being loaded, or null if none.
|
* Returns the name of the current file being loaded, or null if none.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -220,6 +220,15 @@ public class Game extends BasicGameState {
|
||||||
/** Whether the game is currently seeking to a replay position. */
|
/** Whether the game is currently seeking to a replay position. */
|
||||||
private boolean isSeeking;
|
private boolean isSeeking;
|
||||||
|
|
||||||
|
/** Music position bar coordinates and dimensions (for replay seeking). */
|
||||||
|
private float musicBarX, musicBarY, musicBarWidth, musicBarHeight;
|
||||||
|
|
||||||
|
/** Music position bar background colors. */
|
||||||
|
private static final Color
|
||||||
|
MUSICBAR_NORMAL = new Color(12, 9, 10, 0.25f),
|
||||||
|
MUSICBAR_HOVER = new Color(12, 9, 10, 0.35f),
|
||||||
|
MUSICBAR_FILL = new Color(255, 255, 255, 0.75f);
|
||||||
|
|
||||||
// game-related variables
|
// game-related variables
|
||||||
private GameContainer container;
|
private GameContainer container;
|
||||||
private StateBasedGame game;
|
private StateBasedGame game;
|
||||||
|
@ -245,6 +254,12 @@ public class Game extends BasicGameState {
|
||||||
gOffscreen = offscreen.getGraphics();
|
gOffscreen = offscreen.getGraphics();
|
||||||
gOffscreen.setBackground(Color.black);
|
gOffscreen.setBackground(Color.black);
|
||||||
|
|
||||||
|
// initialize music position bar location
|
||||||
|
musicBarX = width * 0.01f;
|
||||||
|
musicBarY = height * 0.05f;
|
||||||
|
musicBarWidth = Math.max(width * 0.005f, 7);
|
||||||
|
musicBarHeight = height * 0.9f;
|
||||||
|
|
||||||
// create the associated GameData object
|
// create the associated GameData object
|
||||||
data = new GameData(width, height);
|
data = new GameData(width, height);
|
||||||
}
|
}
|
||||||
|
@ -525,6 +540,18 @@ public class Game extends BasicGameState {
|
||||||
if (isReplay || GameMod.AUTO.isActive())
|
if (isReplay || GameMod.AUTO.isActive())
|
||||||
playbackSpeed.getButton().draw();
|
playbackSpeed.getButton().draw();
|
||||||
|
|
||||||
|
// draw music position bar (for replay seeking)
|
||||||
|
if (isReplay && Options.isReplaySeekingEnabled()) {
|
||||||
|
int mouseX = input.getMouseX(), mouseY = input.getMouseY();
|
||||||
|
g.setColor((musicPositionBarContains(mouseX, mouseY)) ? MUSICBAR_HOVER : MUSICBAR_NORMAL);
|
||||||
|
g.fillRoundRect(musicBarX, musicBarY, musicBarWidth, musicBarHeight, 4);
|
||||||
|
if (!isLeadIn()) {
|
||||||
|
g.setColor(MUSICBAR_FILL);
|
||||||
|
float musicBarPosition = Math.min((float) trackPosition / beatmap.endTime, 1f);
|
||||||
|
g.fillRoundRect(musicBarX, musicBarY, musicBarWidth, musicBarHeight * musicBarPosition, 4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// returning from pause screen
|
// returning from pause screen
|
||||||
if (pauseTime > -1 && pausedMouseX > -1 && pausedMouseY > -1) {
|
if (pauseTime > -1 && pausedMouseX > -1 && pausedMouseY > -1) {
|
||||||
// darken the screen
|
// darken the screen
|
||||||
|
@ -613,7 +640,7 @@ public class Game extends BasicGameState {
|
||||||
if (replayIndex >= replay.frames.length)
|
if (replayIndex >= replay.frames.length)
|
||||||
updateGame(replayX, replayY, delta, MusicController.getPosition(), lastKeysPressed);
|
updateGame(replayX, replayY, delta, MusicController.getPosition(), lastKeysPressed);
|
||||||
|
|
||||||
//TODO probably should to disable sounds then reseek to the new position
|
// seeking to a position earlier than original track position
|
||||||
if (isSeeking && replayIndex - 1 >= 1 && replayIndex < replay.frames.length &&
|
if (isSeeking && replayIndex - 1 >= 1 && replayIndex < replay.frames.length &&
|
||||||
trackPosition < replay.frames[replayIndex - 1].getTime()) {
|
trackPosition < replay.frames[replayIndex - 1].getTime()) {
|
||||||
replayIndex = 0;
|
replayIndex = 0;
|
||||||
|
@ -633,7 +660,6 @@ public class Game extends BasicGameState {
|
||||||
timingPointIndex++;
|
timingPointIndex++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
isSeeking = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// update and run replay frames
|
// update and run replay frames
|
||||||
|
@ -648,6 +674,12 @@ public class Game extends BasicGameState {
|
||||||
}
|
}
|
||||||
mouseX = replayX;
|
mouseX = replayX;
|
||||||
mouseY = replayY;
|
mouseY = replayY;
|
||||||
|
|
||||||
|
// unmute sounds
|
||||||
|
if (isSeeking) {
|
||||||
|
isSeeking = false;
|
||||||
|
SoundController.mute(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
data.updateDisplays(delta);
|
data.updateDisplays(delta);
|
||||||
|
@ -923,9 +955,10 @@ public class Game extends BasicGameState {
|
||||||
MusicController.setPitch(GameMod.getSpeedMultiplier() * playbackSpeed.getModifier());
|
MusicController.setPitch(GameMod.getSpeedMultiplier() * playbackSpeed.getModifier());
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO
|
// replay seeking
|
||||||
else if (!GameMod.AUTO.isActive() && y < 50) {
|
else if (Options.isReplaySeekingEnabled() && !GameMod.AUTO.isActive() && musicPositionBarContains(x, y)) {
|
||||||
float pos = (float) x / container.getWidth() * beatmap.endTime;
|
SoundController.mute(true); // mute sounds while seeking
|
||||||
|
float pos = (y - musicBarY) / musicBarHeight * beatmap.endTime;
|
||||||
MusicController.setPosition((int) pos);
|
MusicController.setPosition((int) pos);
|
||||||
isSeeking = true;
|
isSeeking = true;
|
||||||
}
|
}
|
||||||
|
@ -1188,6 +1221,8 @@ public class Game extends BasicGameState {
|
||||||
MusicController.setPosition(0);
|
MusicController.setPosition(0);
|
||||||
MusicController.setPitch(GameMod.getSpeedMultiplier());
|
MusicController.setPitch(GameMod.getSpeedMultiplier());
|
||||||
MusicController.pause();
|
MusicController.pause();
|
||||||
|
|
||||||
|
SoundController.mute(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
skipButton.resetHover();
|
skipButton.resetHover();
|
||||||
|
@ -1753,4 +1788,14 @@ public class Game extends BasicGameState {
|
||||||
gameObjects[i].updatePosition();
|
gameObjects[i].updatePosition();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the coordinates are within the music position bar bounds.
|
||||||
|
* @param cx the x coordinate
|
||||||
|
* @param cy the y coordinate
|
||||||
|
*/
|
||||||
|
private boolean musicPositionBarContains(float cx, float cy) {
|
||||||
|
return ((cx > musicBarX && cx < musicBarX + musicBarWidth) &&
|
||||||
|
(cy > musicBarY && cy < musicBarY + musicBarHeight));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -93,7 +93,8 @@ public class OptionsMenu extends BasicGameState {
|
||||||
GameOption.FIXED_HP,
|
GameOption.FIXED_HP,
|
||||||
GameOption.FIXED_AR,
|
GameOption.FIXED_AR,
|
||||||
GameOption.FIXED_OD,
|
GameOption.FIXED_OD,
|
||||||
GameOption.CHECKPOINT
|
GameOption.CHECKPOINT,
|
||||||
|
GameOption.REPLAY_SEEKING
|
||||||
});
|
});
|
||||||
|
|
||||||
/** Total number of tabs. */
|
/** Total number of tabs. */
|
||||||
|
|
Loading…
Reference in New Issue
Block a user