且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

模拟两个 Sprite Kit 节点的万有引力

更新时间:2023-02-01 20:00:14

您可以循环遍历所有节点,并使用万有引力方程的适当比率计算对所有其他节点的冲量.我刚刚写了一个简单的例子来展示这是如何完成的.您可以制作自己的自定义质量"因子,但我只是使用 Sprite Kit 的.我还添加了一个强度因子来放大冲动.我还假设固定时间步长为 1/60 秒.

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)
            }
        }
    }
}

除了手动执行计算,您还可以添加 场节点 到您的物理实体以模拟效果.尽管受到警告,但在某些 Sprite Kit 版本中,字段节点损坏.

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.