Callback errors, strange behavior

Official forum for the Chipmunk2D Physics Library.
Post Reply
LtEnder
Posts: 5
Joined: Tue Nov 09, 2010 4:34 am
Contact:

Callback errors, strange behavior

Post by LtEnder »

I have some strange behavior with the collision callbacks....

I am trying to replace object A with object B when object A passes through a sensor. I have tried setting up post step callbacks, however the weird thing is, it triggers another "COLLISION_SEPERATE" moment. The poststep callback creates a new body with the coordinates of object A, and recreates the shape based on object B specs (stored outside). Then another collision occurs with "COLLISION_SEPERATE", without ever a matching COLLISION_BEGIN. Another callback occurs and it crashes trying to work with an already released object.

Any ideas?! Anybody tried replacing one object with another?
User avatar
slembcke
Site Admin
Posts: 4166
Joined: Tue Aug 14, 2007 7:13 pm
Contact:

Re: Callback errors, strange behavior

Post by slembcke »

Not quite sure I follow. It might be the case where you need to be very careful about the ordering of your calls.

The relevant parts of cpSpaceStep() work like this:
1) All collisions are detected, begin and pre-solve are called on each pair as collisions are found.
2) The cached collisions are checked, separate is called for any collision that happened last step but not this step.
3) Collisions are solved.
4) Run the post-solve callbacks.
5) Run the post-step callbacks.

Additionally, when you remove an object from the space, it immediately calls separate callbacks for all the shapes it was touching. This means that when you remove the object within the post-step callback it's calling the separate callback which you might not have been expecting.

Posting some code snippets might help.
Can't sleep... Chipmunks will eat me...
Check out our latest projects! -> http://howlingmoonsoftware.com/wordpress/
LtEnder
Posts: 5
Joined: Tue Nov 09, 2010 4:34 am
Contact:

Re: Callback errors, strange behavior

Post by LtEnder »

Aha! Yes the collision_seperate call i did not expect. The problem is I want to schedule the shape removal from the collision_seperate case, so it gets called again and crashes. I have added a check for shape->body->shape == nil, which solves the problem, but is there a better way to handle this? Or could some functionality be added to chipmunk?

In my program, widgets (collision types 1,2,3,...) move around and collide with triggerZones (collision type 9999). All those collisions are routed through one function, which uses performselector() to call the appropriate function on a triggerZone's owner.

triggerZone interface:

Code: Select all

@interface TriggerZone : NSObject {
    CGFloat zoneWidth;
    CGFloat zoneHeight;
    cpVect triggerZoneOffset;
    
    id owner;
    SEL sensorFuncBegin;
    SEL sensorFuncPresolve;
    SEL sensorFuncPostsolve;
    SEL sensorFuncSeperate;
    
    int zoneID;
}
The routing function:

Code: Select all

// all triggerzone<->widget collisions route through here
- (BOOL) handleTriggerZoneCollision:(CollisionMoment)moment arbiter:(cpArbiter*)arb space:(cpSpace*)space
{
    //NSLog(@"Routing triggerzone collision...");
    
    CP_ARBITER_GET_SHAPES(arb, triggerSensorShape, widgetShape);
    
    WidgetTemplate *widget = widgetShape->body->data;
    TriggerZone *triggerZone = triggerSensorShape->body->data;

    NSLog(@"Routing triggerzone collision... widget has position %f,%f arb timestamp=%d zoneID=%d widget has type=%d key=%@", widgetShape->body->p.x, widgetShape->body->p.y, arb->stamp, triggerZone.zoneID, widget.collision_type, widget.key);
    
    switch(moment)
    {
        case COLLISION_BEGIN:
            NSLog(@"COLLISION_BEGIN");
             if (triggerZone.sensorFuncBegin != nil) {
             [triggerZone.owner performSelector:triggerZone.sensorFuncBegin withObject:widgetShape];
             }
            break;
            
        case COLLISION_PRESOLVE:
            NSLog(@"COLLISION PRESOLVE");
            if (triggerZone.sensorFuncPresolve != nil) {
                [triggerZone.owner performSelector:triggerZone.sensorFuncPresolve withObject:widgetShape];
            }
            break;
        
        case COLLISION_POSTSOLVE:
            NSLog(@"POSTSOLVE");
            if (triggerZone.sensorFuncPostsolve != nil) {
                [triggerZone.owner performSelector:triggerZone.sensorFuncPostsolve withObject:widgetShape];
            }
            break;
            
        case COLLISION_SEPARATE: // why is this called twice?!
            NSLog(@"COLLISION SEPERATE");
            if (triggerZone.sensorFuncSeperate != nil && widgetShape->body->space != NULL) {
                [triggerZone.owner performSelector:triggerZone.sensorFuncSeperate withObject:widgetShape];
            }
            break;
    }
    
    return YES;
}
User avatar
slembcke
Site Admin
Posts: 4166
Joined: Tue Aug 14, 2007 7:13 pm
Contact:

