Serious performance problems with few objects

Official forum for the Chipmunk2D Physics Library.
Post Reply
Novskj
Posts: 12
Joined: Wed May 15, 2013 2:59 am
Contact:

Serious performance problems with few objects

Post by Novskj »

Hi there!

I'm working in a Cocos2D + Chipmunk game and I'm experiencing some annoying performance problems in cases where maybe there shouldn't be... The game has some static chipmunk squares (around 150-200, but which didn't even move: they're just like walls or floors) and some moving chipmunk circles (around 10-20). The game starts with 60 FPS as expected, but as the moving circles begin to appear, the FPS count begin to fall and reaches around 40 or 30... It is possible that the fact that exists around 20 moving entities is enough to drop the framerate as I'm experiencing, or maybe it has something to do with my internal code?

Here is an example on how the game creates each static "wall-floor" blocks:

Code: Select all

CCNode *parent = [self getChildByTag:kTag];
    
    CGRect spriteRect = CGRectMake(offset.x, offset.y, size.width, size.height);
    PhysicsSprite *sprite = [PhysicsSprite spriteWithTexture:text rect:spriteRect];
    
    sprite.position = pos;
    
    int num = 4;
    cpVect verts[] = {
        cpv(-bSize.x/2.0f,-bSize.y/2.0f),
        cpv(-bSize.x/2.0f, bSize.y/2.0f),
        cpv( bSize.x/2.0f, bSize.y/2.0f),
        cpv( bSize.x/2.0f,-bSize.y/2.0f),
    };
    
    cpBody *body = cpBodyNew(INFINITY, INFINITY);
    cpBodySetPos( body, pos);
    
    cpShape* shape = cpPolyShapeNew(body, num, verts, CGPointZero);
    cpShapeSetElasticity( shape, 0.3f );
    cpShapeSetFriction( shape, 0.5f );
    cpShapeSetCollisionType(shape, kCollisionTypeNormal);
    shape->data = sprite;
    
    [parent addChild: sprite];
     cpSpaceAddShape(space_, shape);
    [sprite setPhysicsBody:body];
And how it creates each moving circle:

Code: Select all

CCNode *parent = [self getChildByTag:kTag];
    
	CGRect spriteRect = CGRectMake(offset.x, offset.y, size.width, size.height);
    PhysicsSprite *sprite = [PhysicsSprite spriteWithTexture:text rect:spriteRect];
	sprite.position = pos;
	
	int num = 4;
	cpVect verts[] = {
		cpv(-bSize.x/2.0f,-bSize.y/2.0f),
		cpv(-bSize.x/2.0f, bSize.y/2.0f),
		cpv( bSize.x/2.0f, bSize.y/2.0f),
		cpv( bSize.x/2.0f,-bSize.y/2.0f),
	};
	
	cpBody *body = cpBodyNew(1.0f, cpMomentForPoly(1.0f, num, verts, CGPointZero));
	cpBodySetPos( body, pos );
	
    cpShape* shape = cpCircleShapeNew(body, bSize.x/2.0f, CGPointZero);

	cpShapeSetElasticity( shape, 0.6f );
	cpShapeSetFriction( shape, 0.5f );
    cpShapeSetCollisionType(shape, kCollisionTypeBestiola);
    cpShapeSetGroup(shape, kCollisionGroupNoCollision);
    
    [parent addChild: sprite];
    cpSpaceAddBody(space_, body);
    cpSpaceAddShape(space_, shape);
    [sprite setPhysicsBody:body];
Is there something I'm doing wrong or doing extremely inefficiently in these methods, or it should be something related to my in-game "update scene" loop?

Thanks in advance for your time and effort! :)
User avatar
slembcke
Site Admin
Posts: 4166
Joined: Tue Aug 14, 2007 7:13 pm
Contact:

Re: Serious performance problems with few objects

Post by slembcke »

Well, I stopped when I saw this big red flag:

Code: Select all

    cpBody *body = cpBodyNew(INFINITY, INFINITY);
