如何按度旋转和锁定 SCNNode 的旋转?

How to rotate and lock the rotation of a SCNNode by degrees?

我需要将一个可以自由旋转的模型旋转到精确的度数,而不管它旋转了多少次。

我有一个 UIPanGestureRecognizer,它可以绕 Y 轴自由旋转 3D 模型。然而,当平移停止时,我正在努力让它锁定到整数度,并且我正在努力能够知道它在 0-359 之间的度数旋转。

let translation = recognizer.translation(in: self.view)

var newAngleY = Double(translation.x) * (Double.pi) / 180.0
newAngleY += self.currentAngle

self.shipNode?.eulerAngles.y = Float(newAngleY)

if (recognizer.state == .ended)
{
   self.currentAngle = newAngleY
}

它可以自由旋转,但所有尝试锁定到最接近的精确度数,并且能够'know'它的旋转度数在 0-359 之间。

我知道:

let degrees = newAngleY * ( 180 / Double.pi)

而且我知道如果度数 > 360 那么 -= 360(伪代码)

然而,虽然 UIPanGestureRecognizer 正在做它的事情,但这些检查似乎失败了,我不知道为什么。是不是因为还在平移的时候不能编辑ViewController的私有属性?

您可以在手势发生时编辑值。

有很多选择,所以这似乎是最简单的开始:

您可以尝试仅在状态发生变化且仅在 .x > .x *(某个值,例如 1.1)时应用欧拉。这将提供更多 "snap to" 种方法,例如:

 var currentLocation = CGPoint.zero
 var beginLocation = CGPoint.zero

 @objc func handlePan(recognizer: UIPanGestureRecognizer) {
    currentLocation = recognizer.location(in: gameScene)

    var newAngleY = Double(translation.x) * (Double.pi) / 180.0
    newAngleY += self.currentAngle

    switch recognizer.state
    {
     case UIGestureRecognizer.State.began: break
     case UIGestureRecognizer.State.changed:
         if(currentLocation.x > beginLocation.x * 1.1)
         {
           gNodes.bnode.eulerAngles.y = Float(newAngleY)
           beginLocation.x = currentLocation.x
         }
         if(currentLocation.x < beginLocation.x * 0.9) { .etc. }
         break
         case UIGestureRecognizer.State.ended:
           gNodes.bnode.eulerAngles.y = Float(newAngleY)
           break
    }
}

然后您可以切换到 SCNAction(更改您的数学)以提供更多控制,例如

let vAction = SCNAction.rotateTo(x: 0, y: vAmount, z: 0, duration: 0)
bnode.runAction(vAction)