如何约束水平轴旋转?

huangapple go评论94阅读模式
英文:

How do I clamp horizontal axis rotation?

问题

// WallClimbing script
public void OnTriggerEnter(Collider other)
{
    if (col.gameObject.tag == "Wall")
    {
        isClimbingWall = true;
    }
}
// CameraLook script
Vector2 mouseDelta = new Vector2(Input.GetAxis(xAxis), Input.GetAxis(yAxis));

rotation.x += mouseDelta.x * sensitivity;

//Keep rotation in the range 0-360.
if (rotation.x < 0) rotation.x += 360f;
if (rotation.x > 360f) rotation.x -= 360f;

rotation.y += mouseDelta.y * sensitivity;
rotation.y = Mathf.Clamp(rotation.y, -yRotationLimit, yRotationLimit); // vertical clamp

if (wallClimbing.isClimbingWall)
{
    //horizontal clamp
    rotation.x = Mathf.Clamp(rotation.x, -xRotationLimit, xRotationLimit); // xRotLimit 35f
}

var xQuaternion = Quaternion.AngleAxis(rotation.x, Vector3.up);
var yQuaternion = Quaternion.AngleAxis(rotation.y, Vector3.left);

transform.localRotation = yQuaternion; 
player.transform.rotation = xQuaternion;

However what happens is, no matter which angle the wall is positioned, when I enter the trigger my player/camera rotation will "snap" forward.


<details>
<summary>英文:</summary>

I have two scripts for this and how it is supposed to work is, if I enter a trigger, my `isClimbingWall` bool turns true which performs specific movements inside of my WallClimbing script. I also use that bool in my second script CameraLook in order to clamp my x-axis rotation.

// WallClimbing script
public void OnTriggerEnter(Collider other)
{
if (col.gameObject.tag == "Wall")
{
isClimbingWall = true;
}
}

To get the clamp to work, I just add a quick if statement in the middle of my code so that if I am climbing, clamp x-axis rotation but it does not seem to work. I replaced `eulerAngles` with `AngleAxis` but I still get gimbal lock.

// CameraLook script
Vector2 mouseDelta = new Vector2(Input.GetAxis(xAxis), Input.GetAxis(yAxis));

rotation.x += mouseDelta.x * sensitivity;

//Keep rotation in the range 0-360.
if (rotation.x < 0) rotation.x += 360f;
if (rotation.x > 360f) rotation.x -= 360f;

rotation.y += mouseDelta.y * sensitivity;
rotation.y = Mathf.Clamp(rotation.y, -yRotationLimit, yRotationLimit); // vertical clamp

if (wallClimbing.isClimbingWall)
{
//horizontal clamp
rotation.x = Mathf.Clamp(rotation.x, -xRotationLimit, xRotationLimit); // xRotLimit 35f
}

var xQuaternion = Quaternion.AngleAxis(rotation.x, Vector3.up);
var yQuaternion = Quaternion.AngleAxis(rotation.y, Vector3.left);

transform.localRotation = yQuaternion;
player.transform.rotation = xQuaternion;


However what happens is, no matter which angle the wall is positioned, when I enter the trigger my player/camera rotation will &quot;snap&quot; forward. 

</details>


# 答案1
**得分**: 1

将旋转限制在+/-35度范围内,通过仅使用`Clamp`应用于270度,将得到+35度,但应该得到-35度,因为270度与-90度相同。

因此,创建一个将角度标准化在-180到+180度之间的函数:
``` c#
public static float NormalizeAngle(float angle)
{
    angle = (angle + 180) % 360;
    if (angle < 0) {
        angle += 360;
    }
    return angle - 180;
}

然后您可以编写:

rotation.x =
    Mathf.Clamp(NormalizeAngle(rotation.x), -xRotationLimit, xRotationLimit);
英文:

Limiting the rotation to +/-35 degrees will yield +35 for 270 degrees by applying only Clamp, but should yield -35, since 270 is the same as -90.

Therefore, create a function which normalizes the angle between -180 and +180 degrees:

public static float NormalizeAngle(float angle)
{
    angle = (angle + 180) % 360;
    if (angle &lt; 0) {
        angle += 360;
    }
    return angle - 180;
}

Then you can write:

rotation.x =
    Mathf.Clamp(NormalizeAngle(rotation.x), -xRotationLimit, xRotationLimit);

huangapple
  • 本文由 发表于 2023年8月10日 20:58:58
  • 转载请务必保留本文链接:https://go.coder-hub.com/76875952.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定