Game Development Community

Items from my inventory disappear. How to check memory usage?

by Vlad I · in Torque Game Builder · 11/24/2012 (8:16 am) · 9 replies

I'm still working on my hidden object game.
Found a wierd bug.

My usable items disappear when I run from level to level in about 10 minutes of game play.
The items I pick up are stored in my inventory and written into a file inventory.sav every time I pick one up. Then the items are read/loaded from that file to the inventory on a onLevelLoaded every time I go to another level.

I have about 450 images, some of them have size 1024*1024. They are all preloaded, could this be the cause?

What's the difference between preloaded and not?

Also, when I progress in the game after some 5-10 minutes it tends to load levels with a slight delay.

How to check the fps, memory, CPU, and video memory usage?

P.S.
While I run the game and this bug happens, the inventory.sav file is empty. Usually there is some data about the items I pick up so they could be read and loaded to the game onLevelLoaded.


#1
11/24/2012 (9:32 am)
Are you using the GuiMLTextCtrl to populate the items for the user when he/she checks their inventory? If so I have found it to be very glitch-prone. For instance when I have it read a .txt file and there are any newlines on the text file that I created by using the enter key then it will reject it and not populate the info (read error).

In theory, if you are using this or something similar then it might be that you are not closing out the %file (%file.close(); file.delete();) that you had created in script to populate the data on the inventory. When the user exits out of the inventory it may result in strange artifacts that you are describing.
#2
11/24/2012 (9:42 am)
%yourSceneGraph.setDebugOn(0);

Also, make sure that you close a file once you write to it. In most languages, it will be empty like you said, until you close it.
#3
11/24/2012 (10:09 am)
I dont use Guis at all.
The items are stored into the file with some data such as image map, size, class etc. Then read out and recreated as
new t2dStaticSprite()

Yeap, everything is closed
$stream.close();
 $stream.delete();

There was a hot key or smth. that brings an fps or memory usage screen with green fonts in TGB editor or when you run the game, I just don't remember how to call it.

Kevin what do you mean by :
%yourSceneGraph.setDebugOn(0);
#4
11/24/2012 (12:48 pm)
If you know what your scenegraph is named, you can call setDebugOn on it and see a debug banner that includes FPS, and some other useful information, but not everything that you're looking for ...

What do you want to do with memory??
#5
11/24/2012 (3:00 pm)
scenegraph.setDebugOn(0) should have all you need:
docs.garagegames.com/tgb/official/index.html?content/documentation/Scripting/Int...

Your images may be putting a strain on the system if they are all that large, and you're shrinking them down. I would recommend sizing down as much as possible.

Here's info on preload:
“preload”

Although you can happily leave T2D to deal with the memory used by image-maps, there comes a time when you might want to provide some hint on how it's handled. By default, when you create an image-map, T2D compiles all the imagery and packs it into textures which are then activated so you can start using it immediately. The trouble is that when the textures are activated, they occupy memory. If you define all your image-maps at the start of your game, they can occupy considerable memory. This is essentially preloading in action. The “preload” field allows you to control this aspect; if you set this field to false (off) then T2D will compile and pack the image-maps but it won't load the textures.

