如何让 object 慢慢地朝着目标平滑旋转? object 没有面向目标旋转

How to rotate object towards target smooth slowly ? The object is not rotating facing the target

最后的目标是在他开始移动时旋转 object,这样 object 将朝向他正在移动的目标,并且从 object眼睛将朝向同一个目标。

我要旋转的 object 首先位于位置 0,0,0,因为 object 是 child。玩家用手拿着 object。然后 object 开始向目标投掷动画。

object 正在向目标移动,但现在我希望 object 也能平滑地缓慢旋转到目标,在这种情况下,我将旋转持续时间设置为 1 秒。我看到 object 旋转正在改变但没有朝向目标。

此屏幕截图显示 object 仍在玩家手中的位置 0,0,0

然后object得到投掷并开始向目标移动此时object旋转变化:

投掷的 object 有一个 child 变换眼睛,激光束应该从眼睛出来,然后我想让 object 旋转到目标,因此来自眼睛的激光将朝向目标。

我用小红圈标记了眼睛:

在这张截图中我把目标标记的很远,绿色的激光没有正对着目标,眼睛也没有正对着目标。激光应该从眼睛出来,整个 object 应该面对目标,所以激光也应该用眼睛面对目标。

此屏幕截图是 object 在 运行 游戏之前 object 眼睛正对着 object 的游戏。这只是为了表明眼睛与面向前方的 object 对齐。

这个脚本附在我的播放器上并使 object 被扔向目标并且还应该使 object 向目标旋转:

使 object 移动到目标的投掷部分工作正常,但旋转部分不是:

private IEnumerator AnimateRotationTowards(Quaternion transformRot, Quaternion targetRot, float dur)
        {
            float t = 0f;
            while (t < dur)
            {
                transformRot = Quaternion.Slerp(transformRot, targetRot, t / dur);
                yield return null;
                t += Time.deltaTime;
            }
    
            transformRot = targetRot;
        }

我还看到制作 transformRot = targetRot;由于某种原因,有一条小消息说不必要的分配不知道为什么。

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

public class ThrowObject : MonoBehaviour
{
    public Transform objectToThrow;
    public Transform target;
    public Transform objectToThrowParent;
    public float throwingSpeed;
    public float waitAtTargetTime;
    public float distanceToStopFromTarget;
    public bool go = false;
    public AnimationCurve animationCurve;

    private Animator anim;
    private bool startThrowAnimationOnce = true;
    private bool reParent = false;
    private bool startMovingBack = false;

    private void Start()
    {
        anim = GetComponent<Animator>();
    }

    private void Update()
    {
        if (anim != null && startThrowAnimationOnce)
        {
            anim.SetTrigger("Throw");
            startThrowAnimationOnce = false;
        }

        if (go)
        {
            objectToThrow.parent = null;
            StartCoroutine(Throw());
            StartCoroutine(AnimateRotationTowards(objectToThrow.rotation, target.rotation, 1f));

            go = false;
        }

        if (reParent)
        {
            objectToThrow.position = objectToThrowParent.position;
        }

        if (startMovingBack)
        {
            if (Vector3.Distance(objectToThrow.position, objectToThrowParent.position) >= 0.1f)
            {
                float step = 5 * Time.deltaTime;
                objectToThrow.position = Vector3.MoveTowards(objectToThrow.position, objectToThrowParent.position, step);
            }
            else
            {
                objectToThrow.position = objectToThrowParent.position;

                objectToThrow.parent = objectToThrowParent;
                objectToThrow.localPosition = new Vector3(0, 0, 0);
            }
        }
    }

    public void ThrowEvent()
    {
        go = true;
    }

    IEnumerator Throw()
    {
        while(Vector3.Distance(objectToThrow.position, target.position) >= distanceToStopFromTarget)
        {
            objectToThrow.position = Vector3.MoveTowards(
                  objectToThrow.position,
                  target.position,
                  throwingSpeed * Time.deltaTime
             );

            yield return null;
        }

        yield return new WaitForSeconds(waitAtTargetTime);

        startMovingBack = true;
    }

    private IEnumerator AnimateRotationTowards(Quaternion transformRot, Quaternion targetRot, float dur)
    {
        float t = 0f;
        while (t < dur)
        {
            transformRot = Quaternion.Slerp(transformRot, targetRot, t / dur);
            yield return null;
            t += Time.deltaTime;
        }

        transformRot = targetRot;
    }
}

此脚本附加到 object 眼睛并发射激光: 此脚本中的目标与 ThrowObject 脚本中的目标相同:

using System.Collections;
using System.Collections.Generic;
using System.Runtime.Serialization.Formatters;
using System;
using UnityEngine;

public class Hovl_DemoLasers : MonoBehaviour
{
    public List<Transform> targets;
    public GameObject FirePoint;
    public Camera Cam;
    public float MaxLength;
    public GameObject[] Prefabs;

    private Ray RayMouse;
    private Vector3 direction;
    private Quaternion rotation;

    [Header("GUI")]
    private float windowDpi;

    private int Prefab;
    private GameObject Instance;
    private Hovl_Laser LaserScript;
    private Hovl_Laser2 LaserScript2;

    private bool rotateMouse = true;
    private bool startLaser = true;

    private float buttonSaver = 0f;
    private Hovl_LaserDemo hovl_laserDemo;

