子对象合拢旋转

时间:2018-11-11 10:10:02

标签: c# unity3d math quaternions

我有一个游戏对象,其中包含另一个游戏对象,该对象应该能够朝目标旋转(想象一下坦克炮塔)。因此,我创建了以下脚本:

public class Rotator : MonoBehaviour {

    public GameObject _enemy;

    void Update () {
        var actualTarget = _enemy.transform.position;
        var targetDir = actualTarget - transform.position;
        var step = 2 * Time.deltaTime;
        var target = Quaternion.LookRotation(targetDir.normalized, Vector3.up);
        var actual = target * Quaternion.Inverse(transform.parent.rotation);
        var targetRotation = Quaternion.Slerp(transform.localRotation, actual, step);

        targetRotation.eulerAngles = ClampRotation(targetRotation.eulerAngles);
        transform.localRotation = targetRotation;
    }

    private static Vector3 ClampRotation(Vector3 eulerAngles) {
        var x = Mathf.Clamp(eulerAngles.x > 180 ? eulerAngles.x - 360 : eulerAngles.x, -180, 180);
        var y = Mathf.Clamp(eulerAngles.y > 180 ? eulerAngles.y - 360 : eulerAngles.y, -45, 45);

        return new Vector3(x, y, 0);
    }

}

对象设置:

enter image description here

名为“ parent”的对象在Y轴上旋转90度,其他所有内容均未旋转。

y轴上的夹紧效果很好-旋转保持在-45到45度之间。但是,旋转在x轴上不起作用(带或不带夹紧)。 因此,这里的目标是当我左右移动多维数据集时,红色的一个绕Y轴旋转[-45,45]度,当我上下移动它时,红色的一个旋转[-180,180]度绕X轴。 使用LookAt类别的Transform方法取得了一些成功,但是由于某些原因,如果我尝试手动修改eulerAngles的{​​{1}},则会突然失去旋转的可能性即使我只对Y值做一些操作,也可以在X轴上向后退...

enter image description here

1 个答案:

答案 0 :(得分:2)

经过长时间的尝试和错误并疯狂地浏览了互联网,我设法找到了可以满足自己需求的答案。对Clamp方法的第一个if语句发表评论-如果我希望将对象也固定在其倒置位置(如果目标位于其后),则这很有用:

void Update() {
    transform.LookAt(_target.transform);

    var rotation = transform.localRotation;
    var eulers = ClampRotation(rotation.eulerAngles);

    transform.localEulerAngles = eulers;
}

private static Vector3 ClampRotation(Vector3 eulerAngles) {
    var x = Clamp(eulerAngles.x, -60, 60);
    var y = Clamp(eulerAngles.y, -45, 45);

    return new Vector3(x, y, 0);
}

private static float Clamp(float angle, float min, float max) {
    if ((angle <= 180 && angle >= 180 - Mathf.Abs(min)) || (angle >= 180 && angle <= 180 + max)) {
        return Mathf.Clamp(angle, 180 - Mathf.Abs(min), 180 + max);
    }

    if (angle > 180f) {
        angle -= 360f;
    }

    angle = Mathf.Clamp(angle, min, max);

    if (angle < 0f) {
        angle += 360f;
    }

    return angle;
}

编辑:

事实证明,有时候创建自己的细粒度解决方案更好,您可以更轻松地进行修改,因此对于感兴趣的任何人,您也可以使用以下代码来完成我想做的事情:

void Update() {
    var actualTarget = _enemy.transform.position;
    var targetDir = actualTarget - transform.position;
    var target = Quaternion.LookRotation(targetDir.normalized, transform.up);
    var actual = Quaternion.Inverse(transform.parent.rotation) * target;

    actual.eulerAngles = ClampRotation(actual.eulerAngles);

    var targetRotation = Quaternion.Slerp(transform.localRotation, actual, 8 * Time.deltaTime);

    transform.localRotation = targetRotation;
}

private static Vector3 ClampRotation(Vector3 newRotation) {
    var x = Clamp(newRotation.x, -179, 179);
    var y = Clamp(newRotation.y, -45, 45);

    return new Vector3(x, y, 0);
}

private static float Clamp(float angle, float min, float max) {
    if ((angle <= 180 && angle >= 180 - Mathf.Abs(min)) || (angle >= 180 && angle <= 180 + max)) {
        return Mathf.Clamp(angle, 180 - Mathf.Abs(min), 180 + max);
    }

    if (angle > 180f) {
        angle -= 360f;
    }

    angle = Mathf.Clamp(angle, min, max);

    if (angle < 0f) {
        angle += 360f;
    }

    if (Mathf.Abs(angle) == 360) {
        angle = 0;
    }

    return angle;
}