Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

EXC_BAD_ACCESS SKPhysicsWorld

I'm really confused on why I am getting an EXC_BAD_ACCESS (code=1, address=0x1c) at [world addJoint:pinJoin];.

JointTest.m

#import "JointTest.h"

@implementation JointTest
-(SKNode *)initWithWorld:(SKPhysicsWorld *)pWorld{
    if(self = [super init]){
       world = pWorld;
       [self attachBodies];
    }
    return self;
}
-(void)attachBodies{
    SKSpriteNode * spriteA = [[SKSpriteNode alloc]initWithImageNamed:@"rocket"];
    SKSpriteNode * spriteB = [[SKSpriteNode alloc]initWithImageNamed:@"rocket"];

    SKPhysicsBody * bodyA = [SKPhysicsBody bodyWithRectangleOfSize:spriteA.size];
    SKPhysicsBody * bodyB = [SKPhysicsBody bodyWithRectangleOfSize:spriteB.size];

    spriteA.position = CGPointMake(150, 300);
    spriteB.position = CGPointMake(150, 300 + spriteB.size.height/2);

    [self addChild:spriteA];
    [self addChild:spriteB];

    bodyA.dynamic = NO;

    spriteA.physicsBody = bodyA;
    spriteB.physicsBody = bodyB;

    SKPhysicsJointPin * pinJoin = [SKPhysicsJointPin jointWithBodyA:spriteA.physicsBody bodyB:spriteB.physicsBody anchor:spriteA.position];
    [world addJoint:pinJoin];

}
@end

JointTest.h

#import <SpriteKit/SpriteKit.h>

@interface JointTest : SKNode{
    SKPhysicsWorld * world;
}
-(SKNode *)initWithWorld:(SKPhysicsWorld *)pWorld;
@end

In the SKScene

JointTest * test = [[JointTest alloc]initWithWorld:self.physicsWorld];
[self addChild:test];

What confuses me is moving the code in the attachBodies method into the scene and calling the the addJoint method with the scene's physicsWorld works great. For instance:

SKSpriteNode * spriteA = [[SKSpriteNode alloc]initWithImageNamed:@"rocket"];
SKSpriteNode * spriteB = [[SKSpriteNode alloc]initWithImageNamed:@"rocket"];

SKPhysicsBody * bodyA = [SKPhysicsBody bodyWithRectangleOfSize:spriteA.size];
SKPhysicsBody * bodyB = [SKPhysicsBody bodyWithRectangleOfSize:spriteB.size];

spriteA.position = CGPointMake(150, 300);
spriteB.position = CGPointMake(150, 300 + spriteB.size.height/2);

[self addChild:spriteA];
[self addChild:spriteB];

bodyA.dynamic = NO;

spriteA.physicsBody = bodyA;
spriteB.physicsBody = bodyB;

SKPhysicsJointPin * pinJoin = [SKPhysicsJointPin jointWithBodyA:spriteA.physicsBody bodyB:spriteB.physicsBody anchor:spriteA.position];
[self.physicsWorld addJoint:pinJoin];

I've been pulling my hair out for a few hours over this so if anyone has an idea I would greatly appreciate it. Thanks!

like image 850
Eric Avatar asked Jan 02 '14 00:01

Eric


Video Answer


1 Answers

Passing in the physics world on init is not good design. Instead create the instance of the class normally, then send the attachBodies message to it from wherever you created the JointTest instance. Then you can access the physics world through self.scene.physicsWorld rather than having to pass the world around and keeping an extraneous reference to it.

Instead of this:

JointTest * test = [[JointTest alloc]initWithWorld:self.physicsWorld];
[self addChild:test];

Do this:

JointTest * test = [JointTest node];
[self addChild:test];
[test attachBodies];

Note that attachBodies is sent after addChild because before addChild the JointTest's scene property will still be nil.

I bet this will also solve your problem, though this is a guess:

You create JointTest and immediately add two sprites with joints to it, but at this point the JointTest instance isn't added to the node graph yet (via addChild). Thus the JointTest and its two child nodes are simply not yet "registered" with the physics world to begin with, which may lead to the crash.

like image 58
LearnCocos2D Avatar answered Oct 13 '22 09:10

LearnCocos2D