Game Development Community

1.1.3 to 1.5 SimSet add, remove act different

by Stanley D Chatman · in Torque Game Builder · 07/19/2007 (7:03 pm) · 7 replies

I have been using Kevin Ryan's Flying Letters technique for my game

It creates a guiBitmapCtrl on the fly using the mainScreenGui.add functioin. It later is removed using the remove command.

www.garagegames.com/blogs/105/11116

In TGB 1.5 it will bring your system to a screeching halt after adding over 10 guiBitmapCtrls.

I need someone to run a test program I have created on their system and let me know if they can get it to crash also. I am trying to determine if it is my system or not. This worked flawlessly under TGB 1.1.3 only when I converted has it been behaving like this


To download sample code
www.tccons.com/TestSimSet.zip


Here is the gut of the sample program
function TestSimSet::onUpdateScene(%this)
{
   %TC = 20;  // Change this to find number that makes crash
   
   for (%i = 0; %i < %TC; %i++)
   {
      
         %bitmap = "~/gui/hud_numbers2/" @ getRandom(9);      
         
         $tsp[%i] = new GuiBitmapCtrl() {
            //profile = "GuiDefaultProfile";
            profile = "GuiTransparentProfile";
            isContainer = "0";
            horizSizing = "width";
            vertSizing = "height";
            //position = "-100 0";
            extent = "24 40.39";
            minExtent = "8 8";
            visible = "1";
            helpTag = "0";
            bitmap = %bitmap @ ".png";
            wrap = "0";
            canSave = "1";            
         };
      
      mainScreenGui.add($tsp[%i]);
      
   }
   for (%i = 0; %i < %TC; %i++)
   {      
         
      mainScreenGui.remove($tsp[%i]);    
      
   }
}

#1
07/20/2007 (1:21 pm)
Stanley,

I'm not sure what you're trying to do here, and have looked at your example project thoroughly. The one thing I did notice is that this should never work. What the code you have posted will actually do is create an object leak. That is to say that it will create (n) objects every time the scene is updated in a call to onUpdateScene.

With your example code you can see this in action by running it with a number of objects that will not crash the engine (10 worked for me). Once you run it and it's going, open up the console and execute the following command.

$newObject = new SimObject(); error($newObject.getId());

You'll notice that when you run this is creates an object and then echo's that object's assigned SimObjectID to the console in red text.

Object ID's are assigned by incrementing the ID from the last ID assigned. That is to say when Torque starts up it will create objects and give them an ID that is one more than the last object that was created.

By repeatedly executing this line over and over in the console, you would expect that each time you called it, the ID would be (1) more than the last one, because you just created an object.

With your code you'll find that your ID keeps jumping much more than one each time you execute that statement. That is because in between the time you execute it the first time and the second time, onUpdateScene has been called, and your code has created (n) more new objects which it immediately removes from the mainScreenGui. It does not however delete the objects, so they stay around, mucking things up for you.

Hope this helps,
-Justin
#2
07/20/2007 (2:08 pm)
It is used for creating flying letters This code is taken verbatim from the code in Mini Golf Mania as posted in Kevin Ryan's blog @ www.garagegames.com/blogs/105/11116


I have been running this code for over a year and never had a problem. Try running in TGB 1.1.3 and you will not have a problem. Something has changed. Take a look at the code below it is taken from Kevin's blog about flying letters in his game mini Golf Mania.


www.topmeadow.com/plans/popUpText.cs
#3
07/20/2007 (3:18 pm)
Stanley,

Thanks for the offer to try this out myself, but I've not the time to do so unfortunately. If you want to post a real usage example (I'm assuming the test code you posted is not verbatim what you're doing) then I'd be glad to check it out.

Regardless of Kevin's code (which is nifty), the code and example project you posted does exactly what I outlined in my previous post. It creates and does not free objects. Worse yet, it creates them every time the scene is updated.

Kevin's use was in the context of 'create these objects when i call the showPopupMessage function', and your use is 'create these objects every time the scene gets a time update'.

Unless you can make available to me exactly what you're doing, I cannot help you any further.

Cheers,
-Justin
#4
07/20/2007 (3:44 pm)
Here are the links to my real-usage code

