saner transition management

This commit is contained in:
yugecin 2017-05-05 00:44:51 +02:00
parent 0a0320e81a
commit 1ebf2c2dcb
9 changed files with 78 additions and 314 deletions

View File

@ -62,8 +62,6 @@ import yugecin.opsudance.core.events.EventBus;
import yugecin.opsudance.core.inject.Inject; import yugecin.opsudance.core.inject.Inject;
import yugecin.opsudance.core.inject.InstanceContainer; import yugecin.opsudance.core.inject.InstanceContainer;
import yugecin.opsudance.core.state.ComplexOpsuState; import yugecin.opsudance.core.state.ComplexOpsuState;
import yugecin.opsudance.core.state.transitions.FadeInTransitionState;
import yugecin.opsudance.core.state.transitions.FadeOutTransitionState;
import yugecin.opsudance.events.BarNotificationEvent; import yugecin.opsudance.events.BarNotificationEvent;
import yugecin.opsudance.events.BubbleNotificationEvent; import yugecin.opsudance.events.BubbleNotificationEvent;
import yugecin.opsudance.objects.curves.FakeCombinedCurve; import yugecin.opsudance.objects.curves.FakeCombinedCurve;
@ -766,7 +764,7 @@ public class Game extends ComplexOpsuState {
// focus lost: go back to pause screen // focus lost: go back to pause screen
else if (!Display.isActive()) { else if (!Display.isActive()) {
displayContainer.switchStateNow(GamePauseMenu.class); displayContainer.switchState(GamePauseMenu.class);
pausePulse = 0f; pausePulse = 0f;
} }
@ -1050,7 +1048,7 @@ public class Game extends ComplexOpsuState {
if (MusicController.isPlaying() || isLeadIn()) { if (MusicController.isPlaying() || isLeadIn()) {
pauseTime = trackPosition; pauseTime = trackPosition;
} }
displayContainer.switchStateNow(GamePauseMenu.class); displayContainer.switchStateInstantly(GamePauseMenu.class);
} }
// drain health // drain health
@ -1077,7 +1075,7 @@ public class Game extends ComplexOpsuState {
rotations = new IdentityHashMap<>(); rotations = new IdentityHashMap<>();
SoundController.playSound(SoundEffect.FAIL); SoundController.playSound(SoundEffect.FAIL);
displayContainer.switchState(GamePauseMenu.class, FadeOutTransitionState.class, MUSIC_FADEOUT_TIME - LOSE_FADEOUT_TIME, FadeInTransitionState.class, 300); displayContainer.switchState(GamePauseMenu.class, MUSIC_FADEOUT_TIME - LOSE_FADEOUT_TIME, 300);
} }
} }
} }
@ -1158,7 +1156,7 @@ public class Game extends ComplexOpsuState {
if (MusicController.isPlaying() || isLeadIn()) { if (MusicController.isPlaying() || isLeadIn()) {
pauseTime = trackPosition; pauseTime = trackPosition;
} }
displayContainer.switchStateNow(GamePauseMenu.class); displayContainer.switchStateInstantly(GamePauseMenu.class);
break; break;
case Input.KEY_SPACE: case Input.KEY_SPACE:
// skip intro // skip intro
@ -1311,7 +1309,7 @@ public class Game extends ComplexOpsuState {
if (MusicController.isPlaying() || isLeadIn()) { if (MusicController.isPlaying() || isLeadIn()) {
pauseTime = trackPosition; pauseTime = trackPosition;
} }
displayContainer.switchStateNow(GamePauseMenu.class); displayContainer.switchStateInstantly(GamePauseMenu.class);
return true; return true;
} }

View File

