package stu.tnt.gdx.core;
import stu.tnt.gdx.core.Timer.Task;
import stu.tnt.gdx.core.loader.SafeLoader;
import stu.tnt.gdx.core.utils.Bridge;
import stu.tnt.gdx.core.utils.BridgePool;
import stu.tnt.gdx.graphics.graphics2d.NWorld;
import stu.tnt.gdx.screen.LoadingScreen;
import stu.tnt.gdx.utils.E;
import stu.tnt.gdx.utils.EasyNativeLoader;
import stu.tnt.gdx.utils.exception.EasyGEngineRuntimeException;
import stu.tnt.gdx.widget.Dialog;
import stu.tnt.platform.DesktopHandler;
import stu.tnt.platform.IActivityHandler;
import com.badlogic.gdx.ApplicationListener;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.PauseableThread;
/**
* @FileName: GameCore.java
* @CreateOn: Sep 15, 2012 - 11:05:26 AM
* @Author: TrungNT
*/
public abstract class GameCore implements ApplicationListener {
// ============= Screen mangage =============
/** This screen is the main screen which is visible all time */
protected Screen screen;
/**
* when the game is call onPause from activity core save it current screen to this reference
*/
private Screen mSavedScreen;
/** The main loading screen use to load and reload openGL context */
private LoadingScreen mStartScreen;
/**
* This flag show that the game core is come back from pause and now it is resume
* <p>
*
* @True if is on from running turn to onPause
* @False if is on from onPause back to onResume
*/
private boolean isStarted = false;
/** Flag show that the game is pause */
private boolean isPause = false;
private Class<? extends SafeLoader> mDefaultLoader;
// ============= Utils manage =============
private final BridgePool bridgePool;
final IActivityHandler mActivity;
// ============= Schedule code =============
final Timer mSchedulerTimer;
final ThreadManager mThreadManager;
// ============= Runnable for synchoronize schedule =============
final Array<Runnable> runnables = new Array();
final Array<Runnable> executedRunnables = new Array();
/***********************************************************
* Constructors
* ***********************************************************/
public GameCore (IActivityHandler activity) {
this.mActivity = activity;
bridgePool = new BridgePool(13);
Bridge.registerRecyleListener(bridgePool);
mSchedulerTimer = new Timer();
mThreadManager = new ThreadManager();
}
public GameCore () {
this(new DesktopHandler());
}
// ============= default loader method =============
/**
* The safe loader is use to change screen in safe mode when you not sure all contexts are loaded
*
* @param yourSafeLoader
*/
public void setDefaultSafeLoader (Class<? extends SafeLoader> yourSafeLoader) {
mDefaultLoader = yourSafeLoader;
}
/**************************************************************
* ApplicationListener methods
* **************************************************************/
@Override
public void create () {
eAdmin.egame = GameCore.this;
eAdmin.einput = new eInput();
eAdmin.egraphics = new eGraphics();
eAdmin.eaudio = new eAudio();
eAdmin.econtext = new eContext();
Screen.setCoreProcessor(this);
Screen.batch = new SpriteBatch();
Screen.layout = null;
EasyNativeLoader.load();
mSchedulerTimer.reset();
Gdx.input.setInputProcessor(eAdmin.einput);
Dialog.DIALOG_NUMBER = 0;
onGameConfig();
}
protected void CreateNativeWorld (int size_of_NSprite, int size_of_NSpriteA) {
eAdmin.eworld = new NWorld(size_of_NSprite, size_of_NSpriteA);
}
@Override
public void resize (int width, int height) {
eAdmin.egraphics.resolve(width, height);
if (screen != null) screen.resize(width, height);
onGameChanged(width, height);
}
private float delta;
@Override
public void render () {
if (isPause) return;
delta = Gdx.graphics.getDeltaTime();
// ============= Start schedule =============
synchronized (runnables) {
executedRunnables.clear();
executedRunnables.addAll(runnables);
runnables.clear();
for (int i = 0; i < executedRunnables.size; i++) {
try {
executedRunnables.get(i).run();
} catch (Throwable t) {
t.printStackTrace();
}
}
}
// ============= Update screen =============
if (screen != null) {
screen.onRender(delta);
screen.update(delta);
}
onGameRender(delta);
}
@Override
public void pause () {
isPause = true;
onGamePause();
// stop scheduler
mSchedulerTimer.stop();
// save context if you want to reload
isStarted = false;
mSavedScreen = screen;
// call pause
if (screen != null) screen.pause();
}
@Override
public void resume () {
isPause = false;
onGameResume();
// reload context
if (!isStarted) {
screen = mStartScreen;
mStartScreen.setChangedScreenListener(new LoadingScreen.OnChangedScreen() {
@Override
public Screen screenChanged () {
// re-start schedule
mSchedulerTimer.start();
return mSavedScreen;
}
});
mStartScreen.show();
mStartScreen.resize(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
isStarted = true;
return;
}
}
@Override
public void dispose () {
if (screen != null) screen.destroy(E.screen.RELEASE);
isStarted = false;
onGameDestroy();
// ------ clear all list ------
this.bridgePool.clear();
runnables.clear();
executedRunnables.clear();
// ------ dispose native ------
eAdmin.eworld.dispose();
}
/**************************************************************
* Main GameCore methods
* **************************************************************/
/** Config all game components */
protected abstract void onGameConfig ();
/**
* Listen to surface size
*
* @param width the screen width
* @param height the screen height
*/
protected abstract void onGameChanged (int width, int height);
/**
* Render all stuff here
*
* @param DeltaTime the time each frame repeat
*/
protected abstract void onGameRender (float delta);
/** Your pause stuff here ,such as: save your preferences */
public abstract void onGamePause ();
/** This method do the same function as resume */
protected abstract void onGameResume ();
/** This method will release memory */
protected abstract void onGameDestroy ();
/**********************************************
* Screen changing methods
* **********************************************/
private boolean isLoading = false;
protected void setStartScreen (LoadingScreen loadScreen) {
if (isStarted) throw new EasyGEngineRuntimeException("One GameCore cant set start screen twice");
this.mStartScreen = loadScreen;
setScreen(loadScreen, E.screen.RELEASE);
isStarted = true;
}
/**
* Set the current screen to the new screen
*
* @param screen new Screen
* @param destroyMode destroyMode of old Screen
*/
void setScreen (Screen screen, int destroyMode) {
/*
* check if the current screen is the loading screen , if is the loading screen, the show method of next screen only call
* for the first time load
*/
isLoading = (this.screen instanceof LoadingScreen);
if (isLoading) isLoading = isLoading & !((LoadingScreen)this.screen).isFirstTimeLoad();
if (this.screen != null) this.screen.destroy(destroyMode);
this.screen = screen;
if (this.screen != null) {
if (!isLoading)
screen.show();
else
mSavedScreen.resume();
screen.resize(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
}
}
void setScreen (Screen screen, ResourceContext... contexts) {
final ResourcePack pack = new ResourcePack(SafeLoader.name, contexts);
if (pack.isTotallyLoaded()) {
setScreen(screen, E.screen.RELEASE);
return;
}
if (mDefaultLoader == null) throw new EasyGEngineRuntimeException("The default safe loader is null");
SafeLoader loader;
try {
loader = mDefaultLoader.newInstance();
loader.setLoaderInfo(screen, pack);
setScreen(loader, E.screen.RELEASE);
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
void setScreen (Screen screen, ResourcePack pack) {
if (pack.isTotallyLoaded()) {
setScreen(screen, E.screen.RELEASE);
return;
}
if (mDefaultLoader == null) throw new EasyGEngineRuntimeException("The default safe loader is null");
SafeLoader loader;
try {
loader = mDefaultLoader.newInstance();
loader.setLoaderInfo(screen, pack);
setScreen(loader, E.screen.RELEASE);
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
public Screen getCurrentScreen () {
return screen;
}
/**************************************************************
* Bridge Manage method
* **************************************************************/
public Bridge newBridge (Class<?> firstClass, Class<?> secondClass) {
Bridge tmp = getBridge(firstClass, secondClass);
if (tmp == null) return this.bridgePool.obtain(firstClass, secondClass);
return tmp;
}
public Bridge newBridge (String name) {
Bridge tmp = getBridge(name);
if (tmp == null) return this.bridgePool.obtain(name);
return tmp;
}
private Bridge getBridge (Class<?> firstClass, Class<?> secondClass) {
return bridgePool.getUsingBridges().get(firstClass.getName() + secondClass.getName());
}
private Bridge getBridge (String name) {
return bridgePool.getUsingBridges().get(name);
}
/**************************************************************
* Activity handler methods
* **************************************************************/
public IActivityHandler getActivity () {
return mActivity;
}
public boolean isBindActivity () {
return mActivity == null;
}
/**************************************************************
* Schedule method for timer
* **************************************************************/
public void postTask (Task task) {
mSchedulerTimer.postTask(task);
}
public void schedule (Task task) {
mSchedulerTimer.scheduleTask(task);
}
public void schedule (Task task, float delaySeconds) {
mSchedulerTimer.scheduleTask(task, delaySeconds);
}
public void schedule (Task task, float delaySeconds, float intervalSeconds) {
mSchedulerTimer.scheduleTask(task, delaySeconds, intervalSeconds);
}
public void schedule (Task task, float delaySeconds, float intervalSeconds, int repeatCount) {
mSchedulerTimer.scheduleTask(task, delaySeconds, intervalSeconds, repeatCount);
}
public void stopScheduler () {
mSchedulerTimer.stop();
}
public void startScheduler () {
mSchedulerTimer.start();
}
public void clearScheduler () {
mSchedulerTimer.clear();
}
public void removeTask (Task task) {
mSchedulerTimer.removeTask(task);
}
public void postRunnable (Runnable runnable) {
synchronized (runnables) {
runnables.add(runnable);
Gdx.graphics.requestRendering();
}
}
/**************************************************************
* Thread manager
* **************************************************************/
public int newThreadId (Runnable runnable) {
return mThreadManager.obtainForID(runnable);
}
public PauseableThread newThread (Runnable runnable) {
return mThreadManager.obtainForThread(runnable);
}
public boolean startThread (int id) {
return mThreadManager.startThread(id);
}
public boolean stopThread (int id) {
return mThreadManager.stopThread(id);
}
/**
* Pause a given thread which have your id
*
* @param id
* @return true if successful pause , otherwise false
*/
public boolean pauseThread (int id) {
return mThreadManager.pauseThread(id);
}
/**
* Resume a given thread which have your id
*
* @param id
* @return true if successful resume , otherwise false
*/
public boolean resumeThread (int id) {
return mThreadManager.resumeThread(id);
}
public boolean containThread (int id) {
return mThreadManager.containThread(id);
}
public boolean containThread (PauseableThread thread) {
return mThreadManager.containThread(thread);
}
public int sizeOfThread () {
return mThreadManager.size();
}
public int sizeOfRunningThread () {
return mThreadManager.sizeOfAlive();
}
}