Clear cpSpace

Official forum for the Chipmunk2D Physics Library.
Post Reply
qwertyp
Posts: 21
Joined: Wed Apr 14, 2010 6:36 pm
Contact:

Clear cpSpace

Post by qwertyp »

I have a conundrum. I'm using the following code:

Code: Select all

cpSpaceAddCollisionHandler(space, 1, 2, levelCompleted, NULL, NULL, NULL, NULL);

static int
levelCompleted(cpArbiter *arb, cpSpace *space, void *unused) {
	cpSpaceRemoveCollisionHandler(space, 1, 2);

	if (cleared == FALSE) {
		cleared = TRUE;
		cpSpaceFreeChildren(space);
	}
	return 0;
}
It crashes. I have no idea why. To put in context, When the player reaches the "goal", I want all cpShapes cleared so that I can generate the next level. Is there a way to do this? Preferably one that DOESN'T involve crashing.
User avatar
slembcke
Site Admin
Posts: 4166
Joined: Tue Aug 14, 2007 7:13 pm
Contact:

Re: Clear cpSpace

Post by slembcke »

That should work just fine. Can you give any additional information? What does the debugger say?

Also, any real reason to reuse the space? It only takes a microsecond to release the old one and make a new one.
Can't sleep... Chipmunks will eat me...
Check out our latest projects! -> http://howlingmoonsoftware.com/wordpress/
qwertyp
Posts: 21
Joined: Wed Apr 14, 2010 6:36 pm
Contact:

Re: Clear cpSpace

Post by qwertyp »

I should clarify that I'm using Chipmunk on the iPhone, but without the Obj-C wrapper. When the 2 objects intersect, the app freezes and throws: EXC_BAD_ACCESS. The compiler says some code in cpArbiter is what caused it. At first, I thought I was trying to remove objects twice, which is why the if statement. However, that didn't help.

To answer your other question, there is no reason why I couldn't just remove the whole space, besides the fact I thought it would be faster not to.
User avatar
slembcke
Site Admin
Posts: 4166
Joined: Tue Aug 14, 2007 7:13 pm
Contact:

Re: Clear cpSpace

Post by slembcke »

Are you trying to remove an object from the space in a collision handler callback without using a post step callback maybe? It sounds like the code snippet you posted isn't what's causing the crash. Can you compile as debug so you get a stack trace with line numbers? Otherwise it could be just about anything causing it.
Can't sleep... Chipmunks will eat me...
Check out our latest projects! -> http://howlingmoonsoftware.com/wordpress/
qwertyp
Posts: 21
Joined: Wed Apr 14, 2010 6:36 pm
Contact:

Re: Clear cpSpace

Post by qwertyp »

Code: Select all

//
//  ChipmuckTutorialViewController.m
//  ChipmuckTutorial
//
//  Created by Alexandre on 27/04/2009.
//  Copyright __MyCompanyName__ 2009. All rights reserved.
//

#import "ChipmuckTutorialViewController.h"
#import "chipmunk.h"
BOOL cleared;
@implementation ChipmuckTutorialViewController
@synthesize joystick;

// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
    [super viewDidLoad];

	[[UIAccelerometer sharedAccelerometer] setUpdateInterval:0.01];
	[[UIAccelerometer sharedAccelerometer] setDelegate:self];
	
	ball = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"wheels.png"]];
	ball.center = CGPointMake(120, 230);
	ball2 = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"wheels.png"]];
	ball2.center = CGPointMake(160, 230);
	chassis = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"car.png"]];
	chassis.center = CGPointMake(160, 230);

	[self.view addSubview:ball];
	[self.view addSubview:ball2];
	[self.view addSubview:chassis];
	
	[self setupChipmuck];
}

static int
levelCompleted(cpArbiter *arb, cpSpace *space, void *unused) {
	cpSpaceRemoveCollisionHandler(space, 1, 2);
	cpSpaceFreeChildren(space);

	return 0;
}

static void
postStepRemoveDoor(cpSpace *space, cpShape *shape, void *unused)
{
	if (shape->switchOn == 1) {
		[shape->data setImage:[UIImage imageNamed:@"switchOn.png"]];
		[shape->corrDoorData setImage:nil];
		shape->switchOn = 0;
		
		cpSpaceRemoveBody(space, shape->corrDoorBody);
		cpBodyFree(shape->corrDoorBody);
		
		cpSpaceRemoveShape(space, shape->corrDoor);
		cpShapeFree(shape->corrDoor);
	} else {
		NSLog(@"shape does not exist");
	}
}