@ -48,7 +48,6 @@ import yugecin.opsudance.core.state.OpsuState;
import yugecin.opsudance.core.state.specialstates.BarNotificationState; import yugecin.opsudance.core.state.specialstates.BarNotificationState;
import yugecin.opsudance.core.state.specialstates.BubbleNotificationState; import yugecin.opsudance.core.state.specialstates.BubbleNotificationState;
import yugecin.opsudance.core.state.specialstates.FpsRenderState; import yugecin.opsudance.core.state.specialstates.FpsRenderState;
import yugecin.opsudance.core.state.transitions.*;
import yugecin.opsudance.events.BubbleNotificationEvent; import yugecin.opsudance.events.BubbleNotificationEvent;
import yugecin.opsudance.events.ResolutionOrSkinChangedEvent; import yugecin.opsudance.events.ResolutionOrSkinChangedEvent;
import yugecin.opsudance.options.Configuration; import yugecin.opsudance.options.Configuration;
@ -79,12 +78,6 @@ public class DisplayContainer implements ErrorDumpable, KeyListener, MouseListen
private BarNotificationState barNotifState; private BarNotificationState barNotifState;
private BubbleNotificationState bubNotifState; private BubbleNotificationState bubNotifState;
private TransitionState outTransitionState;
private TransitionState inTransitionState;
private final TransitionFinishedListener outTransitionListener;
private final TransitionFinishedListener inTransitionListener;
private OpsuState state; private OpsuState state;
public final DisplayMode nativeDisplayMode; public final DisplayMode nativeDisplayMode;
@ -123,31 +116,52 @@ public class DisplayContainer implements ErrorDumpable, KeyListener, MouseListen
public final Cursor cursor; public final Cursor cursor;
public boolean drawCursor; public boolean drawCursor;
class Transition {
int in;
int out;
int total;
int progress = -1;
OpsuState nextstate;
Color OVERLAY = new Color(Color.black);
public void update() {
if (progress == -1) {
return;
}
progress += delta;
if (progress > out && nextstate != null) {
switchStateInstantly(nextstate);
nextstate = null;
}
if (progress > total) {
progress = -1;
}
}
public void render(Graphics graphics) {
if (progress == -1) {
return;
}
int relprogress = progress;
int reltotal = out;
if (progress > out) {
reltotal = in;
relprogress = total - progress;
}
OVERLAY.a = (float) relprogress / reltotal;
graphics.setColor(OVERLAY);
graphics.fillRect(0, 0, width, height);
}
}
private final Transition transition = new Transition();
@Inject @Inject
public DisplayContainer(InstanceContainer instanceContainer) { public DisplayContainer(InstanceContainer instanceContainer) {
this.instanceContainer = instanceContainer; this.instanceContainer = instanceContainer;
this.cursor = new Cursor(); this.cursor = new Cursor();
drawCursor = true; drawCursor = true;
outTransitionListener = new TransitionFinishedListener() {
@Override
public void onFinish() {
state.leave();
outTransitionState.getApplicableState().leave();
state = inTransitionState;
state.enter();
inTransitionState.getApplicableState().enter();
}
};
inTransitionListener = new TransitionFinishedListener() {
@Override
public void onFinish() {
state.leave();
state = inTransitionState.getApplicableState();
}
};
EventBus.subscribe(ResolutionOrSkinChangedEvent.class, new EventListener<ResolutionOrSkinChangedEvent>() { EventBus.subscribe(ResolutionOrSkinChangedEvent.class, new EventListener<ResolutionOrSkinChangedEvent>() {
@Override @Override
public void onEvent(ResolutionOrSkinChangedEvent event) { public void onEvent(ResolutionOrSkinChangedEvent event) {
@ -220,6 +234,7 @@ public class DisplayContainer implements ErrorDumpable, KeyListener, MouseListen
mouseX = input.getMouseX(); mouseX = input.getMouseX();
mouseY = input.getMouseY(); mouseY = input.getMouseY();
transition.update();
fpsState.update(); fpsState.update();
state.update(); state.update();
@ -258,6 +273,8 @@ public class DisplayContainer implements ErrorDumpable, KeyListener, MouseListen
} }
UI.drawTooltip(graphics); UI.drawTooltip(graphics);
transition.render(graphics);
timeSinceLastRender = 0; timeSinceLastRender = 0;
Display.update(false); Display.update(false);
@ -454,16 +471,6 @@ public class DisplayContainer implements ErrorDumpable, KeyListener, MouseListen
public void writeErrorDump(StringWriter dump) { public void writeErrorDump(StringWriter dump) {
dump.append("> DisplayContainer dump\n"); dump.append("> DisplayContainer dump\n");
dump.append("OpenGL version: ").append(glVersion).append( "(").append(glVendor).append(")\n"); dump.append("OpenGL version: ").append(glVersion).append( "(").append(glVendor).append(")\n");
if (isTransitioning()) {
dump.append("doing a transition\n");
dump.append("using out transition ").append(outTransitionState.getClass().getSimpleName()).append('\n');
dump.append("using in transition ").append(inTransitionState.getClass().getSimpleName()).append('\n');
if (state == inTransitionState) {
dump.append("currently doing the in transition\n");
} else {
dump.append("currently doing the out transition\n");
}
}
state.writeErrorDump(dump); state.writeErrorDump(dump);
} }
@ -471,32 +478,37 @@ public class DisplayContainer implements ErrorDumpable, KeyListener, MouseListen
return state.isInstance(state); return state.isInstance(state);
} }
public boolean isTransitioning() { public void switchState(Class<? extends OpsuState> newState, int outtime, int intime) {
return state instanceof TransitionState; if (transition.progress != -1) {
}
public void switchState(Class<? extends OpsuState> newState) {
switchState(newState, FadeOutTransitionState.class, 200, FadeInTransitionState.class, 300);
}
public void switchStateNow(Class<? extends OpsuState> newState) {
switchState(newState, EmptyTransitionState.class, 0, FadeInTransitionState.class, 300);
}
public void switchStateInstantly(Class<? extends OpsuState> newState) {
state.leave();
state = instanceContainer.provide(newState);
state.enter();
}
public void switchState(Class<? extends OpsuState> newState, Class<? extends TransitionState> outTransition, int outTime, Class<? extends TransitionState> inTransition, int inTime) {
if (isTransitioning()) {
return; return;
} }
outTransitionState = instanceContainer.provide(outTransition).set(state, outTime, outTransitionListener); // TODO remove this v
inTransitionState = instanceContainer.provide(inTransition).set(instanceContainer.provide(newState), inTime, inTransitionListener); OpsuState _newstate = instanceContainer.provide(newState);
state = outTransitionState; if (outtime == 0) {
state.enter(); switchStateInstantly(_newstate);
_newstate = null;
}
transition.nextstate = _newstate;
transition.total = transition.in = intime;
transition.out = outtime;
transition.total += outtime;
transition.progress = 0;
}
@Deprecated // TODO instcontainer
public void switchState(Class<? extends OpsuState> state) {
switchState(state, 200, 300);
}
@Deprecated // TODO instcontainer
public void switchStateInstantly(Class<? extends OpsuState> state) {
switchStateInstantly(instanceContainer.provide(state));
}
public void switchStateInstantly(OpsuState state) {
this.state.leave();
this.state = state;
this.state.enter();
} }
/* /*

View File

@ -13,6 +13,7 @@
* GNU General Public License for more details. * GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
*
* along with opsu!dance. If not, see <http://www.gnu.org/licenses/>. * along with opsu!dance. If not, see <http://www.gnu.org/licenses/>.
*/ */
package yugecin.opsudance.core.inject; package yugecin.opsudance.core.inject;
@ -27,9 +28,6 @@ import yugecin.opsudance.core.DisplayContainer;
import yugecin.opsudance.core.state.specialstates.BarNotificationState; import yugecin.opsudance.core.state.specialstates.BarNotificationState;
import yugecin.opsudance.core.state.specialstates.BubbleNotificationState; import yugecin.opsudance.core.state.specialstates.BubbleNotificationState;
import yugecin.opsudance.core.state.specialstates.FpsRenderState; import yugecin.opsudance.core.state.specialstates.FpsRenderState;
import yugecin.opsudance.core.state.transitions.EmptyTransitionState;
import yugecin.opsudance.core.state.transitions.FadeInTransitionState;
import yugecin.opsudance.core.state.transitions.FadeOutTransitionState;
import yugecin.opsudance.core.errorhandling.ErrorHandler; import yugecin.opsudance.core.errorhandling.ErrorHandler;
import yugecin.opsudance.options.Configuration; import yugecin.opsudance.options.Configuration;
import yugecin.opsudance.options.OptionsService; import yugecin.opsudance.options.OptionsService;
@ -57,10 +55,6 @@ public class OpsuDanceInjector extends Injector {
bind(BarNotificationState.class).asEagerSingleton(); bind(BarNotificationState.class).asEagerSingleton();
bind(BubbleNotificationState.class).asEagerSingleton(); bind(BubbleNotificationState.class).asEagerSingleton();
bind(EmptyTransitionState.class).asEagerSingleton();
bind(FadeInTransitionState.class).asEagerSingleton();
bind(FadeOutTransitionState.class).asEagerSingleton();
bind(GameObjectRenderer.class).asEagerSingleton(); bind(GameObjectRenderer.class).asEagerSingleton();
bind(Splash.class).asEagerSingleton(); bind(Splash.class).asEagerSingleton();

View File

@ -1,27 +0,0 @@
/*
* opsu!dance - fork of opsu! with cursordance auto
* Copyright (C) 2017 yugecin
*
* opsu!dance is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* opsu!dance is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with opsu!dance. If not, see <http://www.gnu.org/licenses/>.
*/
package yugecin.opsudance.core.state.transitions;
public class EmptyTransitionState extends TransitionState {
@Override
public void enter() {
finish();
}
}

View File

@ -1,27 +0,0 @@
/*
* opsu!dance - fork of opsu! with cursordance auto
* Copyright (C) 2017 yugecin
*
* opsu!dance is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* opsu!dance is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with opsu!dance. If not, see <http://www.gnu.org/licenses/>.
*/
package yugecin.opsudance.core.state.transitions;
public class FadeInTransitionState extends FadeTransitionState {
@Override
protected float getMaskAlphaLevel(float fadeProgress) {
return 1f - fadeProgress;
}
}

View File

@ -1,27 +0,0 @@
/*
* opsu!dance - fork of opsu! with cursordance auto
* Copyright (C) 2017 yugecin
*
* opsu!dance is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* opsu!dance is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with opsu!dance. If not, see <http://www.gnu.org/licenses/>.
*/
package yugecin.opsudance.core.state.transitions;
public class FadeOutTransitionState extends FadeTransitionState {
@Override
protected float getMaskAlphaLevel(float fadeProgress) {
return fadeProgress;
}
}

View File

@ -1,42 +0,0 @@
/*
* opsu!dance - fork of opsu! with cursordance auto
* Copyright (C) 2017 yugecin
*
* opsu!dance is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* opsu!dance is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with opsu!dance. If not, see <http://www.gnu.org/licenses/>.
*/
package yugecin.opsudance.core.state.transitions;
import org.newdawn.slick.Color;
import org.newdawn.slick.Graphics;
public abstract class FadeTransitionState extends TransitionState {
private final Color black;
public FadeTransitionState() {
super();
black = new Color(Color.black);
}
@Override
public void render(Graphics g) {
applicableState.render(g);
black.a = getMaskAlphaLevel((float) transitionTime / transitionTargetTime);
g.setColor(black);
g.fillRect(0, 0, displayContainer.width, displayContainer.height);
}
protected abstract float getMaskAlphaLevel(float fadeProgress);
}

View File

@ -1,24 +0,0 @@
/*
* opsu!dance - fork of opsu! with cursordance auto
* Copyright (C) 2017 yugecin
*
* opsu!dance is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* opsu!dance is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with opsu!dance. If not, see <http://www.gnu.org/licenses/>.
*/
package yugecin.opsudance.core.state.transitions;
public interface TransitionFinishedListener {
void onFinish();
}

View File

@ -1,93 +0,0 @@
/*
* opsu!dance - fork of opsu! with cursordance auto
* Copyright (C) 2017 yugecin
*
* opsu!dance is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* opsu!dance is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with opsu!dance. If not, see <http://www.gnu.org/licenses/>.
*/
package yugecin.opsudance.core.state.transitions;
import org.newdawn.slick.Graphics;
import yugecin.opsudance.core.state.BaseOpsuState;
import yugecin.opsudance.core.state.OpsuState;
import java.io.StringWriter;
public abstract class TransitionState extends BaseOpsuState {
protected OpsuState applicableState;
protected int transitionTargetTime;
protected int transitionTime;
private TransitionFinishedListener listener;
public final TransitionState set(OpsuState applicableState, int targetTime, TransitionFinishedListener listener) {
this.applicableState = applicableState;
this.transitionTargetTime = targetTime;
this.listener = listener;
return this;
}
public final OpsuState getApplicableState() {
return applicableState;
}
@Override
public void update() {
applicableState.update();
transitionTime += displayContainer.delta;
if (transitionTime >= transitionTargetTime) {
finish();
}
}
@Override
public void preRenderUpdate() {
applicableState.preRenderUpdate();
}
@Override
public void render(Graphics g) {
applicableState.render(g);
}
@Override
public void enter() {
super.enter();
transitionTime = 0;
}
protected final void finish() {
listener.onFinish();
}
@Override
public boolean onCloseRequest() {
return false;
}
@Override
public void writeErrorDump(StringWriter dump) {
dump.append("> TransitionState dump\n");
dump.append("progress: ").append(String.valueOf(transitionTime)).append("/").append(String.valueOf(transitionTargetTime)).append('\n');
dump.append("applicable state: ");
if (applicableState == null) {
dump.append("IS NULL");
return;
}
dump.append(applicableState.getClass().getSimpleName()).append('\n');
applicableState.writeErrorDump(dump);
}
}