    private float maxDistance = 0;
    private int closestIndex = 0;

    void Start()
    {
        if (Screen.dpi < 1) windowDpi = 1;
        if (Screen.dpi < 200) windowDpi = 1;
        else windowDpi = Screen.dpi / 200f;
        Counter(0);
    }

    void Update()
    {
        //Enable lazer
        if (Input.GetMouseButtonDown(0))
        {
            Destroy(Instance);
            Instance = Instantiate(Prefabs[Prefab], FirePoint.transform.position, FirePoint.transform.rotation);
            Instance.transform.parent = transform;
            LaserScript = Instance.GetComponent<Hovl_Laser>();
            LaserScript2 = Instance.GetComponent<Hovl_Laser2>();

            rotateMouse = true;
        }

        if (Input.GetMouseButtonDown(1))
        {
            rotateMouse = false;
        }

        if ((Input.GetKey(KeyCode.A) || Input.GetAxis("Horizontal") < 0) && buttonSaver >= 0.4f)// left button
        {
            buttonSaver = 0f;
            Counter(-1);
        }
        if ((Input.GetKey(KeyCode.D) || Input.GetAxis("Horizontal") > 0) && buttonSaver >= 0.4f)// right button
        {
            buttonSaver = 0f;
            Counter(+1);
        }
        buttonSaver += Time.deltaTime;

        if (startLaser)
        {
            rotateMouse = false;

            Destroy(Instance);

            Instance = Instantiate(Prefabs[Prefab], FirePoint.transform.position, FirePoint.transform.rotation);
            Instance.transform.parent = transform;
            LaserScript = Instance.GetComponent<Hovl_Laser>();
            LaserScript2 = Instance.GetComponent<Hovl_Laser2>();

            hovl_laserDemo = Instance.GetComponent<Hovl_LaserDemo>();

            startLaser = false;
        }

        if (targets != null)
        {
            maxDistance = Mathf.Infinity;

            for (int i = 0; i < targets.Count; i++)
            {
                float distance = Vector3.Distance(gameObject.transform.position, targets[i].position);
                if (distance < maxDistance)
                {
                    maxDistance = distance;
                    closestIndex = i;
                }
            }

            if (hovl_laserDemo != null)
            {
                float distance = Vector3.Distance(gameObject.transform.position, targets[closestIndex].position);
                MaxLength = distance;
                hovl_laserDemo.MaxLength = distance;
            }

            RaycastHit hit;

            if (Physics.Raycast(transform.position, transform.TransformDirection(Vector3.forward), out hit, MaxLength))
            {
                RotateToMouseDirection(gameObject, targets[closestIndex].position);
            }
            else
            {
                RotateToMouseDirection(gameObject, targets[closestIndex].position);
            }
        }

        if (Cam != null && rotateMouse)
        {
            RaycastHit hit;
            var mousePos = Input.mousePosition;
            RayMouse = Cam.ScreenPointToRay(mousePos);

            if (Physics.Raycast(RayMouse.origin, RayMouse.direction, out hit, MaxLength))
            {
                RotateToMouseDirection(gameObject, hit.point);
            }
            else
            {
                var pos = RayMouse.GetPoint(MaxLength);
                RotateToMouseDirection(gameObject, pos);
            }
        }
        else
        {
            Debug.Log("No camera");
        }
    }

    void OnGUI()
    {
        GUI.Label(new Rect(10 * windowDpi, 5 * windowDpi, 400 * windowDpi, 20 * windowDpi), "Use the keyboard buttons A/<- and D/-> to change lazers!");
        GUI.Label(new Rect(10 * windowDpi, 20 * windowDpi, 400 * windowDpi, 20 * windowDpi), "Use left mouse button for shooting!");
    }

    void Counter(int count)
    {
        Prefab += count;
        if (Prefab > Prefabs.Length - 1)
        {
            Prefab = 0;
        }
        else if (Prefab < 0)
        {
            Prefab = Prefabs.Length - 1;
        }
    }

    void RotateToMouseDirection(GameObject obj, Vector3 destination)
    {
        direction = destination - obj.transform.position;
        rotation = Quaternion.LookRotation(direction);
        obj.transform.localRotation = Quaternion.Lerp(obj.transform.rotation, rotation, 1);
    }
}

在这种情况下,了解 passing by value, or passing by reference 之间的区别很重要。在您的 AnimateRotationTowards 函数中,该函数的所有参数都是按值传递的。对这些旋转的更改将影响函数范围内的局部值,但这些值与场景中使用的值不同。

您可能需要的是对某些 Transform 对象的引用。如果您为该变换分配新的旋转,它将在场景中使用该旋转。

看起来这个脚本组件附加到将要旋转的游戏对象上。那正确吗?如果是,您可以通过为 transform.rotation:

赋值来设置新的旋转
private IEnumerator AnimateRotationTowards(Quaternion transformRot, Quaternion targetRot, float dur)
        {
            float t = 0f;
            while (t < dur)
            {
                transform.rotation = Quaternion.Slerp(transformRot, targetRot, t / dur);
                yield return null;
                t += Time.deltaTime;
            }
    
            transform.rotation = targetRot;
        }

如果您需要为其他游戏对象指定旋转,您可以传入对该游戏对象或其变换的引用,并使用它来指定旋转。