tag:robotlegs.tenderapp.com,2009-10-18:/discussions/solutions/12-best-way-to-restart-an-appRobotlegs: Discussion 2018-10-18T16:35:23Ztag:robotlegs.tenderapp.com,2009-10-18:Comment/55726812011-02-25T10:11:17Z2011-02-25T10:11:17ZBest way to restart an app<div><p>Hi there,</p>
<p>I had to deal with this for restarting my strategy game - the
solution I came up with was that the ResetGameCommand dispatches an
event on the contextView.</p>
<p>The contextView is actually a child of the root view. The root
view picks up this event and then chucks away the old context and
contextView, waits for a moment, and then makes a completely new
once.</p>
<p>All the code is on github (the whole game):</p>
<p><a href=
"https://github.com/Stray/robotlegs-demo-StrategyGame/blob/master/src/PyramidGame.as">
https://github.com/Stray/robotlegs-demo-StrategyGame/blob/master/sr...</a></p>
<p>But the key bits are the the command:</p>
<pre>
<code>public class RestartGameCommand extends Command
{
override public function execute():void
{
var evt:GameEvent = new GameEvent(GameEvent.GAME_RESTARTED);
contextView.dispatchEvent(evt);
}
}</code>
</pre>
<p>And the way the root view adds the context etc and listens for
the event:</p>
<pre>
<code>public class PyramidGame extends Sprite {
protected const PAUSE_FRAME_COUNT:uint = 25;
protected var _context:PyramidGameContext;
protected var _contextView:Sprite;
protected var frameCount:uint;
public function PyramidGame() {
createNewContext();
}
protected function listenForRestart():void
{
_contextView.addEventListener(GameEvent.GAME_RESTARTED, restartHandler);
}
protected function restartHandler(e:GameEvent):void
{
removeChild(_contextView);
_contextView = null;
_context = null;
restartAfterPause();
}
protected function restartAfterPause():void
{
frameCount = 0;
addEventListener(Event.ENTER_FRAME, enterFrameHandler);
}
protected function enterFrameHandler(e:Event):void
{
frameCount++;
if(frameCount > PAUSE_FRAME_COUNT)
{
removeEventListener(Event.ENTER_FRAME, enterFrameHandler);
createNewContext();
}
}
protected function createNewContext():void
{
_contextView = new Sprite();
addChild(_contextView);
_context = new PyramidGameContext(_contextView);
listenForRestart();
}
}</code>
</pre>
<p>I found that I needed to allow about a second for garbage
collection to fully run - that's what the 25 frame pause is for. It
actually feels more 'right' as a player as well.</p>
<p>So - really it's achieving the same but you don't need to use a
nasty static public method :)</p>
<p>Stray</p></div>Straytag:robotlegs.tenderapp.com,2009-10-18:Comment/55726812011-02-25T10:19:30Z2011-02-25T10:22:46ZBest way to restart an app<div><p>The current approach we have taken at work for console games is
to have a RestartGameCommand which will basically display the title
screen of the game. On the title screen we have a big start button
which will as you can imagine start the game. If the user clicks on
the button the GameEvent.START_GAME is getting dispatches which
gets handled by the StartGameCommand which update the
StatisticsModel and then recreate the game model for the new game
session. At the end of the command it will open the appropriate
game screen/view.</p>
<p>As you can see we are currently recycling the application
context and only cleanly dispose the views and recreate the game
session models and re-initalise it. The statistics model wont get
recreated:</p>
<pre>
<code> // update the game statistics data
model.gameStarted = new Date().getTime() / TimeUnits.SECOND;
model.gameEnded = 0;
model.gameScore = 0;
model.gameWon = false;
model.statTotalGames++;
screenManager.openScreen( GameScreen, true, true ); // opens a new screen (view)
dispatch( new GameEvent( GameEvent.GAME_STARTED ) );</code>
</pre>
<p>The nice thing about this that you can have idle detection in
your application mediator and then let it dispatch
GameEvent.RESTART_GAME when idling has (n seconds of no user input)
which reset the game and show the title screen. You can then even
do a forced garbage collection.</p></div>Weyerttag:robotlegs.tenderapp.com,2009-10-18:Comment/55726812011-02-25T10:25:09Z2011-02-25T10:26:26ZBest way to restart an app<div><p>The only problem I am experiencing what the best way is to open
different screens of the game. Such as, title screen, highscore,
help, score submission screen etc. Currently we have a class called
ScreenManager which manages the screens. It's doing things as
playing a sound effect when switching screens, doing a transitions
like cross fades and then add/remove the screens.</p>
<p>Maybe I should replace the openScreen-method with an event which
gets received by the application mediator which calls the screen
manager or something.</p></div>Weyerttag:robotlegs.tenderapp.com,2009-10-18:Comment/55726812011-02-25T11:51:55Z2011-02-25T11:51:56ZBest way to restart an app<div><p>Thanks for all your very swift help guys! Cool thing is that
I've already built Stray's method myself, because it triggers a
complete fresh game. But it was missing 2 things:<br>
1) the command dispatching the event<br>
2) the delay for garbage collection.</p>
<p>FDT profiler showed the old context and it wasnt GCed, so I'm
gonna try that delay now first. Hope it'll work.</p>
<p>@Weyert: you should take a look at Navigator for AS3. That will
solve your navigational issues for sure! You can check it out here:
<a href=
"https://github.com/epologee/navigator-as3">https://github.com/epologee/navigator-as3</a></p></div>eriktag:robotlegs.tenderapp.com,2009-10-18:Comment/55726812011-02-25T12:04:11Z2011-02-25T12:04:11ZBest way to restart an app<div><p>Aah yes, we weren't able to use Stray's approach because we need
to keep tracking of the played game sessions statistics during the
duration the application is running. I think it's a bit daunting to
keep saving statistics back to the database before recreating the
context and then loading it in again.</p>
<p>I will have a look at navigator-as3</p></div>Weyerttag:robotlegs.tenderapp.com,2009-10-18:Comment/55726812011-02-25T12:46:06Z2011-02-25T12:46:06ZBest way to restart an app<div><p>Nice one Erik - sounds like you were almost there.</p>
<p>Weyert - In your situation another option would be to pass the
data you wish to save out to your parent view, and then send it
back in to the new context.</p>
<p>Eg - make your context constructor like</p>
<pre>
<code>public function GameContext(contextView:DisplayObjectContainer, reusableGameObjects:GameObjectsVO, autoStartup:Boolean = true):void
{
if(reusableGameObjects == null)
{
// do this extra stuff...
}
}</code>
</pre>
<p>Then add a function to be run before the context is disposed</p>
<pre>
<code>public function getReusableGameObjects():GameObjectsVO
{
// return the stuff you want to use again
}</code>
</pre>
<p>Then you pass it back in</p>
<pre>
<code>context = new GameContext(contextView, reusableGameObjects);</code>
</pre>
<p>Personally I don't like conditionals much, so I'd likely have 2
contexts - GameContext and FirstGameContext and FirstGameContext
would just extend GameContext and add the extra wiring to get the
stats etc that are needed from the server.</p>
<p>Maybe the way you are doing it is better :) - was just a
thought.</p></div>Straytag:robotlegs.tenderapp.com,2009-10-18:Comment/55726812011-02-25T13:35:40Z2011-02-25T13:35:40ZBest way to restart an app<div><p>Well, easiest way for me to do it ;)</p>
<p>A bootstrap context and separate application context is an
interesting thought!!! The bootstrap context could do all the
daunting work like loading the language files, settings files,
sound data, asset packages etc. Stuff that only should be loaded
once and then afterwards the application context kicks in. You can
then recreate the latter context when the game needs to be
restarted. The bootstrap context could then just inject utilities
or data into the application context. Like the settings and
language model from the bootstrap context</p>
<p>Otherwise you have all kind of issues when settings files are
being changes between game sessions e.g. maximum game session
duration or score ranges. This would be a bit unfair when you would
reload the whole application. Also in off-line games you don't want
to reload megs of assets etc. when restarting the game.</p></div>Weyerttag:robotlegs.tenderapp.com,2009-10-18:Comment/55726812011-02-25T16:17:23Z2011-02-25T16:17:25ZBest way to restart an app<div><p>Hmmmm, restarting seems to work fine, but I've got a problem.
When using the FDT profiler, it seems the nullified <em>context
and</em> contextView instances aren't getting garbage collected,
causing my memory consumption to rise to high levels. When tracing
the member values, they return 'null' , but they still don't get
garbage collected...</p>
<p>@stray: did you ever profile this solution yourself when
building that pyramid game?</p>
<p>Is it just friday that I'm missing something?!!?!</p></div>eriktag:robotlegs.tenderapp.com,2009-10-18:Comment/55726812011-02-25T16:33:30Z2011-02-25T16:33:30ZBest way to restart an app<div><p>Little update: Using Mr Doobs Stats class, I get completely
different memory results than with the FDT profiler.</p>
<p>Also, I can't imagine Stray's solution isn't garbage collected
since all references are removed in the restart() method. I get the
feeling that something isn't working properly in the FDT profiler.
Gonna send Meinhard Gredig an email :-)</p>
<p>Cheers and happy weekend.</p></div>eriktag:robotlegs.tenderapp.com,2009-10-18:Comment/55726812011-02-25T16:55:18Z2011-02-25T16:55:18ZBest way to restart an app<div><p>Hi erik,</p>
<p>I don't use a profiler (I build in TextMate rather than any of
the eclipse based monsters) but using the standard mac app profiler
I don't find the memory footprint growing over restarts - it seems
rather constant.</p>
<p>Let me know what you find - I can't think of any reason why it
wouldn't be GC'd ...</p>
<p>Stray</p></div>Stray