Implement playback speed in replays.

This commit is contained in:
Pavel Kolchev 2015-04-02 19:38:45 +03:00
parent 5f3ce74c64
commit d8425197a7
8 changed files with 105 additions and 9 deletions

BIN
res/playback-05x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

BIN
res/playback-1x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

BIN
res/playback-2x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

@ -104,6 +104,10 @@ public enum GameImage {
} }
}, },
REPLAY_05XPLAYBACK ("playback-05x", "png"),
REPLAY_1XPLAYBACK ("playback-1x", "png"),
REPLAY_2XPLAYBACK ("playback-2x", "png"),
// Circle // Circle
HITCIRCLE ("hitcircle", "png"), HITCIRCLE ("hitcircle", "png"),
HITCIRCLE_OVERLAY ("hitcircleoverlay", "png"), HITCIRCLE_OVERLAY ("hitcircleoverlay", "png"),

View File

@ -279,6 +279,11 @@ public class MenuButton {
*/ */
public void removeHoverEffects() { hoverEffect = 0; } public void removeHoverEffects() { hoverEffect = 0; }
/**
* Sets the image of the button.
*/
public void setImage(Image image) { img = image; }
/** /**
* Sets the "expand" hover effect. * Sets the "expand" hover effect.
*/ */

View File

@ -279,13 +279,13 @@ public class MusicController {
* Plays the current track. * Plays the current track.
* @param loop whether or not to loop the track * @param loop whether or not to loop the track
*/ */
public static void play(float pitch, boolean loop) { public static void play(boolean loop) {
if (trackExists()) { if (trackExists()) {
trackEnded = false; trackEnded = false;
if (loop) if (loop)
player.loop(); player.loop();
else else
player.play(pitch, 1f); player.play();
} }
} }
@ -297,6 +297,14 @@ public class MusicController {
SoundStore.get().setMusicVolume((isTrackDimmed()) ? volume * dimLevel : volume); SoundStore.get().setMusicVolume((isTrackDimmed()) ? volume * dimLevel : volume);
} }
/**
* Sets the music pitch.
* @param pitch [0, ..]
*/
public static void setPitch(float pitch) {
SoundStore.get().setMusicPitch(pitch);
}
/** /**
* Returns whether or not the current track has ended. * Returns whether or not the current track has ended.
*/ */

View File

@ -0,0 +1,50 @@
package itdelatrisu.opsu.replay;
import itdelatrisu.opsu.GameImage;
import itdelatrisu.opsu.GameMod;
import org.newdawn.slick.Image;
public enum PlaybackSpeed {
NORMAL(GameImage.REPLAY_1XPLAYBACK, 1f),
DOUBLE(GameImage.REPLAY_2XPLAYBACK, 2f),
HALF(GameImage.REPLAY_05XPLAYBACK, 0.5f);
/** The file name of the button image. */
private GameImage gameImage;
/** The speed modifier of the playback. */
private float modifier;
PlaybackSpeed(GameImage gameImage, float modifier) {
this.gameImage = gameImage;
this.modifier = modifier;
}
private static int index = 1;
public static PlaybackSpeed next() {
PlaybackSpeed next = values()[index++ % values().length];
if((GameMod.DOUBLE_TIME.isActive() && next == PlaybackSpeed.DOUBLE) ||
(GameMod.HALF_TIME.isActive() && next == PlaybackSpeed.HALF))
next = next();
return next;
}
public static void reset() {
index = 1;
}
/**
* Returns the image.
* @return the associated image
*/
public Image getImage() { return gameImage.getImage(); }
/**
* Returns the speed modifier.
* @return the speed
*/
public float getModifier() { return modifier; }
}

View File

@ -50,6 +50,7 @@ import java.io.File;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.Stack; import java.util.Stack;
import itdelatrisu.opsu.replay.PlaybackSpeed;
import org.lwjgl.input.Keyboard; import org.lwjgl.input.Keyboard;
import org.lwjgl.opengl.Display; import org.lwjgl.opengl.Display;
import org.newdawn.slick.Animation; import org.newdawn.slick.Animation;
@ -131,6 +132,9 @@ public class Game extends BasicGameState {
/** Skip button (displayed at song start, when necessary). */ /** Skip button (displayed at song start, when necessary). */
private MenuButton skipButton; private MenuButton skipButton;
/** Playback button (displayed in replays). */
private MenuButton playbackButton;
/** Current timing point index in timingPoints ArrayList. */ /** Current timing point index in timingPoints ArrayList. */
private int timingPointIndex; private int timingPointIndex;
@ -527,6 +531,9 @@ public class Game extends BasicGameState {
cursorCirclePulse.drawCentered(pausedMouseX, pausedMouseY); cursorCirclePulse.drawCentered(pausedMouseX, pausedMouseY);
} }
if (isReplay || GameMod.AUTO.isActive())
playbackButton.draw();
if (isReplay) if (isReplay)
UI.draw(g, replayX, replayY, replayKeyPressed); UI.draw(g, replayX, replayY, replayKeyPressed);
else if (GameMod.AUTO.isActive()) else if (GameMod.AUTO.isActive())
@ -544,6 +551,8 @@ public class Game extends BasicGameState {
UI.update(delta); UI.update(delta);
int mouseX = input.getMouseX(), mouseY = input.getMouseY(); int mouseX = input.getMouseX(), mouseY = input.getMouseY();
skipButton.hoverUpdate(delta, mouseX, mouseY); skipButton.hoverUpdate(delta, mouseX, mouseY);
if (isReplay || GameMod.AUTO.isActive())
playbackButton.hoverUpdate(delta, mouseX, mouseY);
int trackPosition = MusicController.getPosition(); int trackPosition = MusicController.getPosition();
// returning from pause screen: must click previous mouse position // returning from pause screen: must click previous mouse position
@ -871,16 +880,24 @@ public class Game extends BasicGameState {
@Override @Override
public void mousePressed(int button, int x, int y) { public void mousePressed(int button, int x, int y) {
if (Options.isMouseDisabled())
return;
// watching replay // watching replay
if (isReplay) { if (isReplay || GameMod.AUTO.isActive()) {
// only allow skip button // allow skip button
if (button != Input.MOUSE_MIDDLE_BUTTON && skipButton.contains(x, y)) if (button != Input.MOUSE_MIDDLE_BUTTON && skipButton.contains(x, y)) {
skipIntro(); skipIntro();
return; return;
} }
if (button != Input.MOUSE_MIDDLE_BUTTON && playbackButton.contains(x, y)) {
PlaybackSpeed playbackSpeed = PlaybackSpeed.next();
playbackButton.setImage(playbackSpeed.getImage());
MusicController.setPitch(GameMod.getSpeedMultiplier() * playbackSpeed.getModifier());
return;
}
return;
}
if (Options.isMouseDisabled())
return;
// mouse wheel: pause the game // mouse wheel: pause the game
if (button == Input.MOUSE_MIDDLE_BUTTON && !Options.isMouseWheelDisabled()) { if (button == Input.MOUSE_MIDDLE_BUTTON && !Options.isMouseWheelDisabled()) {
@ -1085,6 +1102,8 @@ public class Game extends BasicGameState {
previousMods = GameMod.getModState(); previousMods = GameMod.getModState();
GameMod.loadModState(replay.mods); GameMod.loadModState(replay.mods);
PlaybackSpeed.reset();
// load initial data // load initial data
replayX = container.getWidth() / 2; replayX = container.getWidth() / 2;
replayY = container.getHeight() / 2; replayY = container.getHeight() / 2;
@ -1116,12 +1135,15 @@ public class Game extends BasicGameState {
restart = Restart.FALSE; restart = Restart.FALSE;
// needs to play before setting position to resume without lag later // needs to play before setting position to resume without lag later
MusicController.play(GameMod.getSpeedMultiplier(), false); MusicController.play(false);
MusicController.setPosition(0); MusicController.setPosition(0);
MusicController.setPitch(GameMod.getSpeedMultiplier());
MusicController.pause(); MusicController.pause();
} }
skipButton.resetHover(); skipButton.resetHover();
if (isReplay || GameMod.AUTO.isActive())
playbackButton.resetHover();
} }
@Override @Override
@ -1280,6 +1302,7 @@ public class Game extends BasicGameState {
MusicController.resume(); MusicController.resume();
} }
MusicController.setPosition(firstObjectTime - SKIP_OFFSET); MusicController.setPosition(firstObjectTime - SKIP_OFFSET);
MusicController.setPitch(GameMod.getSpeedMultiplier());
replaySkipTime = (isReplay) ? -1 : trackPosition; replaySkipTime = (isReplay) ? -1 : trackPosition;
if (isReplay) { if (isReplay) {
replayX = (int) skipButton.getX(); replayX = (int) skipButton.getX();
@ -1317,6 +1340,12 @@ public class Game extends BasicGameState {
} }
skipButton.setHoverExpand(1.1f, MenuButton.Expand.UP_LEFT); skipButton.setHoverExpand(1.1f, MenuButton.Expand.UP_LEFT);
if (isReplay || GameMod.AUTO.isActive()) {
Image playback = GameImage.REPLAY_1XPLAYBACK.getImage();
playbackButton = new MenuButton(playback, width * 0.98f - (playback.getWidth() / 2f), height * 0.25f);
playbackButton.setHoverExpand(1.1f, MenuButton.Expand.CENTER);
}
// load other images... // load other images...
((GamePauseMenu) game.getState(Opsu.STATE_GAMEPAUSEMENU)).loadImages(); ((GamePauseMenu) game.getState(Opsu.STATE_GAMEPAUSEMENU)).loadImages();
data.loadImages(); data.loadImages();