Callbacks not working properly when mixing Obj-c & C

Discuss any Chipmunk bugs here.
Post Reply
ndizazzo
Posts: 15
Joined: Thu Feb 10, 2011 7:53 pm
Contact:

Callbacks not working properly when mixing Obj-c & C

Post by ndizazzo »

Hello,

I have a physics entity contained in an Objective-C class. I have many of these entities, and they're responsible for adding themselves to the physics space (through a singleton physics manager interface). This includes creating the callbacks to the entities collision methods.

Since I'm using Objective-C, I can't use any of the selectors as the callback function for cpSpaceAddCollisionHandler() ... IE, I am forced to do something akin to this:

Code: Select all


// C callbacks to invoke Objective-C method hooks >:(

int wall_begin(cpArbiter *arb, cpSpace *space, void *unused);
int wall_pre(cpArbiter *arb, cpSpace *space, void *unused);
void wall_post(cpArbiter *arb, cpSpace *space, void *unused);
void wall_end(cpArbiter *arb, cpSpace *space, void *unused);

@interface Polygon : DynamicEntity
{	
	cpVect polygonVerts[8];	
	int numSides;
	
	... (other stuffs) ...
}

... (some methods) ...

// Obj-C collision method hooks so we have access to iVars and class data

-(int)wall_beginCollision:(cpArbiter *)arb :(cpSpace *)space :(void *)data;
-(void)wall_endCollision:(cpArbiter *)arb :(cpSpace *)space :(void *)data;

@end

Then,

Code: Select all


/* PHYSICS CALLBACKS */

int wall_begin(cpArbiter *arb, cpSpace *space, void *ptrToSelf)
{
	int r = [(Polygon *)ptrToSelf wall_beginCollision :arb :space :ptrToSelf];
	return r;
}

// Unused
int wall_pre(cpArbiter *arb, cpSpace *space, void *unused)
{
	return 1;
}

// Unused
void wall_post(cpArbiter *arb, cpSpace *space, void *unused)
{
}

void wall_end(cpArbiter *arb, cpSpace *space, void *ptrToSelf)
{
	[(Polygon *)ptrToSelf wall_endCollision:arb :space :ptrToSelf];
}

/* END PHYSICS CALLBACKS */

@implementation Polygon

... (stuff) ...

-(void)addCollisionHandlers
{
	// Add collision callbacks for a wall 
	[_sharedPhysicsManager addCollisionHandler :TYPE_WALL 
											   :TYPE_POLYGON 
											   :wall_begin
											   :nil 
											   :nil 
											   :wall_end
											   :self];
}

-(int)wall_beginCollision:(cpArbiter *)arb :(cpSpace *)space :(void *)data
{
	NSLog(@"Polygon / Wall collision begin: %x\n", self);
	
	cpShape *a, *b; cpArbiterGetShapes(arb, &a, &b);
	cpVect cp = cpArbiterGetPoint(arb, 0);

	return 1;
}

-(void)wall_endCollision:(cpArbiter *)arb :(cpSpace *)space :(void *)data
{
	NSLog("Polygon / Wall Seperate");
}

@end

I've stepped through each entity adding its self via the Shared Physics Manager interface and each entity adds its self properly, which includes a pointer back to its self as the "ptrToSelf" as such:

(Shared Physics Manager)

Code: Select all

-(void)addCollisionHandler :(cpCollisionType)a
						   :(cpCollisionType)b
						   :(cpCollisionBeginFunc)begin
						   :(cpCollisionPreSolveFunc)pre
						   :(cpCollisionPostSolveFunc)post
						   :(cpCollisionSeparateFunc)sep
						   :(void *)data
{
	cpSpaceAddCollisionHandler(physicsSpace, a, b, begin, pre, post, sep, data);
}



Yet, when the first collision happens, the data that is sent to the "int wall_begin(cpArbiter *arb, cpSpace *space, void *ptrToSelf)" method is the address of the same object, every time - no matter which object collides.

I feel as if Chipmunk might be hashing, or using some sort of "bookmark" method to keep track of the data, causing the same data reference to be passed back every time. I'm not sure, but its causing issues for me as it doesn't follow conventional callback standards.

Any help on this matter?
ndizazzo
Posts: 15
Joined: Thu Feb 10, 2011 7:53 pm
Contact:

Re: Callbacks not working properly when mixing Obj-c & C

Post by ndizazzo »

Now that I've been reading through cpSpace.c, I don't think this is a bug, just a mis-understanding of the API.

The method name of cpSpaceAddCollisionHandler() implies that we're ADDING (possibly more than one addition?) individual methods to handle collisions between objects of type a, and type b. In a class-based language, this would mean that if an object adds one of it's instance methods as a collision handler, the address would be different for every instance.

In reality, it's a generic method to handle collisions based on objects of collision_type a, and collision_type b. It tracks only one method to handle these collisions.

1) Can we move this topic elsewhere?
2) Still looking for ideas regarding how to overcome this issue based on my set up. Any ideas?
ndizazzo
Posts: 15
Joined: Thu Feb 10, 2011 7:53 pm
Contact:

Re: Callbacks not working properly when mixing Obj-c & C

Post by ndizazzo »

A potential solution for me might be to comment out line 227 in cpSpace.c:

Code: Select all

        // Remove any old function so the new one will get added.
        cpSpaceRemoveCollisionHandler(space, a, b);
But I'm unsure how the hash set would behave having multiple entries with the same HASH_PAIR(0 ,1) function --- (0, 1) in my case ---.

It looks to me as it would overwrite previous hash entries due to cpHashSet.c:159, so I'm still at a loss as to how to approach this.
ndizazzo
Posts: 15
Joined: Thu Feb 10, 2011 7:53 pm
Contact:

Re: Callbacks not working properly when mixing Obj-c & C

Post by ndizazzo »

Ok - It seems like I've been having a nice conversation with myself, but I've managed to figure this out and hope to share it with other forum users in the case that they run into the same issue.

I started to think: "How can I use one generic callback to handle many different instances of object..." Then it hit me...

- You can get the colliding shapes from the arbiter
- Each shape has a 'body' field
- You can put anything you want in the 'data' field of shape->body
- So I put a reference back to my class instance in 'data' ...

Voila, you can invoke specific instance method hooks from a generic "handle-all" collision callback. Here's an example:

Code: Select all

int collision_begin(cpArbiter *arb, cpSpace *space, void *unused)
{
	// Need to request the shapes from the arbiter first
	cpShape *wall, *polygon; cpArbiterGetShapes(arb, &wall, &polygon);
	
	// Look up the body associated with the polygon thats colliding
	// Grab our class instance pointer from the body associated with the shape
	Polygon *p = (Polygon *)polygon->body->data;
	
	// Invoke instance method on our class
	int r = [p wall_beginCollision :arb :space :unused];
	
	return r;
}
Hope this helps somebody else!
markhula
Posts: 188
Joined: Wed Feb 02, 2011 4:23 am
Contact:

Re: Callbacks not working properly when mixing Obj-c & C

Post by markhula »

Hey,

Just to let you know I enjoyed the read. :-)
And although no fan of obj-c; I did implement a similar setup so that body->data actually points back to my real object, to avoid a similar problem.

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

Re: Callbacks not working properly when mixing Obj-c & C

Post by slembcke »

Yep, that is the intended way to do things. Bodies, shapes, and joints all have a data pointer that you can set to point to whatever game object that owns the physics object.
Can't sleep... Chipmunks will eat me...
Check out our latest projects! -> http://howlingmoonsoftware.com/wordpress/
Post Reply

Who is online

Users browsing this forum: No registered users and 6 guests