尽管速度保持恒定,是什么导致节点变慢?

时间:2019-02-17 17:38:03

标签: ios swift scenekit

我有一个SCNSphere,它正在爬45度的山丘。

节点保持一致的速度,直到每个级别上的相同点为止,这时它的速度意外下降,这是问题的10秒片段。

this clip中,速度下降发生在8秒。

当节点到达-240的z位置时,似乎整个游戏速度降低了一半。

我已经通过以下方式对此进行了测试,但始终没有成功。

  • 在没有重力的情况下进行了测试。
  • 尝试过测试而不会与山碰撞。
  • 尝试过测试,没有阻尼或摩擦。
  • 尝试打印节点速度以注意到任何变化,尽管在z轴持续时间内速度在z轴上保持为-5.0。 速度显着下降。
  • 尝试打印physicsWorld速度以注意到任何变化,尽管在整个过程中速度保持在1.0 速度显着下降。
  • 尽管帧速率保持60 fps,但检查了帧速率是否下降,总共进行了14次描图调用,多边形计数低于15k。

使用以下函数在渲染器的每一帧更新球的速度。

func updatePositions() {

        if let playerPhysicsBod = playerNode.physicsBody {
            playerPhysicsBod.velocity.x = (lastXPosition - playerNode.position.x) * 8
            playerPhysicsBod.velocity.z = -5
            print("player velocity is \(playerNode.physicsBody!.velocity)")
        }
    }

func renderer(_ renderer: SCNSceneRenderer, updateAtTime time: TimeInterval) {
        updatePositions()
        updateSegments()
    }

这个项目是一个新鲜的项目,因此没有多少行,我将在下面包括整个代码库。

class GameViewController: UIViewController {


    let scene = SCNScene(named: "art.scnassets/gameScene.scn")!
    let jump = SCNScene(named: "art.scnassets/jump.scn")!.rootNode.childNode(withName: "jump", recursively: true)!
    let box = SCNScene(named: "art.scnassets/box.scn")!.rootNode.childNode(withName: "box", recursively: true)!
    var playerNode = SCNNode()
    var cameraNode = SCNNode()
    var lastXPosition = Float()
    var floorSegments = [SCNNode]()


    override func viewDidLoad() {
        super.viewDidLoad()

        // retrieve the SCNView
        let scnView = self.view as! SCNView
//        scnView.isJitteringEnabled = true
        scnView.scene = scene
        scnView.delegate = self
        scnView.showsStatistics = true

        setupCamera()
        setupPlayer()
        setupSegments()
    }

    override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {

        guard let tLocationX = touches.first?.location(in: self.view).x else { return }
        let ratio = tLocationX / self.view.frame.maxX
        lastXPosition = Float((5 * ratio) - 2.5)

    }

    func setupCamera() {
        if let camera = scene.rootNode.childNode(withName: "camera", recursively: true) {
            cameraNode = camera
            cameraNode.name = "camera"
        }
    }

    func setupPlayer() {
        if let player = scene.rootNode.childNode(withName: "player", recursively: true) {
            playerNode = player
            playerNode.name = "player"
        }
    }

    func setupSegments() {
        if let segment = scene.rootNode.childNode(withName: "segment", recursively: true) {
            floorSegments.append(segment)
        }
    }




}

extension GameViewController: SCNSceneRendererDelegate {


    func updateSegments() {

        playerNode.position = playerNode.presentation.position
        if let lastSegmentClone = floorSegments.last?.clone() {

            lastSegmentClone.childNodes.forEach { (node) in
                node.removeFromParentNode()
            }


            if abs(playerNode.position.z - lastSegmentClone.position.z) < 30 {
                // set up next segment
                lastSegmentClone.position = SCNVector3(lastSegmentClone.position.x, lastSegmentClone.position.y + 4, lastSegmentClone.position.z - 4)
                floorSegments.append(lastSegmentClone)


                // Add falling blocks to the segment
                for _ in 0...2 {

                    let boxClone = box.clone()
                    let randomX = Int.random(in: -2...2)
                    let randomY = Int.random(in: 1...3)
                    boxClone.eulerAngles.z = Float(GLKMathDegreesToRadians(-45))
                    boxClone.position = SCNVector3(randomX, randomY, -randomY)
                    lastSegmentClone.addChildNode(boxClone)

                }

                // Add falling blocks to the segment
                for (index,segment) in floorSegments.enumerated().reversed() {
                    if segment.position.z > playerNode.position.z + 5 {
                        floorSegments.remove(at: index)
                        segment.childNodes.forEach { (node) in
                            node.removeFromParentNode()
                        }
                        segment.removeFromParentNode()
                    }
                }

                scene.rootNode.addChildNode(lastSegmentClone)
            }
        }
    }

    func updatePositions() {

        if let playerPhysicsBod = playerNode.physicsBody {
            playerPhysicsBod.velocity.x = (lastXPosition - playerNode.position.x) * 8
            playerPhysicsBod.velocity.z = -5
            print("player velocity is \(playerNode.physicsBody!.velocity)")
        }
    }

    func renderer(_ renderer: SCNSceneRenderer, updateAtTime time: TimeInterval) {
        updatePositions()
        updateSegments()
    }

}

1 个答案:

答案 0 :(得分:1)

很难判断没有看到scn文件。

我希望播放器和地板节点之间没有冲突...

Player的Position是一个浮点数,对于相等性可能是不精确的比较。我认为您应该避免调整球员的位置,因为它应该几乎相同:

playerNode.position = playerNode.presentation.position

为什么不在空的细分节点上保持引用?

在方法setupSegments中克隆该段,并在删除子节点之后将其保留。总是删除子节点毫无意义:

 lastSegmentClone.childNodes.forEach { (node) in
            node.removeFromParentNode()
        }

另外,我认为您应该在updateSegments中“反转”顺序:

if let lastSegment = floorSegments.last { // no cloning here....

            if abs(playerNode.position.z - lastSegment.position.z) < 30 {

               let lastSegmentClone = lastSegment.clone() // better to use emptySegmentNode

                 /* If empty segment then it's not needed to remove children nodes...
                  lastSegmentClone.childNodes.forEach { (node) in
                   node.removeFromParentNode() */

如果要删除父节点,子节点也将自动删除。...

// Avoid commented code
/*segment.childNodes.forEach { (node) in
                            node.removeFromParentNode()
                        }*/
                        segment.removeFromParentNode()

不确定,但是对于地板部分来说,最好使用自定义操作进行删除:

// calculate somehow wait duration, based on the player's position, velocity or use pure constant..
   let removeAction = SCNAction.sequence([SCNAction.waitForDuration(2.0), SCNAction.removeFromParent()])

   lastSegmentClone.run(removeAction)

在这种情况下,您只需要在最后一个楼层节点上引用一个空楼层节点即可。