This is simple, very simple, but it works. It need to be used internally by jme, for example, in simpleUpdate/controlUpdate/etc. the tpf should be 0 if GameTime is in pause state, but a special Node at the very top of the scene’s tree, which overrides updateLogicalState will do the trick. This way you can stop everything: animations, particles etc.
There are an example functions loadFromSave and getSaveData which shows that including the game time in savegame file is an easy task.
Having an access to current time (not only tpf) in object’s controllers allows you to calculate everything like x = f(time);
This is the way everything works in my Skullstone. Doors? I have _timeStartSwitchState and _timeEndSwitchState, which are serialized during savegame too, I can save/reload/pause game whilethe doors are opening and everything works like a charm.
GameTime class is thread safe.
@nehon if you find it useful add it to 3.1.
Here is the code:
import java.io.IOException;
import com.dungeongame.gameclient.util.SaveReader;
import com.dungeongame.gameclient.util.SaveWriter;
public class GameTimer
{
public class GameTimeState
{
private long _time;
private boolean _paused;
public long getTime()
{
return _time;
}
public boolean isPaused()
{
return _paused;
}
}
private static GameTimer _instance;
public static GameTimer getInstance()
{
if (_instance == null) _instance = new GameTimer();
return _instance;
}
private boolean _pause;
private long _beforePauseTime;
private long _resumeTime;
private long _internalTime;
private long _gameTime;
private GameTimer()
{
_pause = false;
_beforePauseTime = 0;
_internalTime = System.nanoTime() / 1000000;
_resumeTime = _internalTime;
_gameTime = 0;
pause();
}
public GameTimeState createState()
{
return new GameTimeState();
}
public synchronized boolean isPaused()
{
return _pause;
}
public synchronized long pause()
{
_internalTime = System.nanoTime() / 1000000;
_gameTime = _beforePauseTime + (_internalTime - _resumeTime);
if (_pause) return _gameTime;
_pause = true;
_beforePauseTime = _gameTime;
return _gameTime;
}
public synchronized void resume()
{
_pause = false;
_resumeTime = System.nanoTime() / 1000000;
}
/**
*
* @param newTime czas gry np. sprzed zrobienia save
*/
public synchronized void resume(long newTime)
{
_beforePauseTime = newTime;
_pause = false;
_resumeTime = System.nanoTime() / 1000000;
}
public synchronized void fillState(GameTimeState st)
{
st._paused = _pause;
if (_pause) st._time = _gameTime;
else st._time = _beforePauseTime + ((System.nanoTime() / 1000000) - _resumeTime);
}
public synchronized long getGameTime()
{
if (_pause) return _gameTime;
return _beforePauseTime + ((System.nanoTime() / 1000000) - _resumeTime);
}
public synchronized int loadFromSave(SaveReader sav)
{
try
{
_gameTime = sav.readLong();
_beforePauseTime = sav.readLong();
_resumeTime = sav.readLong();
}
catch (IOException e)
{
e.printStackTrace();
}
return 0;
}
public synchronized SaveWriter getSaveData()
{
SaveWriter sw = new SaveWriter();
try
{
sw.writeLong(_gameTime);
sw.writeLong(_beforePauseTime);
sw.writeLong(_resumeTime);
}
catch (IOException e)
{
e.printStackTrace();
}
return sw;
}
}