unity3d 为什么Mathf.Clamp()不能正确限制Angular ?

u4dcyp6a  于 2023-04-07  发布在  Angular
关注(0)|答案(3)|浏览(216)

bounty还有7天到期。回答此问题可获得+50声望奖励。Matin正在寻找规范答案

我正在Unity中开发一个2D platformer game。我有一个GunController脚本,可以控制玩家的枪的Angular :

脚本:

using UnityEngine;
using UnityEngine.InputSystem;

public class GunController : MonoBehaviour
{
    public float rotationSpeed = 5f;
    public float minAngle = -45f;
    public float maxAngle = 45f;

    private void Update ()
    {
        // Get input from up and down arrow keys
        float input = 0;

        if (Keyboard.current.upArrowKey.isPressed) // I'm using Input system package
        {
            input = 1;
        }
        else if (Keyboard.current.downArrowKey.isPressed)
        {
            input = -1;
        }

        // Calculate new rotation based on input and speed
        float newRotation = transform.localEulerAngles.z + (-input * rotationSpeed);

        // Clamp the new rotation to be within the minimum and maximum angles
        newRotation = Mathf.Clamp (newRotation, minAngle, maxAngle);

        // Set the new rotation of the gun
        transform.localEulerAngles = new Vector3 (0, 0, newRotation);
    }
}

但是有一个问题,当枪到达0Angular 时,它会重置为最大Angular 值。例如,当我顺时针旋转时,枪的旋转达到0,它会立即转到120(这是设置为最大Angular )。

我试过这个方法,但不起作用:

private float ClampAngle (float angle, float min, float max)
    {
        if (angle < 0) angle += 360;
        if (angle > 360) angle -= 360;
        return Mathf.Clamp (angle, min, max);
    }

我在组件代码中使用了这个方法而不是Mathf.Clamp()

mrphzbgm

mrphzbgm1#

要限制Angular ,您可以在Mathf.MoveTowardsAngle的帮助下更改Angular 值,然后Clamp它。

[SerializeField] private float rotationSpeed = 6;
private float newZ;
void Update()
{
    ...
    if (input != 0)
    {
       newZ = Mathf.MoveTowardsAngle(newZ, newZ + input, Time.deltaTime * Mathf.PI * rotationSpeed);
       newZ = Mathf.Clamp(newZ, minAngle, maxAngle);
       transform.localEulerAngles = new Vector3 (0, 0, newZ);
    }
    ...
}
s4chpxco

s4chpxco2#

问题是Unity的EulerAngular 范围从0到360,但您使用的系统范围从-180到180。当您使用transform.localEulerAngles.Set()设置Angular 时,您无法阻止Unity将值转换为自己的系统。因此,您需要将从transform.localEulerAngles.z获得的Angular 转换回您的系统:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class NewBehaviourScript : MonoBehaviour
{

    public float rotationSpeed = 5f;
    public float minAngle = -45f;
    public float maxAngle = 45f;

    public float newRotation;

    private void Update()
    {
        // Get input from up and down arrow keys
        float input = 0;

        if (Keyboard.current.upArrowKey.isPressed) // I'm using Input system package
        {
            input = 1;
        }
        else if (Keyboard.current.downArrowKey.isPressed)
        {
            input = -1;
        }

        // Calculate new rotation based on input and speed
        newRotation = ShiftAngle(transform.localEulerAngles.z) + (-input * rotationSpeed);

        // Clamp the new rotation to be within the minimum and maximum angles
        newRotation = Mathf.Clamp(newRotation, minAngle, maxAngle);

        // Set the new rotation of the gun
        transform.localEulerAngles = new Vector3(0, 0, newRotation);
    }

    float ShiftAngle(float a)
    {
        if (a > 180) a -= 360;
        return a;
    }
}
ddarikpa

ddarikpa3#

过去我在尝试修改现有Angular 时遇到过很多问题,因为你是以欧拉角的形式阅读和写入Angular ,但Unity的内部旋转表示是四元数。这意味着你读取的Angular 将取决于Unity从四元数到欧拉角的转换,这可能与你写的值不一致。你可以写一个360度的值,当你读它时,你可能得到零。当你写270度时,你读它时得到270,还是-90等等
对我个人来说,过去最好的解决方案是跟踪我自己的Angular 。如果你所做的只是阅读旋转,修改它,然后编写旋转,那么就自己跟踪这些Angular ,并使用它,而不是轮询对象的旋转:

using UnityEngine;
using UnityEngine.InputSystem;

public class GunController : MonoBehaviour
{
    public float rotationSpeed = 5f;
    public float minAngle = -45f;
    public float maxAngle = 45f;
    public float currentAngle = 0f;

    private void Update ()
    {
        // Get input from up and down arrow keys
        float input = 0;

        if (Keyboard.current.upArrowKey.isPressed) // I'm using Input system package
        {
            input = 1;
        }
        else if (Keyboard.current.downArrowKey.isPressed)
        {
            input = -1;
        }

        // Calculate new rotation based on input and speed
        currentAngle += -input * rotationSpeed;

        // Clamp the new rotation to be within the minimum and maximum angles
        currentAngle = Mathf.Clamp (currentAngle, minAngle, maxAngle);

        // Set the new rotation of the gun
        transform.localEulerAngles = new Vector3 (0, 0, currentAngle);
    }
}

相关问题