Re: Callback errors, strange behavior

Post by slembcke »

It sounds like you need to be setting a boolean on your widgets. Removing objects from separate callbacks can get sticky as you've seen. There isn't really a consistent thing that Chipmunk can do to cover all the possibilities to fix the situation.
Can't sleep... Chipmunks will eat me...
Check out our latest projects! -> http://howlingmoonsoftware.com/wordpress/
LtEnder
Posts: 5
Joined: Tue Nov 09, 2010 4:34 am
Contact:

Re: Callback errors, strange behavior

Post by LtEnder »

It seems the space==null check is not enough. I still get crashes after 5-10 widgets pass through the transformer. I don't currently track each gameobject so i am considering adding that to the code.

After thinking about what happens in a collision_seperate...
Additionally, when you remove an object from the space, it immediately calls separate callbacks for all the shapes it was touching. This means that when you remove the object within the post-step callback it's calling the separate callback which you might not have been expecting.
Yet if the shape removal was trigger from a collision_seperate, it -shouldn't- have been touching any shapes... at least any that matter. (the triggerzone)

Is this supposed to happen?
User avatar
slembcke
Site Admin
Posts: 4166
Joined: Tue Aug 14, 2007 7:13 pm
Contact:

Re: Callback errors, strange behavior

Post by slembcke »

Are you sure it's only touching one shape or sensor at a time? It would be a pretty serious bug if Chipmunk was calling separate for the same shape pair more than once. Keep in mind that the collision events work on the level of shapes. If a body has multiple shapes each shape gets it's own events, even if they are marked with the same collision_type.
Can't sleep... Chipmunks will eat me...
Check out our latest projects! -> http://howlingmoonsoftware.com/wordpress/
LtEnder
Posts: 5
Joined: Tue Nov 09, 2010 4:34 am
Contact:

Re: Callback errors, strange behavior

Post by LtEnder »

Currently the setup is very simple.... I drop the widget in from above. (Widgets have 1 shape) It falls onto a conveyor belt shape, which generates no collisions and uses surface velocity to move the widget. A transformer has one triggerzone.

Heres a log of just before the crash.

Code: Select all

2010-11-10 10:36:25.337 cocosFactory[24715:207] Routing triggerzone collision... widget has position 140.693130,255.399933 arb timestamp=1551 zoneID=0 widget has type=1 key=red
2010-11-10 10:36:25.338 cocosFactory[24715:207] COLLISION SEPERATE
2010-11-10 10:36:25.340 cocosFactory[24715:207] transformer event for shape
2010-11-10 10:36:25.342 cocosFactory[24715:207] postStepRemoveAndAdd
2010-11-10 10:36:25.343 cocosFactory[24715:207] Routing triggerzone collision... widget has position 140.693130,255.399933 arb timestamp=1551 zoneID=0 widget has type=1 key=red
2010-11-10 10:36:25.344 cocosFactory[24715:207] COLLISION SEPERATE
2010-11-10 10:36:25.346 cocosFactory[24715:207] transformer event for shape
I'm trying to step through the chipmunk code but I don't really understand whats going on.
User avatar
slembcke
Site Admin
Posts: 4166
Joined: Tue Aug 14, 2007 7:13 pm
Contact:

Re: Callback errors, strange behavior

Post by slembcke »

You should also log the values of the triggerSensorShape and widgetShape pointers. They should be different.
Can't sleep... Chipmunks will eat me...
Check out our latest projects! -> http://howlingmoonsoftware.com/wordpress/
User avatar
slembcke
Site Admin
Posts: 4166
Joined: Tue Aug 14, 2007 7:13 pm
Contact:

Re: Callback errors, strange behavior

Post by slembcke »

Actually, that got me thinking that there are actually two code paths that call separate, and it looks like there is a bug in one of them after all.

Search for contactSetFilterRemovedShape in cpSpace.c. Change this line:

Code: Select all

arb->handler->separate(arb, context->space, arb->handler->data);
To This:

Code: Select all

if(arb->state != cpArbiterStateCached){
  arb->handler->separate(arb, context->space, arb->handler->data);
}
I didn't make a test case to try it out, but I'm pretty certain that should fix the problem. Let me know if it works and I'll commit it to trunk and release it with 5.3.3.

After calling separate, the arbiter (collision pair) goes into a cached state where it might exist for a few frames longer if the collision happens again. Removing a shape was calling the separate callback on all arbiters for that shape, even cached ones which had already called separate.
Can't sleep... Chipmunks will eat me...
Check out our latest projects! -> http://howlingmoonsoftware.com/wordpress/
LtEnder
Posts: 5
Joined: Tue Nov 09, 2010 4:34 am
Contact:

Re: Callback errors, strange behavior

Post by LtEnder »

Woohoo! Yeah that solved the problem. I no longer get the duplicate collision_seperate.
Post Reply

Who is online

Users browsing this forum: No registered users and 34 guests