Merge pull request #150 from mad-s/master
Add falling game objects on fail
This commit is contained in:
commit
b55b6c3079
|
@ -264,6 +264,10 @@ public class Slider implements GameObject {
|
||||||
if (sliderTime == 0)
|
if (sliderTime == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
// Don't draw follow ball if already done
|
||||||
|
if (trackPosition > hitObject.getTime() + sliderTimeTotal)
|
||||||
|
return;
|
||||||
|
|
||||||
Vec2f c = curve.pointAt(getT(trackPosition, false));
|
Vec2f c = curve.pointAt(getT(trackPosition, false));
|
||||||
Vec2f c2 = curve.pointAt(getT(trackPosition, false) + 0.01f);
|
Vec2f c2 = curve.pointAt(getT(trackPosition, false) + 0.01f);
|
||||||
|
|
||||||
|
|
|
@ -56,6 +56,7 @@ import itdelatrisu.opsu.ui.animations.AnimationEquation;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.Stack;
|
import java.util.Stack;
|
||||||
|
import java.util.IdentityHashMap;
|
||||||
|
|
||||||
import org.lwjgl.input.Keyboard;
|
import org.lwjgl.input.Keyboard;
|
||||||
import org.lwjgl.opengl.Display;
|
import org.lwjgl.opengl.Display;
|
||||||
|
@ -90,6 +91,12 @@ public class Game extends BasicGameState {
|
||||||
LOSE
|
LOSE
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Music fade-out time, in milliseconds. */
|
||||||
|
private static final int FADEOUT_TIME = 2000;
|
||||||
|
|
||||||
|
/** Maximal rotation over fade out, in degrees */
|
||||||
|
private static final float MAX_ROTATION = 90.0f;
|
||||||
|
|
||||||
/** Minimum time before start of song, in milliseconds, to process skip-related actions. */
|
/** Minimum time before start of song, in milliseconds, to process skip-related actions. */
|
||||||
private static final int SKIP_OFFSET = 2000;
|
private static final int SKIP_OFFSET = 2000;
|
||||||
|
|
||||||
|
@ -176,6 +183,12 @@ public class Game extends BasicGameState {
|
||||||
/** Track position at death, used if "Easy" mod is enabled. */
|
/** Track position at death, used if "Easy" mod is enabled. */
|
||||||
private int deathTime = -1;
|
private int deathTime = -1;
|
||||||
|
|
||||||
|
/** System time position at death. */
|
||||||
|
private long failTime;
|
||||||
|
private int failTrackTime;
|
||||||
|
|
||||||
|
private IdentityHashMap<GameObject, Float> rotations;
|
||||||
|
|
||||||
/** Number of retries. */
|
/** Number of retries. */
|
||||||
private int retries = 0;
|
private int retries = 0;
|
||||||
|
|
||||||
|
@ -650,6 +663,7 @@ public class Game extends BasicGameState {
|
||||||
deathTime = -1;
|
deathTime = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// normal game update
|
// normal game update
|
||||||
if (!isReplay)
|
if (!isReplay)
|
||||||
addReplayFrameAndRun(mouseX, mouseY, lastKeysPressed, trackPosition);
|
addReplayFrameAndRun(mouseX, mouseY, lastKeysPressed, trackPosition);
|
||||||
|
@ -793,7 +807,7 @@ public class Game extends BasicGameState {
|
||||||
}
|
}
|
||||||
if (MusicController.isPlaying() || isLeadIn())
|
if (MusicController.isPlaying() || isLeadIn())
|
||||||
pauseTime = trackPosition;
|
pauseTime = trackPosition;
|
||||||
game.enterState(Opsu.STATE_GAMEPAUSEMENU);
|
game.enterState(Opsu.STATE_GAMEPAUSEMENU, new EmptyTransition(), new FadeInTransition(Color.black));
|
||||||
}
|
}
|
||||||
|
|
||||||
// drain health
|
// drain health
|
||||||
|
@ -809,25 +823,38 @@ public class Game extends BasicGameState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// game over, force a restart
|
// game over, force a restart
|
||||||
if (!isReplay) {
|
if (!isReplay) {
|
||||||
restart = Restart.LOSE;
|
if (restart != Restart.LOSE) {
|
||||||
game.enterState(Opsu.STATE_GAMEPAUSEMENU);
|
restart = Restart.LOSE;
|
||||||
|
failTime = System.currentTimeMillis();
|
||||||
|
failTrackTime = MusicController.getPosition();
|
||||||
|
MusicController.fadeOut(FADEOUT_TIME);
|
||||||
|
MusicController.pitchFadeOut(FADEOUT_TIME);
|
||||||
|
rotations = new IdentityHashMap<GameObject, Float>();
|
||||||
|
SoundController.playSound(SoundEffect.FAIL);
|
||||||
|
//fade to pause menu
|
||||||
|
game.enterState(Opsu.STATE_GAMEPAUSEMENU, new FadeOutTransition(Color.black, FADEOUT_TIME), new FadeInTransition(Color.black));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// update objects (loop in unlikely event of any skipped indexes)
|
//don't process hit results when already lost
|
||||||
boolean keyPressed = keys != ReplayFrame.KEY_NONE;
|
if (restart != Restart.LOSE) {
|
||||||
while (objectIndex < gameObjects.length && trackPosition > beatmap.objects[objectIndex].getTime()) {
|
// update objects (loop in unlikely event of any skipped indexes)
|
||||||
// check if we've already passed the next object's start time
|
boolean keyPressed = keys != ReplayFrame.KEY_NONE;
|
||||||
boolean overlap = (objectIndex + 1 < gameObjects.length &&
|
while (objectIndex < gameObjects.length && trackPosition > beatmap.objects[objectIndex].getTime()) {
|
||||||
trackPosition > beatmap.objects[objectIndex + 1].getTime() - hitResultOffset[GameData.HIT_50]);
|
// check if we've already passed the next object's start time
|
||||||
|
boolean overlap = (objectIndex + 1 < gameObjects.length &&
|
||||||
|
trackPosition > beatmap.objects[objectIndex + 1].getTime() - hitResultOffset[GameData.HIT_50]);
|
||||||
|
|
||||||
// update hit object and check completion status
|
// update hit object and check completion status
|
||||||
if (gameObjects[objectIndex].update(overlap, delta, mouseX, mouseY, keyPressed, trackPosition))
|
if (gameObjects[objectIndex].update(overlap, delta, mouseX, mouseY, keyPressed, trackPosition))
|
||||||
objectIndex++; // done, so increment object index
|
objectIndex++; // done, so increment object index
|
||||||
else
|
else
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1276,6 +1303,10 @@ public class Game extends BasicGameState {
|
||||||
trackPosition < beatmap.objects[objectIndex].getTime() && !beatmap.objects[objectIndex - 1].isSpinner())
|
trackPosition < beatmap.objects[objectIndex].getTime() && !beatmap.objects[objectIndex - 1].isSpinner())
|
||||||
lastObjectIndex = objectIndex - 1;
|
lastObjectIndex = objectIndex - 1;
|
||||||
|
|
||||||
|
if (restart == Restart.LOSE) {
|
||||||
|
trackPosition = failTrackTime + (int)(System.currentTimeMillis() - failTime);
|
||||||
|
}
|
||||||
|
|
||||||
// draw hit objects in reverse order, or else overlapping objects are unreadable
|
// draw hit objects in reverse order, or else overlapping objects are unreadable
|
||||||
Stack<Integer> stack = new Stack<Integer>();
|
Stack<Integer> stack = new Stack<Integer>();
|
||||||
for (int index = objectIndex; index < gameObjects.length && beatmap.objects[index].getTime() < trackPosition + approachTime; index++) {
|
for (int index = objectIndex; index < gameObjects.length && beatmap.objects[index].getTime() < trackPosition + approachTime; index++) {
|
||||||
|
@ -1340,8 +1371,38 @@ public class Game extends BasicGameState {
|
||||||
lastObjectIndex = index;
|
lastObjectIndex = index;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (!stack.isEmpty())
|
while (!stack.isEmpty()){
|
||||||
gameObjects[stack.pop()].draw(g, trackPosition);
|
if (restart == Restart.LOSE){
|
||||||
|
int ix = stack.pop();
|
||||||
|
GameObject obj = gameObjects[ix];
|
||||||
|
// the time the object began falling
|
||||||
|
int objTime = Math.max( beatmap.objects[ix].getTime() - approachTime, failTrackTime );
|
||||||
|
float dt = (trackPosition - objTime)/(float)(FADEOUT_TIME);
|
||||||
|
|
||||||
|
// would the object already be visible?
|
||||||
|
if (dt > 0) {
|
||||||
|
float rotSpeed;
|
||||||
|
//generate rotation speeds for each objects
|
||||||
|
if (rotations.containsKey(obj)){
|
||||||
|
rotSpeed = rotations.get(obj);
|
||||||
|
} else {
|
||||||
|
rotSpeed = (float)(2.0f*(Math.random()-0.5f)*MAX_ROTATION);
|
||||||
|
rotations.put(obj, rotSpeed);
|
||||||
|
}
|
||||||
|
|
||||||
|
g.pushTransform();
|
||||||
|
|
||||||
|
g.translate(0, dt*dt * container.getHeight());
|
||||||
|
Vec2f rotationCenter = obj.getPointAt(beatmap.objects[ix].getTime());
|
||||||
|
g.rotate(rotationCenter.x, rotationCenter.y, rotSpeed * dt);
|
||||||
|
gameObjects[ix].draw(g, trackPosition);
|
||||||
|
|
||||||
|
g.popTransform();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
gameObjects[stack.pop()].draw(g, trackPosition);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// draw OsuHitObjectResult objects
|
// draw OsuHitObjectResult objects
|
||||||
data.drawHitResults(trackPosition);
|
data.drawHitResults(trackPosition);
|
||||||
|
|
|
@ -47,16 +47,6 @@ import org.newdawn.slick.state.transition.FadeOutTransition;
|
||||||
* or return to the song menu from this state.
|
* or return to the song menu from this state.
|
||||||
*/
|
*/
|
||||||
public class GamePauseMenu extends BasicGameState {
|
public class GamePauseMenu extends BasicGameState {
|
||||||
/** Music fade-out time, in milliseconds. */
|
|
||||||
private static final int FADEOUT_TIME = 2000;
|
|
||||||
|
|
||||||
/** Additional delay time to block state changes during music fade-out, in milliseconds.
|
|
||||||
This prevents music playback issues when the track hasn't completely finished fading out. */
|
|
||||||
private static final int FADEOUT_EXTRA_DELAY = 100;
|
|
||||||
|
|
||||||
/** Track position when the pause menu was loaded (for FADEOUT_TIME). */
|
|
||||||
private long pauseStartTime;
|
|
||||||
|
|
||||||
/** "Continue", "Retry", and "Back" buttons. */
|
/** "Continue", "Retry", and "Back" buttons. */
|
||||||
private MenuButton continueButton, retryButton, backButton;
|
private MenuButton continueButton, retryButton, backButton;
|
||||||
|
|
||||||
|
@ -131,12 +121,9 @@ public class GamePauseMenu extends BasicGameState {
|
||||||
|
|
||||||
// if music faded out (i.e. health is zero), don't process any state changes before FADEOUT_TIME
|
// if music faded out (i.e. health is zero), don't process any state changes before FADEOUT_TIME
|
||||||
boolean loseState = (gameState.getRestart() == Game.Restart.LOSE);
|
boolean loseState = (gameState.getRestart() == Game.Restart.LOSE);
|
||||||
boolean loseBlockDelay = (loseState && System.currentTimeMillis() - pauseStartTime < FADEOUT_TIME + FADEOUT_EXTRA_DELAY);
|
|
||||||
|
|
||||||
switch (key) {
|
switch (key) {
|
||||||
case Input.KEY_ESCAPE:
|
case Input.KEY_ESCAPE:
|
||||||
if (loseBlockDelay)
|
|
||||||
break;
|
|
||||||
// 'esc' will normally unpause, but will return to song menu if health is zero
|
// 'esc' will normally unpause, but will return to song menu if health is zero
|
||||||
if (loseState) {
|
if (loseState) {
|
||||||
SoundController.playSound(SoundEffect.MENUBACK);
|
SoundController.playSound(SoundEffect.MENUBACK);
|
||||||
|
@ -152,8 +139,6 @@ public class GamePauseMenu extends BasicGameState {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case Input.KEY_R:
|
case Input.KEY_R:
|
||||||
if (loseBlockDelay)
|
|
||||||
break;
|
|
||||||
// restart
|
// restart
|
||||||
if (input.isKeyDown(Input.KEY_RCONTROL) || input.isKeyDown(Input.KEY_LCONTROL)) {
|
if (input.isKeyDown(Input.KEY_RCONTROL) || input.isKeyDown(Input.KEY_LCONTROL)) {
|
||||||
gameState.setRestart(Game.Restart.MANUAL);
|
gameState.setRestart(Game.Restart.MANUAL);
|
||||||
|
@ -179,9 +164,6 @@ public class GamePauseMenu extends BasicGameState {
|
||||||
|
|
||||||
boolean loseState = (gameState.getRestart() == Game.Restart.LOSE);
|
boolean loseState = (gameState.getRestart() == Game.Restart.LOSE);
|
||||||
|
|
||||||
// if music faded out (i.e. health is zero), don't process any actions before FADEOUT_TIME
|
|
||||||
if (loseState && System.currentTimeMillis() - pauseStartTime < FADEOUT_TIME + FADEOUT_EXTRA_DELAY)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (continueButton.contains(x, y) && !loseState) {
|
if (continueButton.contains(x, y) && !loseState) {
|
||||||
SoundController.playSound(SoundEffect.MENUBACK);
|
SoundController.playSound(SoundEffect.MENUBACK);
|
||||||
|
@ -200,6 +182,7 @@ public class GamePauseMenu extends BasicGameState {
|
||||||
MusicController.resume();
|
MusicController.resume();
|
||||||
if (UI.getCursor().isBeatmapSkinned())
|
if (UI.getCursor().isBeatmapSkinned())
|
||||||
UI.getCursor().reset();
|
UI.getCursor().reset();
|
||||||
|
MusicController.setPitch(1.0f);
|
||||||
game.enterState(Opsu.STATE_SONGMENU, new FadeOutTransition(Color.black), new FadeInTransition(Color.black));
|
game.enterState(Opsu.STATE_SONGMENU, new FadeOutTransition(Color.black), new FadeInTransition(Color.black));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -216,24 +199,12 @@ public class GamePauseMenu extends BasicGameState {
|
||||||
public void enter(GameContainer container, StateBasedGame game)
|
public void enter(GameContainer container, StateBasedGame game)
|
||||||
throws SlickException {
|
throws SlickException {
|
||||||
UI.enter();
|
UI.enter();
|
||||||
pauseStartTime = System.currentTimeMillis();
|
MusicController.pause();
|
||||||
if (gameState.getRestart() == Game.Restart.LOSE) {
|
|
||||||
MusicController.fadeOut(FADEOUT_TIME);
|
|
||||||
MusicController.pitchFadeOut(FADEOUT_TIME);
|
|
||||||
SoundController.playSound(SoundEffect.FAIL);
|
|
||||||
} else
|
|
||||||
MusicController.pause();
|
|
||||||
continueButton.resetHover();
|
continueButton.resetHover();
|
||||||
retryButton.resetHover();
|
retryButton.resetHover();
|
||||||
backButton.resetHover();
|
backButton.resetHover();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void leave(GameContainer container, StateBasedGame game)
|
|
||||||
throws SlickException {
|
|
||||||
// reset pitch fade out
|
|
||||||
MusicController.pitchFadeOut(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads all game pause/fail menu images.
|
* Loads all game pause/fail menu images.
|
||||||
|
|
Loading…
Reference in New Issue
Block a user