9

I'm testing out pin joints with Sprite Kit, and I'm finding something unusual happening.

My desired setup is this: one wide, flat box, and two circles; the circles are connected via SKPhysicsPinJoints to the box, so they can act as wheels.

Here's my code. I've tried to make it as concise as possible:

- (SKNode*) createWheelWithRadius:(float)wheelRadius {
    CGRect wheelRect = CGRectMake(-wheelRadius, -wheelRadius, wheelRadius*2, wheelRadius*2);

    SKShapeNode* wheelNode = [[SKShapeNode alloc] init];
    wheelNode.path = [UIBezierPath bezierPathWithOvalInRect:wheelRect].CGPath;

    wheelNode.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:wheelRadius];

    return wheelNode;
}


- (void) createCar {

    // Create the car
    SKSpriteNode* carNode = [SKSpriteNode spriteNodeWithColor:[SKColor yellowColor] size:CGSizeMake(150, 50)];
    carNode.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:carNode.size];
    carNode.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame));
    [self addChild:carNode];

    // Create the left wheel
    SKNode* leftWheelNode = [self createWheelWithRadius:30];
    leftWheelNode.position = CGPointMake(carNode.position.x-80, carNode.position.y);
    [self addChild:leftWheelNode];

    // Create the right wheel
    SKNode* rightWheelNode = [self createWheelWithRadius:30];
    rightWheelNode.position = CGPointMake(carNode.position.x+80, carNode.position.y);
    [self addChild:rightWheelNode];

    // Attach the wheels to the body
    CGPoint leftWheelPosition = leftWheelNode.position;
    CGPoint rightWheelPosition = rightWheelNode.position;

    SKPhysicsJointPin* leftPinJoint = [SKPhysicsJointPin jointWithBodyA:carNode.physicsBody bodyB:leftWheelNode.physicsBody anchor:leftWheelPosition];
    SKPhysicsJointPin* rightPinJoint = [SKPhysicsJointPin jointWithBodyA:carNode.physicsBody bodyB:rightWheelNode.physicsBody anchor:rightWheelPosition];

    [self.physicsWorld addJoint:leftPinJoint];
    [self.physicsWorld addJoint:rightPinJoint];
}

What I'm expecting is that the pin joints are anchored at their centre points; however, when I test this, the anchors for the joints appear to be far off.

Am I missing something really obvious?

Jon Manning
  • 133
  • 1
  • 4

2 Answers2

10

I also had this issue and the cause is setting the physics body before setting the sprites position.

carNode.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:carNode.size];
carNode.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame));

Change the above to

carNode.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame));
carNode.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:carNode.size];

It should work. Thanks Smick.

SpriteKit: How to create Basic Physics Joints

Community
  • 1
  • 1
Bavan
  • 1,021
  • 1
  • 10
  • 24
  • Nice little example, in your TVC, you can comment out numberOfSectionsInTableView, and for numberOfRowsInSection, just use [_dataSourceArray count]. Its a nice example, you should add [head.physicsBody applyTorque:0.2]; to the pin join to really show its difference to the fixed joint. Good job - thanks for sharing. – DogCoffee Oct 13 '13 at 22:36
  • Thank you Smick.. I updated the Example. But, TVC is coded that way, because it has two sections. I couldn't add your car example as a Joint Type. :) That example is put into a different section. – Bavan Oct 14 '13 at 01:43
  • i cant see the car in the example one now, still only has the list of joints. I'll be putting all my test code into a TVC - cool idea! – DogCoffee Oct 14 '13 at 02:09
  • @Bavan: I have used your code to joint to SpriteNodes. But it changes position of my spritenode. Can you please help me ? – Nirav Nov 17 '16 at 10:46
4

Try this code, I used yours and got weird issues, so started from scratch.

- (SKShapeNode*) makeWheel
{
    SKShapeNode *wheel = [[SKShapeNode alloc] init];
    CGMutablePathRef myPath = CGPathCreateMutable();
    CGPathAddArc(myPath, NULL, 0,0, 16, 0, M_PI*2, YES);
    wheel.path = myPath;
    return wheel;
}


- (void) createCar 
{

    self.physicsBody = [SKPhysicsBody bodyWithEdgeLoopFromRect:CGRectMake(0, 0, self.size.width, self.size.height)];

    // 1. car body
    SKSpriteNode *carBody = [SKSpriteNode spriteNodeWithColor:[UIColor whiteColor] size:CGSizeMake(120, 8)];
    carBody.position = CGPointMake(200, 200);
    carBody.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:carBody.size];
    [self addChild:carBody];

    // 2. wheels
    SKShapeNode *leftWheel = [self makeWheel];
    leftWheel.position = CGPointMake(carBody.position.x - carBody.size.width / 2, carBody.position.y);
    leftWheel.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:16];
    [self addChild:leftWheel];

    SKShapeNode *rightWheel = [self makeWheel];
    rightWheel.position = CGPointMake(carBody.position.x + carBody.size.width / 2, carBody.position.y);
    rightWheel.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:16];
    [self addChild:rightWheel];

    // 3. Join wheels to car
    [self.physicsWorld addJoint:[SKPhysicsJointPin jointWithBodyA:carBody.physicsBody bodyB:leftWheel.physicsBody anchor:leftWheel.position]];
    [self.physicsWorld addJoint:[SKPhysicsJointPin jointWithBodyA:carBody.physicsBody bodyB:rightWheel.physicsBody anchor:rightWheel.position]];

    // 4. drive car
    [carBody.physicsBody applyForce:CGVectorMake(10, 0)];
}
DogCoffee
  • 19,820
  • 10
  • 87
  • 120
  • Thanks very much! I marked Bavan's answer as correct, since it's more concise and easier for future readers to follow, but you provided the correct solution first. – Jon Manning Oct 14 '13 at 07:18
  • @DogCoffee: I have used your code to joint to SpriteNodes. But it changes position of my spritenode. Can you please help me ? – Nirav Nov 17 '16 at 10:46
  • @Nirav I suggest you post a new question. I haven't used sprite kit for a while. – DogCoffee Nov 17 '16 at 11:43