【问题标题】:How can I wait for the object to end spinning and then play the animation?如何等待对象结束旋转然后播放动画?
【发布时间】:2020-03-09 13:15:57
【问题描述】:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;

public class RoboSphereWindowBreakInteraction : MonoBehaviour
{
    public Transform target;
    public InteractableObjects interactableObjects;
    public AudioClip audioClip;
    public float speed;

    private bool hasStarted = false;
    private Animator anim;

    void Update()
    {
        if ((Input.GetKeyDown(KeyCode.B) || (hasStarted == true)))
        {
            float step = speed * Time.deltaTime; // calculate distance to move
            transform.position = Vector3.MoveTowards(transform.position, target.position, step);

            hasStarted = true;
        }
    }

    private void OnTriggerEnter(Collider other)
    {
        if (other.gameObject.name == "Square 1")
        {
            GetComponent<Rigidbody>().isKinematic = false;
            hasStarted = false;
            Destroy(GameObject.Find("Wall_Window_Long_03"));
        }
    }

    public void ActivateRoboSphere()
    {
        foreach(Transform child in transform)
        {
            if(child.name == "Camera")
            {
                RepositionCamera(child);
            }
        }

        anim = GetComponent<Animator>();
        anim.enabled = true;

        StartCoroutine(PlayAudio());
    }

    private void RepositionCamera(Transform camera)
    {
        var Eyes = GameObject.Find("eyeDome");

        camera.position = Eyes.transform.position + Eyes.transform.forward;
        camera.LookAt(Eyes.transform);
        camera.GetComponent<Camera>().enabled = true;
    }

    IEnumerator PlayAudio()
    {
        AudioSource audio = GetComponent<AudioSource>();

        audio.clip = audioClip;
        audio.Play();
        yield return new WaitForSeconds(audio.clip.length);

        var rotation = Quaternion.LookRotation(target.position - transform.position);
        StartCoroutine(Spin(3f, rotation));

        anim.SetBool("Roll_Anim", true);
    }

    IEnumerator Spin(float lerpTime, Quaternion rotation)
    {
        float elapsedTime = 0f;

        while (elapsedTime <= lerpTime)
        {
            transform.rotation = Quaternion.Slerp(transform.rotation, rotation, elapsedTime / lerpTime);
            elapsedTime += Time.deltaTime;
            yield return null;
        }
    }
}

但是当动画开始时,对象旋转但没有面向目标,至少不是我想要的目标。

球体开始旋转面向窗口的对象(在顶部场景视图的背景屏幕截图中),但随后它改变了面向相机(变换的子相机)的面向背面。

在点击事件中点击鼠标时,ActivateRoboSphere 方法调用 RepositionCamera 和 ActivateRoboSphere 被调用一次。

但由于某种原因,当对象播放“Roll_Anim”动画时,它再次面向相机而不是目标窗口。

我在屏幕截图中用红色方块标记了它应该面对的窗口目标:

【问题讨论】:

    标签: c# unity3d


    【解决方案1】:

    在您的情况下,您可以让您的呼叫 IEnumerator 等到另一个呼叫完成,只需 yielding 它就可以了

    ...
    
    // executes and at the same time waits for Spin to finish
    yield return Spin(3f, rotation);
    
    // called when Spin routine is finished
    anim.SetBool("Roll_Anim", true);
    

    或者,您可以简单地添加一个回调,而不是像 suggested here 这样的第三方工具库

    IEnumerator Spin(float lerpTime, Quaternion rotation, Action whenDone)
    {
        float elapsedTime = 0f;
    
        while (elapsedTime <= lerpTime)
        {
            transform.rotation = Quaternion.Slerp(transform.rotation, rotation, elapsedTime / lerpTime);
            elapsedTime += Time.deltaTime;
            yield return null;
        }
    
        whenDone?.Invoke();
    }
    

    然后使用类似的 lambda 表达式启动例程

    StartCoroutine(Spin(3f, rotation, () => 
    {
        anim.SetBool("Roll_Anim", true);
    }));
    

    或类似的方法调用

    private void AfterSpinning()
    {
        anim.SetBool("Roll_Anim", true);
    }
    
    ...
    
    StartCoroutine(Spin(3f, rotation, AfterSpinning));
    

    【讨论】:

      【解决方案2】:

      最好使用补间引擎,例如http://dotween.demigiant.com/

      如果你安装了 Dotween 那么你可以简单地使用

      transform.DORotate(new vector3(0 ,100 , 0) , duration);
      

      您还可以为补间设置轻松。或使用 Oncomplete 函数;

      transform.DORotate(new vector3(1 ,0 , 1) , duration)
          .SetEase(Ease.OutCubic)
          .OnCompelete(() => { shouldClose = true; }); 
      

      您还可以为补间.SetLoops(-1) 设置循环。

      除此之外,您还可以使用sequences 将多个补间显示在一起。

      【讨论】:

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