Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice
  3. Join us on November 16th, 2023, between 1 pm and 9 pm CET for Ask the Experts Online on Discord and on Unity Discussions.
    Dismiss Notice

[SOLVED] Particle effect activated when it's not supposed to

Discussion in 'Scripting' started by PlazmaInteractive, Sep 24, 2016.

  1. PlazmaInteractive

    PlazmaInteractive

    Joined:
    Aug 8, 2016
    Posts:
    114
    (Long post ahead...)
    Hello guys.
    So, I've got quite a confusing problem that I've been trying to fix since yesterday but to no avail. I've got no idea why this is happening and would like inputs from other people.

    First off, I've been trying to get effects to play when the player collects a powerup. I successfully did it but there's a bug of some sort. So, when the player collects a powerup, a public method from another script is called to activate the particle effect. However, for some weird reason, when I start the game and move the player forward, the method gets called when it shouldn't. The method should get called only when the player collected the powerup, not move forward. So I checked my entire game to find where the problem occurs and here's what I analysed...
    • When the player moves forward, the particle effect played, however, when the player moves backward first, the particle effect doesn't play.
    • If the player doesn't move in the start of the game, no particle effect can be seen but as soon as I start moving the player forward, the particle effect can be seen.
    This leads me to a conclusion that the bug must have something to do with player movement. The only script that has something to do with particle effect and player movement is my Thruster script which controls thruster on/off based on player's current movement/behaviour.
    Thruster script (located in thruster particle system):
    Code (csharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class ThrusterController : MonoBehaviour
    5. {
    6.     private bool isThrust = false;
    7.  
    8.     void Update()
    9.     {
    10.         var em = gameObject.GetComponent<ParticleSystem>().emission;
    11.  
    12.         // Thruster on/off
    13.         if (Input.GetKey(KeyCode.UpArrow) || Input.GetKey(KeyCode.W) && isThrust == false)
    14.         {
    15.             isThrust = true;
    16.             em.enabled = true;
    17.         }
    18.         else
    19.         {
    20.             isThrust = false;
    21.             em.enabled = false;
    22.         }
    23.     }
    24. }
    Not sure if it has something to do with the thruster script. I debugged the game and found out the public method still gets called from another script. The Powerup script controls which powerup is collected, while the Player script has a public method that activates the particle effects.
    Powerup script (located in each powerup prefab):
    Code (csharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class PowerupSystem : MonoBehaviour
    5. {
    6.     public bool isHealth;
    7.     public bool isShield;
    8.     public bool isDamage;
    9.     public bool isRate;
    10.  
    11.     private GameObject player;
    12.     private GameObject shield;
    13.  
    14.     void Start()
    15.     {
    16.         shield = GameObject.FindWithTag("Shield");
    17.         player = GameObject.FindWithTag("Player");
    18.     }
    19.  
    20.     void OnTriggerEnter2D(Collider2D other)
    21.     {
    22.         if(other.gameObject.tag == "Player")
    23.         {
    24.             if (isHealth)
    25.             {
    26.                 PlayerStatsController playerStats = other.GetComponent<PlayerStatsController>();
    27.  
    28.                 playerStats.CurHealth += 50f;
    29.                 Destroy(gameObject);
    30.             }
    31.  
    32.             if (isShield)
    33.             {
    34.                 shield.GetComponent<SpriteRenderer>().enabled = true;
    35.                 shield.GetComponent<Collider2D>().enabled = true;
    36.                 shield.GetComponent<ShieldController>().isActivated = true;
    37.                 Destroy(gameObject);
    38.             }
    39.  
    40.             if (isDamage)
    41.             {
    42.                 player.GetComponent<PlayerController>().SetDamagePower();
    43.                 Debug.Log("Damage powerup collected!"); // Somehow, this gets called...
    44.                 Destroy(gameObject);
    45.             }
    46.  
    47.             if (isRate)
    48.             {
    49.                 player.GetComponent<PlayerController>().SetRatePower();
    50.                 Destroy(gameObject);
    51.             }
    52.         }
    53.     }
    54. }
    Player script (located in player gameobject, check line 149 for the public method that activates particle):
    Code (csharp):
    1. using UnityEngine;
    2. using UnityEngine.UI;
    3. using System.Collections;
    4.  
    5. public class PlayerController : MonoBehaviour
    6. {
    7.     public float bound;
    8.     public float powerupTime;
    9.     public StatusIndicator status;
    10.     public GameObject[] weaponTypes;
    11.     public GameObject gameOverText;
    12.     public GameObject gameOverButton;
    13.     public Text coinText;
    14.     public LayerMask collectiblesLayer;
    15.  
    16.     [HideInInspector]
    17.     public int curCoin;
    18.     [HideInInspector]
    19.     public int lastCoin;
    20.     [HideInInspector]
    21.     public int displayedCoin;
    22.     [HideInInspector]
    23.     public float coinTimer;
    24.  
    25.     private int currentWeaponType;
    26.     private bool isDamagePowered;
    27.     private bool isRatePowered;
    28.     private bool isAlreadyDamage;
    29.     private bool isAlreadyRate;
    30.     private float shakeAmount;
    31.     private Rigidbody2D player;
    32.     private GameObject shield;
    33.     private GameObject damageEffect;
    34.     private GameObject rateEffect;
    35.     private PlayerStatsController stats;
    36.     private WeaponStatsController[] weaponStats;
    37.  
    38.     void Awake()
    39.     {
    40.         damageEffect = GameObject.FindWithTag("DamageEffect");
    41.         rateEffect = GameObject.FindWithTag("RateEffect");
    42.     }
    43.  
    44.     void Start()
    45.     {
    46.         player = GetComponent<Rigidbody2D>();
    47.         stats = GetComponent<PlayerStatsController>();
    48.         shield = GameObject.FindWithTag("Shield");
    49.         damageEffect.SetActive(false);
    50.         rateEffect.SetActive(false);
    51.         stats.CurHealth = stats.maxHealth;
    52.         SwitchWeaponType(currentWeaponType);
    53.     }
    54.  
    55.     void Update()
    56.     {        
    57.         coinTimer += Time.deltaTime;
    58.         float progress = coinTimer / 0.5f;
    59.         displayedCoin = (int)Mathf.Lerp(lastCoin, curCoin, progress);
    60.         coinText.text = "Coins: " + displayedCoin;
    61.  
    62.         if (stats.CurHealth <= 0)
    63.         {
    64.             Time.timeScale = 0;
    65.             gameOverText.SetActive(true);
    66.             gameOverButton.SetActive(true);
    67.             Destroy(gameObject);
    68.         }
    69.  
    70.         status.SetHealth(stats.CurHealth, stats.maxHealth);
    71.  
    72.         if (Input.GetKeyDown(KeyCode.Q))
    73.         {
    74.             currentWeaponType = 0;
    75.             SwitchWeaponType(currentWeaponType);
    76.         }
    77.         if (Input.GetKeyDown(KeyCode.E))
    78.         {
    79.             currentWeaponType = 1;
    80.             SwitchWeaponType(currentWeaponType);
    81.         }
    82.  
    83.         Collider2D[] collectibles = Physics2D.OverlapCircleAll(transform.position, 1f, collectiblesLayer);
    84.         if (collectibles != null)
    85.         {
    86.             foreach (var collectible in collectibles)
    87.             {
    88.                 collectible.transform.position = Vector3.MoveTowards(collectible.transform.position, transform.position, 2f * Time.deltaTime);
    89.             }
    90.         }
    91.     }
    92.  
    93.     void FixedUpdate()
    94.     {
    95.         float horizontal = Input.GetAxis("Horizontal");
    96.         float vertical = Input.GetAxis("Vertical");
    97.  
    98.         // Movement
    99.         player.velocity = transform.up * stats.speed * vertical;
    100.         transform.Rotate(0, 0, horizontal * -stats.rotateSpeed);
    101.  
    102.         transform.position = new Vector2(Mathf.Clamp(transform.position.x, -bound, bound), Mathf.Clamp(transform.position.y, -bound, bound));
    103.     }
    104.  
    105.     IEnumerator OnTriggerEnter2D(Collider2D other)
    106.     {
    107.         if (!shield.GetComponent<ShieldController>().isActivated)
    108.         {
    109.             if (other.GetComponent<EnemyStatsController>() != null)
    110.             {
    111.                 stats.CurHealth -= other.GetComponent<EnemyStatsController>().collisionDamage;
    112.             }
    113.  
    114.             if (other != null && other.gameObject.tag == "Ice")
    115.             {
    116.                 stats.speed = stats.speed / 1.2f;
    117.                 stats.rotateSpeed = stats.rotateSpeed / 1.2f;
    118.  
    119.                 yield return new WaitForSeconds(4);
    120.  
    121.                 stats.speed = stats.speed * 1.2f;
    122.                 stats.rotateSpeed = stats.rotateSpeed * 1.2f;
    123.             }
    124.         }
    125.  
    126.         if (other != null && other.gameObject.tag == "Coin")
    127.         {
    128.             lastCoin = displayedCoin;
    129.             curCoin += (int)other.GetComponent<CoinController>().reward;
    130.             coinTimer = 0f;
    131.         }
    132.     }
    133.  
    134.     void SwitchWeaponType(int index)
    135.     {
    136.         for (int i = 0; i < weaponTypes.Length; i++)
    137.         {
    138.             if (i == index)
    139.             {
    140.                 weaponTypes[i].gameObject.SetActive(true);
    141.             }
    142.             else
    143.             {
    144.                 weaponTypes[i].gameObject.SetActive(false);
    145.             }
    146.         }
    147.     }
    148.  
    149.     public void SetDamagePower()
    150.     {
    151.         weaponStats = FindObjectsOfType<WeaponStatsController>();
    152.         isDamagePowered = true;
    153.  
    154.         if (isDamagePowered)
    155.         {
    156.             damageEffect.SetActive(true);
    157.             var em = damageEffect.GetComponent<ParticleSystem>().emission;
    158.             em.enabled = true;
    159.             if (!isAlreadyDamage)
    160.             {
    161.                 foreach (var weaponStat in weaponStats)
    162.                 {
    163.                     weaponStat.damage *= 2;
    164.                 }
    165.  
    166.                 isAlreadyDamage = true;
    167.             }
    168.             CancelInvoke("ExpireDamage");
    169.             Invoke("ExpireDamage", powerupTime);
    170.         }
    171.     }
    172.  
    173.     public void SetRatePower()
    174.     {
    175.         weaponStats = FindObjectsOfType<WeaponStatsController>();
    176.         isRatePowered = true;
    177.  
    178.         if (isRatePowered)
    179.         {
    180.             rateEffect.SetActive(true);
    181.             Debug.Log("Particle effect playing");
    182.             var em = rateEffect.GetComponent<ParticleSystem>().emission;
    183.             em.enabled = true;
    184.             if (!isAlreadyRate)
    185.             {
    186.                 foreach (var weaponStat in weaponStats)
    187.                 {
    188.                     weaponStat.fireRate /= 2;
    189.                 }
    190.             }
    191.  
    192.             isAlreadyRate = true;
    193.         }
    194.         CancelInvoke("ExpireRate");
    195.         Invoke("ExpireRate", powerupTime);
    196.     }
    197.  
    198.     void ExpireDamage()
    199.     {
    200.         isDamagePowered = false;
    201.         if (isAlreadyDamage)
    202.         {
    203.             var em = damageEffect.GetComponent<ParticleSystem>().emission;
    204.             em.enabled = false;
    205.             foreach (var weaponStat in weaponStats)
    206.             {
    207.                 weaponStat.damage /= 2;
    208.             }
    209.         }
    210.         isAlreadyDamage = false;
    211.     }
    212.  
    213.     void ExpireRate()
    214.     {
    215.         isRatePowered = false;
    216.         if (isAlreadyRate)
    217.         {
    218.             var em = rateEffect.GetComponent<ParticleSystem>().emission;
    219.             em.enabled = false;
    220.             foreach (var weaponStat in weaponStats)
    221.             {
    222.                 weaponStat.fireRate *= 2;
    223.             }
    224.         }
    225.         isAlreadyRate = false;
    226.     }
    227. }
    Just so you know what's happening, I got GIFs of the problems. Notice how in one GIF, the game works fine when player moves backward then collects powerup while in the other GIF, the particle effects activates when player moves forward. Also, notice how no particles are played if the player doesn't move in the beginning. The smoke effect is the particle that's getting activated.
    http://imgur.com/a/avZcR
     
  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,807
    Unity particles can be set to "emit over distance" rather than "emit over time," a setting in the particle system. Are you sure that isn't going on?

    The other thing to make sure is you don't have another "stray" particle system attached to your script, like from a mis-click or mis-drag of the mouse. The particles in your GIF look like they're a different color.

    In your scene you can type "ParticleSystem" in the search field and it will find that component on any object, as well as find it by name.
     
  3. PlazmaInteractive

    PlazmaInteractive

    Joined:
    Aug 8, 2016
    Posts:
    114
    Emit over distance didn't do anything to fix it and I want the particles to emit over time anyways. There is no stray particles in my scene and I can assure you that the particles in the GIF is the same one (zoom in and you can see the faint blue tint in both GIFs). I'm not sure if this has to do with this but all my particle effects are placed under one gameobject, which is the player. So the thruster, damage effect and rate effect (fire rate powerup) are placed under my player gameobject.

    Here's a pic of what the hierarchy looks like in the beginning of the game (I didn't move my player):
    Capture.PNG
    And a pic of the hierarchy when I move player forward:
    Capture2.PNG
    You can see that the DamageEffect particle is not activated at first, but once I start moving my player, it got activated... By the way ignore the HealthEffect particle gameobject, was creating new particles.
     
  4. PlazmaInteractive

    PlazmaInteractive

    Joined:
    Aug 8, 2016
    Posts:
    114
    Alright, I think it's best if I gave you guys the unitypackage file of my project so far so you guys can hunt down the problem practically too. I'm sorry that the project is kinda messy so yeah. Play the game and move forward to see if you guys have any particle problems too or not.
    Here's the download link (apparently, file was too big to upload to forums):
    http://s000.tinyupload.com/index.php?file_id=88947719668975518324
     
  5. PVisser

    PVisser

    Joined:
    Apr 24, 2014
    Posts:
    61
    I've read your description and though I'm not deep into programming I've been messing around with particles for the past few weeks so maybe I can help you in that way. Are those particles separated in the hierarchy so one does not get called by accident? Have you set the problem particle to prewarm or play on awake, maybe mess around in the particle settings to see if there's a problem there if you feel that the coding is solid.

    *nvm just saw the gifs.
     
    Last edited: Sep 26, 2016
  6. ArachnidAnimal

    ArachnidAnimal

    Joined:
    Mar 3, 2015
    Posts:
    1,727
    I don't know what version of unity you are running, but when I was using Unity 5.2.3 I noticed that many OnTriggerEnters were being called as soon as the game started, even when it was impossible for this to be occurring based on the starting position of the colliders.
    Figure out if your OnTriggerEnter2D is being called when you very first start the game.
     
  7. PlazmaInteractive

    PlazmaInteractive

    Joined:
    Aug 8, 2016
    Posts:
    114
    Hey guys, sorry I didn't let you guys know but I've already solved the problem. I just delete the powerup prefab and make a new one so I conclude that the problem must be from the powerup prefab and not the script or particles. Thanks anyways.
     
    Kurt-Dekker likes this.
  8. ReadyVR_Official

    ReadyVR_Official

    Joined:
    Jan 14, 2022
    Posts:
    1
    Omg I was trying create a scripts to do that when I didn't check the particle system options. Thank you sir
     
    Kurt-Dekker likes this.