0

私は、Swift と SceneKit を使用して次の設定で構築されたトップダウンの宇宙ゲームに取り組んでいます。

宇宙船を表す SCNNode

  • 回転は y 軸に制限されます。値の範囲は-M_PI_2M_PI + M_PI_2
  • 移動は x 軸と z 軸に制限されます。

ゲームコントローラーのサムスティック入力

  • 値の範囲は-1.01.0x 軸と y 軸で ~ です。

ゲーム コントローラーのサムスティックの位置が変わると、物理ボディを使用して宇宙船が回転し、サムスティックのラジアンに一致する必要があります。

サムスティックのターゲット ラジアンは、次のように計算できます。

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

ノードの現在のラジアンは、次のように取得できます。

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

NSTimeInterval deltaTime最後の回転計算からの時間を秒単位で提供します。

angularVelocityapplyTorque、または別の物理メソッドを使用してノードを回転させ、 に到達するにはどうすればよいtargetRadianですか?

4

1 に答える 1

0

と の差はの値に応じてから までtargetRadiancurrentRadian範囲でした。この方程式は、 に到達するための最短方向、またはを決定します。0.0-2πcurrentRadian.Clockwise.CounterClockwisetargetRadian

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

を使用すると、回転が に到達するために方向を前後に変更するため、ある点に向かって磁化するコンパスのように、ぐらつき効果が生じるapplyTorque可能性があります。以下は、完全な解決策ではありませんが、効果を弱めました。targetRadiantargetRadian

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)
}
于 2016-02-02T07:32:34.670 に答える