Jeremiah2911 Jeremiah2911 - 6 months ago 92
iOS Question

Sprite Kit - Spring Joints (shock absorber)

Frist off, thank you @Smick for the initial vehicle code as posted here:
Sprite Kit pin joints appear to have an incorrect anchor

I'm trying to add a slide joint between the wheel (left wheel) and chassis, along with a spring joint in order to create a shock absorbing effect.

With my code below, I get no compression. I realize the documentation shows a spring joint pulling two bodes together - the reverse of what I want. Is this possible in SK?

I think the pin joint may be the culprit? When I comment out the pin joint, the car parts go haywire - everything flies around the screen. Originally, the pin joint pinned the wheel to the chassis, but obviously I want to pin the wheel to the "shock absorber".

Also, the "axis" argument for SKPhysicsJointSliding has me a bit confused. It wants a vector. A vector relative to?

Thank you in advance.

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

- (void) createCar{

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

// 2. wheels
SKShapeNode *leftWheel = [self makeWheel];
leftWheel.position = CGPointMake(carBody.position.x - carBody.size.width / 2, carBody.position.y-40);
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];


/* Build left shock absorber and attach wheel */

CGVector av =CGVectorMake(0.0, 5.0);

SKPhysicsJointSliding *leftSlide = [SKPhysicsJointSliding jointWithBodyA:carBody.physicsBody
bodyB:leftWheel.physicsBody
anchor:leftWheel.position
axis:av];


SKPhysicsJointSpring *leftSpring = [SKPhysicsJointSpring jointWithBodyA:carBody.physicsBody bodyB:leftWheel.physicsBody
anchorA:CGPointMake(carBody.position.x - carBody.size.width / 2, carBody.position.y)
anchorB:leftWheel.position];



SKPhysicsJointPin *leftPin = [SKPhysicsJointPin jointWithBodyA:leftSpring.bodyA
bodyB:leftSpring.bodyB
anchor:leftWheel.position];


[self.physicsWorld addJoint:leftSlide];
[self.physicsWorld addJoint:leftSpring];
[self.physicsWorld addJoint:leftPin];

[self.physicsWorld addJoint:[SKPhysicsJointPin jointWithBodyA:carBody.physicsBody bodyB:rightWheel.physicsBody anchor:rightWheel.position]];


}

Answer

Editing my answer. The suspension requires the wheels to be attached to a sliding body versus attaching the wheels via the slide joint. Doing the former allows wheels to rotate. The latter does not.

Vehicle.m

#import "Vehicle.h"

@implementation Vehicle

- (SKSpriteNode*) makeWheel
{
    SKSpriteNode *wheel = [SKSpriteNode spriteNodeWithImageNamed:@"wheel.png"];
//    wheel.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:wheel.size.width/2];
    return wheel;
}

-(id)initWithPosition:(CGPoint)pos {

    if (self = [super init]) {

        _joints = [NSMutableArray array];

        int wheelOffsetY    =   60;
        CGFloat damping     =   1;
        CGFloat frequency   =   4;

        SKSpriteNode *chassis = [SKSpriteNode spriteNodeWithColor:[UIColor whiteColor] size:CGSizeMake(120, 8)];
        chassis.position = pos;
        chassis.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:chassis.size];
        [self addChild:chassis];

        _ctop = [SKSpriteNode spriteNodeWithColor:[UIColor greenColor] size:CGSizeMake(70, 16)];
        _ctop.position = CGPointMake(chassis.position.x+20, chassis.position.y+12);
        _ctop.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:_ctop.size];
        [self addChild:_ctop];

        SKPhysicsJointFixed *cJoint = [SKPhysicsJointFixed jointWithBodyA:chassis.physicsBody
                                                                    bodyB:_ctop.physicsBody
                                                                   anchor:CGPointMake(_ctop.position.x, _ctop.position.y)];


        _leftWheel = [self makeWheel];
        _leftWheel.position = CGPointMake(chassis.position.x - chassis.size.width / 2, chassis.position.y - wheelOffsetY);  //Always set position before physicsBody
        _leftWheel.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:_leftWheel.size.width/2];
        _leftWheel.physicsBody.allowsRotation = YES;
        [self addChild:_leftWheel];

        SKSpriteNode *rightWheel = [self makeWheel];
        rightWheel.position = CGPointMake(chassis.position.x + chassis.size.width / 2, chassis.position.y - wheelOffsetY);
        rightWheel.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:rightWheel.size.width/2];
        rightWheel.physicsBody.allowsRotation = YES;
        [self addChild:rightWheel];

