Game Development Community

Make not visible t2DSceneObjects off screens can improve FPS?

by Edoardo · in iTorque 2D · 09/03/2010 (10:17 am) · 11 replies

Hi TGB Guru's ;-)

My question is on the title... If I Hack the source code in the method:

void t2dSceneObject::integrateObject( const F32 sceneTime, const F32 elapsedTime, CDebugStats* pDebugStats )

like the particles with PUAP_OPTIMIZE but only HIDE the objects...

#ifdef PUAP_OPTIMIZE
	//%PUAP%   optimizer  kill particles that are not on-screen
	t2dVector CameraPOS = gCurrentSceneWindow->getCurrentCameraPosition();
	t2dVector CameraWH(gCurrentSceneWindow->getCurrentCameraWidth(),
						gCurrentSceneWindow->getCurrentCameraHeight());

	CameraPOS.mX -= CameraWH.mX/2;
	CameraPOS.mY -= CameraWH.mY/2;


//now check our rect with this one
	RectF ourRect = getWorldClipRectangle();

	RectF cameraRect = RectF(CameraPOS.mX, CameraPOS.mY, CameraWH.mX, CameraWH.mY);
	
	
	if( !RectIntersect( ourRect, cameraRect ) ) {
		visible( false );
	} else {
		visible( true );
		}
	}
	}

	//%PUAP%
#endif

The FPS increase on Iphone?

#1
09/03/2010 (2:11 pm)
If your asking if making an object that is offscreen invisible or disabled etc, so it is not eating up computing power when it doesn't need to, I believe yes it will help. The iDevice is not a very powerful gaming computer. I have had to render my game down 3 times by building "on off switches" for many of my game objects. Helping quite a bit.




#2
09/03/2010 (2:16 pm)
I've ENABLED and DISABLED a t2dSceneObject and the performances increase a lot!!!
#3
09/03/2010 (4:16 pm)
Yes, it will make a difference. In my object pools I always disable the object on the way back into the pool and enable it when it comes back out. Otherwise the object is still processed by the scenegraph.
#4
09/03/2010 (11:17 pm)
in your professional opinion,
what do you think would be less stressful to the computer (iDevice)?

Having 400 objects, and any offscreen are disabled, enabled when on? 30 objects on screen at once max.
Or...
having 100 objects, always enabled, but set positions, in waves as player moves throughout level so they do they job of the 400. As a player passes from section to section, section A, may move to F, B Moves to G etc.





And having said that, can you enable an object directly through a collision? So no global variable is passed, and no schedule is used. Will a disabled object even sense a collision? ( I know I can test, but just thought I would throw it out there)


::)()()(
#5
09/03/2010 (11:26 pm)
I did a small test + logic tells me no. If this is different, if you think I can enabled a disabled object directly through collision please tell.
#6
09/03/2010 (11:35 pm)
I did a small hack on t2dSceneObject, Only object with the dynamic field (HideOffScreen) are disabled and when enter on screen I enable these objects.

But this solution depend on game genre.... In my case I've a platform game and I've added this option only to level elements (trees, stones, etc..)
#7
09/04/2010 (7:24 pm)
ah,
it would be cool if I could have a box, mounted/following camera (attached to/follows player) and that box, which reaches just outside cameraview, will trigger any object into existence or out. But there is no way to do that, that I can think of, that would not require massive scheduling. Something I am trying to avoid.
#8
09/09/2010 (2:51 am)
Just letting you know. I am pooling some of my objects (sprites, and animated sprites), for explosions and things like that, but so far I've been leaving them enabled when I put them back into the pool. Anyway, I made some changes so that I enable/disable them, in the way that Scott described, and it has made a huge improvement. Using my second gen iPod Touch, my FPS has increased from around 35 to over 50! I haven't tried it on my 3rd gen yet, but I was getting about 50 before so now it should be through the roof.

Just thought you'd be interested to know how much of a difference it makes. I can't believe I wasn't doing this already.
#9
09/09/2010 (8:36 am)
@Mark Can you post an example code to how you put and pull objects into a pool?

Thanks
#10
09/09/2010 (11:29 am)
The simplest way is to use SimSets. See the source code for Go Beryllium for some examples:

www.torquepowered.com/community/blogs/view/15213
#11
09/09/2010 (8:24 pm)
Same as Conor, I also use SimSets. Here is an example of what I am doing currently. It seems to work well.

1) Creating and loading the SimSet
At the beginning of a level I create the SimSet and load it with objects. Here is an example of where I create a container of explosions:

