Search code examples
sprite-kitskphysicsjoint

Problems with spring going Sprite Kit (It acts like a stick)


So I have a bit of a simple goal. I am just trying to have two skspritenodes go towards eachother, as if attached by an elastic band. I figured that a SKSpringJoint would be perfect for this since the documentation says that it has similar properties, however this isn't working out too well for me!

I am able to make the contact between the two sprite, however no "spring like" things are happening, instead they stay the same distance apart the whole time as if it is a stick connecting them together, not something that can expand and contract.

Could you please look at my code and tell me what I am doing wrong? The simulation is simple, 2 balls and some walls. When the screen is tapped the connection between the two balls gets established.

import SpriteKit

class GameScene: SKScene {
    var it1 = SKSpriteNode()
    var it2 = SKSpriteNode()
    override func didMoveToView(view: SKView) {
        /* Setup your scene here */
        it1 = SKSpriteNode(texture: SKTexture(imageNamed: "Spaceship"))
        it1.position.x = self.frame.size.width / 2
        it1.position.y = self.frame.size.height / 2
        it1.size.width = self.frame.size.height / 10
        it1.size.height = self.frame.size.height / 10

        it1.physicsBody = SKPhysicsBody(circleOfRadius: it1.size.width / 2)


        it2 = SKSpriteNode(texture: SKTexture(imageNamed: "Spaceship"))
        it2.position.x = self.frame.size.width / 2 + 2
        it2.position.y = self.frame.size.height
        it2.size.width = self.frame.size.height / 10
        it2.size.height = self.frame.size.height / 10

        it2.physicsBody = SKPhysicsBody(circleOfRadius: it2.size.width / 2)

        self.addChild(it1)
        self.addChild(it2)

        var ground = SKNode() // just an object
        ground.position = CGPointMake(0, 0) //borrom left
        ground.physicsBody = SKPhysicsBody(rectangleOfSize: CGSizeMake(self.frame.size.width * 2, 1))
        ground.physicsBody!.dynamic = false
        self.addChild(ground)

        var ground2 = SKNode() // just an object
        ground2.position = CGPointMake(0, 0) //borrom left
        ground2.physicsBody = SKPhysicsBody(rectangleOfSize: CGSizeMake(1, self.frame.size.height * 2))
        ground2.physicsBody!.dynamic = false
        self.addChild(ground2)

        var ground3 = SKNode() // just an object
        ground3.position = CGPointMake(self.frame.size.width, 0) //borrom left
        ground3.physicsBody = SKPhysicsBody(rectangleOfSize: CGSizeMake(1, self.frame.size.height * 2))
        ground3.physicsBody!.dynamic = false
        self.addChild(ground3)

    }
    var it = SKPhysicsJointSpring()
    override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
        /* Called when a touch begins */

        var poso = CGPointMake(0, 0)
        var posm = CGPointMake(0.5, 0.5)
        var p1s = it1.position
        var p2s = it2.position
        var p1 = p1s
        var p2 = p2s
        it = SKPhysicsJointSpring.jointWithBodyA(it1.physicsBody, bodyB: it2.physicsBody, anchorA: p1, anchorB: p2)
        //it.frequency = 2349.0
        //it.damping = 0.0
        self.physicsWorld.addJoint(it)
        //Make the tether
    }

}

If you have any ideas please let me know!

