Subversion Repositories AndroidProjects

Rev

Rev 856 | Blame | Compare with Previous | Last modification | View Log | RSS feed

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; }
       
       
}