// load explosions into container
if (%thelevel.explosionCount > 0)
{   
   $theSmallExplosions = new SimSet(){};

   // Create explosions and load load them into the container
   %numExplosions = %thelevel.explosionCount;
   for (%n=0; %n<%numExplosions; %n++)
   {
      %smallExplosion = new t2dAnimatedSprite() { scenegraph = $thescenegraph; };
      %smallExplosion.setPosition("0 -70");	
      %smallExplosion.animationName = "smallExplosionAnimation";
      %smallExplosion.setSize("15 15");
      %smallExplosion.setLayer("5");
      %smallExplosion.class = "smallExplosionClass";
   }
}

The animations are executed offscreen (making them invisible would achieve the same thing), and then when the animations have finished I disable them and put them into the the container. Here is the code that does that:

function t2dAnimatedSprite::onAnimationEnd(%this)
{
   if (%this.class $= "smallExplosionClass")
   {
      %this.setEnabled(false);
      $theSmallExplosions.add(%this);
      echo("n\n\Num Explosions: " @ $theSmallExplosions.getCount());
   }
}


2) Pooling the objects during the level
Here is where I take an object out of the pool:

if (%explosionType $= "smallExplosion")
{
   // how many in the container ?
   %numExplosions = $theSmallExplosions.getCount();
   if (%numExplosions <= 0)
      echo("n\n\Error! no Explosions!");
   else
   {
      // Get an Exposion from the container
      %explosion = $theSmallExplosions.getObject(0);
      $theSmallExplosions.remove(%explosion);
      %explosion.setEnabled(true);
      %explosion.setPosition(%collisionPoints);	
      %explosion.setSize("15 15");
      %explosion.playAnimation(smallExplosionAnimation);
      alxPlay(tileExplosion);
      echo("n\n\Num Explosions: " @ $theSmallExplosions.getCount());
      }
   }
}

When the animation is complete, the t2dAnimatedSprite::onAnimationEnd function from above gets executed, which disables the animation and puts it back into the container.

3) Removing the SimSet
At the end of the level I delete the SimSet to free up resources. Here is the code I use for doing that:

// delete $theSmallExplosions
if (isObject($theSmallExplosions))
{
   %numObjects = $theSmallExplosions.getCount();
   %index = %numObjects - 1;
   while (%numObjects > 0)
   {
      //echo("n\n\SmallExplosions left: " @ %numObjects);
      %theObject = $theSmallExplosions.getObject(%index);
      $theSmallExplosions.remove(%theObject);
      %theObject.safeDelete();
      %numObjects = %numObjects - 1;
      %index = %index - 1;
   }
}

For static objects I do something similar except that these are not collected using the t2dAnimatedSprite::onAnimationEnd callback. In this case I use a collision callback. Here is an example code for collecting a missile after it has hit something:

function missileClass::onCollision(%srcObject, %dstObject, %srcRef, %dstRef, %time, %normal, %contacts, %points) 
{
   if (%srcObject.name $= "baseMissile")
   {
      %srcObject.setCollisionActive(0,0);      
      %srcObject.setVisible(false);
      %srcObject.setEnabled(false);
      // put back into container
      $theBaseMissiles.add(%srcObject);
      //echo("n\n\Number of BaseMissiles: " @ $theBaseMissiles.getCount());
   }
}