static int
switchHit(cpArbiter *arb, cpSpace *space, void *unused)
{
	cpShape *a, *b; cpArbiterGetShapes(arb, &a, &b);
	cpSpaceAddPostStepCallback(space, (cpPostStepFunc)postStepRemoveDoor, b, NULL);
	return 1;
}

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
	UITouch *touch = [[event allTouches] anyObject];
	[self handleTouches:[touch locationInView:touch.view]];
}

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
	UITouch *touch = [[event allTouches] anyObject];
	[self handleTouches:[touch locationInView:touch.view]];
}

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
	joystick.center = CGPointMake(76, 287);
	joystickLocation = 0;
}

- (void)handleTouches:(CGPoint)location {
	CGPoint xLocation = CGPointMake(location.x,joystick.center.y);
	if (xLocation.x > 20 && xLocation.x < 130 && location.y > 265 && location.y <310) {
		joystick.center = xLocation;
		joystickLocation = (int)xLocation.x-75;
	}
}

// Bootsraps chipmuck and the timer
- (void)setupChipmuck {
	// Start chipmuck
	cpInitChipmunk();
	
	// Create a space object
	space = cpSpaceNew();
	
	// Define a gravity vector
	space->gravity = cpv(0, -200);
	
	// Add some elastic effects to the simulation
	space->elasticIterations = 10;
	
	// Creates a timer firing at a constant interval (desired framerate)
	// Note that if you are using too much CPU the real framerate will be lower and
	// the timer might fire before the last frame was complete.
	// There are techniques you can use to avoid this but I won't approach them here.
	[NSTimer scheduledTimerWithTimeInterval:1.0f/60.0f target:self selector:@selector(tick:) userInfo:nil repeats:YES];
	
	[self makeCarWithPos:CGPointMake(20, 300)];
	// Create our floor's body and set it's position
	
	// Define our shape's vertexes
	cpSpaceAddStaticShape(space, [cpShapeMake rect:350 withAngle:0 andPos:cpv(175, 265)]);
	cpSpaceAddStaticShape(space, [cpShapeMake rect:295 withAngle:0 andPos:cpv(345, 175)]);
	cpSpaceAddStaticShape(space, [cpShapeMake rect:380 withAngle:0 andPos:cpv(290, 100)]);
	
	UIImageView* doorImg = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"wallVert.png"]];
	doorImg.frame = CGRectMake(0, 0, 15, 55);
	doorImg.center = CGPointMake(320, 185);
	[self.view addSubview:doorImg];
	cpShape *door = [cpShapeMake door:doorImg withPos:CGPointMake(doorImg.center.x, 320-doorImg.center.y) andHorizontal:FALSE andLength:55];
	
	UIImageView* switchImg = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"switchOff.png"]];
	switchImg.center = CGPointMake(230, 210);
	[self.view addSubview:switchImg];
	cpShape* switchShape = [cpShapeMake switchButton:switchImg withPos:CGPointMake(switchImg.center.x, 320-switchImg.center.y) andDoor:door andDoorBody:door->body andDoorData:door->data];
	cpSpaceAddStaticShape(space, switchShape);
	cpSpaceAddStaticShape(space, switchShape->corrDoor);
	cpSpaceAddCollisionHandler(space, 1, 3, levelCompleted, NULL, NULL, NULL, NULL);
	cpSpaceAddCollisionHandler(space, 1, 2, switchHit, NULL, NULL, NULL, NULL);
}

