Added initial sound effect support.
- Added SoundController module, which uses Java Sound since OpenAL has a slight delay on playing sounds. - Uploaded all effect WAVs. (credits: WWWskin, AL's IA, Fantasy's Skin, Minimalist Miku) - Added a missing entry in credits. Signed-off-by: Jeffrey Han <itdelatrisu@gmail.com>
This commit is contained in:
@@ -25,6 +25,7 @@ import itdelatrisu.opsu.Opsu;
|
||||
import itdelatrisu.opsu.OsuFile;
|
||||
import itdelatrisu.opsu.OsuHitObject;
|
||||
import itdelatrisu.opsu.OsuTimingPoint;
|
||||
import itdelatrisu.opsu.SoundController;
|
||||
import itdelatrisu.opsu.objects.Circle;
|
||||
import itdelatrisu.opsu.objects.Slider;
|
||||
import itdelatrisu.opsu.objects.Spinner;
|
||||
@@ -134,6 +135,11 @@ public class Game extends BasicGameState {
|
||||
*/
|
||||
private int breakTime = 0;
|
||||
|
||||
/**
|
||||
* Whether the break sound has been played.
|
||||
*/
|
||||
private boolean breakSound;
|
||||
|
||||
/**
|
||||
* Skip button (displayed at song start, when necessary).
|
||||
*/
|
||||
@@ -164,6 +170,13 @@ public class Game extends BasicGameState {
|
||||
countdown2, // "1" text
|
||||
countdownGo; // "GO!" text
|
||||
|
||||
/**
|
||||
* Whether the countdown sound has been played.
|
||||
*/
|
||||
private boolean
|
||||
countdownReadySound, countdown3Sound, countdown1Sound,
|
||||
countdown2Sound, countdownGoSound;
|
||||
|
||||
/**
|
||||
* Glowing hit circle outline which must be clicked when returning from pause menu.
|
||||
*/
|
||||
@@ -276,10 +289,19 @@ public class Game extends BasicGameState {
|
||||
trackPosition - breakTime > 2000 &&
|
||||
trackPosition - breakTime < 5000) {
|
||||
// show break start
|
||||
if (score.getHealth() >= 50)
|
||||
if (score.getHealth() >= 50) {
|
||||
breakStartPass.drawCentered(width / 2f, height / 2f);
|
||||
else
|
||||
if (!breakSound) {
|
||||
SoundController.playSound(SoundController.SOUND_SECTIONPASS);
|
||||
breakSound = true;
|
||||
}
|
||||
} else {
|
||||
breakStartFail.drawCentered(width / 2f, height / 2f);
|
||||
if (!breakSound) {
|
||||
SoundController.playSound(SoundController.SOUND_SECTIONFAIL);
|
||||
breakSound = true;
|
||||
}
|
||||
}
|
||||
} else if (breakLength >= 4000) {
|
||||
// show break end (flash twice for 500ms)
|
||||
int endTimeDiff = endTime - trackPosition;
|
||||
@@ -326,18 +348,41 @@ public class Game extends BasicGameState {
|
||||
if (osu.countdown > 0) { // TODO: implement half/double rate settings
|
||||
int timeDiff = osu.objects[0].time - trackPosition;
|
||||
if (timeDiff >= 500 && timeDiff < 3000) {
|
||||
if (timeDiff >= 1500)
|
||||
if (timeDiff >= 1500) {
|
||||
countdownReady.drawCentered(width / 2, height / 2);
|
||||
|
||||
if (timeDiff < 2000)
|
||||
if (!countdownReadySound) {
|
||||
SoundController.playSound(SoundController.SOUND_READY);
|
||||
countdownReadySound = true;
|
||||
}
|
||||
}
|
||||
if (timeDiff < 2000) {
|
||||
countdown3.draw(0, 0);
|
||||
if (timeDiff < 1500)
|
||||
if (!countdown3Sound) {
|
||||
SoundController.playSound(SoundController.SOUND_COUNT3);
|
||||
countdown3Sound = true;
|
||||
}
|
||||
}
|
||||
if (timeDiff < 1500) {
|
||||
countdown2.draw(width - countdown2.getWidth(), 0);
|
||||
if (timeDiff < 1000)
|
||||
if (!countdown2Sound) {
|
||||
SoundController.playSound(SoundController.SOUND_COUNT2);
|
||||
countdown2Sound = true;
|
||||
}
|
||||
}
|
||||
if (timeDiff < 1000) {
|
||||
countdown1.drawCentered(width / 2, height / 2);
|
||||
if (!countdown1Sound) {
|
||||
SoundController.playSound(SoundController.SOUND_COUNT1);
|
||||
countdown1Sound = true;
|
||||
}
|
||||
}
|
||||
} else if (timeDiff >= -500 && timeDiff < 500) {
|
||||
countdownGo.setAlpha((timeDiff < 0) ? 1 - (timeDiff / -1000f) : 1);
|
||||
countdownGo.drawCentered(width / 2, height / 2);
|
||||
if (!countdownGoSound) {
|
||||
SoundController.playSound(SoundController.SOUND_GO);
|
||||
countdownGoSound = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -432,6 +477,8 @@ public class Game extends BasicGameState {
|
||||
beatLengthBase = beatLength = timingPoint.beatLength;
|
||||
else
|
||||
beatLength = beatLengthBase * (timingPoint.velocity / -100f);
|
||||
SoundController.setSampleSet(timingPoint.sampleType);
|
||||
SoundController.setSampleVolume(timingPoint.sampleVolume);
|
||||
timingPointIndex++;
|
||||
}
|
||||
}
|
||||
@@ -456,6 +503,7 @@ public class Game extends BasicGameState {
|
||||
} else if (trackPosition >= breakValue) {
|
||||
// start a break
|
||||
breakTime = breakValue;
|
||||
breakSound = false;
|
||||
breakIndex++;
|
||||
return;
|
||||
}
|
||||
@@ -638,22 +686,33 @@ public class Game extends BasicGameState {
|
||||
}
|
||||
}
|
||||
|
||||
// reset indexes
|
||||
// reset data
|
||||
MusicController.setPosition(0);
|
||||
MusicController.pause();
|
||||
score.clear();
|
||||
objectIndex = 0;
|
||||
breakIndex = 0;
|
||||
breakTime = 0;
|
||||
breakSound = false;
|
||||
timingPointIndex = 0;
|
||||
pauseTime = -1;
|
||||
pausedMouseX = -1;
|
||||
pausedMouseY = -1;
|
||||
countdownReadySound = false;
|
||||
countdown3Sound = false;
|
||||
countdown1Sound = false;
|
||||
countdown2Sound = false;
|
||||
countdownGoSound = false;
|
||||
|
||||
// load the first timingPoint
|
||||
if (!osu.timingPoints.isEmpty() && osu.timingPoints.get(0).velocity >= 0) {
|
||||
beatLengthBase = beatLength = osu.timingPoints.get(0).beatLength;
|
||||
timingPointIndex++;
|
||||
if (!osu.timingPoints.isEmpty()) {
|
||||
OsuTimingPoint timingPoint = osu.timingPoints.get(0);
|
||||
if (timingPoint.velocity >= 0) {
|
||||
beatLengthBase = beatLength = timingPoint.beatLength;
|
||||
SoundController.setSampleSet(timingPoint.sampleType);
|
||||
SoundController.setSampleVolume(timingPoint.sampleVolume);
|
||||
timingPointIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
leadInTime = osu.audioLeadIn + approachTime;
|
||||
@@ -675,6 +734,7 @@ public class Game extends BasicGameState {
|
||||
MusicController.resume();
|
||||
}
|
||||
MusicController.setPosition(osu.objects[0].time - skipOffsetTime);
|
||||
SoundController.playSound(SoundController.SOUND_MENUHIT);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
@@ -21,6 +21,7 @@ package itdelatrisu.opsu.states;
|
||||
import itdelatrisu.opsu.GUIMenuButton;
|
||||
import itdelatrisu.opsu.MusicController;
|
||||
import itdelatrisu.opsu.Opsu;
|
||||
import itdelatrisu.opsu.SoundController;
|
||||
|
||||
import org.newdawn.slick.Color;
|
||||
import org.newdawn.slick.GameContainer;
|
||||
@@ -142,6 +143,7 @@ public class GamePauseMenu extends BasicGameState {
|
||||
if (Game.getRestart() == Game.RESTART_LOSE) {
|
||||
MusicController.stop();
|
||||
MusicController.playAt(Game.getOsuFile().previewTime, true);
|
||||
SoundController.playSound(SoundController.SOUND_MENUBACK);
|
||||
game.enterState(Opsu.STATE_SONGMENU, new FadeOutTransition(Color.black), new FadeInTransition(Color.black));
|
||||
} else
|
||||
unPause(Game.RESTART_FALSE);
|
||||
@@ -171,6 +173,7 @@ public class GamePauseMenu extends BasicGameState {
|
||||
} else if (backButton.contains(x, y)) {
|
||||
MusicController.pause(); // lose state
|
||||
MusicController.playAt(Game.getOsuFile().previewTime, true);
|
||||
SoundController.playSound(SoundController.SOUND_MENUBACK);
|
||||
game.enterState(Opsu.STATE_SONGMENU, new FadeOutTransition(Color.black), new FadeInTransition(Color.black));
|
||||
}
|
||||
}
|
||||
@@ -179,9 +182,10 @@ public class GamePauseMenu extends BasicGameState {
|
||||
public void enter(GameContainer container, StateBasedGame game)
|
||||
throws SlickException {
|
||||
pauseStartTime = System.currentTimeMillis();
|
||||
if (Game.getRestart() == Game.RESTART_LOSE)
|
||||
if (Game.getRestart() == Game.RESTART_LOSE) {
|
||||
MusicController.fadeOut(FADEOUT_TIME);
|
||||
else
|
||||
SoundController.playSound(SoundController.SOUND_FAIL);
|
||||
} else
|
||||
MusicController.pause();
|
||||
}
|
||||
|
||||
@@ -189,6 +193,10 @@ public class GamePauseMenu extends BasicGameState {
|
||||
* Unpause and return to the Game state.
|
||||
*/
|
||||
private void unPause(byte restart) {
|
||||
if (restart == Game.RESTART_MANUAL)
|
||||
SoundController.playSound(SoundController.SOUND_MENUHIT);
|
||||
else
|
||||
SoundController.playSound(SoundController.SOUND_MENUBACK);
|
||||
Game.setRestart(restart);
|
||||
game.enterState(Opsu.STATE_GAME);
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ import itdelatrisu.opsu.GameScore;
|
||||
import itdelatrisu.opsu.MusicController;
|
||||
import itdelatrisu.opsu.Opsu;
|
||||
import itdelatrisu.opsu.OsuFile;
|
||||
import itdelatrisu.opsu.SoundController;
|
||||
|
||||
import org.lwjgl.opengl.Display;
|
||||
import org.newdawn.slick.Color;
|
||||
@@ -143,7 +144,9 @@ public class GameRanking extends BasicGameState {
|
||||
public void keyPressed(int key, char c) {
|
||||
switch (key) {
|
||||
case Input.KEY_ESCAPE:
|
||||
MusicController.pause();
|
||||
MusicController.playAt(Game.getOsuFile().previewTime, true);
|
||||
SoundController.playSound(SoundController.SOUND_MENUBACK);
|
||||
game.enterState(Opsu.STATE_SONGMENU, new FadeOutTransition(Color.black), new FadeInTransition(Color.black));
|
||||
break;
|
||||
case Input.KEY_F12:
|
||||
@@ -162,12 +165,15 @@ public class GameRanking extends BasicGameState {
|
||||
OsuFile osu = Game.getOsuFile();
|
||||
Display.setTitle(String.format("%s - %s", game.getTitle(), osu.toString()));
|
||||
Game.setRestart(Game.RESTART_MANUAL);
|
||||
SoundController.playSound(SoundController.SOUND_MENUHIT);
|
||||
game.enterState(Opsu.STATE_GAME, new FadeOutTransition(Color.black), new FadeInTransition(Color.black));
|
||||
} else if (exitButton.contains(x, y))
|
||||
} else if (exitButton.contains(x, y)) {
|
||||
SoundController.playSound(SoundController.SOUND_MENUBACK);
|
||||
game.enterState(Opsu.STATE_MAINMENU, new FadeOutTransition(Color.black), new FadeInTransition(Color.black));
|
||||
else if (Options.getBackButton().contains(x, y)) {
|
||||
MusicController.stop();
|
||||
} else if (Options.getBackButton().contains(x, y)) {
|
||||
MusicController.pause();
|
||||
MusicController.playAt(Game.getOsuFile().previewTime, true);
|
||||
SoundController.playSound(SoundController.SOUND_MENUBACK);
|
||||
game.enterState(Opsu.STATE_SONGMENU, new FadeOutTransition(Color.black), new FadeInTransition(Color.black));
|
||||
}
|
||||
}
|
||||
@@ -176,5 +182,6 @@ public class GameRanking extends BasicGameState {
|
||||
public void enter(GameContainer container, StateBasedGame game)
|
||||
throws SlickException {
|
||||
Display.setTitle(game.getTitle());
|
||||
SoundController.playSound(SoundController.SOUND_APPLAUSE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import itdelatrisu.opsu.GUIMenuButton;
|
||||
import itdelatrisu.opsu.MusicController;
|
||||
import itdelatrisu.opsu.Opsu;
|
||||
import itdelatrisu.opsu.OsuGroupNode;
|
||||
import itdelatrisu.opsu.SoundController;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
@@ -287,17 +288,22 @@ public class MainMenu extends BasicGameState {
|
||||
logoTimer = 0;
|
||||
playButton.getImage().setAlpha(0f);
|
||||
exitButton.getImage().setAlpha(0f);
|
||||
SoundController.playSound(SoundController.SOUND_MENUHIT);
|
||||
}
|
||||
}
|
||||
|
||||
// other button actions (if visible)
|
||||
else if (logoClicked) {
|
||||
if (logo.contains(x, y))
|
||||
if (logo.contains(x, y)) {
|
||||
SoundController.playSound(SoundController.SOUND_MENUHIT);
|
||||
logoTimer = MOVE_DELAY;
|
||||
else if (playButton.contains(x, y))
|
||||
} else if (playButton.contains(x, y)) {
|
||||
SoundController.playSound(SoundController.SOUND_MENUHIT);
|
||||
game.enterState(Opsu.STATE_SONGMENU, new FadeOutTransition(Color.black), new FadeInTransition(Color.black));
|
||||
else if (exitButton.contains(x, y))
|
||||
} else if (exitButton.contains(x, y)) {
|
||||
SoundController.playSound(SoundController.SOUND_MENUHIT);
|
||||
game.enterState(Opsu.STATE_MAINMENUEXIT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ package itdelatrisu.opsu.states;
|
||||
|
||||
import itdelatrisu.opsu.GUIMenuButton;
|
||||
import itdelatrisu.opsu.Opsu;
|
||||
import itdelatrisu.opsu.SoundController;
|
||||
|
||||
import java.awt.Font;
|
||||
import java.io.BufferedReader;
|
||||
@@ -148,12 +149,13 @@ public class Options extends BasicGameState {
|
||||
// OPTIONS_FULLSCREEN = ,
|
||||
OPTIONS_TARGET_FPS = 1,
|
||||
OPTIONS_MUSIC_VOLUME = 2,
|
||||
OPTIONS_MUSIC_OFFSET = 3,
|
||||
OPTIONS_SCREENSHOT_FORMAT = 4,
|
||||
OPTIONS_DISPLAY_FPS = 5,
|
||||
OPTIONS_HIT_LIGHTING = 6,
|
||||
OPTIONS_COMBO_BURSTS = 7,
|
||||
OPTIONS_MAX = 8; // not an option
|
||||
OPTIONS_EFFECT_VOLUME = 3,
|
||||
OPTIONS_MUSIC_OFFSET = 4,
|
||||
OPTIONS_SCREENSHOT_FORMAT = 5,
|
||||
OPTIONS_DISPLAY_FPS = 6,
|
||||
OPTIONS_HIT_LIGHTING = 7,
|
||||
OPTIONS_COMBO_BURSTS = 8,
|
||||
OPTIONS_MAX = 9; // not an option
|
||||
|
||||
/**
|
||||
* Screen resolutions.
|
||||
@@ -208,7 +210,12 @@ public class Options extends BasicGameState {
|
||||
/**
|
||||
* Default music volume.
|
||||
*/
|
||||
private static int musicVolume = 20;
|
||||
private static int musicVolume = 30;
|
||||
|
||||
/**
|
||||
* Default sound effect volume.
|
||||
*/
|
||||
private static int effectVolume = 20;
|
||||
|
||||
/**
|
||||
* Offset time, in milliseconds, for music position-related elements.
|
||||
@@ -258,8 +265,8 @@ public class Options extends BasicGameState {
|
||||
Options.game = game;
|
||||
this.input = container.getInput();
|
||||
|
||||
// game settings;
|
||||
container.setTargetFrameRate(60);
|
||||
// game settings
|
||||
container.setTargetFrameRate(targetFPS[targetFPSindex]);
|
||||
container.setMouseCursor("cursor.png", 16, 16);
|
||||
container.setMusicVolume(getMusicVolume());
|
||||
container.setShowFPS(false);
|
||||
@@ -375,6 +382,10 @@ public class Options extends BasicGameState {
|
||||
String.format("%d%%", musicVolume),
|
||||
"Global music volume."
|
||||
);
|
||||
this.drawOption(g, OPTIONS_EFFECT_VOLUME, "Effect Volume",
|
||||
String.format("%d%%", effectVolume),
|
||||
"Sound effect volume."
|
||||
);
|
||||
this.drawOption(g, OPTIONS_MUSIC_OFFSET, "Music Offset",
|
||||
String.format("%dms", musicOffset),
|
||||
"Adjust this value if hit objects are out of sync."
|
||||
@@ -509,6 +520,14 @@ public class Options extends BasicGameState {
|
||||
container.setMusicVolume(getMusicVolume());
|
||||
return;
|
||||
}
|
||||
if (isOptionClicked(OPTIONS_EFFECT_VOLUME, oldy)) {
|
||||
effectVolume += diff;
|
||||
if (effectVolume < 0)
|
||||
effectVolume = 0;
|
||||
else if (effectVolume > 100)
|
||||
effectVolume = 100;
|
||||
return;
|
||||
}
|
||||
if (isOptionClicked(OPTIONS_MUSIC_OFFSET, oldy)) {
|
||||
musicOffset += diff;
|
||||
if (musicOffset < -500)
|
||||
@@ -601,6 +620,12 @@ public class Options extends BasicGameState {
|
||||
*/
|
||||
public static float getMusicVolume() { return musicVolume / 100f; }
|
||||
|
||||
/**
|
||||
* Returns the default sound effect volume.
|
||||
* @return the sound volume [0, 1]
|
||||
*/
|
||||
public static float getEffectVolume() { return effectVolume / 100f; }
|
||||
|
||||
/**
|
||||
* Returns the music offset time.
|
||||
* @return the offset (in milliseconds)
|
||||
@@ -639,6 +664,8 @@ public class Options extends BasicGameState {
|
||||
SimpleDateFormat date = new SimpleDateFormat("yyyyMMdd_HHmmss");
|
||||
String file = date.format(new Date());
|
||||
|
||||
SoundController.playSound(SoundController.SOUND_SHUTTER);
|
||||
|
||||
// copy the screen
|
||||
Image screen = new Image(container.getWidth(), container.getHeight());
|
||||
container.getGraphics().copyArea(screen, 0, 0);
|
||||
@@ -760,6 +787,11 @@ public class Options extends BasicGameState {
|
||||
if (i >= 0 && i <= 100)
|
||||
musicVolume = i;
|
||||
break;
|
||||
case "VolumeEffect":
|
||||
i = Integer.parseInt(value);
|
||||
if (i >= 0 && i <= 100)
|
||||
effectVolume = i;
|
||||
break;
|
||||
case "Offset":
|
||||
i = Integer.parseInt(value);
|
||||
if (i >= -500 && i <= 500)
|
||||
@@ -827,6 +859,8 @@ public class Options extends BasicGameState {
|
||||
writer.newLine();
|
||||
writer.write(String.format("VolumeMusic = %d", musicVolume));
|
||||
writer.newLine();
|
||||
writer.write(String.format("VolumeEffect = %d", effectVolume));
|
||||
writer.newLine();
|
||||
writer.write(String.format("Offset = %d", musicOffset));
|
||||
writer.newLine();
|
||||
writer.write(String.format("ScreenshotFormat = %d", screenshotFormatIndex));
|
||||
|
||||
@@ -25,6 +25,7 @@ import itdelatrisu.opsu.OsuFile;
|
||||
import itdelatrisu.opsu.OsuGroupList;
|
||||
import itdelatrisu.opsu.OsuGroupNode;
|
||||
import itdelatrisu.opsu.OsuParser;
|
||||
import itdelatrisu.opsu.SoundController;
|
||||
|
||||
import org.lwjgl.opengl.Display;
|
||||
import org.newdawn.slick.Color;
|
||||
@@ -343,6 +344,7 @@ public class SongMenu extends BasicGameState {
|
||||
|
||||
// back
|
||||
if (Options.getBackButton().contains(x, y)) {
|
||||
SoundController.playSound(SoundController.SOUND_MENUBACK);
|
||||
game.enterState(Opsu.STATE_MAINMENU, new FadeOutTransition(Color.black), new FadeInTransition(Color.black));
|
||||
return;
|
||||
}
|
||||
@@ -422,8 +424,10 @@ public class SongMenu extends BasicGameState {
|
||||
if (!search.getText().isEmpty()) {
|
||||
search.setText("");
|
||||
searchTimer = SEARCH_DELAY;
|
||||
} else
|
||||
} else {
|
||||
SoundController.playSound(SoundController.SOUND_MENUBACK);
|
||||
game.enterState(Opsu.STATE_MAINMENU, new FadeOutTransition(Color.black), new FadeInTransition(Color.black));
|
||||
}
|
||||
break;
|
||||
case Input.KEY_F1:
|
||||
game.enterState(Opsu.STATE_OPTIONS, new EmptyTransition(), new FadeInTransition(Color.black));
|
||||
@@ -592,8 +596,10 @@ public class SongMenu extends BasicGameState {
|
||||
if (MusicController.isConverting())
|
||||
return;
|
||||
|
||||
SoundController.playSound(SoundController.SOUND_MENUHIT);
|
||||
Display.setTitle(String.format("%s - %s", game.getTitle(), osu.toString()));
|
||||
OsuParser.parseHitObjects(osu);
|
||||
SoundController.setSampleSet(osu.sampleSet);
|
||||
Game.setOsuFile(osu);
|
||||
Game.setRestart(Game.RESTART_NEW);
|
||||
game.enterState(Opsu.STATE_GAME, new FadeOutTransition(Color.black), new FadeInTransition(Color.black));
|
||||
|
||||
Reference in New Issue
Block a user