Search Unity

Cannot Trigger Sound Effect from Health Variable on another script

Discussion in 'Scripting' started by Zellcorp, Aug 24, 2016.

  1. Zellcorp

    Zellcorp

    Joined:
    Mar 29, 2014
    Posts:
    47
    Hello people I am just a student at this so please be kind.

    I have been searching for 2 days now just can't seem to find the answer I am looking for.

    I have a game where if the player kills the other enemy player, I want it to trigger an explosion sound when the enemy player's health reaches 0.

    so I have 2 scripts

    player2.cs
    and
    AudioScript.cs

    player 2 has a health variable


    Code (CSharp):
    1. public int enemyhealth = 100;
    and in that script is a function to decrease health on hit.

    Code (CSharp):
    1.       if (enemyhealth < 0)
    2.         {
    3.             Destroy(this.gameObject);
    4.         }
    and that all works fine.

    but in AudioScript.cs is where my problem lies.

    Code (CSharp):
    1. public class AudioScript : MonoBehaviour {
    2.  
    3.     //Oneshot Explode Sound
    4.     public AudioClip ExplodeSound;
    5.     private AudioSource source;
    6.     private float volLowRange = .5f;
    7.     private float volHighRange = 1.5f;
    8.  
    9.     //Reference to player2 Script
    10.     public player2 healthRef;
    11.  
    12.  
    13.     //reference to UI Manager
    14.     public InGameUIManager UIManager;
    15.  
    16.  
    17.     void Awake()
    18.     {
    19.         source = GetComponent<AudioSource>();
    20.     }
    21.  
    22.     void Start()
    23.     {
    24.         healthRef = GetComponent<player2>();
    25.     }
    26.  
    27. void Update()
    28.     {
    29.         if (healthRef.enemyhealth < 0)
    30.         {
    31.             explodeSound();
    32.         }
    33.     }
    34.  
    35.     void explodeSound()
    36.     {
    37.             float vol = Random.Range(volLowRange, volHighRange);
    38.             source.PlayOneShot(ExplodeSound, vol);
    39.     }
    40.  
    41. }
    I make a sound emmitter object, I attach AudioScript.cs to it, I attach the explosion to the script, I add an audiosource and link the sound, I link the healthRef variable to player2 in Unity.

    but when I run unity I keep getting a red error on each frame.

    when I double click the error its complaining about this line in AudioScript.cs

    Code (CSharp):
    1. if (healthRef.enemyhealth < 0)
    its like its not linking to the other script correctly or something I been trying everything I can find to make it get past this error I feel I'm really close but I am missing something.

    Any help is greatly appreciated.
     
  2. Brathnann

    Brathnann

    Joined:
    Aug 12, 2014
    Posts:
    7,188
    When your enemy health == 0, you're destroying your object, so it's probably not going to work right anyways to begin with even if you fix the problem as I mention below.

    Second issue is how you're setting up your healthRef.
    healthRef = GetComponent<Player2>(). looks at the same gameobject to try to find a Player2 script, which it can't find, so it's value is null. This is the start of your error.

    Honestly, coding a sound to play in update this way isn't the best. Your better action would be to have the player2 script call your explodesound method on the audioscript before you destroy it. This way you aren't checking constantly on health, you trigger the sound only when needed and told to.
     
  3. Zellcorp

    Zellcorp

    Joined:
    Mar 29, 2014
    Posts:
    47
    no if you read I have put the AudioScript on a empty game object and I have attached that to player1, so this is really to get around that destroy problem, I'm trying to play the sound from an empty gameobject with the AudioScript attached to it.

    if you have a code suggestion for me please post thx
     
  4. Zellcorp

    Zellcorp

    Joined:
    Mar 29, 2014
    Posts:
    47
    I did what you said I played the sound before destroy but it just destroys the object before the sound gets a chance to play so that hasn't solved it.
     
  5. Brathnann

    Brathnann

    Joined:
    Aug 12, 2014
    Posts:
    7,188
    What do you mean? I read it. You have an audioscript on an empty gameobject that is using getComponent<player2>. This isn't going to work because there is no player2 script on the same gameobject as your audioscript. Even if you drag and drop the player into the variable in the inspector, you're overwritting it in start.

    Your player2 script should call the audioscript before you destroy the player2 gameobject. I'm assuming the audioscript object has your sound on it since you're doing source = getComponent<audiosource>() which would look for the audiosource component on the same gameobject.
     
  6. Zellcorp

    Zellcorp

    Joined:
    Mar 29, 2014
    Posts:
    47
    Right so I should be getting components and calling the function from the Audioscript not the other way around. I think I understand this.
     
  7. Brathnann

    Brathnann

    Joined:
    Aug 12, 2014
    Posts:
    7,188
    Yes. You have two objects.
    Object 1 has your audioscript and audiosource. It stays in the scene. It should have a public method that plays your explosion sound when called.
    Object 2 is your player, each time player is damaged, it's health is reduced. Once it's <= 0, player script calls the audioscript on object 1 to play the explosion sound and then you can destroy the player (object 2). The sound should still play because it's still there on object 1.
     
  8. Zellcorp

    Zellcorp

    Joined:
    Mar 29, 2014
    Posts:
    47
    Ok this clears things up thanks a lot
     
  9. Zellcorp

    Zellcorp

    Joined:
    Mar 29, 2014
    Posts:
    47
    ok I have reversed things around and now attempted to call the sound effect function from the SoundEffectSpawner with the AudioScript attached to it and the function being triggered by the enemy health <0 on player2.cs

    but the damn sound still wont play!! and I seem to be back where I started where one script refuses to call functions from another.

    so this is the code in player2.cs

    Code (CSharp):
    1.  public AudioScript explode;
    2.  
    3.     void Start()
    4.     {
    5.         explode = GetComponent<AudioScript>();
    6.     }
    7.  
    8.     void OnCollisionEnter(Collision other)
    9.     {
    10.         if (other.gameObject.tag == "bullet")//change tag to bulit or enemy
    11.         {
    12.             enemyhealth = enemyhealth - 10;
    13.         }
    14.  
    15.  
    16.    void AttackSpeedandFunction()
    17.     {
    18.         if (enemyhealth < 0)
    19.         {
    20.             explode.explodeSound();
    21.             Destroy(this.gameObject);
    22.         }
    23.  
    24.  
    AudioScript.cs
    Code (CSharp):
    1. public class AudioScript : MonoBehaviour {
    2.  
    3.     //Oneshot Explode Sound
    4.     public AudioClip ExplodeSound;
    5.     public AudioSource source;
    6.     public float volLowRange = .5f;
    7.     public float volHighRange = 1.5f;
    8.  
    9.  
    10.     //reference to UI Manager
    11.     public InGameUIManager UIManager;
    12.  
    13.  
    14.     void Awake()
    15.     {
    16.         source = GetComponent<AudioSource>();
    17.     }
    18.  
    19.     void Start()
    20.     {
    21.        
    22.     }
    23.  
    24. void Update()
    25.     {
    26.  
    27.     }
    28.  
    29. public void explodeSound()
    30.     {
    31.             float vol = Random.Range(volLowRange, volHighRange);
    32.             source.PlayOneShot(ExplodeSound, vol);
    33.     }
    34.  
    35. }
    36.  
    explosion.wav is attached to the sound emitter, the health is going to 0, the gameobject is destroying......why wont it play the damn explosion?
     
  10. Brathnann

    Brathnann

    Joined:
    Aug 12, 2014
    Posts:
    7,188
    Are you getting a null error again?
    Code (CSharp):
    1. public AudioScript explode;
    2.     void Start()
    3.     {
    4.         explode = GetComponent<AudioScript>();
    5.     }
    This here is probably creating a problem. You said it's on your playerscript. So, as I pointed out, even if you drag and drop your audioscript object into the explode variable on your playerscript in the inspector, your start is telling it to check your player for a component call AudioScript, which it doesn't find, so it returns null.

    GetComponent by itself without a target object always targets the gameobject that the script is on.
    basically, look at gameobject.GetComponent as the same thing as GetComponent.

    Either you remove the line if you did a drag and drop (thus you don't overwrite the variable) or you need to have a reference to the audioscript gameobject and do

    Code (CSharp):
    1.  
    2. public GameObject audioObject;
    3.  
    4. void Start()
    5. {
    6.    explode = audioObject.GetComponent<AudioScript>();
    7. }
     
  11. Zellcorp

    Zellcorp

    Joined:
    Mar 29, 2014
    Posts:
    47
    ok I have added these lines but still I get no result.

    I have uploaded my sourcecode here.

    https://www.sendspace.com/file/py1voe

    I'm working on this game with others, maybe some of their setup in Unity is messing it up? I'm not sure.

    I get a new variable in player2 inspector AudioObject ,I add Enemy, Player1 every object available. Still no Result

    one of my team members setup this UI for resetting I'm not sure if that's causing a problem, the scene im working with is Scene1.

    if someone can have a look for me would be appreciated. thx

    controlls are WASD and mouse, move to the tank and shoot it.
     
  12. takatok

    takatok

    Joined:
    Aug 18, 2016
    Posts:
    1,496
    Your problem is your destroying your player2 GameObject before, or duing the sound playing. Here's how you can fix it:
    1. Rip out all the code , public variable relating getting the audioclip from another script
    2. add an AudioSource to your player2 object and set its clip to explosion (uncheck Play on Awake
    3. In the player2 script AttackSpeedAndFunction Remove the EnemyHealth check and Destroy call
    Then your player2 Code should look like this (this is just snippets not the complete script)
    Code (CSharp):
    1.  void Awake()
    2.     {
    3.         source = GetComponent<AudioSource>();
    4.     }
    5.  
    6.     void Start()
    7.     {
    8.         // Just here so you get a baseline for what the sound SHOULD sound like
    9.         // This plays one-time when game starts
    10.         source.PlayOneShot(Explode, 0.5f);
    11.     }
    12. void HealthFunction()
    13.     {
    14.         HealthSlider.value = enemyhealth;
    15.         if (enemyhealth == 0)
    16.         {
    17.             source.PlayOneShot(Explode, .5f);
    18.             StartCoroutine(PlaySoundAndKill());
    19.         }
    20.     }
    21.  
    22.     IEnumerator PlaySoundAndKill()
    23.     {
    24.         bool flag = true;
    25.         while (flag)
    26.         {
    27.             if (!source.isPlaying)
    28.                 flag = false;
    29.             yield return null; // Lets only check once per update till sound is done
    30.         }
    31.         // Sound is done.. NOW lets kill our guy
    32.         Destroy(this.gameObject);
    33.     }
    This will play the sound when Player2 is killed, then destroy player2 and restart game
    Note: the sound plays really long and distorted when you kill Player2. I'm not sure why this is. It has nothing to do with the CoRoutine (I checked.. I commented out all the Destroy(this.GameObject) and didn't call the CoRoutine. still played long and strangely. This will at least get you the right idea on how to use co-routines to stall other actions (like reloading the scene).
     
  13. takatok

    takatok

    Joined:
    Aug 18, 2016
    Posts:
    1,496
    Hehe it was bugging me so I figured it out the distortion bug. its because the main program keeps running while the sound is playing so it keeps seeing Health == 0 and plays another sound.. ends up playing the sound 5-6 times in a very short frame. Here's the fix:
    Code (CSharp):
    1. // In your variables
    2. private bool  isDead;
    3.  
    4. void Awake()
    5.     {
    6.         isDead = false;
    7.         source = GetComponent<AudioSource>();
    8.     }
    9.  
    10. void HealthFunction()
    11.     {
    12.         if (isDead)
    13.             return;
    14.         HealthSlider.value = enemyhealth;
    15.         if (enemyhealth == 0)
    16.         {
    17.             isDead = true;
    18.             source.PlayOneShot(Explode, .5f);
    19.             StartCoroutine(PlaySoundAndKill());
    20.         }
    21.     }
    Works perfectly now. Of course you'll need someway to tell the Player1 he can't move anymore. Basically pause the game while sound plays. Could also use this time to do something cool like animate the Restart button. Have it start really small and flipping and make it grow bigger while spinning towards you. Could time the animation to stop with a big restart button at the same time the sound file finishes Exploding.
     
  14. Zellcorp

    Zellcorp

    Joined:
    Mar 29, 2014
    Posts:
    47
    Thanks for that Ill play around with it
     
  15. Zellcorp

    Zellcorp

    Joined:
    Mar 29, 2014
    Posts:
    47
    No I am still getting red lines and errors

    I cannot see what you have called your variables at the top of player2.cs, I am getting red lines under Explode

    Code (CSharp):
    1.  void HealthFunction()
    2.     {
    3.         HealthSlider.value = enemyhealth;
    4.         if (enemyhealth == 0)
    5.         {
    6.             source.PlayOneShot(Explode, .5f);
    7.             StartCoroutine(PlaySoundAndKill());
    8.         }
    9.  
    10.     }
    Red line under Explode - cannot convert from 'AudioScript' to 'UnityEngine.AudioClip'
     
  16. takatok

    takatok

    Joined:
    Aug 18, 2016
    Posts:
    1,496
    Somewhere Explode is not declared correctly. Do you have public AudioClip Explode; declared at the top of the file? Then you have to drag your explode sound into it, in the editor. Sounds like you didn't fully get rid of all the code that was trying to call the sound from another script