SpriteKit can't change SKPhysicsJointLimit maxLength

195 views Asked by At

I have a simple project where I have two SKShapeNodes with a SKPhysicsBody for each. I have a SKPhysicsJointLimit that connects them. While the program is running, I need to change the SKPhysicsJointLimit.maxLength property. However, while the value does change, the physics onscreen do not show it.

I am running Xcode 6.4 and deploying to iOS 7.0+

How do I change the maxLength property so that it updates the joint's physics?

I have my code here, which is modified from the default SpriteKit project:

GameScene.h

#import <SpriteKit/SpriteKit.h>

@interface GameScene : SKScene

@property (strong) SKShapeNode *node1;
@property (strong) SKShapeNode *node2;
@property (strong) SKPhysicsJointLimit *limitJoint;
@property bool running;

@end

GameScene.m

#import "GameScene.h"

@implementation GameScene

-(void)didMoveToView:(SKView *)view {
    self.running = NO;

    // Create a simple square path for the nodes to use
    CGMutablePathRef square = CGPathCreateMutable();
    CGPathMoveToPoint(square, NULL, -10, 10);
    CGPathAddLineToPoint(square, NULL, -10, -10);
    CGPathAddLineToPoint(square, NULL, 10, -10);
    CGPathAddLineToPoint(square, NULL, 10, 10);
    CGPathAddLineToPoint(square, NULL, -10, 10);
    CGPathCloseSubpath(square);

    // Create node 1
    self.node1 = [SKShapeNode node];
    self.node1.position = CGPointMake(450, 512);
    self.node1.path = square;
    self.node1.fillColor = [SKColor blackColor];
    // I know that I'm using a circular physics body here, but for me a circle is fine
    self.node1.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:10];
    // Will turn it on after the user taps the screen, so that we can watch it run
    self.node1.physicsBody.dynamic = NO;
    [self.scene addChild:self.node1];

    // Create node 2
    self.node2 = [SKShapeNode node];
    self.node2.position = CGPointMake(550, 512);
    self.node2.path = square;
    self.node2.fillColor = [SKColor blackColor];
    self.node2.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:10];
    // Node 2 will always stay in place
    self.node2.physicsBody.dynamic = NO;
    [self.scene addChild:self.node2];

    // Create the limit joint between the two nodes
    self.limitJoint = [SKPhysicsJointLimit jointWithBodyA:self.node1.physicsBody bodyB:self.node2.physicsBody anchorA:self.node1.position anchorB:self.node2.position];
    [self.scene.physicsWorld addJoint:self.limitJoint];
}

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    if (self.running) {
        // Set the new maxLength
        float newMaxLength = self.limitJoint.maxLength + 50.0;
        [self.limitJoint setMaxLength:newMaxLength];
        NSLog(@"New length: %f", self.limitJoint.maxLength);
    } else {
        // Turn on the physics for node 1
        self.running = YES;
        self.node1.physicsBody.dynamic = YES;
    }
}

-(void)update:(CFTimeInterval)currentTime {
    // Nothing here
}

@end

The output of this code is:

2015-08-18 19:55:33.494 LimitTest[6925:60b] New length: 150.000015
2015-08-18 19:55:33.706 LimitTest[6925:60b] New length: 200.000031
2015-08-18 19:55:33.897 LimitTest[6925:60b] New length: 250.000031
2015-08-18 19:55:34.134 LimitTest[6925:60b] New length: 300.000031
2015-08-18 19:55:34.381 LimitTest[6925:60b] New length: 350.000031
2015-08-18 19:55:34.614 LimitTest[6925:60b] New length: 400.000061
2015-08-18 19:55:35.784 LimitTest[6925:60b] New length: 450.000061
2015-08-18 19:55:36.136 LimitTest[6925:60b] New length: 500.000061
2015-08-18 19:55:36.401 LimitTest[6925:60b] New length: 550.000061
2015-08-18 19:55:36.630 LimitTest[6925:60b] New length: 600.000061
2015-08-18 19:55:36.890 LimitTest[6925:60b] New length: 650.000122
2015-08-18 19:55:37.130 LimitTest[6925:60b] New length: 700.000122
2015-08-18 19:55:37.368 LimitTest[6925:60b] New length: 750.000122
2015-08-18 19:55:37.611 LimitTest[6925:60b] New length: 800.000183
2015-08-18 19:55:37.846 LimitTest[6925:60b] New length: 850.000183
2015-08-18 19:55:38.102 LimitTest[6925:60b] New length: 900.000244
2015-08-18 19:55:38.313 LimitTest[6925:60b] New length: 950.000244
2015-08-18 19:55:38.568 LimitTest[6925:60b] New length: 1000.000244

I am pretty sure the really small decimal value is just some inaccuracy, which I'm not worried about. I'm just showing that the maxLength property does change.

I have seen this question here, which was asked over a year ago, but with no solution. In the comments, he says he found a solution, and his brief description of the fix is something about making the change before returning the object. But as far as I can tell, that does not apply to me. Somebody asked him for clarification, but it appears to have been ignored.

1

There are 1 answers

0
Gliderman On BEST ANSWER

0x141E provided information on how to do this, making the connection I could not make. Basically create a new joint after removing the first one. I have a global variable for my joint, and this worked nicely for me. Here is the code that I'm now using in the touchesBegan

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    if (self.running) {
        // Create the new maxLength
        float newMaxLength = self.limitJoint.maxLength + 50.0;
        [self.scene.physicsWorld removeJoint:self.limitJoint];

        self.limitJoint = [SKPhysicsJointLimit jointWithBodyA:self.node1.physicsBody bodyB:self.node2.physicsBody anchorA:self.node1.position anchorB:self.node2.position];
        [self.limitJoint setMaxLength:newMaxLength];

        [self.scene.physicsWorld addJoint:self.limitJoint];
        NSLog(@"New length: %f", self.limitJoint.maxLength);
    } else {
        self.running = YES;
        self.node1.physicsBody.dynamic = YES;
    }
}