I have a SCNSphere that is climbing a 45 degree hill.
The node maintains a consistent speed until the same point at every level, at which point it unexpectedly drops in speed, here is a 10 second clip of the issue.
The drop in speed occurs at 8 seconds in this clip.
When the node reaches a z position of -240, it seems as though the entire game speed is cut in half.
I have tested this in the following ways always without success.
- Tried testing without gravity.
- Tried testing without colliding with the hill.
- Tried testing without damping or friction.
- Tried printing the nodes velocity to notice any changes, although the velocity remains at -5.0 on the z axis for the duration of the level despite the significant drop in speed.
- Tried printing the physicsWorld speed to notice any changes, although the speed remains at 1.0 for the duration of the level despite the significant drop in speed.
- Checked for a drop in frame rate although it maintains a frame rate of 60 fps, making only 14 draw calls in total with a poly count under 15k.
The sphere's velocity is updated at every frame in the renderer using the following function.
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()
}
This project is a fresh one, and so there aren't many lines, I will include the entire code base below.
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()
}
}