That's not a static body. Static bodies are created using cpBodyNewStatic(). Instead what you've created is a regular body with infinite mass (so it doesn't move from forces/collisions). You don't add it to the space, so it doesn't apply gravity and such to it, that makes it a "rogue" body. So what you've done is to create 200 shapes that don't move, but Chipmunk is still required to update each frame as well as check for collisions between them.

Switch to using cpBodyNewStatic() and your problems should go away. (unless there are other issues that I didn't see)
Can't sleep... Chipmunks will eat me...
Check out our latest projects! -> http://howlingmoonsoftware.com/wordpress/
Novskj
Posts: 12
Joined: Wed May 15, 2013 2:59 am
Contact:

Re: Serious performance problems with few objects

Post by Novskj »

Hi slembcke!

Thanks for your reply! I was aware of the cpBodyNewStatic function, so I assumed that I've decided not to use this one for some reason... Now I've find why: the game "view" or "scenario" can be moved by the user (because the level size is bigger than the screen size) and, when the user moves the "view", the game kind of pauses and all elements are moved according to the user's finger movement on the screen. However, if I declare my wall / floor blocks as static bodies using the function you provided, I can't find a way of moving them correctly... It seems that, though the sprites move as expected, the physic bodies linked to them kind of remain at the same position or something... Here is how I'm moving the wall / floor bodies:

Code: Select all

// Iterates over the array containing custom objects with references to the cpBody linked to each one
for(ChipmunkEntity* c in arrStaticBlocks)
    {
        [c move:p]; // Updates the internal, custom-made position
        cpBodySetPos([c getBody], [c getPosition]); // Updates the cpBody position
    }
When using cpBody with INFINITY mass and moment the bodies' positions are updated as expected. However, when the bodies are created as static (using the function you suggested), it seems as if the cpBodySetPos function doesn't work as expected... Is it possible? Is there any what I can use to update the bodies' position if they are static bodies? Of course I assume deleting and recreating each wall / floor body every time the view is moved is kind of crazy...

Thanks for your time! :)
Novskj
Posts: 12
Joined: Wed May 15, 2013 2:59 am
Contact:

Re: Serious performance problems with few objects

Post by Novskj »

Hmmm maybe I've figured a way to do so... I've added the following function at the end of the "moveAllElements" custom-function (which moves every wall / floor body and every other living in-game body):

Code: Select all

    cpSpaceReindexStatic(space_);
I haven't tested the performance yet, but, if this function solves the "cannot move a static body" problem, and if its execution isn't critical, it may be the way so I can declare the wall / floor bodies as staticBodies (avoiding the terrible performance) and even move them when required (that is, when the user moves the "view point")... Do you think it's a good way to handle it?

Thanks! :)
User avatar
slembcke
Site Admin
Posts: 4166
Joined: Tue Aug 14, 2007 7:13 pm
Contact:

Re: Serious performance problems with few objects

Post by slembcke »

So yes, static bodies cannot be moved without special treatment. The assumption that they don't move is why Chipmunk is able to handle them in a more optimized way.

cpSpaceReindexStatic() is perfectly fine to call every once in a while. It's does no more work than making the bodies non-static and forcing Chipmunk to reindex them every frame anyway. It's only if you are calling it every frame that it starts to make no sense. In that case you really don't want static bodies after all.
Can't sleep... Chipmunks will eat me...
Check out our latest projects! -> http://howlingmoonsoftware.com/wordpress/
Novskj
Posts: 12
Joined: Wed May 15, 2013 2:59 am
Contact:

Re: Serious performance problems with few objects

Post by Novskj »

Hi slembcke!

I've applied all the changes (declare wall / floor blocks as staticBodies, moving them using the cpSpaceReindexStatic when the "viewpoint" is moved, ...) but the problem still seems to persist... The game has a kind of "creature-emitter" spots that create a specific number of dynamic chipmunk bodies every N seconds (the code is in my first message). These bodies move around the level through the physics engine, except when they x-axis velocity is less than a certain amount:

Code: Select all

velMin = abs([creature getVelocity].x / 1.25f);
                            
if(abs([creature getBody]->v.x) < velMin)
{
   cpBodySetVel([creature getBody], ccp([creature getBody]->v.x+([creature getVelocity].x),[creature getBody]->v.y));
}
The weird part of it is that when there are, for example, around 10 creatures or less, the game performance works fine. However, when there are about 15 creatures, the performance gets very worse and FPS rate drops from around 60 to around 40...

So, here is the question: performance issues may be caused due the fact that processing 15 moving blocks is hard enough for the physics engine, or the performance problem must be related with some own code?

Thanks in advance, and sorry for asking so many questions, but I'm unable to find the clue about this...!

PS: I ran the Instruments and the living memory is about 2 MB, so it shouldn't be a problem in any way, and Instruments didn't find any leak...
User avatar
slembcke
Site Admin
Posts: 4166
Joined: Tue Aug 14, 2007 7:13 pm
Contact:

Re: Serious performance problems with few objects

Post by slembcke »

I find it hard to believe that Chipmunk is having performance problems with that few objects unless there is some setting that is really messed up. I often have simulations with hundreds of dynamic objects in them, and even like older iPhones can handle that ok.

Try running the Time Profiler instrument. The amount of memory you are using isn't really all that important for performance generally.
Can't sleep... Chipmunks will eat me...
Check out our latest projects! -> http://howlingmoonsoftware.com/wordpress/
Novskj
Posts: 12
Joined: Wed May 15, 2013 2:59 am
Contact:

Re: Serious performance problems with few objects

Post by Novskj »

Hi slembcke!

After debugging the game with the Time Profiler I've found that indeed the problem isn't with the physics engine, but with my code... However, I can't think of a way of achieving the same effect with the (yes, I admit it) enormous loop I have in the 'update' function...