So when will it? T2D will load the textures as soon as any object references the texture; if you were to assign a frame to a sprite for instance. The downside here is that it can take a little time to activate the textures, dependent upon the current machine's performance. The good thing though is that you use as little memory as possible right up to the point where you use it. Of course, this is totally your choice and should be used with care as not preloading things can potentially hurt performance if T2D ends up doing lots of work activating textures when, as far as the user is concerned, it should be creating sprites at a critical moment.
You can use "$prefs::T2D::imageMapPreloadDefault" to control the default value for the “preload” field.
#6
11/24/2012 (7:41 pm)
Awesome to know, thanks Doc!
#7
11/25/2012 (10:49 am)
Still having that problem :(

Here is my code for saving and loading my inventory. Perhaps you can spot something wrong with it.
function levelTransition::onMouseDown(%this, %modifier, %worldPosition, %clicks)
{
   //NOTE: THIS CODE CAN BE CHANGED HOWEVER YOU MUST ALWAYS CALL THE ENDLEVEL() AND LOADINVENTORY() BEFORE AND AFTER YOU LOAD
   //A LEVEL RESPECTIVELY.
   
   //if the player has clicked on an item which is a leveltransition item and the cursorActive is false.
   if($cursorActive == false)
   {
      //exit the function.
      return;
   }
   
   //otherwise record the levelNo of the levelTransition object, this is the level you want to move it, make it in the engine on the object.
   %level = %this.levelNo;
   //This is for once use only then the levelTransition object disappears. You must set dynamic variable useOnce value 1   
   if(%this.useOnce == true)
   {
      updateSceneSave(%this);
   }
  
   
   //call the endLevel function
   endLevel(); 
   sceneWindow2D.schedule( 0, endLevel );
   //load the new level. (make sure to name accordingly)
   //this adds a 100ms delay just to make sure it doesn't crash from loading.
   sceneWindow2D.schedule( 0, loadLevel, "game/data/levels/level_" @ %level @ ".t2d" );
}

function endLevel()
{
   //create a new filestreamobject to write to a file.
   $stream = new FileStreamObject();
   //lets open up the inventory.sav file or if it is not there make one.
   $stream.open("~/data/inventory.sav","Write");
   
   for(%count = 0; %count < 21; %count ++)
   {
      //let us loop through all the objects in our inventory and check if they are there or not.
      if(isObject($inventoryItem[%count]))
      {
         //if they are there lets just write down their attributes to the file.
         $stream.writeline($inventoryItem[%count].scenegraph);
         $stream.writeline($inventoryItem[%count].class);
         $stream.writeline($inventoryItem[%count].imagemap);
         $stream.writeline($inventoryItem[%count].size);
         $stream.writeline($inventoryItem[%count].usemouseevents);
         $stream.writeline($inventoryItem[%count].usable);
         $stream.writeline($inventoryItem[%count].colour);
         $stream.writeline($inventoryItem[%count].opened);
         $stream.writeline($inventoryItem[%count].key);
         $stream.writeline($inventoryItem[%count].shape);
         $stream.writeline($inventoryItem[%count].saveable);
         //and delete the object when done.
         $inventoryItem[%count].delete();
      }
   }
      
   //we now close the old filestreamobject and delete it
   $stream.close();
   $stream.delete(); 
   
   //and make a new filestreamobject
   $stream = new FileStreamObject();
   //we open or create the save.sav file depending whether or not it exists.
   $stream.open("~/data/save.sav","Write");
   
   //we write the and the inventorytotal to the file
   $stream.writeline($inventoryTotal);
      
   //we close and delete the filestreamobject
   $stream.close();
   $stream.delete();
   
   //and we tell the engine that we have saved our game/inventory.
   $saved = true; 
}
#8
11/25/2012 (10:51 am)
function thescene::onLevelLoaded(%this, %scenegraph)
{
   //Create the inventory, this only needs to be called once.
   createInventory();
   //call the createInventoryGUI function.
   createInventoryGUI();
   //call the checkCurrentInventory function to check if we already have the items on the field.
   checkScenes();
   //load the inventory into the level.
   loadInventory(); 
}

function updateSceneSave(%object)
{
   $streamscenes = new FileStreamObject();
   $streamScenes.open("~/data/scenes.sav", "read");
   
   %objectCount = 0;
   
   while(!$streamscenes.isEOF())
   {
      %lines[%objectCount] = $streamscenes.readLine();
      %objectCount ++;
   }
      
   $streamScenes.close();
   
   $streamScenes.open("~/data/scenes.sav", "write");
   
   for(%count2 = 0; %count2 < %objectCount; %count2 ++)
   {
      $streamscenes.writeLine(%lines[%count2]);
   }
   
   $streamscenes.writeLine(%object.getImageMap());
   $streamscenes.writeLine(%object.getFrame());
   
   //we close and delete the filestreamobject
   $streamScenes.close();
   $streamScenes.delete();
}

function checkScenes()
{
   %scenegraph = sceneWindow2D.getSceneGraph();
   %objectList = %scenegraph.getSceneObjectList();
   %sceneobjectCount = %scenegraph.getSceneObjectCount();
   
   //we make another one to read the user save data
   $stream = new filestreamobject();
   $stream.open("~/data/scenes.sav", "read");  
   
   %objectCount = 0;
   
   while(!$stream.isEOF())
   {
      %lines[%objectCount] = $stream.readLine();
      %objectCount ++;
   }
   
   $stream.close();   
   $stream.open("~/data/scenes.sav", "read");  
   
   %objectCount /= 3;   
   
   %count = 0;
   
   while(%count < %objectCount)
   {
      %imageMap = $stream.readLine();
      %frame = $stream.readLine();
      %spaceBreaker = $stream.readLine();
      %count2 = 0;
      
      while(%count2 < %sceneobjectCount)
      {
         %previousObject = getWord(%objectList, %count2);
         
         //HERE IS WHERE THE OBJECTS WHICH GET PICKED UP ARE (LIKE KEYS)
         //This is for the squares/triangles/keys
         if(%previousObject.usable == true)
         {
            if(%previousObject.getImageMap() $= %imageMap && %previousObject.getFrame() $= %frame)
            {
               %previousObject.safeDelete();
            }
         }
         
         //HERE IS WHERE THE OBJECTS WHICH GET USED ON ARE (LIKE CHESTS)
         //for chests/black triangle/black squares
         else if(%previousObject.usedon == true)
         {
            if(%previousObject.getImageMap() $= %imageMap && %previousObject.getFrame() $= %frame)
            {
               //check what it is
               if(%previousObject.key !$= "")
               {
                  //if the object has a key value then it is a chest so
                  %previousObject.opened = true;
                  //make the current imagemap of the chest into the opened version of it by getting its colour
                  //be sure to set the colour of the chest as the first word in the imagemap name
                  %chestColour = %previousObject.key;
                  %previousObject.imagemap = %chestColour @"ChestOpened";
               }
               
               else
               
               if(%previousObject.shape !$= "")
               {
                  //if it has a shape it means it is a square/triangle object, so we just delete it.
                  %previousObject.safeDelete();
               }
            }
         }
         else if(%previousObject.useOnce == true)
         {
            %previousObject.safeDelete();
         } 
         %count2 ++;
      }
      
      %count ++;            
   }
   
   //we close and delete the stream object.
   $stream.close();
   $stream.delete(); 
}
}
#9
11/25/2012 (10:52 am)
function createInventory()
{
   //This just creates the inventory variables, this is only ever called on the first ever startup.
   $inventoryList = 1;
   $cursorActive = true;
}

