如何在 Unity 中为特定的克隆游戏对象播放粒子?

How to play particles for a specific cloned game object in Unity?

我现在正在用Unity做一个简单的游戏。有锥体从天而降,玩家需要控制一个立方体来躲避它们。当锥体撞击立方体时,它会降低立方体的 HP 并发射一些粒子。这是我的脚本:

public class move : MonoBehaviour{

ParticleSystem particle;

static move instance;

void Start()
{
    particle = FindObjectOfType<ParticleSystem>();
    instance = this;
}

public static void PlayParticles()
{
    instance.particle.Play();
}
}

第二个:

private void OnCollisionEnter(Collision collision)
{
    if (collision.gameObject.CompareTag("cone"))
    {
        move.PlayParticles();
        GameDirector.DecreaseHp(0.25f);

    }

}

第一个脚本附加到圆锥体预制件,第二个脚本附加到立方体。但问题是,当一个锥体撞击立方体时,其他锥体会发射粒子,而不是撞击立方体的锥体。 我该如何解决这个问题? 非常感谢任何帮助!

  1. 从立方体中删除圆锥体相关逻辑:

    private void OnCollisionEnter(碰撞碰撞) { 如果 (collision.gameObject.CompareTag("cone")) { // move.PlayParticles(); //------------ 删除这一行 GameDirector.DecreaseHp(0.25f); }

    }

  2. 使粒子变量可在检查器中分配 - 添加 [SerializeField] 属性。并在 inspector 中赋值。

  3. 将碰撞处理添加到您的圆锥体脚本中。
  4. 从脚本中删除不必要的静态信息。

像这样:

public class move : MonoBehaviour
{

[SerializeField] //------- Add attribute and do not forget to assign PS in inspector
ParticleSystem particle;

//static move instance; //----- Remove

//Remove Start:
/*
    void Start()
    {
        particle = FindObjectOfType<ParticleSystem>();
        instance = this;
    }
*/
//Remove PlayParticles:
/*
    public void PlayParticles()
    {
        Change:
        instance.particle.Play();
    }
*/
    //---- Add collision check
    private void OnCollisionEnter(Collision collision)
    {
        if (collision.gameObject.CompareTag("cube")) //----- Set proper tag to your cube
        {
            particle.Play();
        }

    }

}

正如我所看到的,您(ab!)对所有内容都使用单例模式并调用了很多应该实例化的东西 static methods/properties。


所以假设每个预制件都有您的 move 脚本以及 ParticleSystem 在其自己的层次结构中的某个地方,您可以这样做

public class move : MonoBehaviour
{
    // Already reference this via the Inspector by dragging the 
    // GameObject with the ParticleSystem into this slot
    [SerializeField] private ParticleSystem particle;

    private void Awake()
    {
        // As fallback get it on runtime
        if(!particle) particle = GetComponentInChildren<ParticleSystem>(true);
    }

    // Use a normal instanced method
    public void PlayParticles()
    {
        particle.Play();
    }
}

然后从碰撞中获取实例:

private void OnCollisionEnter(Collision collision)
{
    if (collision.gameObject.CompareTag("cone"))
    {
        // Get the instance of the component
        var moveInstance = collision.gameObject.GetComponent<move>();
        if(!moveInstance)
        {
             Debug.LogError($"There is no {nameof(move)} component attached to the colliding object {collision.gameObject.name}!", this);   
        }
        else
        {
            // call the method of this instance
            moveInstance.PlayParticles();
        }
        GameDirector.DecreaseHp(0.25f);
    }
}

但似乎您也可以让您的播放器自己直接处理整个事情。而是将粒子系统附加到它上面,然后将 move 放在播放器(立方体)上,如

public class move : MonoBehaviour
{
    // Already reference this via the Inspector by dragging the 
    // GameObject with the ParticleSystem into this slot
    [SerializeField] private ParticleSystem particle;

    void Start()
    {
        if(!particle) particle = GetComponentInChildren<ParticleSystem>(true);
    }

    private void OnCollisionEnter(Collision collision)
    {
        if (collision.gameObject.CompareTag("cone"))
        {
            particle.Play();
            GameDirector.DecreaseHp(0.25f);
        }
    }
}

注意GameDirector可能是一样的,你应该有一个字段

[SerilaizeField] private GameDirector gameDirector;

并通过检查器引用它或(仅作为后备)通过

在运行时获取它
private void Awake()
{
    if(!gameDirector) gameDirector = FindObjectOfType<GameDirector>();
}

这里 FindObjectOfType 似乎是 "ok" 因为 GameDirector 听起来像是在场景中只存在 一次 的东西。