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:
Jeffrey Han
2014-07-01 01:14:03 -04:00
parent 60eaa42997
commit 0604a25822
54 changed files with 500 additions and 61 deletions

View File

@@ -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;

View File

@@ -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);
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}
}

View File

@@ -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));

View File

@@ -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));