如何将物体旋转限制在特定角度范围内?

4
我有一个方向盘,由物理的 daydream 控制器控制(它的工作方式类似于 Wii 控制器)。我使用以下代码来实现它:
void Update() {
    transform.localRotation = GvrController.Orientation;
    transform.localRotation = new Quaternion(0.0f, 0.0f, -transform.localRotation.y, transform.localRotation.w);
}

我需要调整轴,因为控制器的默认位置对于方向盘不是很好。
但是在三维角度中,最大向左和向右旋转之间的角度范围为180度。在此范围内一切都好,但如果我再多旋转一点,这些值就会变成负数,一切都会混乱。有什么办法让玩家只能在此范围内(3轴旋转的z轴上的0-180)旋转?
编辑:主要问题在于,跨越0或180后旋转的值会变为负值,它们对于两者都相同,但顺序不同。跨越0时为-1到-180,而180时为-180到-1。
4个回答

3

首先,我们需要一个实际可以限制的值。我们将从eulerAngles.z字段获取该值(因为典型的屏幕上的旋转轮围绕z轴旋转 - 根据控制器的不同,您可能需要将其更改为其他字段):

void Update() {

    // Get the angle:
    float angle = GvrController.Orientation.eulerAngles.z;

    // The magic - clamp it:
    if(angle < -180f){
        angle = -180f;
    }
    else if(angle > 180f){
        angle = 180f;
    }

    // Apply it as a new rotation:
    transform.localRotation = Quaternion.Euler(0f,0f,angle);
}

Quaternion.AngleAxis函数需要一个浮点数和一个Vector3作为参数,我应该使用不同的函数吗? - Wojtek Wencel
@faken 编辑:尝试使用 Quaternion.Euler 替代(我必须承认-我自己并不经常使用欧拉方法,但它使其非常容易跟踪) - Luke Briggs
当我使用它时,它变得更加混乱,在“范围”内甚至工作不正常。我认为这是由于将Vector3转换为四元数所致。 - Wojtek Wencel
@faken 你可能需要更改轴的方向(因为这将取决于控制器)。比如,可能使用 eulerAngles.y。在你的问题中,你直接使用四元数的 'y' 分量,这将简而言之给出意想不到的结果。 - Luke Briggs
@faken 好的,我现在明白你的意思了——四元数在使用得当时非常棒。控制器并不知道你是把它倒过来拿着的,它只知道自己的绝对方向。所以你实际上要找的是如何避免当有人把控制器倒过来旋转然后“继续旋转”时造成的非常突然的“颠簸”? - Luke Briggs
我已经想通了并添加了一个答案。 - Wojtek Wencel

2

试试这个:

if (transform.eulerAngles.z > 180)
     transform.eulerAngles = new Vector3(transform.eulerAngles.y, transform.eulerAngles.y, 180);
else if (transform.eulerAngles.z < 0)
     transform.eulerAngles = new Vector3(transform.eulerAngles.y, transform.eulerAngles.y, 0);

这会把一切都搞砸,因为我在编辑中写了些东西 :/ - Wojtek Wencel
我有一个关于代码的小问题。您是通过使用euerAngles.y创建新的z轴旋转,因为Z旋转围绕该轴旋转吗?或者您能否解释一下为什么要使用Y值,而不是例如X和Y,或仅使用Z值? - Pfinnn
这段代码不正常工作,它会弄乱旋转。 - Pfinnn

1
如果有人想知道,我找到了一个解决方案,基于Luke答案中的脚本。我意识到变为负数的值是正确的,唯一不对的是它们是负数。所以这是有效的脚本:
transform.localRotation = GvrController.Orientation;

float angle = -transform.localRotation.y;

if (angle < 0.0f) {
    angle = Mathf.Abs(angle);
}

transform.localRotation = new Quaternion(0.0f, 0.0f, angle, transform.localRotation.w);

1
就算你仍在使用四元数的原始组件,在某些情况下会得到意外的结果。四元数代表一个角度和一些任意轴(例如,有两个解将给出相同的可见旋转,但那个y分量完全不同 - 所以在你的用法中它看起来是错误的)。 - Luke Briggs
我不知道,也许你是对的,但它运行得很好,所以看来我只是幸运。 - Wojtek Wencel

-4

试试这个:

If (transform.rotation > 180)
     transforn.rotation = 180;

1
这个有大约三个问题。首先,我们使用的是 localRotation 而不是 rotation。其次,你正在检查旋转是否为 180 度。什么?你必须检查一个轴。第三,它会变成负数,所以即使正确编写了此检查,该检查也无法解决问题,因为它应该是 if(transform.localRotation.z < 0) - Alfie Goodacre
2
请使用[编辑]链接解释这段代码的工作原理,而不只是给出代码,因为解释更有可能帮助未来的读者。另请参见[回答]。 - Jed Fox

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接