//------------- LEFT SUSPENSION ----------------------------------------------------------------------------------------------- //

        SKSpriteNode *leftShockPost = [SKSpriteNode spriteNodeWithColor:[UIColor blueColor] size:CGSizeMake(7, wheelOffsetY)];
        leftShockPost.position = CGPointMake(chassis.position.x - chassis.size.width / 2, chassis.position.y - leftShockPost.size.height/2);
        leftShockPost.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:leftShockPost.size];
        [self addChild:leftShockPost];

       SKPhysicsJointSliding  *leftSlide = [SKPhysicsJointSliding jointWithBodyA:chassis.physicsBody
                                                                           bodyB:leftShockPost.physicsBody
                                                    anchor:CGPointMake(leftShockPost.position.x, leftShockPost.position.y)
                                                      axis:CGVectorMake(0, 1)];

        leftSlide.shouldEnableLimits = TRUE;
        leftSlide.lowerDistanceLimit = 5;
        leftSlide.upperDistanceLimit = wheelOffsetY;


        SKPhysicsJointSpring *leftSpring = [SKPhysicsJointSpring jointWithBodyA:chassis.physicsBody bodyB:_leftWheel.physicsBody
                                                                        anchorA:CGPointMake(chassis.position.x - chassis.size.width / 2, chassis.position.y)
                                                                        anchorB:_leftWheel.position];
        leftSpring.damping = damping;
        leftSpring.frequency = frequency;

        SKPhysicsJointPin *lPin = [SKPhysicsJointPin jointWithBodyA:leftShockPost.physicsBody bodyB:_leftWheel.physicsBody anchor:_leftWheel.position];


//------------- RIGHT SUSPENSION ----------------------------------------------------------------------------------------------- //

        SKSpriteNode *rightShockPost = [SKSpriteNode spriteNodeWithColor:[UIColor blueColor] size:CGSizeMake(7, wheelOffsetY)];
        rightShockPost.position = CGPointMake(chassis.position.x + chassis.size.width / 2, chassis.position.y - rightShockPost.size.height/2);
        rightShockPost.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:rightShockPost.size];
        [self addChild:rightShockPost];

        SKPhysicsJointSliding  *rightSlide = [SKPhysicsJointSliding jointWithBodyA:chassis.physicsBody
                                                                            bodyB:rightShockPost.physicsBody
                                                                           anchor:CGPointMake(rightShockPost.position.x, rightShockPost.position.y)
                                                                             axis:CGVectorMake(0, 1)];

        rightSlide.shouldEnableLimits = TRUE;
        rightSlide.lowerDistanceLimit = 5;
        rightSlide.upperDistanceLimit = wheelOffsetY;


        SKPhysicsJointSpring *rightSpring = [SKPhysicsJointSpring jointWithBodyA:chassis.physicsBody bodyB:rightWheel.physicsBody
                                                                        anchorA:CGPointMake(chassis.position.x + chassis.size.width / 2, chassis.position.y)
                                                                        anchorB:rightWheel.position];
        rightSpring.damping = damping;
        rightSpring.frequency = frequency;

        SKPhysicsJointPin *rPin = [SKPhysicsJointPin jointWithBodyA:rightShockPost.physicsBody bodyB:rightWheel.physicsBody anchor:rightWheel.position];


        // Add all joints to the array.

        [_joints addObject:cJoint];

        [_joints addObject:leftSlide];
        [_joints addObject:leftSpring];
        [_joints addObject:lPin];

        [_joints addObject:rightSlide];
        [_joints addObject:rightSpring];
        [_joints addObject:rPin];

    }

    return self;
}


@end
Comments