-(void)makeCarWithPos:(CGPoint)pos {
	
	// Create our ball's body with 100 mass and infinite moment
	ballBody = cpBodyNew(1, cpMomentForCircle(1, 0.0, 7.5, cpvzero));
	
	// Set the initial position
	ballBody->p = CGPointMake(pos.x+15, pos.y+160);
	
	// Add the body to the space
	cpSpaceAddBody(space, ballBody);
	
	// Create our shape associated with the ball's body
	cpShape *ballShape = cpCircleShapeNew(ballBody, 7.5, cpvzero);
	ballShape->e = 0.0; // Elasticity
	ballShape->u = 1.5; // Friction
	ballShape->data = ball; // Associate with out ball's UIImageView
	ballShape->collision_type = 1; // Collisions are grouped by types
	ballShape->group = 1;
	// Add the shape to out space
	cpSpaceAddShape(space, ballShape);
	//
	///
	///
	///
	///
	// Create our ball's body with 100 mass and infinite moment
	ballBody2 = cpBodyNew(1, cpMomentForCircle(1, 0.0, 7.5, cpvzero));
	
	// Set the initial position
	ballBody2->p = CGPointMake(pos.x-15, pos.y+160);
	
	// Add the body to the space
	cpSpaceAddBody(space, ballBody2);
	
	// Create our shape associated with the ball's body
	cpShape *ballShape2 = cpCircleShapeNew(ballBody2, 7.5, cpvzero);
	ballShape2->e = 0.5; // Elasticity
	ballShape2->u = 1.5; // Friction
	ballShape2->data = ball2; // Associate with out ball's UIImageView
	ballShape2->collision_type = 1; // Collisions are grouped by types
	ballShape2->group = 1;
	// Add the shape to out space
	cpSpaceAddShape(space, ballShape2);
	
	////
	//
	//
	//
	//
	//
	//
	
	cpVect carVerts[] = { cpv(-19.0, -7.5), cpv(-19.0, 7.5), cpv(19.0, 7.5), cpv(19.0, -7.5) };
	carBody = cpBodyNew(2.0, cpMomentForPoly(2.0,4,carVerts, cpvzero));
	carBody->p = CGPointMake(pos.x, pos.y+170);
	cpSpaceAddBody(space, carBody);
	// Define our shape's vertexes
	
	// Create all shapes
	cpShape *carShape = cpPolyShapeNew(carBody, 4, carVerts, cpvzero);
	carShape->e = 0.5; carShape->u = 0.5; carShape->collision_type = 1;
	carShape->data = chassis;
	carShape->group = 1;
	cpSpaceAddShape(space, carShape);
	
	///
	//
	//
	//
	cpConstraint *grooveJoint1;
	cpConstraint *grooveJoint2;
	cpConstraint *springJoint1;
	cpConstraint *springJoint2;
	
	grooveJoint1 = cpGrooveJointNew(carBody, ballBody, cpv(-15,-15), cpv(-15, 15), cpvzero);
	cpSpaceAddConstraint(space, grooveJoint1);
	
	springJoint1 = cpDampedSpringNew(carBody, ballBody, cpv(-15,0), cpvzero, 20.0, 50.0, 1.5);
	cpSpaceAddConstraint(space, springJoint1);
	
	grooveJoint2 = cpGrooveJointNew(carBody, ballBody2, cpv(15,-15), cpv(15, 15), cpvzero);
	cpSpaceAddConstraint(space, grooveJoint2);
	
	springJoint2 = cpDampedSpringNew(carBody, ballBody2, cpv(15,0), cpvzero, 20.0, 50.0, 1.5);
	cpSpaceAddConstraint(space, springJoint2);
	//
	//
	//
}

-(void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration {
	cpBodyApplyImpulse(carBody, cpv(acceleration.y/4,0), cpv(0,1000));
}

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
	[[UIApplication sharedApplication] setStatusBarOrientation: UIInterfaceOrientationLandscapeLeft];
 	return (interfaceOrientation == UIInterfaceOrientationLandscapeLeft);
}

// Called at each "frame" of the simulation
- (void)tick:(NSTimer *)timer {
		ballBody->w = -joystickLocation/3;
		ballBody2->w = -joystickLocation/3;
	// Tell Chipmuck to take another "step" in the simulation
	cpSpaceStep(space, 1.0f/60.0f);
	
	// Call our function for each shape
	cpSpaceHashEach(space->activeShapes, &updateShape, nil);
}

// Updates a shape's visual representation (i.e. sprite)
void updateShape(void *ptr, void* unused) {
	// Get our shape
	cpShape *shape = (cpShape*)ptr;
	
	// Make sure everything is as expected or tip & exit
	if(shape == nil || shape->body == nil || shape->data == nil) {
		NSLog(@"Unexpected shape please debug here...");
		return;
	}
	
	// Lastly checks if the object is an UIView of any kind
	// and update its position accordingly
	[(UIView *)shape->data setCenter:CGPointMake(shape->body->p.x, 480 - shape->body->p.y)];
	[UIView beginAnimations:nil context:nil];
	CGAffineTransform rotate = CGAffineTransformMakeRotation(-shape->body->a);
	[(UIView *)shape->data setTransform:rotate];
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning]; // Releases the view if it doesn't have a superview
    // Release anything that's not essential, such as cached data
}


- (void)dealloc {
    [super dealloc];
	[joystick release];
}

@end
And here is my cpShapeMake class:

Code: Select all

//  Rectangle.m
//  DrivR
//
//  Created by Ruth Douglas Miller on 4/10/10.
//  Copyright 2010 Kansas State University. All rights reserved.
//

#import "cpShapeMake.h"


@implementation cpShapeMake

float RAD_DEG(int degrees)
{
	return degrees * M_PI / 180;
}