The 'creatures' should keep rolling and colliding with the walls. The 'only' thing I do is to check in each step if the creature's velocity is less than the "minimum" velocity they should have and, if so, I apply the velocity to the creature's body. Then, I check if the creature is colliding with a wall-block (I'm checking this in a kind of hand-made way): if so, the creature must invert his X velocity (so the next time I check the minimum velocity, the applied value faces the right direction). The whole loop is done like this:

Code: Select all

for(Creature* c in arrCreatures) // 10 creatures, more or less
{
     if([c getActive])
     {
          float velMin = abs([c getVelocity].x / 1.25f); // this is a custom-made-object's minimum velocity
                            
          if(abs([c getBody]->v.x) < velMin)
          {
               // if the physic body's velocity is less than the minimun, then apply the minimum
               cpBodySetVel([c getBody], ccp([c getBody]->v.x+([c getVelocity].x),[c getBody]->v.y));
          }
                        
          // this update the custom-made object's position according to the physic body's position
          [c setPosition:cpBodyGetPos([c getBody])];

          for(BlocEstatic* b in arrStaticBlocks) // 200 or 300 blocks
          {
               // if the custom-made wall block is touched by the custom-made creature, it should turn
               if([b touch:[c getSideMiddlePoint:0]] || [b touch:[c getSideMiddlePoint:1]])
               {
                     [c turn]; // this function simply invert the X coordinate of the custom-object's velocity
               }
          }
     }
}
As you can see, I'm merging my own objects' data with the physics engine... I know there are collision handling functions, but as I need to update my custom-made objects, I think may be better to handle this way, so I don't know how to access custom-made objects from a collision handler function...

Any idea on how could I improve this to "integrate" it with the physics engine, so the game's performance can get improved?

Thanks in advance for your time and effort, and sorry for asking so many things, but I'm really stuck with it... U_U'
User avatar
slembcke
Site Admin
Posts: 4166
Joined: Tue Aug 14, 2007 7:13 pm
Contact:

Re: Serious performance problems with few objects

Post by slembcke »

I guess I don't see why in particular you couldn't use static sensor shapes and Chipmunk collision callbacks in place of your inner loop of turning rectangles. I suspect the real performance killer is that inner loop. 100 creatures * 100 rectangles is going to be tens of thousands of rectangle checks (and method calls). You could rewrite that inner loop to be more efficient (avoiding as many method calls as possible is a good start). You might be able to get the performance you want that way, but you still have a loop there that is going to be very sensitive to the number of creatures and rectangles they check.

The best solution is still probably going to be to use sensors and callbacks. Since Chipmunk uses spatial indexing, checking a dynamic object against a bunch of static ones is going to be much less expensive since it doesn't need to check them all individually. It's not a hard solution, but it's not going to have the comfort of a simple "do it yourself" one.
Can't sleep... Chipmunks will eat me...
Check out our latest projects! -> http://howlingmoonsoftware.com/wordpress/
Novskj
Posts: 12
Joined: Wed May 15, 2013 2:59 am
Contact:

Re: Serious performance problems with few objects

Post by Novskj »

Hi slembcke!

Finally I've found a way to solve my problem by combining my own-object properties and the physics engine. Maybe it's kind of creepy, but it works perfectly as expected and the framerate is always 60 (even in my old 3GS device!)... Here is how it's done:

Code: Select all

for(Bestiola* c in arrCreatures)
{
     if([c getActive])
     {
          float velMin = abs([c getVelocity].x / 1.25f);
                
          // HERE lies the "magic" (or trick): this conditionals checks whether the physic body's velocity has just
          // changed (positive / negative) according to the own-made object's velocity, which only occurs when the
          // physic body collides with a wall object
          if([c getVelocity].x > 0.0f)
          {
               if(cpBodyGetVel([c getBody]).x < 0.0f)
               {
                    [c setVelocity:CGPointMake(-[c getVelocity].x, [c getVelocity].y)];
               }
          }else{
               if(cpBodyGetVel([c getBody]).x > 0.0f)
               {
                    [c setVelocity:CGPointMake(-[c getVelocity].x, [c getVelocity].y)];
               }
          }

          if(abs([c getBody]->v.x) < velMin)
          {
               cpBodySetVel([c getBody], ccp([c getBody]->v.x+([c getVelocity].x),[c getBody]->v.y));
          }
     ...
}
As you can see it's kind of a "it-works-but-dont-look-how" solution, but this way the game can know when a creature collides with a wall and change it's "internal" own-made object's velocity without the need of checking EVERY wall (in fact there's no need to check a single wall)... I've ran some tests with different devices and situations and the game behaves as expected, so I think it'll do the trick for my situation. Maybe it can be better handled with collision detections and Chipmunk functions, but this way works fine and I can still maintain the main loop structure (where other things are processed)...

Thanks for all your time and effort, slembcke: your help has been the key for solving this! :)
Post Reply

Who is online

Users browsing this forum: No registered users and 39 guests