package com.gebauz.bauzoid.gamestates;
import java.lang.reflect.InvocationTargetException;
import com.badlogic.gdx.Gdx;
import com.gebauz.bauzoid.app.Consts;
import com.gebauz.bauzoid.game.Game;
import com.gebauz.bauzoid.game.GameObject;
import com.gebauz.bauzoid.math.MathUtil;
/** Manages game state switching, updating, rendering, and initialization/destruction. */
public class GameStateManager
extends GameObject
{
// Constants========================================================================================
static final float FADE_TIME = 0.4f
;
// Embedded Types===================================================================================
private enum StateMode
{
MODE_NORMAL,
// everything normal
MODE_FADEIN,
// fade in
MODE_FADEOUT,
// fade out
MODE_EXIT_STATE,
// during exiting a state
MODE_INIT_STATE,
// during loading a state
};
// Fields===========================================================================================
private BaseGameState mCurrentState =
null;
private Class<? extends BaseGameState
> mNextStateClass =
null;
private String mParam =
"";
private StateMode mStateMode = StateMode.
MODE_NORMAL;
/** Tracks how much time was spend in each state mode. */
private float mStateModeTimer = 0.0f
;
/** The default package name for the actual game's gamestates. */
private String mDefaultPackage =
"";
private ScreenFader mScreenFader =
null;
private BaseLoadingScreen mLoadingScreen =
null;
// Methods==========================================================================================
/** Constructor. */
public GameStateManager
(Game game
)
{
super(game
);
}
/** Called when the GameStateManager should initially set up its internals. */
public void init
()
{
mScreenFader =
new ScreenFader
(getGame
().
getGraphics());
mScreenFader.
init();
}
/** Called when the GameStateManager should clean up. */
public void exit
()
{
if (mScreenFader
!=
null)
{
mScreenFader.
exit();
mScreenFader =
null;
}
if (mCurrentState
!=
null)
{
// reset everything
mCurrentState.
exit();
mCurrentState =
null;
mNextStateClass =
null;
mStateMode = StateMode.
MODE_NORMAL;
mStateModeTimer = 0.0f
;
}
}
/** Queue a game state switch. */
public void switchTo
(Class<? extends BaseGameState
> nextState,
String param
)
{
mParam = param
;
mNextStateClass = nextState
;
}
/** Switch to state specified by String - must be fully qualified Class name! */
public void switchTo
(String nextState,
String param
)
{
Class<? extends BaseGameState
> nextStateClass =
null;
try
{
//mNextStateClass = Class.forName(nextState);
nextStateClass =
Class.
forName(mDefaultPackage +
"." + nextState
).
asSubclass(BaseGameState.
class);
}
catch (ClassNotFoundException ex
)
{
// Gdx.app.log(Consts.LOG_TAG, "ClassNotFoundException when switching to " + mDefaultPackage + "." + nextState + ", trying without default package name");
/** Try without package name. */
try
{
nextStateClass =
Class.
forName(nextState
).
asSubclass(BaseGameState.
class);
}
catch (ClassNotFoundException ex2
)
{
Gdx.
app.
log(Consts.
LOG_TAG,
"ClassNotFoundException when switching to " + nextState
);
return;
}
}
switchTo
(nextStateClass, param
);
}
public BaseGameState createNextState
(Class<? extends BaseGameState
> newState
)
{
BaseGameState result
;
try
{
//mCurrentState = (BaseGameState)newState.newInstance();
result =
(BaseGameState
)newState.
getDeclaredConstructor(Game.
class).
newInstance(getGame
());
}
catch (NoSuchMethodException ex
)
{
Gdx.
app.
log(Consts.
LOG_TAG,
"NoSuchMethodException when switching to " + newState.
toString());
return null;
}
catch (InvocationTargetException ex
)
{
Gdx.
app.
log(Consts.
LOG_TAG,
"InvocationTargetEception when switching to " + newState.
toString());
return null;
}
catch (InstantiationException ex
)
{
Gdx.
app.
log(Consts.
LOG_TAG,
"InstantiationException when switching to " + newState.
toString());
return null;
}
catch (IllegalAccessException ex
)
{
Gdx.
app.
log(Consts.
LOG_TAG,
"IllegalAccessException when switching to " + newState.
toString());
return null;
}
return result
;
}
/** Update the current game state (if one is running). */
public void update
(float deltaTime
)
{
mStateModeTimer += deltaTime
;
switch (mStateMode
)
{
case MODE_NORMAL:
updateNormal
(deltaTime
);
break;
case MODE_FADEIN:
updateFadeIn
(deltaTime
);
break;
case MODE_FADEOUT:
updateFadeOut
(deltaTime
);
break;
case MODE_EXIT_STATE:
updateExitState
(deltaTime
);
if (mLoadingScreen
!=
null)
mLoadingScreen.
update(deltaTime
);
break;
case MODE_INIT_STATE:
updateInitState
(deltaTime
);
if (mLoadingScreen
!=
null)
mLoadingScreen.
update(deltaTime
);
break;
}
}
public void switchState
(StateMode nextStateMode
)
{
mStateMode = nextStateMode
;
mStateModeTimer = 0.0f
;
}
public void updateNormal
(float deltaTime
)
{
// check if state switch queued
if (mNextStateClass
!=
null)
{
// if current state is null or doesn't want to fade out, switch directly
if ((mCurrentState
!=
null) && (mCurrentState.
doFadeOut()))
{
switchState
(StateMode.
MODE_FADEOUT);
updateFadeColor
();
}
else
switchState
(StateMode.
MODE_EXIT_STATE);
}
if (mCurrentState
!=
null)
{
mCurrentState.
update(deltaTime
);
}
}
public void updateFadeIn
(float deltaTime
)
{
if (mCurrentState
!=
null)
{
mCurrentState.
updateFading(deltaTime
);
}
if (mStateModeTimer
> FADE_TIME
)
{
// after fade in, switch to normal state mode
switchState
(StateMode.
MODE_NORMAL);
return;
}
updateFadeColor
();
}
public void updateFadeOut
(float deltaTime
)
{
if (mCurrentState
!=
null)
{
mCurrentState.
updateFading(deltaTime
);
}
if (mStateModeTimer
> FADE_TIME
)
{
// switch to exiting current state
switchState
(StateMode.
MODE_EXIT_STATE);
return;
}
updateFadeColor
();
}
public void updateInitState
(float deltaTime
)
{
// if current state is null, current state has not been created yet
if (mCurrentState ==
null)
{
if (mNextStateClass ==
null)
return;
mCurrentState = createNextState
(mNextStateClass
);
mNextStateClass =
null;
// call asynchronous loading first.
if (mCurrentState
!=
null)
mCurrentState.
initAsync(mParam
);
}
else
{
// Current state was already been created, so wait for asynchronous loading to finish
if (getAssetManager
().
update())
{
//Gdx.app.log("BLA", "DONE");
// done loading, so call synchronous loading
mCurrentState.
init(mParam
);
getGame
().
updateInternalTimer();
// now finally switch
if ((mCurrentState
!=
null) && (mCurrentState.
doFadeIn()))
{
switchState
(StateMode.
MODE_FADEIN);
updateFadeColor
();
}
else
switchState
(StateMode.
MODE_NORMAL);
}
}
}
public void updateExitState
(float deltaTime
)
{
if (mCurrentState
!=
null)
{
mCurrentState.
exit();
mCurrentState =
null;
}
switchState
(StateMode.
MODE_INIT_STATE);
}
public void updateFadeColor
()
{
float r = 0.0f
;
float g = 0.0f
;
float b = 0.0f
;
float alpha = 0.0f
;
if (mStateMode == StateMode.
MODE_FADEOUT)
{
if (mCurrentState
!=
null)
{
r = mCurrentState.
getFadeOutColor().
x;
g = mCurrentState.
getFadeOutColor().
y;
b = mCurrentState.
getFadeOutColor().
z;
}
alpha = MathUtil.
clamp(mStateModeTimer / FADE_TIME, 0.0f, 1.0f
);
}
else if (mStateMode == StateMode.
MODE_FADEIN)
{
if (mCurrentState
!=
null)
{
r = mCurrentState.
getFadeInColor().
x;
g = mCurrentState.
getFadeInColor().
y;
b = mCurrentState.
getFadeInColor().
z;
}
alpha = 1.0f-MathUtil.
clamp(mStateModeTimer / FADE_TIME, 0.0f, 1.0f
);
}
mScreenFader.
setFadeColor(r, g, b, alpha
);
}
/** Render the current game state (if one is running). */
public void render
()
{
float r =
0;
float g =
0;
float b =
0;
if (mCurrentState
!=
null)
{
r = mCurrentState.
getFadeOutColor().
x;
g = mCurrentState.
getFadeOutColor().
y;
b = mCurrentState.
getFadeOutColor().
z;
}
switch (mStateMode
)
{
case MODE_NORMAL:
if (mCurrentState
!=
null)
mCurrentState.
render();
break;
case MODE_FADEIN:
case MODE_FADEOUT:
if (mCurrentState
!=
null)
mCurrentState.
render();
mScreenFader.
render();
break;
case MODE_EXIT_STATE:
// black out completely
mScreenFader.
setFadeColor(r, g, b, 1.0f
);
mScreenFader.
render();
break;
case MODE_INIT_STATE:
// render loading screen
if ((mCurrentState
!=
null) && (mCurrentState.
haveLoadingScreen()) && (mLoadingScreen
!=
null))
{
// render loading screen
mLoadingScreen.
render();
}
else
{
// no loading screen or not specified to use, so just render fade-in color in preparation
mScreenFader.
setFadeColor(r, g, b, 1.0f
);
mScreenFader.
render();
}
break;
}
}
/** Called when the surface properties changed. */
public void onSurfaceChanged
(int w,
int h
)
{
if (mCurrentState
!=
null)
{
mCurrentState.
onSurfaceChanged(w, h
);
}
}
/** Called when resuming after pausing and initially. */
public void onResume
()
{
if (mCurrentState
!=
null)
{
mCurrentState.
onResume();
}
}
/** Called when the app is paused. */
public void onPause
()
{
if (mCurrentState
!=
null)
{
mCurrentState.
onPause();
}
}
// Getters/Setters==================================================================================
/** Set the default package name. */
public void setDefaultPackage
(String defaultPackage
) { mDefaultPackage = defaultPackage
; }
/** Get the last set parameter. */
public String getCurrentParam
() { return mParam
; }
/** Get the current state or null if no state is set. */
public BaseGameState getCurrentState
() { return mCurrentState
; }
/** Provide a loading screen implementation. */
public final void setLoadingScreen
(BaseLoadingScreen loadingScreen
) { mLoadingScreen = loadingScreen
; }
/** Get the loading screen. */
public final BaseLoadingScreen getLoadingScreen
() { return mLoadingScreen
; }
}