re-assigning a shape's group

Official forum for the Chipmunk2D Physics Library.
Post Reply
Vico
Posts: 13
Joined: Fri Jul 06, 2012 10:12 am
Contact:

re-assigning a shape's group

Post by Vico »

Vico still on air ! Today's topic tease my brain, what about it:

In the (CCLayer*)GameSceneLayer, I'm adding a table to the space like this:

Code: Select all

-(id) init
{
	if( (self=[super init])) {
/*
bla bla code
*/

CGPoint TableAPos = CGPointMake(400, 300);
TableSprite *aTableSprite = [self AddTableAtLocation:TableAPos withBottleNum:2 withGlassNum:1 withCardNum:0];
/*
bla bla code
*/
}

-(TableSprite*)AddTableAtLocation:(CGPoint)location withBottleNum:(NSInteger)numBottles withGlassNum:(NSInteger)glassNum withCardNum:(NSInteger)numCards {
    
    TableSprite *newTableSprite = [[TableSprite alloc] initWithFrameName:@"Table" 
                                                                atLocation:location 
                                                                   inSpace:space 
                                                                staticBody:NO 
                                                            withParentNode:self withBottles:numBottles withGlasses:glassNum withCards:numCards];
    
/*
bla bla code
*/
    
    return newTableSprite;
}

TableSprite class is a subclass of PhysicsSprite, looks like:

Code: Select all

- (id)initWithFrameName:(NSString *)fileName 
             atLocation:(CGPoint)location 
                inSpace:(ChipmunkSpace*)theSpace 
             staticBody:(BOOL)isStatic
         withParentNode:(CCNode*)parentNode
            withBottles:(NSInteger)numBottles
            withGlasses:(NSInteger)numGlasses
              withCards:(NSInteger)numCards {
    
    if (self = [super initWithFrameName:fileName atLocation:location inSpace:theSpace staticBody:isStatic withParentNode:parentNode]) {
        
 /*
Bla bla code putting new objects like glasses, bottles and playing cards on the table
*/

    }
    return self;
}
Now, you will probably want to know about the PhysicsSprite class (a NSObject subclass), the important things are between /////////// :

Code: Select all

- (id)initWithFrameName:(NSString *)fileName atLocation:(CGPoint)location inSpace:(ChipmunkSpace*)theSpace staticBody:(BOOL)isStatic withParentNode:(CCNode*)parentNode {
    
    if(self = [super init]) {
        
        sprite = [CCSprite spriteWithSpriteFrameName:fileName];
        sprite.anchorPoint = [[PhysEdShapeCache sharedShapeCache] anchorPointForShape:fileName];

////////////////////
// The shapesArray will contains every shapes from the body we are going to get next step
 
        NSMutableArray *newArray = [[NSMutableArray alloc] init];
        self.shapesArray = newArray;
        [newArray release];
/////////////////////

// Here we get the shape designed with PhysicsEditor from Andreas Loew
        ChipmunkCocosBody *newBody = [[PhysEdShapeCache sharedShapeCache] createBodyWithName:fileName withData:sprite inSpace:theSpace staticBody:isStatic];

// And we assign it to a pointer declared in class header
        self.body = newBody;
        body.pos = location;

// Then we add the body's shapes to our previously initialized array
        [shapesArray addObjectsFromArray:body.shapes];
        
//////////////////
// Changing the shape's group here will be working while running the game
// The purpose is to make the tables no longer reacting to a certain collision

        for (id aShape in shapesArray) {
            ChipmunkShape *theShape = (ChipmunkShape*)aShape;
            theShape.group = [NSNumber numberWithInt:2];
       }
//////////////////
        
// With or without this line, it works, so far
        [theSpace reindexShapesForBody:body];

        spritesArray = [[NSMutableArray alloc] initWithObjects:sprite, nil];
	body.syncedNodes = spritesArray;
        
        [parentNode addChild:sprite];

	}
	return self;
}

So here we are, running the game like this makes the tables instances change their shape's group as expected, but I don't want that, I'd like to define the group while creating my table instances from the GameSceneLayer.
Actually, I'd like to say "I want 3 tables, A, B and C, and I only want the table C to ignore collisions".
So, deleting the for loop from the PhysicSprite class init method, and back in my GameSceneLayer, I just add the for loop after I have created my tables:

Code: Select all

-(id) init
{
	if( (self=[super init])) {
/*
bla bla code
*/

CGPoint TableAPos = CGPointMake(400, 300);
TableSprite *aTableSprite = [self AddTableAtLocation:TableAPos withBottleNum:2 withGlassNum:1 withCardNum:0];

///////////////////
for (id aShape in aTableSprite.shapesArray) {
            ChipmunkShape *theShape = (ChipmunkShape*)aShape;
            theShape.group = [NSNumber numberWithInt:2];
}

// With or without this line, it works, so far
        [theSpace reindexShapesForBody:aTableSprite.body];
///////////////////////

/*
bla bla code
*/
}
The array is not to be suspected because calling directly the body's shapes property give the same no-result.
This is my brainwasher of the moment, hope you like it :_)
User avatar
slembcke
Site Admin
Posts: 4166
Joined: Tue Aug 14, 2007 7:13 pm
Contact:

Re: re-assigning a shape's group

Post by slembcke »

Hmm. I'm not sure I understood the original question. The issue is that it's not changing the group of the shapes, or that the collisions aren't being ignored because of it?

Another potential issue did catch my eye though.. In Objective-Chipmunk, the group property is an object reference, and it uses reference equality to check if something is in the same group and not object equality. In other words, [obj1 equals:obj2] == TRUE doesn't imply that their pointers are equal (obj1 == obj2 might be false). Be careful when using NSNumbers or NSStrings that aren't referenced from a static global or shared data structure of some kind.

It's probably working just fine right now because cocoa caches NSNumber instances less than 100 (or something like that). If you were using larger numbers, you might find that two equivalent numbers were actually stored in different objects though.

I usually just use static strings stored in global variables:

Code: Select all

NSString *COLLISION_GROUP_TERRAIN = @"COLLISION_GROUP_TERRAIN"
Then stick an extern declaration in a header somewhere.
Can't sleep... Chipmunks will eat me...
Check out our latest projects! -> http://howlingmoonsoftware.com/wordpress/
Vico
Posts: 13
Joined: Fri Jul 06, 2012 10:12 am
Contact:

Re: re-assigning a shape's group

Post by Vico »

slembcke wrote:Hmm. I'm not sure I understood the original question. The issue is that it's not changing the group of the shapes, or that the collisions aren't being ignored because of it?
You're right, I didn't even asked a question ^^
Yes, the group is changed but the collisions aren't being ignored.
Note that collisions aren't being ignored only if I change the group from my GameSceneLayer class, but it works fine when I do it in my PhysicsSprite class (collisions ARE ignored).

In Objective-Chipmunk, the group property is an object reference, and it uses reference equality to check if something is in the same group and not object equality. In other words, [obj1 equals:obj2] == TRUE doesn't imply that their pointers are equal (obj1 == obj2 might be false). Be careful when using NSNumbers or NSStrings that aren't referenced from a static global or shared data structure of some kind.
Just to be sure I understand, are you saying that when I'm using [NSNumber numberWithInt:2] in my "for" loop it creates several identical NSNumber objects but as they don't all point to a same memory block the equality is not returned as TRUE ? I didn't know that, it sounds good. Am I correct?
It's probably working just fine right now because cocoa caches NSNumber instances less than 100 (or something like that). If you were using larger numbers, you might find that two equivalent numbers were actually stored in different objects though.
Seems to me it's only working when creating the table object but not when you re-assign it later with a delayed call...
I usually just use static strings stored in global variables:
Yeah, I saw it in your example codes, but the thing is I'm using PhysicsEditor and it only allow int references for groups and collision types, so I wanted to keep things simple by using integers too in my code...

I guess I can keep my NSNumber workflow if I use a unique pointer. I'm gonna try it and I come back. Thank you for helping :)
Vico
Posts: 13
Joined: Fri Jul 06, 2012 10:12 am
Contact:

Re: re-assigning a shape's group

Post by Vico »

No, It's not working neither with a pointer.
Yet, I can see the group is changed when I print the property.

NSLog(@"shape group:%d", [[[tableBSprite.body.shapes objectAtIndex:0] group] intValue]);

but for some reason collisions aren't ignored :shock:

It seems my classes are in cause since when I change the group in the PhysicsSprite class it works. So why the hell I can't call my shapes back from the GameSceneLayer class :evil:
Vico
Posts: 13
Joined: Fri Jul 06, 2012 10:12 am
Contact:

Re: re-assigning a shape's group

Post by Vico »

Allright, I'm just a big su..er, that's why. :oops:

I was assigning a NSNumber object containing a int value, but the PhysicsEditor software I'm using only assign int values. So when I was changing the group to my NSNumber, it never can be equal to an integer. End of story.

btw, why did you choose not allowing any type for the group property ?

Thank you for your time, you helped by pointing the reference equality check for groups.

Private Message to Andreas : May you update PhysicsEditor so it accepts any value type for the collision types and groups fields :roll: ?
User avatar
slembcke
Site Admin
Posts: 4166
Joined: Tue Aug 14, 2007 7:13 pm
Contact:

Re: re-assigning a shape's group

Post by slembcke »

Aha. I was just thinking that when I came back and read through the second to last post. Yeah, NSNumbers are not the same as regular ints. The C Chipmunk API uses uintptr_t by default, which is an integer type big enough to hold a pointer value. So it could be used for either a pointer reference or a plain old int. It's re-definable at compile time though, look in chipmunk_types.h (which Objective-Chipmunk does).

To make Objective-Chipmunk use uintptr_t again instead of id, comment out the lines in ObjectiveChipmunk.h where it redefines the group type. You shouldn't even need to recompile as id and uintptr_t are equivalent to the machine code. I pushed some header modifications to the Chipmunk Pro git repository as well to change instances of group being id to cpGroup so it can be redefined. There are only a half dozen places to do it though, it might be easier just to edit them yourself.

I didn't write PhysicsEditor, so I can't help you out with that.

Oh, and lastly. About small NSNumbers being cached: The NSNumber class caches small numbers, so [NSNumber numberWithInt:2] will almost certainly return the same object reference each time. Although this is somewhat undocumented behavior, and I don't think it defines what the limit is. [NSNumber numberWithInt:9999999999] almost certainly would return a different object each time it was called. So they would have different pointers, but [num1 equals:num2] would return true. Make sense?
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: re-assigning a shape's group

Post by slembcke »

Actually, to make that even more complicated, on some runtimes (the 64 bit Intel one for sure), small NSNumbers are stored as "immediate objects". Heap allocated memory will always be at least 4 byte aligned on pretty much any computer system, so the first three bits of the pointer will always be 0. You can then fiddle with those bits to tag pointers as being not actually pointers. So if the first bit is set, then treat the remaining x bits as an integer or whatever.

Completely off topic, but interesting things to know. ;)
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 23 guests