Simulate universal gravitation for two Sprite Kit

2019-01-11 08:17发布

I have two nodes in Sprite Kit, and I'm writing in Swift.

How would I make the nodes attracted to each other by the force of gravity? Also, how would I use their masses? If an object has a big mass, it should gravitate more.

1条回答
甜甜的少女心
2楼-- · 2019-01-11 09:14

You can loop through all nodes and calculate the impulse to all other nodes using the appropriate ratios of the universal gravitation equation. I just wrote a quick example showing how this is done. You can make your own custom "mass" factor, however I'm simply using Sprite Kit's. I also added a strength factor to amplify the impulse. I'm also assuming fixed time step of 1/60 seconds.

class GameScene: SKScene {
    var nodes: [SKShapeNode] = []
    let dt: CGFloat = 1.0/60.0 //Delta time.
    let radiusLowerBound: CGFloat = 1.0 //Minimum radius between nodes check.
    let strength: CGFloat = 10000 //Make gravity less weak and more fun!
    override func didMoveToView(view: SKView) {
        self.physicsWorld.gravity = CGVector()
        for i in 1 ... 50 { //Create 50 random nodes.
            let rndRadius = 15 + CGFloat(arc4random_uniform(20))
            let rndPosition = CGPoint(x: CGFloat(arc4random_uniform(UInt32(self.size.width))), y: CGFloat(arc4random_uniform(UInt32(self.size.height))))
            let node = SKShapeNode(circleOfRadius: rndRadius)
            node.position = rndPosition
            node.physicsBody = SKPhysicsBody(circleOfRadius: rndRadius)
            self.addChild(node)
            nodes.append(node)
        }
    }
    override func update(currentTime: NSTimeInterval) {
        for node1 in nodes {
            for node2 in nodes {
                let m1 = node1.physicsBody!.mass*strength
                let m2 = node2.physicsBody!.mass*strength
                let disp = CGVector(dx: node2.position.x-node1.position.x, dy: node2.position.y-node1.position.y)
                let radius = sqrt(disp.dx*disp.dx+disp.dy*disp.dy)
                if radius < radiusLowerBound { //Radius lower-bound.
                    continue
                }
                let force = (m1*m2)/(radius*radius);
                let normal = CGVector(dx: disp.dx/radius, dy: disp.dy/radius)
                let impulse = CGVector(dx: normal.dx*force*dt, dy: normal.dy*force*dt)

                node1.physicsBody!.velocity = CGVector(dx: node1.physicsBody!.velocity.dx + impulse.dx, dy: node1.physicsBody!.velocity.dy + impulse.dy)
            }
        }
    }
}

enter image description here

Instead of performing the calculation manually you could also add field nodes to your physics bodies to simulate the effect. Although be warned, field nodes are broken in certain versions of Sprite Kit.

查看更多
登录 后发表回答