我有一个SCNSphere,它正在爬45度的山丘。
节点保持一致的速度,直到每个级别上的相同点为止,这时它的速度意外下降,这是问题的10秒片段。
在this clip中,速度下降发生在8秒。
当节点到达-240的z位置时,似乎整个游戏速度降低了一半。
我已经通过以下方式对此进行了测试,但始终没有成功。
使用以下函数在渲染器的每一帧更新球的速度。
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()
}
}
答案 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)
在这种情况下,您只需要在最后一个楼层节点上引用一个空楼层节点即可。