Can't remove bodies?

Official forum for the Chipmunk2D Physics Library.
Post Reply
User avatar
Rhaal
Posts: 6
Joined: Mon Oct 26, 2009 7:32 pm
Contact:

Can't remove bodies?

Post by Rhaal »

I am having an issue where bodies are still present in my scene even though I though I freed them. I'll try to explain without too much code bloat, but please know that I have searched these forums up and down for 3 days and am certain I'm doing everything properly according to the solutions I've found. I'm using cocos2d, and the version of Chipmunk it came with.

The 2 problems I encounter are:
  • Sometimes I crash in my update funciton on a setPosition call to my sprites (I think from trying to access body->p)
  • Sometimes when I change levels, blocks from the previous level aren't free'd, though all their dealloc's are being called (not directly by me of course)
I have a class:

Code: Select all

@interface Block : NSObject
{
  // Physics
  ... (mass, friction, etc)...
  cpBody* body;
  cpShape* shape;

  // Graphics
  Sprite* sprite;
  Sprite* arrow;
}
@end

@implementation Block

- (Block*)initWithShape:Alignment:Fixed:X:Y:W:H:Mass:Friction:Elasticity:Rotation:Direction:Layer
{
  /* setup sprite */

  // SQUARE
  if(shapeName isEqualToString:@"Square")
  {
    cpVect vertices[] =
    {
      cpv(-w/2, -h/2),
      cpv(-w/2,  h/2),
      cpv( w/2,  h/2),
      cpv( w/2, -h/2),
    };

    if(fixed)
      body = cpBodyNew(INFINITY, INFINITY);
    else
      body = cpBodyNew(mass, cpMomentForPoly(mass, 4, vertices, cpvzero));
    body->p = cpv(x,y);

    shape = cpPolyShapeNew(body, 4, vertices, cpvzero);
  }

  /* else if circle, etc... */

  shape->e = elasticity;
  shape->u = friction;
  shape->collision_type = fixed ? 0 : 1;
}

- (void)dealloc
{
  // Free sprites
  [scene removeChildByTag:SpriteID cleanup:NO]; // block
  [scene removeChildByTag:SpriteID+1000 cleanup:NO]; // arrow

  // Remove shape and body from space.
  fixed ? cpSpaceRemoveStaticShape(AppDelegate.space, shape) : cpSpaceRemoveShape(AppDelegate.space, shape);
  if(!fixed) cpSpaceRemoveBody(AppDelegate.space, body);

  // Free phsyics memory.
  cpShapeFree(shape);
  cpBodyFree(body);
  shape = nil;
  body = nil;

  // Free strings
  ...

  SpriteID--;
  [super dealloc]
}
@end
I have a feeling my dealloc funcion isn't working properly - but this problem seems random. So sometimes things work, and other times when I load the next level, blocks are affected by invisible blocks that were there before (sprite freed but bodies still present).

I know that I can't access those bodies anymore in my update function, so they are not in my array of Block*'s anymore. Here is my update function if it helps. I've really piled on the error checking in my attempts to resolve this:

Code: Select all

