Search code examples
macossprite-kitskphysicsbodyskphysicsjoint

Spritekit SKPhysicsBody pin joints


I'm trying to create a ferris wheel. It is composed of three different sprites: the base (legs), the body (circular part that rotates) and the seats (16 in total).

In the code below, I added the base to the scene, then attached the body to the base and finally attached each seat to the body. The seats are currently rotating (in a weird way) with the body. I do not want the seats to rotate at all. What am I doing wrong?

NOTE: Updated with comments and suggestions from @dragoneye

-(void) initFerrisWheel {
    self.physicsWorld.gravity = CGVectorMake(0, 0);

    //creates the body of the ferris wheel and attaches it to the base
    SKSpriteNode *ferrisWheel = (SKSpriteNode*)[self childNodeWithName:@"ferriswheel_base"];
    SKTexture *bodyTexture = [[SharedAssetsManager sharedData].menuAssets objectForKey:@"ferriswheel_body"];
    SKSpriteNode *body = [[SKSpriteNode alloc] initWithTexture:bodyTexture];
    [body setZPosition:2];
    [body setPosition:CGPointMake(0, 55)];
    body.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:self.size.height/2];
    [ferrisWheel addChild:body];

    //rotates the body of the ferris wheel
    SKAction *rotateSequence = [SKAction rotateByAngle:-0.785 duration:2.0];
    SKAction *rotateFinal = [SKAction repeatActionForever:rotateSequence];
    [body runAction:rotateFinal];

    SKTexture *seatTexture = [[SharedAssetsManager sharedData].menuAssets objectForKey:@"ferriswheel_seat"];

    int r = 130; //radius of the body for the ferris wheel
    for (int i = 0; i < 16; i++) {
        //creates a seat and places it on the body
        SKSpriteNode *seat = [[SKSpriteNode alloc] initWithTexture:seatTexture];
        float x = r * cosf(2*M_PI*i/16);
        float y = r * sinf(2*M_PI*i/16);
        [seat setPosition:CGPointMake(x, y)];
        [seat setZPosition:3];
        [body addChild:seat];

        //physics body stuff
        seat.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:seat.size.height/2];
        seat.physicsBody.dynamic = YES;

        CGPoint anchor = CGPointMake(x, y);
        SKPhysicsJointPin *pin = [SKPhysicsJointPin jointWithBodyA:body.physicsBody bodyB:seat.physicsBody anchor:anchor];
        [self.physicsWorld addJoint:pin];
        pin.shouldEnableLimits = YES;
        pin.lowerAngleLimit = -0.25;
        pin.upperAngleLimit = 0.25;

    }
}

Solution

  • After wrestling with this for a little while and creating a simple testing project I realized that my issue was that I was attaching the body of the ferris wheel to the base as a child node and I was also attaching the seats to the body as child nodes. While there may be a way to get this to work I based all coordinates on world coordinates instead. This may help someone out in future. Here's the fixed code:

    -(void) initFerrisWheel {
        //creates the body of the ferris wheel and attaches it to the base
        SKSpriteNode *ferrisWheel = (SKSpriteNode*)[self childNodeWithName:@"ferriswheel_base"];
        SKTexture *bodyTexture = [[SharedAssetsManager sharedData].menuAssets objectForKey:@"ferriswheel_body"];
        SKSpriteNode *body = [[SKSpriteNode alloc] initWithTexture:bodyTexture];
        [body setZPosition:2];
        [body setPosition:CGPointMake(ferrisWheel.position.x, ferrisWheel.position.y + 55)];
        body.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:body.size];
        body.physicsBody.affectedByGravity = NO;
        [self addChild:body];
    
        //rotates the body of the ferris wheel
        SKAction *rotateSequence = [SKAction rotateByAngle:-0.785 duration:2.0];
        SKAction *rotateFinal = [SKAction repeatActionForever:rotateSequence];
        [body runAction:rotateFinal];
    
        SKTexture *seatTexture = [[SharedAssetsManager sharedData].menuAssets objectForKey:@"ferriswheel_seat"];
    
        int r = 130; //radius of the body for the ferris wheel
        for (int i = 0; i < 16; i++) {
            //creates a seat and places it on the body
            SKSpriteNode *seat = [[SKSpriteNode alloc] initWithTexture:seatTexture];
            float x = body.position.x + r * cosf(2*M_PI*i/16);
            float y = body.position.y + r * sinf(2*M_PI*i/16);
            [seat setPosition:CGPointMake(x, y)];
            [seat setZPosition:3];
            [self addChild:seat];
    
            //physics body stuff
            seat.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:seat.size];
            seat.physicsBody.affectedByGravity = NO;
    
            SKPhysicsJointPin *pin = [SKPhysicsJointPin jointWithBodyA:body.physicsBody bodyB:seat.physicsBody anchor:seat.position];
            [self.physicsWorld addJoint:pin];
        }
    }