【问题标题】:Clapming rotation of child objects in unity统一鼓掌旋转子对象
【发布时间】:2019-04-14 07:38:50
【问题描述】:

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

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);
    }

}

对象设置:

名为“parent”的对象在 Y 轴上旋转了 90 度,其他一切都没有旋转。

在 y 轴上夹紧效果很好 - 旋转保持在 -45 到 45 度之间。然而,旋转在 x 轴上不起作用(有或没有夹紧)。 所以这里的目标是,当我向左或向右移动立方体时,红色的会围绕 Y 轴在 [-45,45] 度之间旋转,当我向上或向下移动时,红色的会在 [-180,180] 度之间旋转围绕 X 轴。 我使用Transform 类的LookAt 方法取得了一些成功,但由于某种原因,如果我尝试手动修改eulerAngleslocalRotation,它突然失去了在X 轴上向后旋转的可能性,即使我'我只是对 Y 值做一些事情......

【问题讨论】:

  • 我认为还没有答案,因为人们不清楚问题是什么。你说它会旋转,但现在有什么问题?有任何 GIF 动画来展示现在正在发生的事情以及您的期望吗?
  • 现在清楚了吗?
  • 是的,它没有上移。您还希望能够为两个轴添加旋转限制?
  • 如果向上移动的意思是红人在向上/向下移动时没有指向移动的立方体,那么是的 - 这就是问题所在。再一次 - 是的 - 我想为 X 和 Y 轴添加旋转限制。我只是将 Z 设置为 0,因为我根本不希望它受到影响。

标签: c# unity3d math quaternions


【解决方案1】:

经过长时间的反复试验和疯狂浏览互联网后,我设法找到了一个可以满足我需求的答案。对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;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多