【问题标题】:How to play particles for a specific cloned game object in Unity?如何在 Unity 中为特定的克隆游戏对象播放粒子?
【发布时间】:2020-06-05 09:17:31
【问题描述】:

我现在正在 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);

    }

}

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

【问题讨论】:

  • 不使用static(滥用单例模式)?并且不使用FindObjectOfType 而是使用GetComponent ...您的ParticleSystem 附加到什么?

标签: c# unity3d particles particle-system


【解决方案1】:
  1. 从立方体中移除与圆锥相关的逻辑:

    private void OnCollisionEnter(碰撞碰撞) { if (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();
        }

    }

}

【讨论】:

    【解决方案2】:

    正如我所见,您(ab!)对所有事情都使用单例模式,并调用了很多东西 static,而应该是实例化的方法/属性。


    所以假设每个预制件都有你的 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 似乎“没问题”,因为GameDirector 听起来像是场景中只存在一次的东西。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-04-04
      • 1970-01-01
      • 2017-05-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多