Search code examples
swiftsprite-kitskphysicsbodyskphysicsjointskphysicscontact

SKPhysicsJointFixed in SpriteKit and Swift


I'm making a game in Sprite Kit and Swift and I have a Sprite at the bottom of the screen and falling Sprites from the top which I want to catch and stick to the Sprite at the bottom, so I'm trying to use SKPhysicsJointFixed but when the objects collide instead of the falling object sticking to the one at the bottom which is supposed to catch and have it attached, it seems as if the bottom Sprite adapts the physics of the falling sprite and then falls off the screen with it. Here's the code I have in my didBeginContact method. and skewer is the name of the Sprite at the bottom which should always be at the bottom and not disappear.

    if contact.bodyA.node!.name == "Skewer"
    {
        let boundX = skewer.physicsBody?.node?.position.x
        let fixedJoint = SKPhysicsJointFixed.jointWithBodyA(contact.bodyA.node!.physicsBody, bodyB: contact.bodyB.node!.physicsBody, anchor: CGPoint(x: boundX!, y: boundY))
        physicsWorld.addJoint(fixedJoint)

        //            contact.bodyB.node!.removeFromParent()
    }
    else
    {
        contact.bodyA!.node!.removeFromParent()
    }

and the physics for the bottom screen Sprite are here

func makeSkewer()

{
    skewer.name = "Skewer"

    skewer.position = CGPoint(x: size.width * 0.5, y: size.height * 0.244)

    skewer.physicsBody = SKPhysicsBody(rectangleOfSize: skewer.size)
    skewer.physicsBody?.affectedByGravity = false
    skewer.physicsBody?.categoryBitMask = kSkewerCategory
    skewer.physicsBody?.contactTestBitMask = kFoodCategory
    skewer.physicsBody?.collisionBitMask = kSceneEdgeCategory

    addChild(skewer)
}

and physics for the falling Sprites are here

func random() ->CGFloat
{
    return CGFloat(Float(arc4random()) / 0xFFFFFFFF)
}

func random(#min: CGFloat,max: CGFloat) -> CGFloat
{
    return random() * (max - min) + min
}

func addFood()
{
    let randomCatchIndex = Int(arc4random_uniform(UInt32(foods.count)))
    let food = SKSpriteNode(imageNamed: foods[randomCatchIndex])
    let actualX = random(min: food.size.width/2, max: size.width - food.size.width/2)
    let actualDuration = random(min: CGFloat(1.5), max: CGFloat(8.0))
    let actionMove = SKAction.moveTo(CGPoint(x: actualX, y: -food.size.height/2), duration: NSTimeInterval(actualDuration))
    let actionMoveDone = SKAction.removeFromParent()


    food.physicsBody = SKPhysicsBody(rectangleOfSize: food.size)
    food.position = CGPoint(x: actualX, y: size.height + food.size.height/2)

    food.physicsBody?.categoryBitMask = kFoodCategory
    food.physicsBody?.contactTestBitMask = kSkewerCategory
    food.physicsBody?.collisionBitMask = 0x0
    food.physicsBody?.dynamic = true
    food.runAction(SKAction.sequence([actionMove, actionMoveDone]))

    addChild(food)

}

Solution

  • Set the skewer to not have dynamic physics. What you have currently is it not being affected by gravity, and as soon as it locks onto the food (which is traveling down and has momentum), the skewer moves with it.

    In the creation of the skewer, run the following line:

    skewer.physicsBody?.dynamic = false
    

    You can also now ignore the affectedByGravity as that is something that only affects dynamic objects.