用协程使物体活动几秒钟后?

时间:2019-08-11 18:36:59

标签: unity3d

enter image description here

我正在制作一个游戏,在该游戏中,我希望对象开始隐藏或不活动,并在几秒钟后出现。我尝试使用协程,但是问题或错误是,因为我从一开始就将对象设置为隐藏或不活动,协程需要活动对象,因此我从另一个外部脚本进行尝试,但仍然没有成功。第二个脚本甚至没有启动。有人有任何建议或解决方法吗?

我已经从另一个外部脚本尝试过,但是仍然没有成功。在我添加的图片中,Num Trigger脚本在碰撞后只是禁用了对象。

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

public class ActivationRutine : MonoBehaviour
{
    public GameObject objectToActivate;
    // Start is called before the first frame update
    void Start()
    {

        StartCoroutine(StartFunction());
    }

    private IEnumerator StartFunction()
    {
        //Wait for 5 sec.
        yield return new WaitForSeconds(5);

        //Turn My game object that is set to false(off) to True(on).
        objectToActivate.SetActive(true);
    }
}

2 个答案:

答案 0 :(得分:0)

协程是对象而不是函数。是由包含StartCoroutine()调用的游戏对象托管的。调用本身仅添加协程对象,并使用统一的协程调度程序对其进行调度。这意味着协程仅在禁用或销毁宿主对象时,或者在通过StopCoroutine()调用通知调度程序停止协程时才停止。

您可以:

[推荐]

A)将协程存放在与未激活/激活的对象不同的对象上。这是最佳做法。


[不推荐]

B)禁用对象中的组件,例如禁用了“渲染器”,“碰撞器”和逻辑脚本,而对象本身仍处于活动状态。在激活脚本上,启用禁用的组件和脚本。 片段:

private void Awake() {
    var components = GetComponents<MonoBehaviour>().ToList();
    components.Remove(this);
    foreach (var component in components)
        component.enabled = false;
    StartCoroutine(ActivationCountdown(3f));
}

private void Activate() {
    var components = GetComponents<MonoBehaviour>().ToList();
    components.Remove(this);
    foreach (var component in components)
        component.enabled = true;
    Destroy(this);
}

private IEnumerator ActivationCountdown(float time) {
    yield return new WaitForSeconds(time);
    Activate();
}

不建议使用(B)方法,因为尽管在所有其他组件都被禁用的情况下解决方案很容易,但是一旦您开始需要管理哪些内容的列表,它很快就会成为工作的噩梦。需要从启动开始激活VS延迟后激活。我需要在编辑器中为每个对象进行设置,或者需要使用脚本来管理每种情况。变成了依赖性意大利面条。

将协程托管在外部(例如,单例)要容易得多。您具有一个依赖项:您的对象需要在单例上调用函数,将自身作为参数引用,就像我在代码片段中对变量“ time”进行引用一样。这应该很容易管理,因为它是一个单例。

答案 1 :(得分:0)

除了完全不使用协程,您还可以简单地使用Invoke,它仍将在禁用的对象上执行!

您可以将其做成一个类似

的小组件
public class DelayedActivation : MonoBehaviour
{
    [Tooltip("Automatically activtae the object after delay.\n"
             + "If set to false object has to be activated by another script.\n"
             + "Can still be done delayed using 'ActivateDelayed()'")]
    public bool ActivateOnStart = true;
    public float ActivationDelay = 5.0f;

    // Start is called before the first frame update
    private void Start()
    {
        gameObject.SetActive(false);
        if (ActivateOnStart) ActivateDelayed();
    }

    private void AfterDelay()
    {
        gameObject.SetActive(true);
    }

    /*
     * Activates the object after the configured delay
     */
    public void ActivateDelayed()
    {
        Invoke(nameof(AfterDelay), ActivationDelay);
    }

    /*
     * Activates the object after the passed custom delay
     */
    public void ActivateDelayed(float customDelay)
    {
        Invoke(nameof(AfterDelay), customDelay)
    }
}

enter image description here