Box2D - b2body GetUserData always returns null

你。 提交于 2019-12-06 11:14:34

You are assigning the userdata to the bodyDef AFTER you call CreateBody(), so it is never being added to the actual body.

b2BodyDef is a struct that holds settings to create a body. Once you've called CreateBody(), changes to this struct have no effect.

You found the solution yourself by moving the bodyDef.UserData = sprite; line somewhere before CreateBody() is called. This is the correct place to put it. If you think you need it at the end of the function for some reason (other variables?), then you need to refactor your code so that this is not the case.

I would change this line (and the BodyObject class):

BodyObject *bodyObject = [[BodyObject alloc] initWithBody:body 
                                               andFixture:fixture 
                                              andVelocity:vector 
                                                andSprite:sprite];

so that you can instantiate it without needing the box2d elements (i.e. before they have been defined), then use the properties to assign these values after they have been created. This way you can pass this object as the body's userdata, create the body, then assign the b2Body* using [bodyObject setBody:body];

Don't forget to ensure your Body and Fixture properties are not readonly.

The final code might look like this:

-(void) addPlayerShip
{
    CCSpriteSheet *sheet = [CCSpriteSheet spriteSheetWithFile:@"PlayerShip.png" capacity:1];

    //Get sprite sheet
    CCSprite *sprite = [CCSprite spriteWithSpriteSheet:sheet rect:CGRectMake(0,0,64,64)];
    [sheet addChild:sprite];

    CGSize screenSize = [CCDirector sharedDirector].winSize;

    sprite.position = ccp( screenSize.width/2, screenSize.height/2);

    [self addChild:sheet];

    b2Vec2 *vector = new b2Vec2;

    BodyObject *bodyObject = [[BodyObject alloc] initWithSprite:sprite 
                                                   andVelocity:vector];

    //MOVES THE BODY DEFINITION AFTER THE BODYOBJECT DEFINITION
    // Define the dynamic body.
    b2BodyDef bodyDef;
    bodyDef.type = b2_dynamicBody;
    bodyDef.position.Set(sprite.position.x/PTM_RATIO, sprite.position.y /PTM_RATIO);
    bodyDef.angularVelocity=0;
    bodyDef.userData = bodyObject;

    b2Body *body = world->CreateBody(&bodyDef);

    b2PolygonShape dynamicTriangle;

    dynamicTriangle.m_vertexCount=3;
    dynamicTriangle.m_vertices[0].Set(0,-1);
    dynamicTriangle.m_vertices[1].Set(1,1);
    dynamicTriangle.m_vertices[2].Set(-1,1);

    // Define the dynamic body fixture.
    b2FixtureDef fixtureDef;
    fixtureDef.shape = &dynamicTriangle;
    fixtureDef.density = 1.0f;
    fixtureDef.friction = 0.0f;
    fixtureDef.restitution=0.0f;

    b2Fixture *fixture = body->CreateFixture(&fixtureDef);

    [bodyObject setBody:body];
    [bodyObject setFixture:fixture];
}

The bodyObject class would then simply look like this:

#import "BodyObject.h"


@implementation BodyObject

@synthesize Body;
@synthesize Fixture;

-(id) initWithSprite:(CCSprite*) sprite 
       andVelocity:(b2Vec2*) velocity 
{
    self = [super initWithSprite:(CCSprite*)sprite 
                     andVelocity:(b2Vec2*)velocity];

    return self;
}

@end

If anyone has the same problem that GetUserData() returns null, even though you SetUserData. Then don't make my mistake and assume than b2World.QueryShape() gives bodies in callback. Nope, it gives you Fixtures. You have to fixture.GetBody().GetUserData() (my case was: box2dweb in javascript; this is the question I googled for answer, I assume others will come this way)

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!