【问题标题】:Using MoveRotation in Unity 3D to turn player towards a certain angle在 Unity 3D 中使用 MoveRotation 将玩家转向某个角度
【发布时间】:2022-11-25 10:26:05
【问题描述】:

有人告诉我 Rigidbody.MoveRotation 是 Unity 3D 中在固定位置之间旋转玩家同时仍检测命中的最佳方式。然而,虽然我可以从固定位置平稳地移动到另一个位置:

if (Vector3.Distance(player.position, targetPos) > 0.0455f) //FIXES JITTER 
            {
                var direction = targetPos - rb.transform.position;
                rb.MovePosition(transform.position + direction.normalized * playerSpeed * Time.fixedDeltaTime);
            }

我找不到如何在固定位置之间平稳旋转。我可以使用Rigidbody.MoveRotation(Vector3 target); 立即旋转到我想要的角度,但我似乎无法找到一种方法来进行上述旋转。

注意:Vector3.Distance 是唯一阻止抖动的东西。有没有人有任何想法?

【问题讨论】:

    标签: c# unity3d


    【解决方案1】:

    首先MoveRotation 不是Vector3而是Quaternion

    那么一般来说你的抖动可能来自超调- 你可能移动得比你的玩家和目标之间的实际距离更远。

    您可以通过使用 Vector3.MoveTowards 来避免该位,这可以防止目标位置的任何过冲,例如

    Rigidbody rb;
    float playerSpeed;
    Vector3 targetPos;
    
    // in general ONLY g through the Rigidbody as soon as dealing wit Physics
    // do NOT go through transform at all
    var currentPosition = rb.position;
    // This moves with linear speed towards the target WITHOUT overshooting
    // Note: It is recommended to always use "Time.deltaTime". It is correct also during "FixedUpdate"
    var newPosition = Vector3.MoveTowards(currentPosition, targetPos, playerSpeed * Time.deltaTime);
    rb.MovePosition(newPosition);
    
    // [optionally]
    // Note: Vector3 == Vector3 uses approximation with a precision of 1e-5
    if(rb.position == targetPos)
    {
        Debug.Log("Arrived at target!");
    }
    

    然后,您可以通过等效的Quaternion.RotateTowards 基本上只是相同的方法,将相同的概念也简单地应用于旋转

    Rigidbody rb;
    float anglePerSecond;
    Quaternion targetRotation;
    
    var currentRotation = rb.rotation;
    var newRotation = Quaternion.RotateTowards(currentRotation, targetRotation, anglePerSecond * Time.deltaTime);
    rb.MoveRotation(newRotation);
    
    // [optionally]
    // tests whether dot product is close to 1
    if(rb.rotation == targetRotation)
    {
        Debug.Log("Arrived at rotation!");
    }
    

    【讨论】:

    • 谢谢,我可以试试
    【解决方案2】:

    您可以更进一步,使用推文库在旋转之间进行补间。

    DOTween

    有了它,你可以这样称呼它:

    rigidbody.DoRotate(target, 1f) 在 1 秒内旋转到目标。

    甚至添加回调。

    rigidbody.DoRotate(target, 1f).OnComplete(//any method or lambda you want)

    如果在某个时候你想取消推文,你可以将它保存在一个变量中,然后调用tween.Kill();

    【讨论】:

    • 我怀疑这会与物理学一起工作......你需要不是通过 transform 而不是像 OP 那样的 Rigidbody 组件,它必须发生在 FixedUpdate 中......我认为两者都不能在 DoTween 中完成......
    • 另外,如果你想持续跟踪目标而不是只开始一次然后最终完成怎么办?
    • 这些案例不是问题的一部分,我们显然可以根据需要将其复杂化。
    • OP 特别询问 rotate the player between fixed positions while still detecting hits 这几乎需要完整的物理而不会被 DOTween 破坏它们,因为它直接在 transform 上运行。而这个 var direction = targetPos - rb.transform.position; 几乎意味着玩家或目标同时移动
    • 命中意味着检测碰撞和触发,从根本上说,如果中间有一堵墙,你永远不能在 A 和 B 之间移动,如果检测到碰撞或触发,你甚至可以杀死补间,问题不在于代码,问题在于方法问题。
    【解决方案3】:

    因此,您希望随时间对旋转值进行动画处理,直到它达到某个值。

    在 Update 方法内部,您可以使用 Lerp 方法将对象不断旋转到一个点,但是如果使用 Lerp,您将永远无法真正到达这个点。它将永远旋转(总是更接近点)。

    您可以使用以下内容:

    private bool rotating = true;
    public void Update()
    {
        if (rotating)
        {
            Vector3 to = new Vector3(20, 20, 20);
            if (Vector3.Distance(transform.eulerAngles, to) > 0.01f)
            {
                transform.eulerAngles = Vector3.Lerp(transform.rotation.eulerAngles, to, Time.deltaTime);
            }
            else
            {
                transform.eulerAngles = to;
                rotating = false;
            }
        }
     
    }
    

    因此,如果当前对象角度与所需角度之间的距离大于 0.01f,它会直接跳到所需位置并停止执行 Lerp 方法。

    【讨论】:

    • a) 在使用 Physics 时你想不是通过transform,而不是像 OP 那样的Rigidbody 组件。您还想在FixedUpdate 中执行此操作。 b) 你不想在连续动画时通过eulerAngles -> Because, there is more than one way to represent any given rotation using Euler angles, the values you read back out may be quite different from the values you assigned. This can cause confusion if you are trying to gradually increment the values to produce animation.
    • 有趣,感谢分享,学习改进的技术总是好的
    猜你喜欢
    • 1970-01-01
    • 2017-06-22
    • 1970-01-01
    • 2022-01-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-12-16
    • 1970-01-01
    相关资源
    最近更新 更多