Follow-up to #150: delayed fade-out, minor style changes.
Signed-off-by: Jeffrey Han <itdelatrisu@gmail.com>
This commit is contained in:
parent
b55b6c3079
commit
fb789c8fc5
|
@ -54,9 +54,9 @@ import itdelatrisu.opsu.ui.UI;
|
|||
import itdelatrisu.opsu.ui.animations.AnimationEquation;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.IdentityHashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Stack;
|
||||
import java.util.IdentityHashMap;
|
||||
|
||||
import org.lwjgl.input.Keyboard;
|
||||
import org.lwjgl.opengl.Display;
|
||||
|
@ -69,6 +69,7 @@ import org.newdawn.slick.Input;
|
|||
import org.newdawn.slick.SlickException;
|
||||
import org.newdawn.slick.state.BasicGameState;
|
||||
import org.newdawn.slick.state.StateBasedGame;
|
||||
import org.newdawn.slick.state.transition.DelayedFadeOutTransition;
|
||||
import org.newdawn.slick.state.transition.EmptyTransition;
|
||||
import org.newdawn.slick.state.transition.FadeInTransition;
|
||||
import org.newdawn.slick.state.transition.FadeOutTransition;
|
||||
|
@ -92,10 +93,13 @@ public class Game extends BasicGameState {
|
|||
}
|
||||
|
||||
/** Music fade-out time, in milliseconds. */
|
||||
private static final int FADEOUT_TIME = 2000;
|
||||
private static final int MUSIC_FADEOUT_TIME = 2000;
|
||||
|
||||
/** Maximal rotation over fade out, in degrees */
|
||||
private static final float MAX_ROTATION = 90.0f;
|
||||
/** Screen fade-out time, in milliseconds, when health hits zero. */
|
||||
private static final int LOSE_FADEOUT_TIME = 500;
|
||||
|
||||
/** Maximum rotation, in degrees, over fade out upon death. */
|
||||
private static final float MAX_ROTATION = 90f;
|
||||
|
||||
/** Minimum time before start of song, in milliseconds, to process skip-related actions. */
|
||||
private static final int SKIP_OFFSET = 2000;
|
||||
|
@ -185,8 +189,11 @@ public class Game extends BasicGameState {
|
|||
|
||||
/** System time position at death. */
|
||||
private long failTime;
|
||||
|
||||
/** Track time position at death. */
|
||||
private int failTrackTime;
|
||||
|
||||
/** Rotations for game objects at death. */
|
||||
private IdentityHashMap<GameObject, Float> rotations;
|
||||
|
||||
/** Number of retries. */
|
||||
|
@ -663,7 +670,6 @@ public class Game extends BasicGameState {
|
|||
deathTime = -1;
|
||||
}
|
||||
|
||||
|
||||
// normal game update
|
||||
if (!isReplay)
|
||||
addReplayFrameAndRun(mouseX, mouseY, lastKeysPressed, trackPosition);
|
||||
|
@ -823,24 +829,26 @@ public class Game extends BasicGameState {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
// game over, force a restart
|
||||
if (!isReplay) {
|
||||
if (restart != Restart.LOSE) {
|
||||
restart = Restart.LOSE;
|
||||
failTime = System.currentTimeMillis();
|
||||
failTrackTime = MusicController.getPosition();
|
||||
MusicController.fadeOut(FADEOUT_TIME);
|
||||
MusicController.pitchFadeOut(FADEOUT_TIME);
|
||||
MusicController.fadeOut(MUSIC_FADEOUT_TIME);
|
||||
MusicController.pitchFadeOut(MUSIC_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));
|
||||
|
||||
// fade to pause menu
|
||||
game.enterState(Opsu.STATE_GAMEPAUSEMENU,
|
||||
new DelayedFadeOutTransition(Color.black, MUSIC_FADEOUT_TIME, MUSIC_FADEOUT_TIME - LOSE_FADEOUT_TIME),
|
||||
new FadeInTransition(Color.black));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//don't process hit results when already lost
|
||||
// don't process hit results when already lost
|
||||
if (restart != Restart.LOSE) {
|
||||
// update objects (loop in unlikely event of any skipped indexes)
|
||||
boolean keyPressed = keys != ReplayFrame.KEY_NONE;
|
||||
|
@ -1303,17 +1311,17 @@ public class Game extends BasicGameState {
|
|||
trackPosition < beatmap.objects[objectIndex].getTime() && !beatmap.objects[objectIndex - 1].isSpinner())
|
||||
lastObjectIndex = objectIndex - 1;
|
||||
|
||||
if (restart == Restart.LOSE) {
|
||||
trackPosition = failTrackTime + (int)(System.currentTimeMillis() - failTime);
|
||||
}
|
||||
boolean loseState = (restart == Restart.LOSE);
|
||||
if (loseState)
|
||||
trackPosition = failTrackTime + (int) (System.currentTimeMillis() - failTime);
|
||||
|
||||
// draw hit objects in reverse order, or else overlapping objects are unreadable
|
||||
// get hit objects in reverse order, or else overlapping objects are unreadable
|
||||
Stack<Integer> stack = new Stack<Integer>();
|
||||
for (int index = objectIndex; index < gameObjects.length && beatmap.objects[index].getTime() < trackPosition + approachTime; index++) {
|
||||
stack.add(index);
|
||||
|
||||
// draw follow points
|
||||
if (!Options.isFollowPointEnabled())
|
||||
if (!Options.isFollowPointEnabled() || loseState)
|
||||
continue;
|
||||
if (beatmap.objects[index].isSpinner()) {
|
||||
lastObjectIndex = -1;
|
||||
|
@ -1371,40 +1379,47 @@ public class Game extends BasicGameState {
|
|||
lastObjectIndex = index;
|
||||
}
|
||||
|
||||
// draw hit objects
|
||||
while (!stack.isEmpty()){
|
||||
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);
|
||||
int idx = stack.pop();
|
||||
GameObject gameObj = gameObjects[idx];
|
||||
|
||||
// normal case
|
||||
if (!loseState)
|
||||
gameObj.draw(g, trackPosition);
|
||||
|
||||
// death: make objects "fall" off the screen
|
||||
else {
|
||||
// time the object began falling
|
||||
int objTime = Math.max(beatmap.objects[idx].getTime() - approachTime, failTrackTime);
|
||||
float dt = (trackPosition - objTime) / (float) (MUSIC_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);
|
||||
if (dt <= 0)
|
||||
continue;
|
||||
|
||||
// generate rotation speeds for each objects
|
||||
final float rotSpeed;
|
||||
if (rotations.containsKey(gameObj)) {
|
||||
rotSpeed = rotations.get(gameObj);
|
||||
} else {
|
||||
rotSpeed = (float)(2.0f*(Math.random()-0.5f)*MAX_ROTATION);
|
||||
rotations.put(obj, rotSpeed);
|
||||
rotSpeed = (float) (2.0f * (Math.random() - 0.5f) * MAX_ROTATION);
|
||||
rotations.put(gameObj, rotSpeed);
|
||||
}
|
||||
|
||||
g.pushTransform();
|
||||
|
||||
g.translate(0, dt*dt * container.getHeight());
|
||||
Vec2f rotationCenter = obj.getPointAt(beatmap.objects[ix].getTime());
|
||||
// translate and rotate the object
|
||||
g.translate(0, dt * dt * container.getHeight());
|
||||
Vec2f rotationCenter = gameObj.getPointAt(beatmap.objects[idx].getTime());
|
||||
g.rotate(rotationCenter.x, rotationCenter.y, rotSpeed * dt);
|
||||
gameObjects[ix].draw(g, trackPosition);
|
||||
gameObj.draw(g, trackPosition);
|
||||
|
||||
g.popTransform();
|
||||
}
|
||||
} else {
|
||||
gameObjects[stack.pop()].draw(g, trackPosition);
|
||||
}
|
||||
}
|
||||
|
||||
// draw OsuHitObjectResult objects
|
||||
// draw result objects
|
||||
data.drawHitResults(trackPosition);
|
||||
}
|
||||
|
||||
|
|
|
@ -119,13 +119,10 @@ public class GamePauseMenu extends BasicGameState {
|
|||
mousePressed(Input.MOUSE_RIGHT_BUTTON, input.getMouseX(), input.getMouseY());
|
||||
}
|
||||
|
||||
// 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);
|
||||
|
||||
switch (key) {
|
||||
case Input.KEY_ESCAPE:
|
||||
// 'esc' will normally unpause, but will return to song menu if health is zero
|
||||
if (loseState) {
|
||||
if (gameState.getRestart() == Game.Restart.LOSE) {
|
||||
SoundController.playSound(SoundEffect.MENUBACK);
|
||||
((SongMenu) game.getState(Opsu.STATE_SONGMENU)).resetGameDataOnLoad();
|
||||
MusicController.playAt(MusicController.getBeatmap().previewTime, true);
|
||||
|
@ -163,8 +160,6 @@ public class GamePauseMenu extends BasicGameState {
|
|||
return;
|
||||
|
||||
boolean loseState = (gameState.getRestart() == Game.Restart.LOSE);
|
||||
|
||||
|
||||
if (continueButton.contains(x, y) && !loseState) {
|
||||
SoundController.playSound(SoundEffect.MENUBACK);
|
||||
gameState.setRestart(Game.Restart.FALSE);
|
||||
|
@ -205,7 +200,6 @@ public class GamePauseMenu extends BasicGameState {
|
|||
backButton.resetHover();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Loads all game pause/fail menu images.
|
||||
*/
|
||||
|
|
|
@ -0,0 +1,81 @@
|
|||
package org.newdawn.slick.state.transition;
|
||||
|
||||
import org.newdawn.slick.Color;
|
||||
import org.newdawn.slick.GameContainer;
|
||||
import org.newdawn.slick.Graphics;
|
||||
import org.newdawn.slick.state.GameState;
|
||||
import org.newdawn.slick.state.StateBasedGame;
|
||||
|
||||
/**
|
||||
* A transition to fade out to a given colour after a delay.
|
||||
*
|
||||
* @author kevin (base)
|
||||
*/
|
||||
public class DelayedFadeOutTransition implements Transition {
|
||||
/** The color to fade to */
|
||||
private final Color color;
|
||||
/** The time it takes the fade to happen */
|
||||
private final int fadeTime;
|
||||
/** The time it takes before the fade starts */
|
||||
private final int delay;
|
||||
/** The elapsed time */
|
||||
private int elapsedTime = 0;
|
||||
|
||||
/**
|
||||
* Create a new delayed fade out transition.
|
||||
*/
|
||||
public DelayedFadeOutTransition() { this(Color.black, 500, 0); }
|
||||
|
||||
/**
|
||||
* Create a new delayed fade out transition.
|
||||
*
|
||||
* @param color The color we're going to fade out to
|
||||
*/
|
||||
public DelayedFadeOutTransition(Color color) { this(color, 500, 0); }
|
||||
|
||||
/**
|
||||
* Create a new delayed fade out transition
|
||||
*
|
||||
* @param color The color we're going to fade out to
|
||||
* @param fadeTime The time it takes the fade to occur
|
||||
* @param delay The time before the fade starts (must be less than {@code fadeTime})
|
||||
*/
|
||||
public DelayedFadeOutTransition(Color color, int fadeTime, int delay) {
|
||||
if (delay > fadeTime)
|
||||
throw new IllegalArgumentException();
|
||||
|
||||
this.color = new Color(color);
|
||||
this.color.a = 0;
|
||||
this.fadeTime = fadeTime;
|
||||
this.delay = delay;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isComplete() { return (color.a >= 1); }
|
||||
|
||||
@Override
|
||||
public void postRender(StateBasedGame game, GameContainer container, Graphics g) {
|
||||
Color old = g.getColor();
|
||||
g.setColor(color);
|
||||
g.fillRect(0, 0, container.getWidth() * 2, container.getHeight() * 2);
|
||||
g.setColor(old);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(StateBasedGame game, GameContainer container, int delta) {
|
||||
if (elapsedTime < delay) {
|
||||
elapsedTime += delta;
|
||||
return;
|
||||
}
|
||||
|
||||
color.a += delta * (1.0f / (fadeTime - delay));
|
||||
if (color.a > 1)
|
||||
color.a = 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preRender(StateBasedGame game, GameContainer container, Graphics g) {}
|
||||
|
||||
@Override
|
||||
public void init(GameState firstState, GameState secondState) {}
|
||||
}
|
Loading…
Reference in New Issue
Block a user