Add fading transition for changing Screens.
This commit is contained in:
parent
af9a676cc6
commit
573300ae49
@ -33,7 +33,7 @@ public class Main {
|
|||||||
|
|
||||||
// Set up the LoadingScreen
|
// Set up the LoadingScreen
|
||||||
final LoadingScreen loadingScreen = new LoadingScreen(superScreen);
|
final LoadingScreen loadingScreen = new LoadingScreen(superScreen);
|
||||||
superScreen.setOverlay(loadingScreen);
|
superScreen.setOverlay(loadingScreen, false);
|
||||||
|
|
||||||
// Initialize the GameFrame properly within the AWT EventQueue
|
// Initialize the GameFrame properly within the AWT EventQueue
|
||||||
try {
|
try {
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
package de.teamteamteam.spacescooter.screen;
|
package de.teamteamteam.spacescooter.screen;
|
||||||
|
|
||||||
|
import java.awt.Color;
|
||||||
import java.awt.Graphics2D;
|
import java.awt.Graphics2D;
|
||||||
|
|
||||||
|
import de.teamteamteam.spacescooter.brain.GameConfig;
|
||||||
import de.teamteamteam.spacescooter.datastructure.ConcurrentIterator;
|
import de.teamteamteam.spacescooter.datastructure.ConcurrentIterator;
|
||||||
import de.teamteamteam.spacescooter.datastructure.ConcurrentLinkedList;
|
import de.teamteamteam.spacescooter.datastructure.ConcurrentLinkedList;
|
||||||
import de.teamteamteam.spacescooter.entity.Entity;
|
import de.teamteamteam.spacescooter.entity.Entity;
|
||||||
@ -29,6 +31,18 @@ public abstract class Screen {
|
|||||||
* Parent Screen of the current Screen
|
* Parent Screen of the current Screen
|
||||||
*/
|
*/
|
||||||
protected Screen parent;
|
protected Screen parent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Temporary holder of the new Overlay, used by setOverlay() to
|
||||||
|
* implement the transitions before passing focus to the new overlay.
|
||||||
|
*/
|
||||||
|
private Screen newOverlay;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Marker telling whether this Screen is currently processing a
|
||||||
|
* setOverlay call.
|
||||||
|
*/
|
||||||
|
private boolean processSetOverlayCall;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* List of entities this screen is taking care of
|
* List of entities this screen is taking care of
|
||||||
@ -51,10 +65,29 @@ public abstract class Screen {
|
|||||||
private ConcurrentIterator<Entity> collisionIteratorOne;
|
private ConcurrentIterator<Entity> collisionIteratorOne;
|
||||||
private ConcurrentIterator<Entity> collisionIteratorTwo;
|
private ConcurrentIterator<Entity> collisionIteratorTwo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transition state, value in [0,1]. Used to implement
|
||||||
|
* the fade-to-black, fade-to-screen effects.
|
||||||
|
* Value reflects the "visibility" of the Screen, from
|
||||||
|
* 0 (not visible) to 1 (visible).
|
||||||
|
*/
|
||||||
|
private float transitionState;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transition setting, telling whether a transition is currently happening
|
||||||
|
* and in which direction.
|
||||||
|
* Values: -1 (fade to black), 0 (nothing happening), 1 (fade to screen)
|
||||||
|
*/
|
||||||
|
private int transitionSetting;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize parent, overlay and the Entity list
|
* Initialize parent, overlay and the Entity list
|
||||||
*/
|
*/
|
||||||
public Screen(Screen parent) {
|
public Screen(Screen parent) {
|
||||||
|
this.transitionState = 1.0F;
|
||||||
|
this.transitionSetting = 0;
|
||||||
|
this.newOverlay = null;
|
||||||
|
this.processSetOverlayCall = false;
|
||||||
this.setOverlay(null);
|
this.setOverlay(null);
|
||||||
this.parent = parent;
|
this.parent = parent;
|
||||||
this.entities = new ConcurrentLinkedList<Entity>();
|
this.entities = new ConcurrentLinkedList<Entity>();
|
||||||
@ -105,6 +138,8 @@ public abstract class Screen {
|
|||||||
this.paint(g);
|
this.paint(g);
|
||||||
if(this.overlay != null) {
|
if(this.overlay != null) {
|
||||||
this.overlay.doPaint(g);
|
this.overlay.doPaint(g);
|
||||||
|
} else if(this.transitionState != 1.0) {
|
||||||
|
this.paintTransition(g);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -116,46 +151,133 @@ public abstract class Screen {
|
|||||||
public final void doUpdate() {
|
public final void doUpdate() {
|
||||||
if(this.overlay != null) {
|
if(this.overlay != null) {
|
||||||
this.overlay.doUpdate();
|
this.overlay.doUpdate();
|
||||||
|
} else if (this.transitionSetting != 0) {
|
||||||
|
this.updateTransition();
|
||||||
} else {
|
} else {
|
||||||
this.update();
|
this.update();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the overlay Screen for the current Screen. In case an overlay is
|
* Sets the overlay Screen for the current Screen.
|
||||||
* being replaced, the old overlays cleanup-method is called. Also, this
|
* Triggers a fade out transition.
|
||||||
* takes care of the static currentScreen value, which is accessible for
|
* After that transition, fadeOutDone() will bubble back up.
|
||||||
* everybody.
|
* The transition will only trigger if the new overlay is not null
|
||||||
|
* OR an existing overlay is being removed.
|
||||||
*/
|
*/
|
||||||
public final void setOverlay(Screen screen) {
|
public final void setOverlay(Screen screen) {
|
||||||
if(this.overlay != null) this.overlay.cleanup();
|
if(screen != null || (this.overlay != null && screen == null)) {
|
||||||
if(screen == null) {
|
//Trigger the effect if we're fading to the new Screen.
|
||||||
|
this.processSetOverlayCall = true;
|
||||||
|
this.newOverlay = screen;
|
||||||
|
this.fadeOut();
|
||||||
|
} else if(this.overlay == null) {
|
||||||
|
this.overlay = null;
|
||||||
Screen.currentScreen = this;
|
Screen.currentScreen = this;
|
||||||
} else {
|
|
||||||
Screen.currentScreen = screen;
|
|
||||||
}
|
}
|
||||||
this.overlay = screen;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* When a Screens life ends, because it is removed, this method will take
|
* There are very few occasions where the transition effect is not neccessary.
|
||||||
* care of existing overlays and remove all references to existing entities.
|
* This overloaded method is used for this purpose.
|
||||||
*/
|
*/
|
||||||
private final void cleanup() {
|
public final void setOverlay(Screen screen, boolean useEffect) {
|
||||||
if(this.overlay != null) this.overlay.cleanup();
|
if(useEffect == true) {
|
||||||
//tell all entities to cleanup themselves.
|
this.setOverlay(screen);
|
||||||
|
} else {
|
||||||
|
if(this.overlay != null) this.overlay.cleanup();
|
||||||
|
this.overlay = screen;
|
||||||
|
if(screen != null) {
|
||||||
|
Screen.currentScreen = screen;
|
||||||
|
} else {
|
||||||
|
Screen.currentScreen = this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A screen will pass the fadeIn() effect up the most upper
|
||||||
|
* overlay, so the transition will be visible.
|
||||||
|
* After fadeIn, a call will be bubbled up to the parent, telling
|
||||||
|
* it that the transition has finished.
|
||||||
|
*/
|
||||||
|
private void fadeIn() {
|
||||||
|
if(this.overlay != null) {
|
||||||
|
this.overlay.fadeIn();
|
||||||
|
} else {
|
||||||
|
this.initializeTransition(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A screen will pass the fadeOut() effect up the most upper
|
||||||
|
* overlay, so the transition will be visible.
|
||||||
|
* After fadeOut, a call will be bubbled up to the parent, telling
|
||||||
|
* it that the transition has finished.
|
||||||
|
*/
|
||||||
|
private void fadeOut() {
|
||||||
|
if(this.overlay != null) {
|
||||||
|
this.overlay.fadeOut();
|
||||||
|
} else {
|
||||||
|
this.initializeTransition(-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Notification bubbling upwards telling that the fade in transition is done.
|
||||||
|
*/
|
||||||
|
private void fadeInDone() {
|
||||||
|
if(this.parent != null) {
|
||||||
|
this.parent.fadeInDone();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Notification bubbling upwards telling that the fade out transition is done.
|
||||||
|
* In case this Screen is processing a setOverlay call, the old overlay will now receive
|
||||||
|
* the cleanup() call, and the new screen will be put active with a fade in transition.
|
||||||
|
*/
|
||||||
|
private void fadeOutDone() {
|
||||||
|
if(this.processSetOverlayCall) {
|
||||||
|
if(this.overlay != null) {
|
||||||
|
this.overlay.cleanup();
|
||||||
|
}
|
||||||
|
if(this.newOverlay == null) {
|
||||||
|
Screen.currentScreen = this;
|
||||||
|
} else {
|
||||||
|
Screen.currentScreen = this.newOverlay;
|
||||||
|
}
|
||||||
|
this.overlay = this.newOverlay;
|
||||||
|
this.newOverlay = null;
|
||||||
|
this.fadeIn();
|
||||||
|
this.processSetOverlayCall = false;
|
||||||
|
} else {
|
||||||
|
if(this.parent != null) {
|
||||||
|
this.parent.fadeOutDone();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When a Screens life ends, this method will take care of existing overlays
|
||||||
|
* and remove all references to existing entities.
|
||||||
|
*/
|
||||||
|
private void cleanup() {
|
||||||
|
if(this.overlay != null) {
|
||||||
|
this.overlay.cleanup();
|
||||||
|
}
|
||||||
this.entityUpdateIterator.reset();
|
this.entityUpdateIterator.reset();
|
||||||
while(this.entityUpdateIterator.hasNext()) {
|
while(this.entityUpdateIterator.hasNext()) {
|
||||||
Entity e = this.entityUpdateIterator.next();
|
Entity e = this.entityUpdateIterator.next();
|
||||||
e.remove();
|
e.remove();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns second collision iterator.
|
* Returns second collision iterator.
|
||||||
* These are used for collision detection _only_!
|
* These are used for collision detection _only_!
|
||||||
*/
|
*/
|
||||||
public ConcurrentIterator<Entity> getCollisionIteratorOne() {
|
public final ConcurrentIterator<Entity> getCollisionIteratorOne() {
|
||||||
return this.collisionIteratorOne;
|
return this.collisionIteratorOne;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -163,7 +285,62 @@ public abstract class Screen {
|
|||||||
* Returns second collision iterator.
|
* Returns second collision iterator.
|
||||||
* These are used for collision detection _only_!
|
* These are used for collision detection _only_!
|
||||||
*/
|
*/
|
||||||
public ConcurrentIterator<Entity> getCollisionIteratorTwo() {
|
public final ConcurrentIterator<Entity> getCollisionIteratorTwo() {
|
||||||
return this.collisionIteratorTwo;
|
return this.collisionIteratorTwo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Triggered by doUpdate().
|
||||||
|
* Updates the transitionState based on the current transitionSetting.
|
||||||
|
*/
|
||||||
|
private void updateTransition() {
|
||||||
|
this.transitionState += (0.03F * this.transitionSetting);
|
||||||
|
switch(this.transitionSetting) {
|
||||||
|
case 1:
|
||||||
|
if(this.transitionState > 1.0F) {
|
||||||
|
this.transitionState = 1.0F;
|
||||||
|
this.transitionSetting = 0;
|
||||||
|
this.fadeInDone();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case -1:
|
||||||
|
if(this.transitionState < 0.0F) {
|
||||||
|
this.transitionState = 0.0F;
|
||||||
|
this.transitionSetting = 0;
|
||||||
|
this.fadeOutDone();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Kick off a transition.
|
||||||
|
* Setting tells from where to where the transition will happen.
|
||||||
|
*/
|
||||||
|
private void initializeTransition(int setting) {
|
||||||
|
if(this.transitionSetting != 0 || setting == 0) return;
|
||||||
|
switch(setting) {
|
||||||
|
case 1:
|
||||||
|
this.transitionState = 0.0F;
|
||||||
|
break;
|
||||||
|
case -1:
|
||||||
|
this.transitionState = 1.0F;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
this.transitionSetting = setting;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Paint the transition effect.
|
||||||
|
*/
|
||||||
|
private void paintTransition(Graphics2D g) {
|
||||||
|
float alpha = (float) (1.0F - this.transitionState);
|
||||||
|
g.setColor(new Color(0.0F, 0.0F, 0.0F, alpha));
|
||||||
|
g.fillRect(0, 0, GameConfig.windowWidth, GameConfig.windowHeight);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user