首页 > 解决方案 > 如何启动和停止子系统?

问题描述

就像标题所说的那样,我正在尝试使用 Invoke 功能的计时器启动和停止统一 3D 中的“复杂”部分系统,基本上是火炬的火焰发射。问题是,我可以停止 PS(部分系统),但无法重新启动它。

在创建一个数组之前,我尝试使用GetComponentsInChildren不同的标签访问和标记 PS 的孩子。正如我之前所说,我可以成功地停止 PS,方法是在使用函数GetComponent<PartycalSystem>之前标记主要对象并使用数组中的每个对象。Stop()但是由于某种原因,我无法使用该Start()功能以相同的方式重新启动它。

public bool blindmode = false;
public GameObject[] lightfx;
public GameObject[] torches;

void Start()
{
    //getting the reference to the light Objects 
    torches = GameObject.FindGameObjectsWithTag("light");
    lightfx = GameObject.FindGameObjectsWithTag("fx");        
}

void Update()
{
    if (blindmode==false)
    {
        Invoke("blindmodeon", 20);

    }
    if (blindmode==true)
    {
        Invoke("blindmodeoff", 20);

    }
}

void blindmodeon()
{
    blindmode = true;

    foreach (GameObject torch in torches)
    {
        var fire = torch.GetComponent<Light>();
        fire.enabled = false;
    }

    foreach (GameObject fire in lightfx)
    {
        var flame = fire.GetComponent<ParticleSystem>();
        flame.Stop();
    }
}

在代码的最后一部分中,我禁用了灯光和 PS。由于灯光部分工作得很好,我希望你只看一下粒子系统。

void blindmodeoff()
{
    blindmode = false;
    foreach (GameObject torch in torches)
    {
        var fire = torch.GetComponent<Light>();
        fire.enabled = true;
    }

    foreach (GameObject fire in lightfx)
    {
        var flame = fire.GetComponent<ParticleSystem>();
        flame.Play();
        var child1 = transform.GetChild(0).GetComponent<ParticleSystem>();
        child1.Play();
        var child2 = transform.GetChild(1).GetComponent<ParticleSystem>();
        child1.Play();
        var child3 = transform.GetChild(2).GetComponent<ParticleSystem>();
        child1.Play();
        var child4 = transform.GetChild(3).GetComponent<ParticleSystem>();
        child1.Play();
    }
}

这是我最后一次尝试,也未能重新启用 PS。你可以从中猜到,PS 有它的母亲 PS 和 4 个孩子。

火把在 PS 激活时生成。调用的第一个计时器成功停止 PS。第二个计时器应该重新启动它,使用所述计时器创建一个 On 和 Off 循环,但它没有这样做。我尝试了很多东西,包括启用排放,但似乎没有任何效果。提前致谢!

标签: unity3d

解决方案


void Update()
{
    if (blindmode==false)
    {
        Invoke("blindmodeon", 20);

    }
    if (blindmode==true)
    {
        Invoke("blindmodeoff", 20);

    }
}

你重复添加一个调用......每一帧,所以在接下来的 20 秒后的 20 秒后,你可能会得到与你想要做的相矛盾的调用方法。

在我看来,你想把灯开 20 秒,然后一直开 20 秒,对吧?


我建议使用一种方法,例如

private bool blindmode;

private void ToggleLights()
{
    // invert the flag
    blindmode = !blindmode;

    foreach (var torch in torches)
    {
        var fire = torch.GetComponent<Light>();
        // set according to the flag
        fire.enabled = !blindmode;
    }

    foreach (var fire in lightfx)
    {
        // here I would do GetComponentsInChildren
        // passing true so we get also inactive children
        var particleSystems = fire.GetComponentsInChildren<ParticleSystem>(true);
        foreach(var system in particleSystems)
        {
            // according to the blindmode
            if(blindmode) 
                system.Stop();
            else
                system.Play();
        }
    }
}

所以你可以使用InvokeRepeating

private void Start()
{
    InvokeRepeating("ToggleLights", 0, 20f);
}

或者你也可以使用协程,比如

// yes, Start can be a Coroutine
private IEnumerator Start()
{
    while(true)
    {
        ToggleLights();
        yield return WaitForSeconds(20f);
    }
}

或者如果您想坚持该Update方法,请使用类似的计时器

private float timer = 20f;

private void Update()
{
    timer -= Time.deltaTime;

    if(timer > 0) return;

    ToggleLights();

    timer = 20f;
}

一般来说,尽量避免那些重复调用GetComponentand GetComponentsInChildren!而是打一次电话,例如Awake,重新使用参考文献,例如

// rather directly store the type you want
public List<Light> torches = new List<Light>();
public List<ParticleSystem> lightfx = new List<ParticleSystem>();

private void Awake()
{
    //getting the reference to the light Objects 
    var torchObjects = GameObject.FindGameObjectsWithTag("light");
    var lightfxObjects = GameObject.FindGameObjectsWithTag("fx");  

    foreach(var torch in torchObjects)
    {
        torches.Add(torch.GetComponent<Light>());
    }      

    foreach(var fx in lightfxObjects)
    {
        lightfx.AddRange(fx.GetComponentsInChildren<ParticleSystem>(true));
    }     
}

然后以后直接使用

foreach (var torch in torches)
{
    torch.enabled = !blindmode;
}

foreach (var fire in lightfx)
{
    if(blindmode) 
        fire.Stop();
    else
        fire.Play();
}

推荐阅读