2016-01-29 56 views
0

我工作的一個自上而下的空間遊戲用斯威夫特和SceneKit建有以下設置:使用PhysicsBody旋轉的SCNNode匹配搖桿的弧度

SCNNode代表飛船

  • 旋轉被限制在y軸上;值範圍從-M_PI_2M_PI + M_PI_2
  • 運動被限制在x和z軸上。

遊戲控制器拇指操縱桿輸入

  • 值的範圍從-1.01.0在x軸和y軸。

當遊戲控制器的拇指棒改變位置時,宇宙飛船應該使用物理體旋轉以匹配拇指指杆的弧度。

所述搖桿的目標弧度可以與計算以下:

let targetRadian = M_PI_2 + atan2(-y, -x) 

所述節點的當前弧度可以得到以下:

let currentRadian = node.presentationNode.rotation.w * node.presentationNode.rotation.y 

NSTimeInterval deltaTime提供時間,以秒自上次旋轉計算以來。

節點如何使用angularVelocity,applyTorque或其他物理方法旋轉到達targetRadian

回答

0

targetRadiancurrentRadian之間的差異範圍從0.0-2π,具體取決於currentRadian的值。這個方程將決定的最短的方向上轉動,.Clockwise.CounterClockwise,到達targetRadian

let turnDirection = (radianDifference + (M_PI * 2)) % (M_PI * 2) < M_PI ? RotationDirection.CounterClockwise : RotationDirection.Clockwise 

使用applyTorque,存在這樣的可能性過度旋轉經過targetRadian導致擺動的影響,像一個羅盤磁化朝向一個點,因爲旋轉來回地改變方向以達到targetRadian。下面,而不是一個完美的解決方案,挫傷了效果:

let turnDampener = abs(radianDifference) < 1.0 ? abs(radianDifference) : 1.0 

完整的解決方案是這樣的:

enum RotationDirection: Double { 
    case Clockwise = -1.0 
    case CounterClockwise = 1.0 
} 

func rotateNodeTowardDirectionalVector(node: SCNNode, targetDirectionalVector: (x: Double, y: Double), deltaTime: NSTimeInterval) { 
    guard abs(targetDirectionalVector.x) > 0.0 || abs(targetDirectionalVector.y) > 0.0 else { return } 

    let currentRadian = Double(node.presentationNode.rotation.w * node.presentationNode.rotation.y) 
    let targetRadian = M_PI_2 + atan2(-targetDirectionalVector.y, -targetDirectionalVector.x) 

    let radianDifference = targetRadian - currentRadian 

    let π2 = M_PI * 2 
    let turnDirection = (radianDifference + π2) % π2 < M_PI ? RotationDirection.CounterClockwise : RotationDirection.Clockwise 

    let absRadianDifference = abs(radianDifference) 
    let turnDampener = absRadianDifference < 1.0 ? absRadianDifference : 1.0 

    node.physicsBody?.applyTorque(SCNVector4Make(0, CGFloat(turnDirection.rawValue), 0, CGFloat(deltaTime * turnDampener)), impulse: true) 
}