function loadInventory()
{   
   //now let us check if we have a save file or if the player has recently saved and not closed the game.
   if($saved == true || isFile("~/data/save.sav"))
   {
      //create a new file stream object, this is used to read from files and write to files
      $stream = new filestreamobject();
      //open up a file, in this case it is the inventory.sav
      $stream.open("~/data/inventory.sav", "read");
      
      //now we will use a for loop to check what items have been saved in the inventory
      for(%count = 0; %count < 22; %count ++)
      {
         //this is used as a safe check to see if the current line has an object saved on it
         %scenegraphCheck = $stream.readline();
         
         //if there is know object on the current line, we will skip the next 6 lines and check the other ones.
         if(strlen(%scenegraphCheck) != 4)
         {
            //the checkcount has to be less than the number of lines you have for each object
            for(%checkCount = 0; %checkCount < 11; %checkCount ++)
            {
               %scenegraphCheck = $stream.readline();
            }
         }
         
         //here we check if we have reached the end of the opened file or if you have looped 21 times or if we have
         //got no more objects to load to the inventory.
         if($stream.isEOF() || %scenegraphCheck $= "" || %count == 21)
         {
            //we close and delete the stream object.
            $stream.close();
            $stream.delete(); 
      
            //we make another one to read the user save data
            $stream = new filestreamobject();
            $stream.open("~/data/save.sav", "read");
            
            //this is so we can record how much items we have in the inventory and were the initial index of loading them is (for gui only).
            $inventoryTotal = $stream.readLine();
            
            //we close and delete the stream object.
            $stream.close();
            $stream.delete(); 
      
            //and finally we update the inventory.
            updateInventory();
            return;
         }
         
         //if we have found an inventory item in the inventory.sav file we simply recreate it using the reading from the
         //saved attributes.
         $inventoryItem[%count] = new t2dStaticSprite()
         {
            scenegraph = sceneWindow2D.getSceneGraph();
            class = $stream.readline();
            imagemap = $stream.readline();
            size = $stream.readline();
            usemouseevents = $stream.readline();
            usable = $stream.readline();
            colour = $stream.readline();
            opened = $stream.readline();
            key = $stream.readline();
            shape = $stream.readline();
            saveable = $stream.readline();
            layer = 1;
            reference = %count;
         };
      }
   }