+ (cpShape*)rect:(int)width withAngle:(float)degrees andPos:(CGPoint)pos {
	cpBody* rectBody = cpBodyNew(INFINITY, INFINITY);
	rectBody->p = CGPointMake(pos.x, pos.y+160);//makes up for chipmunk still thinking in portrait
	// Define our shape's vertexes
	
	// Create all shapes
	cpShape *rectShape = cpSegmentShapeNew(rectBody, cpv(-(width/2*cos(RAD_DEG(degrees))), -(width/2*sin(RAD_DEG(degrees)))), cpv(width/2*cos(RAD_DEG(degrees)), width/2*sin(RAD_DEG(degrees))), 5);
	rectShape->e = 0.5; rectShape->u = 0.8; rectShape->collision_type = 0;
	return rectShape;
}

+ (cpShape*)switchButton:(UIImageView*)img withPos:(CGPoint)pos andDoor:(cpShape*)door andDoorBody:(cpBody*)doorBody andDoorData:(UIImageView*)doorData {
	cpBody* switchBody = cpBodyNew(INFINITY, INFINITY);
	switchBody->p = CGPointMake(pos.x, pos.y+160);
	// Define our shape's vertexes
	
	// Create all shapes
	cpShape *switchShape = cpSegmentShapeNew(switchBody, cpv(-15,0), cpv(15,0), 5);
	switchShape->e = 0.5; switchShape->u = 0.8; switchShape->collision_type = 2; switchShape->data=img; switchShape->corrDoor=door; switchShape->corrDoorBody=doorBody; switchShape->corrDoorData=doorData;
	return switchShape;
}

+ (cpShape*)door:(UIImageView*)img withPos:(CGPoint)pos andHorizontal:(BOOL)horizontal andLength:(int)length {
	cpBody* doorBody = cpBodyNew(INFINITY, INFINITY);
	doorBody->p = CGPointMake(pos.x, pos.y+160);
	// Define our shape's vertexes
	
	CGPoint locationx = CGPointMake(-length/2, 0);
	CGPoint locationy = CGPointMake(length/2, 0);
	// Create all shapes
	if (horizontal == FALSE) {
		locationx = CGPointMake(0,-length/2);
		locationy = CGPointMake(0,length/2);
	}
		
	cpShape *doorShape = cpSegmentShapeNew(doorBody, locationx, locationy, 7.5);
	doorShape->e = 0.5; doorShape->u = 0.8; doorShape->collision_type = 0; doorShape->data = img;
	doorBody->shape = doorShape;
	return doorShape;
}

@end
Compiling with debug mode does not give any more info, just:

Code: Select all

Program received signal:  “EXC_BAD_ACCESS”.
warning: check_safe_call: could not restore current frame

warning: Unable to restore previously selected frame.
warning: Unable to restore previously selected frame.
I hope this helps

PS:It should be noted that this is a modified tutorial I found
User avatar
slembcke
Site Admin
Posts: 4166
Joined: Tue Aug 14, 2007 7:13 pm
Contact:

Re: Clear cpSpace

Post by slembcke »

Ah, I see what is going on. You are attempting to free the space's children inside of a collision callback. Very very bad.
Can't sleep... Chipmunks will eat me...
Check out our latest projects! -> http://howlingmoonsoftware.com/wordpress/
qwertyp
Posts: 21
Joined: Wed Apr 14, 2010 6:36 pm
Contact:

Re: Clear cpSpace

Post by qwertyp »

So how should I do it then? Could I just remove the whole space in the callback?
User avatar
slembcke
Site Admin
Posts: 4166
Joined: Tue Aug 14, 2007 7:13 pm
Contact:

Re: Clear cpSpace

Post by slembcke »

You need to set a flag or something signifying that you are done with the level. You can't free the space (or stuff it's processing) while the cpSpaceStep() function is still running. Post step callbacks were added to allow you to remove objects from the space after it is done processing all of the objects the space is referencing, but the space itself is still in use.
Can't sleep... Chipmunks will eat me...
Check out our latest projects! -> http://howlingmoonsoftware.com/wordpress/
qwertyp
Posts: 21
Joined: Wed Apr 14, 2010 6:36 pm
Contact:

Re: Clear cpSpace

Post by qwertyp »

slembcke wrote:You need to set a flag or something signifying that you are done with the level. You can't free the space (or stuff it's processing) while the cpSpaceStep() function is still running. Post step callbacks were added to allow you to remove objects from the space after it is done processing all of the objects the space is referencing, but the space itself is still in use.
That was the trick, thanks!
Post Reply

Who is online

Users browsing this forum: Heise IT-Markt [Crawler] and 4 guests