Search code examples
iosswiftgame-physicsscenekit

Gravity field doesn't work, objects float in the vacuum


I'm trying to simulate gravity in a world where there are 5 balls over a plane. The first problem that I've encountered is that the balls pass through the floor is they have a dynamic body. But if I use a kinematic body they're not affected by forces. So I had to use a dynamic body, disable gravity and use a gravity field instead. The scene is loaded from a COLLADA file. This is how I setup things:

self.scene = SCNScene(named: "art.scnassets/Balls.dae")!

for i in 1...5 {
    let sphere = scene.rootNode.childNode(withName: "Sphere\(i)", recursively: true)!
    let shape = SCNPhysicsShape(geometry: sphere.geometry!, options: nil)
    let body = SCNPhysicsBody(type: .dynamic, shape: shape)
    body.mass = 0.2
    body.isAffectedByGravity = false
    body.categoryBitMask = BallCategory
    body.collisionBitMask = PlaneCategory | BallCategory | GravityFieldCategory
    sphere.physicsBody = body

    balls.append(sphere)
}

self.plane = self.scene.rootNode.childNode(withName: "Plane", recursively: true)
let shape = SCNPhysicsShape(geometry: self.plane.geometry!, options: nil)
let body = SCNPhysicsBody(type: .static, shape: shape)
body.categoryBitMask = PlaneCategory
body.collisionBitMask = BallCategory
self.plane.physicsBody = body

// Create a gravity field
let gravityField = SCNPhysicsField.linearGravity()
gravityField.categoryBitMask = GravityFieldCategory
gravityField.direction = SCNVector3Make(0.0, -1.0, 0.0)
gravityField.isActive = true
gravityField.strength = 3.0
let gravityNode = SCNNode()
gravityNode.physicsField = gravityField
self.scene.rootNode.addChildNode(gravityNode)

Then when the user touches the screen, a random ball is moved upwards and it should fall down:

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    let index = Int(arc4random_uniform(5))
    let ball = self.ball(atIndex: index)

    let moveUp = SCNAction.move(by: SCNVector3Make(0.0, 2.0, 0.0), duration: 1.5)
    ball.runAction(moveUp)
}

But instead of falling down it just stop there, floating in the vacuum. The gravity field doesn't work. This is what happens: https://youtu.be/egMe4lgPZY0


Solution

  • It seems like the shape of the plane is incorrect. I tried to create the physics body of the plane by just passing nil as shape argument:

     
        self.plane = self.scene.rootNode.childNode(withName: "Plane", recursively: true) 
         let shape = SCNPhysicsShape(geometry: self.plane.geometry!, options: nil)  
        let body = SCNPhysicsBody(type: .static, shape: nil)
        body.categoryBitMask = PlaneCategory
        body.collisionBitMask = BallCategory
        self.plane.physicsBody = body
     

    And I removed the gravity field and turned on the isAffectedbyGravity property of the balls. It works now.