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.
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