- (void)UpdateBlock:(Block*)block
{
  if(block == nil || ActiveBlocks == nil) // Activeblocks is NSMutableArray
    return;

  cpShape* shape = block.shape;
  cpBody* body = block.body;
  Sprite* sprite = block.sprite;
  Sprite* arrow = block.arrow;

  if(shape== nil || body == nil || sprite == nil)
    return;

  // Block image
  if(sprite)
  {
    [sprite setRotation:CC_RADIANS_TO_DEGREES(-(body->a))];
    [sprite setPosition:cpv(body->p.x, body->p.y)];
  }

  // Arrow image
  if(arrow)
  {
    [arrow setRotation:CC_RADIANS_TO_DEGREES(block.arrowRotation)];
    [arrow setPosition(cpv(body->p.x, body->p.y)];
  }
Any clues? Help is very appreciated as I'm racking my brain here :cry:
User avatar
Tam Toucan
Posts: 141
Joined: Tue Jun 23, 2009 4:26 pm
Contact:

Re: Can't remove bodies?

Post by Tam Toucan »

Looking that snippet could the the problem not be in how you are handling your sprites, not how you are using chipmunk e.g. I don't know how you are managing your sprites etc, but if you have called dealloc on your NSObject, but somehow used it again then you would get a crash. If you didn't call dealloc, but had done other stuff that invalidated the sprite you could get the invisible blocks problem (unfortunately I don't know cocoa so don't know what things could be wrong).

Try not removing the shapes or bodies if you still get a crash then that implies it's how you are managing your resources and not anything specific to how you are using chipmunk. If you still get a crash then it implies the body/shape/space are getting corrupted somehow.

BTW you don't show how you add the shape to the space.
mobilebros
Posts: 90
Joined: Tue Aug 04, 2009 9:53 am
Contact:

Re: Can't remove bodies?

Post by mobilebros »

If it sometimes works and sometimes doesn't that might suggest the way you are adding/removing the shape do not match. For instance you are always removing from the static shape list, but your creation code seems to suggest that you create both static and active shapes (you don't show how you add it tho). Try doing something like this to add/remove the shapes.

Code: Select all

//creation
if (body->m == INFINITY)
   cpSpaceAddStaticShape(space,shape);
else
   cpSpaceAddShape(space,shape);

//deletion
if (body->m == INFINITY)
   cpSpaceRemoveStaticShape(space,shape);
else
   cpSpaceRemoveShape(space,shape);
User avatar
Rhaal
Posts: 6
Joined: Mon Oct 26, 2009 7:32 pm
Contact:

Re: Can't remove bodies?

Post by Rhaal »

Yeah, I was trying to keep the code I did post focused (and I was retyping it). Now that I have svn, I've pulled it down on this computer and here is my entire init function:

Code: Select all

- (Block*)initWithShape:(NSString*)ShapeName
			  Alignment:(NSString*)Alignment
				  Fixed:(bool)Stuck
					  X:(float)x 
					  Y:(float)y 
					  W:(float)w
					  H:(float)h
				   Mass:(float)Mass 
			   Friction:(float)Friction 
			 Elasticity:(float)Elasticity
			   Rotation:(float)Rotation
			  Direction:(int)Direction
				  Layer:(Layer*)Scene
{
	EvilBlocksAppDelegate* AppDelegate = (EvilBlocksAppDelegate*)[[UIApplication sharedApplication] delegate];
	
	// Assign properties.
	shapeName = [[NSString alloc] initWithString:ShapeName];
	alignment = [[NSString alloc] initWithString:Alignment];
	fixed = Stuck;
	mass = Mass;
	friction = Friction;
	elasticity = Elasticity;
	rotation = Rotation;
	direction = Direction;
	scene = Scene;
	
	// Sprite
	NSString* spriteFile;
	if(fixed && [shapeName isEqualToString:@"Circle"])
		spriteFile = [NSString stringWithFormat:@"%@_%@_%i_%i_Fixed.png", shapeName, alignment, (int)w, (int)h];
	else
		spriteFile = [NSString stringWithFormat:@"%@_%@_%i_%i.png", shapeName, alignment, (int)w, (int)h];
		
	sprite = [Sprite spriteWithFile:spriteFile];
	sprite.position = ccp(x,y);
	spriteID = SpriteID;
	
	[scene addChild:sprite z:2 tag:spriteID];
	
	
	
	// SQUARE - Physics body/shape
	if( [shapeName isEqualToString:@"Square"] )
	{
		// Vertex points for a box of the desired size.
		cpVect vertices[] = 
		{ 
			cpv(-w/2, -h/2), 
			cpv(-w/2,  h/2), 
			cpv( w/2,  h/2), 
			cpv( w/2, -h/2) 
		};
		
		// Body
		if(fixed)
			body = cpBodyNew(INFINITY, INFINITY);
		else
			body = cpBodyNew(mass, cpMomentForPoly(mass, 4, vertices, cpvzero));
		
		body->p = cpv(x,y);
		
		// Shape
		shape = cpPolyShapeNew(body, 4, vertices, cpvzero);
	}
	
	// CIRCLE - Physics body/shape
	else if ( [shapeName isEqualToString:@"Circle"] )
	{

		if(fixed)
			body = cpBodyNew(INFINITY, INFINITY);
		else
			body = cpBodyNew(mass, INFINITY);
		
		body->p = cpv(x,y);
		
		shape = cpCircleShapeNew(body, w/2, cpvzero);
		
	}
	
	// BOTH
	shape->e = elasticity;
	shape->u = friction;
	shape->collision_type = fixed ? 0 : 1;
	//shape->data = self;
	
	// Calculate rotation
	cpBodySetAngle(body, -CC_DEGREES_TO_RADIANS(rotation)); //(rotation * M_PI / 180)
	[sprite setRotation:-(shape->body->a)*180/M_PI];
	
	if(fixed)
	{
		cpSpaceAddStaticShape(AppDelegate.space, shape);
	}
	else
	{
		cpSpaceAddBody(AppDelegate.space, body);
		cpSpaceAddShape(AppDelegate.space, shape);
	}
	
	// Arrow sprite.
	if(!fixed)
	{
		arrow = [Sprite spriteWithFile:@"ArrowDirection.png"];
		arrow.position = ccp(x,y);
		[scene addChild:arrow z:2 tag:spriteID+1000];
	}
	
	arrowRotation = 0;
	switch(direction)
	{
		case DIR_DOWN: 
			arrowRotation = 0; 
			cpBodyApplyForce(body, cpv(0, -FORCE), cpvzero);
			break;
		case DIR_LEFT: 
			arrowRotation = CC_DEGREES_TO_RADIANS(90); 
			cpBodyApplyForce(body, cpv(-FORCE, 0), cpvzero);
			break;
		case DIR_UP: 
			arrowRotation = CC_DEGREES_TO_RADIANS(180); 
			cpBodyApplyForce(body, cpv(0, FORCE), cpvzero);
			break;
		case DIR_RIGHT: 
			arrowRotation = CC_DEGREES_TO_RADIANS(270); 
			cpBodyApplyForce(body, cpv(FORCE, 0), cpvzero);
			break;
	}
	[arrow setRotation:arrowRotation];
	
	SpriteID++;
	return self;
		
}
Thanks for the tips. I'm going to start looking into other places of my code and refactor some things.

Right now I have a cocos2d Gameplay Layer that holds an NSMutableArray of these blocks. Then in my AppDelegate, I have another pointer to the blocks that I assign through a "set" property once the Gameplay Layer loads a level. My update function operates on this (AppDelegate's ActiveBlocks) but I occasionally get a crash in objc_msgSend (where NSAutoreleasePool is NOT on the stack, so I can't figure it out).
User avatar
Rhaal
Posts: 6
Joined: Mon Oct 26, 2009 7:32 pm
Contact:

Re: Can't remove bodies?

Post by Rhaal »

Doh, this isn't a chipmunk problem! I've tracked it down to a cocos2d sprite or NSArray problem - resolved the invisible blocks and crash, and now just have disappearing sprites. Go Chipmunk! 8-)
Post Reply

Who is online

Users browsing this forum: No registered users and 4 guests