内容纲要

镜头移动的实现

获取输入设备(鼠标)移动的值,将其作为系数和旋转速度已经时间差做运算,得到摄像机需要旋转的角度。并使其摄像机旋转到该角度。

固定旋转角度范围

由于在Unity中欧拉角的范围是[0,360),所以如果超过360度时,欧拉角的值会变成0,因此我们需要将角度做一个修正,确定其取值范围。
详细代码如下:

 // Start is called before the first frame update
    void Start()
    {
        MaxXDeg = CorrectDeg(transform.eulerAngles.x + MaxDeltaDeg);
        MinXDeg = CorrectDeg(transform.eulerAngles.x - MaxDeltaDeg);
        MaxYDeg = CorrectDeg(transform.eulerAngles.y + MaxDeltaDeg);
        MinYDeg = CorrectDeg(transform.eulerAngles.y - MaxDeltaDeg);

        xFlag = CheckDegSection(MaxXDeg, MinXDeg);
        yFlag = CheckDegSection(MaxYDeg, MinYDeg);
    }

    /// <summary>
    /// 检测是否经过360度
    /// </summary>
    /// <param name="max">最大角度</param>
    /// <param name="min">最小角度</param>
    /// <returns></returns>
    bool CheckDegSection(float max, float min)
    {
        return max < min;
    }

    /// <summary>
    /// 进行角度纠正,正确区间应在 [0, 360)
    /// </summary>
    /// <param name="deg">角度</param>
    /// <returns></returns>
    float CorrectDeg(float deg)
    {
        return deg < 360 && deg >= 0 ? deg : (deg >= 360 ? deg - 360 : deg + 360);
    }

源码

public class CameraCtrl : MonoBehaviour
{
    public float MaxDeltaDeg = 60f;
    public float MouseSpeedScale = 180f;

    float MaxXDeg = 0;
    float MinXDeg = 0;
    float MaxYDeg = 0;
    float MinYDeg = 0;
    // 角度区间是否经过360度
    bool yFlag = false;
    bool xFlag = false;
    float xDeg = 0;
    float yDeg = 0;

    private void Awake()
    {
        Application.targetFrameRate = 60;
    }

    // Start is called before the first frame update
    void Start()
    {
        MaxXDeg = CorrectDeg(transform.eulerAngles.x + MaxDeltaDeg);
        MinXDeg = CorrectDeg(transform.eulerAngles.x - MaxDeltaDeg);
        MaxYDeg = CorrectDeg(transform.eulerAngles.y + MaxDeltaDeg);
        MinYDeg = CorrectDeg(transform.eulerAngles.y - MaxDeltaDeg);

        xFlag = CheckDegSection(MaxXDeg, MinXDeg);
        yFlag = CheckDegSection(MaxYDeg, MinYDeg);
    }

    /// <summary>
    /// 检测是否经过360度
    /// </summary>
    /// <param name="max">最大角度</param>
    /// <param name="min">最小角度</param>
    /// <returns></returns>
    bool CheckDegSection(float max, float min)
    {
        return max < min;
    }

    /// <summary>
    /// 进行角度纠正,正确区间应在 [0, 360)
    /// </summary>
    /// <param name="deg">角度</param>
    /// <returns></returns>
    float CorrectDeg(float deg)
    {
        return deg < 360 && deg >= 0 ? deg : (deg >= 360 ? deg - 360 : deg + 360);
    }

    void Debug()
    {

    }

    /// <summary>
    /// 在一定范围内旋转摄像机
    /// </summary>
    /// <param name="RotateDeg">要旋转的角度</param>
    /// <param name="CurrentEulerAngles">当前的角度</param>
    /// <param name="MaxDeg">最大角度限制</param>
    /// <param name="MinDeg">最小角度限制</param>
    /// <param name="Bound360">角度是否经过360度</param>
    /// <param name="Axis">旋转轴</param>
    /// <param name="isXaxis">是否绕着X轴旋转</param>
    void DoRotate(float RotateDeg, float CurrentEulerAngles, float MaxDeg, float MinDeg, bool Bound360, Vector3 Axis, bool isXaxis)
    {
        if (RotateDeg == 0 || MaxDeg == MinDeg)
            return;
        float tmp = CurrentEulerAngles + RotateDeg;
        if (Bound360)
        {
            if (tmp < MaxDeg || tmp > MinDeg)
            {
                transform.RotateAround(transform.position, Axis, RotateDeg);
            }
            else
            {
                if (isXaxis)
                    transform.rotation = Quaternion.Euler(RotateDeg < 0 ? MinDeg : MaxDeg, transform.eulerAngles.y, transform.eulerAngles.z);
                else
                    transform.rotation = Quaternion.Euler(transform.eulerAngles.x, RotateDeg < 0 ? MinDeg : MaxDeg, transform.eulerAngles.z);
            }
        }
        else
        {
            if (tmp > MinDeg && tmp < MaxDeg)
            {
                transform.RotateAround(transform.position, Axis, RotateDeg);
            }
            else
            {
                if (isXaxis)
                    transform.rotation = Quaternion.Euler(RotateDeg < 0 ? MinDeg : MaxDeg, transform.eulerAngles.y, transform.eulerAngles.z);
                else
                    transform.rotation = Quaternion.Euler(transform.eulerAngles.x, RotateDeg < 0 ? MinDeg : MaxDeg, transform.eulerAngles.z);
            }
        }
    }

    // Update is called once per frame
    void Update()
    {
        if (Input.GetMouseButtonDown(0))
        {
            Debug();
        }
        if (Input.GetMouseButton(1))
        {
            xDeg = -Input.GetAxis("Mouse Y") * MouseSpeedScale * Time.deltaTime;
            yDeg = Input.GetAxis("Mouse X") * MouseSpeedScale * Time.deltaTime;

            DoRotate(xDeg, transform.eulerAngles.x, MaxXDeg, MinXDeg, xFlag, transform.right, true);
            DoRotate(yDeg, transform.eulerAngles.y, MaxYDeg, MinYDeg, yFlag, transform.parent.up, false);
        }
    }
}

1 对 “BrickShooter(镜头移动)”的想法;

发表评论