tccons.com/SmashEmoticons/gameScripts.zip

It crashes in the MoleLevel::onUpdateScene callback after all 4 ShowHuds have been called.
updatePopupMessage();
   showHud( padString($score_text,7,"0"), 120, 50,mainScreenGui); //score  
   
   
  //// showHud( padString("1234567890",7,"0"), 120, 50,mainScreenGui); //score  
   
    
   showHud2( $cl, 40, 34,mainScreenGui); //Level
   if ( $health_score > 99 ) $health_score = 99;
   if ( $health_score <= 0  && $GAME_OVER == false)
   {
       $health_score = 0;
       $GAME_OVER = true;
       %this.onLevelEnded();
      %this.setScenePause( true );
       GameOverStart(%this);
   }
   showHud3(padString($health_score,2,"0") , 325, 34,mainScreenGui); //Health
   showHud4(padString($bonus_score,7,"0") , 440, 50,mainScreenGui); //Bonus Gems
#5
07/20/2007 (7:09 pm)
Stanley,

Oh boy what a find! Long story short, multiple GuiControls should not be created and added to the currently displaying Gui content of the game during a t2dScenegraph::onUpdateScene callback.

I looked into fixing this, but to do so would require changing the order in which the onUpdateScene callbacks occur, and that could potentially cause more compatibility issues between 1.1.3 and 1.5 games.

So for now a good rule of thumb is : Do not create on-screen Gui Controls in the t2dSceneGraph's "onUpdateScene" callback.

The workaround
If you want to patch your game quickly because you need to ship it soon, a good fix for this issue would be to schedule for 0 milliseconds the calls to showHud/2/3/4 functions and you should stop crashing.\

Here's my modified version of your test to demonstrate this workaround.

Note that this code will still *not* delete the objects it creates so it is essentially a memory leak on every onUpdateScene call. (Your actual game did not exhibit this problem because Kevin's code deletes the objects)
function TestSimSet::onUpdateScene(%this)
{
   %this.schedule(0,dontAddObjectsToTheCanvasInUpdateScene);
}

function TestSimSet::dontAddObjectsToTheCanvasInUpdateScene( %this )
{
   %TC = 35; //10;  // Change this to find number that makes crash

   for (%i = 0; %i < %TC; %i++)
   {
         %bitmap = "~/gui/hud_numbers2/" @ getRandom(9);      
         
         $tsp[%i] = new GuiBitmapCtrl() {
            //profile = "GuiDefaultProfile";
            profile = "GuiTransparentProfile";
            isContainer = "0";
            horizSizing = "width";
            vertSizing = "height";
            //position = "-100 0";
            extent = "24 40.39";
            minExtent = "8 8";
            visible = "1";
            helpTag = "0";
            bitmap = %bitmap @ ".png";
            wrap = "0";
            canSave = "1";            
         };      
      mainScreenGui.add($tsp[%i]);      
   }
   for (%i = 0; %i < %TC; %i++)
   {      
      mainScreenGui.remove($tsp[%i]);    
   }   
}


Performance Consideration?
If you do have a bit of time I'm a bit concerned about the fact that every update you are calling showHud which destroys and recreates all these GuibitmapCtrl's. When Kevin wrote that code it made sense because he would only show messages for a short period of time then want them deleted.

If you're trying to your 4 hud's all the time while playing, you may want to create them at level load time and then only destroy/recreate them when they change (say you hit a mole and the counter goes up, then you call showHud/2/3 or 4 based on what stat changed)

To show you what I mean, take a look at the image below that I took from the test code above.

uiObsession.com/images/j/lotsOfObjects.jpg
This shows us that after having your test code, that i modified not to crash, run for just over a minute; TGB has created and properly destroyed over 100,000 objects (using %TC = 35;). That means you will be spending a lot of time creating objects every time the scene is updated.

Hope this all helps in some way
-Justin
#6
07/20/2007 (8:15 pm)
Thanks Justin, I really appreaciate your help in finding this. In looking at this in the context you speak, it probably should have not worked in TGB 1.1.3. I will re-code and create in onLevelLoaded and do a re-create when one of the variables change.



Good Job!!
#7
07/20/2007 (8:16 pm)
Excellent stanley, hope it works out for you