Sep, 17: I just tried apply a physics impulse to one of the balls in the simulation. Still no luck. The two balls simply seem to be attached together with a stick, no spring action :(

Just wanted to post my final code for those of you that want a similar effect some day, or just a good example of how to use SpringJoints. It is basically a 2d Spiderman simulation. The code is pretty reusable, all you need to do is put the draw function in the update loop, and the functions in the project and then simply call the function passing a sprinted, and point. Enjoy!

import SpriteKit

class GameScene: SKScene {
    var it1 = SKSpriteNode()
    var it2 = SKSpriteNode()
    override func didMoveToView(view: SKView) {
        /* Setup your scene here */
        it1 = SKSpriteNode(texture: SKTexture(imageNamed: "Spaceship"))
        it1.position.x = 0

        it1.size.width = self.frame.size.height / 10
        it1.size.height = self.frame.size.height / 10
        it1.position.y = 0 + (it1.size.width / 2)

        it1.physicsBody = SKPhysicsBody(circleOfRadius: it1.size.width / 2)



        it2 = SKSpriteNode(texture: SKTexture(imageNamed: "Spaceship"))
        it2.position.x = self.frame.size.width / 2 + 2
        it2.position.y = self.frame.size.height
        it2.size.width = self.frame.size.height / 10
        it2.size.height = self.frame.size.height / 10
        it2.position.y = 0 + (it1.size.width / 2)

        it2.physicsBody = SKPhysicsBody(circleOfRadius: it2.size.width / 2)
        it2.physicsBody?.dynamic = false

        self.addChild(it1)
        //self.addChild(it2)

        let ground = SKNode() // just an object
        ground.position = CGPointMake(0, 0) //borrom left
        ground.physicsBody = SKPhysicsBody(rectangleOfSize: CGSizeMake(self.frame.size.width * 2, 1))
        ground.physicsBody!.dynamic = false
        self.addChild(ground)

        let ground2 = SKNode() // just an object
        ground2.position = CGPointMake(0, 0) //borrom left
        ground2.physicsBody = SKPhysicsBody(rectangleOfSize: CGSizeMake(1, self.frame.size.height * 2))
        ground2.physicsBody!.dynamic = false
        self.addChild(ground2)

        let ground3 = SKNode() // just an object
        ground3.position = CGPointMake(self.frame.size.width, 0) //borrom left
        ground3.physicsBody = SKPhysicsBody(rectangleOfSize: CGSizeMake(1, self.frame.size.height * 2))
        ground3.physicsBody!.dynamic = false
        self.addChild(ground3)

        self.physicsWorld.gravity = CGVectorMake(-1, self.physicsWorld.gravity.dy)

        //drawmeclose(it1, point: it2.position)


    }
    var it = SKPhysicsJointSpring()
    override  func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {


       // it1.physicsBody?.applyImpulse(CGVectorMake(0, -200))

        for touch in (touches )
        {
            let location:CGPoint = touch.locationInNode(self)
            if (havespring == false)
            {
                //drawmeclose(it1, point: it2.position)
                drawmeclose(it1, point: location)
            }
            else
            {
                undrawme()
            }
        }





    }
    var sd  = false
    override func update(currentTime: NSTimeInterval) {


        drawtether()
    }

    var sp = CGPointMake(0, 0)
    var spring = SKPhysicsJointSpring()
    var string = SKShapeNode()
    var havespring = false
    var haveline = false
    var bA = SKSpriteNode()
    func drawmeclose(bodyA: SKSpriteNode, point: CGPoint)
    {
        sp = bodyA.position

        let tetherp = SKSpriteNode()
        tetherp.position = point
        tetherp.physicsBody = SKPhysicsBody()
        tetherp.physicsBody?.dynamic = false
        self.addChild(tetherp)

        bodyA.position = tetherp.position

        spring = SKPhysicsJointSpring.jointWithBodyA(bodyA.physicsBody!, bodyB: tetherp.physicsBody!, anchorA: bodyA.position, anchorB: tetherp.position)
        spring.frequency = 0.8
        spring.damping = 0.5
        self.physicsWorld.addJoint(spring)

        bodyA.position = sp
        havespring = true

        bA = bodyA

        sp = point


    }
    func drawtether()
    {
        if (haveline == true)
        {
            string.removeFromParent()
            haveline = false
        }

        if (havespring == true)
        {
            let path = CGPathCreateMutable()
            CGPathMoveToPoint(path, nil, bA.position.x, bA.position.y)
            CGPathAddLineToPoint(path, nil, sp.x, sp.y)
            CGPathCloseSubpath(path);
            string = SKShapeNode(path: path )
            self.addChild(string)
            haveline = true
        }
    }
    func undrawme()
    {
        self.physicsWorld.removeJoint(spring)
        havespring = false
    }

}

Solution

  • Try this out:

    it.frequency = 1.0
    it.damping = 0.0
    self.physicsWorld.addJoint(it)
    

    Your frequency I think is way too high to see anything, and the default value is 0.0.