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

Drowning Script Only (NOT SWIMMING)

Discussion in 'Scripting' started by ShatterGlassGames, Nov 15, 2016.

  1. ShatterGlassGames

    ShatterGlassGames

    Joined:
    Jan 14, 2016
    Posts:
    135
    I asked this question in the Answers tab a week ago and haven't got any reply so i figure that maybe someone here can help me out here.
    ------------------------------
    Hi guys, I was wondering if anyone can please help me out with a script that triggers a component at a certain depth. Basically I'm trying to do a drowning script. I already have the swimming script that triggers with the collider of the player but I can't do the same because I can't add a collider to the camera. Basically I want a breath meter I created to trigger below a "Y" axis height and to reset once you go above the "Y" axis but I can't figure out how to do this. Can some please help me with how I should declare the value and how to start this script? I can do the rest but I just don't know how to do the y axis portion.

    I will use 2 separate script. 1 for swimming (done) and 1 for holding the breath. once both re complete I'll try to put them together.
     
  2. Hyblademin

    Hyblademin

    Joined:
    Oct 14, 2013
    Posts:
    725
    A quick outline:

    Code (CSharp):
    1. public float waterLevel;
    2. public float drownTime;
    3.  
    4. private float drownTimer;
    5.  
    6. if (transform.position.y < waterLevel)  //Checks the y-position
    7. {
    8.     drownTimer += Time.deltaTime;
    9. }
    10. else
    11. {
    12.     drownTimer = 0;
    13. }
    14.  
    15. if (drownTimer > drownTime)
    16. {
    17.     //Mercilessly drown the player character here (you monster)
    18. }
    It increments the time spent underwater when under the water level, and resets it to 0 when above it. If you spend more than drownTime under the water level, you call the drowning logic.

    Is this what you're looking for?
     
    JoeStrout likes this.
  3. ShatterGlassGames

    ShatterGlassGames

    Joined:
    Jan 14, 2016
    Posts:
    135
    Hmm that sort of works but i just realized that i can't use y axis as well because i have different water section at different altitudes. I had an idea of using a whole new trigger box and placing it about 6 feet below the swimming trigger. With that i managed to make the player basically made the body (not the head) of the player enter a whole new trigger that triggers the underwater fiction of the hold breath script. Now i'm trying to figure out how i can make the meter regenerate when the player exits the collider. Maybe you can help me with that section? below are the two scripts i;m using to preform this task. If anyone has an easier way of doing this and would like to share it please do. I will appreciate it. Also please excuse my code if it's kind of messy but I'm a C# noob.


    --------------------------------------------------
    Underwater Trigger:
    --------------------------------------------------
    ///////////////////////////////////////////////////////////
    ///
    /// Drowning trigger.
    ///
    ///////////////////////////////////////////////////////////

    using UnityEngine;
    using System.Collections;

    public class DrowningTrigger : MonoBehaviour {
    public DrowningScript _DrowningScript;

    void OnTriggerStay(Collider player){
    if (player.tag == "Player") {
    _DrowningScript.UnderWater ();
    }
    }

    void OnTriggerExit(Collider player){
    if (player.tag == "Player") {
    _DrowningScript.AboveWater ();
    }
    }
    }


    --------------------------------------------------
    UI Scripts:
    --------------------------------------------------
    /////////////////////////////////////////////////////////
    ///
    /// Drowning Script. (UI Meter)
    ///
    /////////////////////////////////////////////////////////

    using UnityEngine;
    using System.Collections;
    using UnityEngine.UI;

    [RequireComponent(typeof(AudioSource))]

    public class DrowningScript : MonoBehaviour
    {
    Image fillImg;
    public float timeAmt = 35;
    float time;
    public AudioClip DrownDeathSfx;
    public AudioClip BreathSfx;

    void Start()
    {
    fillImg = this.GetComponent<Image>();
    time = timeAmt;
    }

    public void UnderWater(){
    if (time > 0) {
    time -= Time.deltaTime;
    fillImg.fillAmount = time / timeAmt;
    if (time <= 0) {
    GetComponent<AudioSource> ().clip = DrownDeathSfx;
    GetComponent<AudioSource> ().Play ();
    }
    }
    }

    public void AboveWater(){
    fillImg.fillAmount = 35f; //sets the meter back to 35 but will start from last update when enter the water :(
    }
    }
     
  4. melle

    melle

    Joined:
    Nov 6, 2016
    Posts:
    16
    It's easier if you set your variable 'fillmg.fillAmount' to be 'time / timeAmt' in the update Method.
    Then in the 'AboveWater' method, simply do this to slowly regenerate your 'time' veriable:

    Code (CSharp):
    1. private float regenSpeed = 0.5f;
    2.  
    3. public void AboveWater()
    4. {
    5.     if (time <= timeAmt)
    6.     {
    7.         time += regenSpeed;
    8.     }
    9.     else
    10.     {
    11.         time = timeAmt;
    12.     }
    13. }
    14.  
    15. void Update()
    16. {
    17.     fillmg.fillAmount = time / timeAmt;
    18. }
    I haven't tested it, message me if you get any errors or something is not working.
     
  5. ShatterGlassGames

    ShatterGlassGames

    Joined:
    Jan 14, 2016
    Posts:
    135
    I tried it and It stops when you exit the trigger but won't regenerate.
     
  6. ShatterGlassGames

    ShatterGlassGames

    Joined:
    Jan 14, 2016
    Posts:
    135
    Of so i was able to go around the issue that the regeneration stopped about less than 1 sec after stepping away of the trigger. I basically made it regenerate instantly by making the regenSpeed the same amount as the timeAmt.
     
  7. melle

    melle

    Joined:
    Nov 6, 2016
    Posts:
    16
    Sorry for the late fix, but of course the OnTriggerExit will only be ran once.

    You simply need to make a flag to tell if you're in the water or outside.

    Here is an example script that would enable slow regeneration, other than resetting the breath instantly:

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3. using UnityEngine.UI;
    4.  
    5. [RequireComponent(typeof(AudioSource))]
    6.  
    7. public class DrowningScript : MonoBehaviour
    8. {
    9.     Image fillImg;
    10.     public float timeAmt = 35;
    11.     float time;
    12.     public AudioClip DrownDeathSfx;
    13.     public AudioClip BreathSfx;
    14.  
    15.     float regenSpeed = 0.5f;
    16.     bool inWater;
    17.  
    18.     void Start()
    19.     {
    20.         fillImg = this.GetComponent<Image>();
    21.         time = timeAmt;
    22.     }
    23.  
    24.     public void UnderWater(){
    25.         inWater = true;
    26.     }
    27.  
    28.     public void AboveWater(){
    29.         inWater = false;
    30.     }
    31.  
    32.     void Update()
    33.     {
    34.         if (inWater)
    35.         {
    36.             if (time > 0) {
    37.                 time -= Time.deltaTime;
    38.             }
    39.             else
    40.             {
    41.                 GetComponent<AudioSource> ().clip = DrownDeathSfx;
    42.                 GetComponent<AudioSource> ().Play ();
    43.             }
    44.         }
    45.         else
    46.         {
    47.             if (time >= timeAmt)
    48.                 return;
    49.  
    50.             time += regenSpeed;
    51.         }
    52.         fillImg.fillAmount = time / timeAmt;
    53.     }
    54. }
    Again, please reply if you have any problems.
    Also, change the OnTriggerStay to OnTriggerEnter, it's more performance effecient.
     
    Last edited: Nov 16, 2016
    ShatterGlassGames likes this.
  8. ShatterGlassGames

    ShatterGlassGames

    Joined:
    Jan 14, 2016
    Posts:
    135
    WOW that did the trick. Thank you very much for your help. Below is the project i'm working on and I will be adding your name to the credits.

    Perish - New Life Redemption
     
  9. ShatterGlassGames

    ShatterGlassGames

    Joined:
    Jan 14, 2016
    Posts:
    135
    Hmm. the script works flawless with the meter but the audio is now broken. I believe it's because it set to the Update function. I tried using the playoneshot method but it still loops constantly. I also tried setting the playoneshot to run when (time <=0) but the loops keeps on. below is what i tried.

    1. if (inWater)
    2. {
    3. if (time > 0)
    4. {
    5. time -= Time.deltaTime;
    6. }
    7. else
    8. {
    9. audio.PlayOneShot(DrownDeathSfx, 1F);
    10. }
    11. }


    I also tried:

    1. if (inWater)
    2. {
    3. if (time > 0)
    4. {
    5. time -= Time.deltaTime;
    6. if (time<=0)
    7. {
    8. audio.PlayOneShot(DrownDeathSfx, 1F);
    9. }
    10. }
    11. }
     
  10. AtomicCabbage33

    AtomicCabbage33

    Joined:
    Aug 31, 2015
    Posts:
    141
    Have you checked to see if the looping boolean is set to true on the audiosource?
     
  11. AtomicCabbage33

    AtomicCabbage33

    Joined:
    Aug 31, 2015
    Posts:
    141
    If it isn't, then you could call a function which then plays the sound.

    Code (CSharp):
    1. if (time > 0)
    2. {
    3.     time -= Time.deltaTime;
    4.     if (time<=0)
    5.     {
    6.         playSound();
    7.     }
    8. }
    9.  
    10. void playSound() //place this outside the update function
    11. {
    12.     audio.PlayOneShot(DrownDeathSfx, 1F);
    13. }
    14.  
     
  12. melle

    melle

    Joined:
    Nov 6, 2016
    Posts:
    16
    That's an easy fix just add this check before you play the sound:

    Code (CSharp):
    1. if (audio.isPlaying)
    2.     return;
     
    ShatterGlassGames likes this.
  13. melle

    melle

    Joined:
    Nov 6, 2016
    Posts:
    16
    Sorry but that wouldn't work as the function you created is in the Update method, thus being ran every frame.
     
  14. AtomicCabbage33

    AtomicCabbage33

    Joined:
    Aug 31, 2015
    Posts:
    141
    Hence why I said don't put it in the Update function
     
  15. melle

    melle

    Joined:
    Nov 6, 2016
    Posts:
    16
    Okay, then it's really unclear how you meant it, either you don't understand when you call methods in the Update method they'll be ran every frame, or you made it really unclear. Your example clearly shows the method inside the update method. Your note makes no sense.
     
  16. AtomicCabbage33

    AtomicCabbage33

    Joined:
    Aug 31, 2015
    Posts:
    141
    I put 'place this outside the update function' what is not to understand
     
  17. melle

    melle

    Joined:
    Nov 6, 2016
    Posts:
    16
    The whole thing, what do you want to be placed 'outside' the update function?

    Remember, calling functions that aren't litterally 'in' the Update function but are 'called' in the Update function will behave the same as if it was 'in' the Update function.

    Example to clearup what we're talking about:

    Code (CSharp):
    1. void Update()
    2. {
    3.     NotInUpdate(); // Called in the update function
    4. }
    5.  
    6. void NotInUpdate()
    7. {
    8.  
    9.     if (value)
    10.         return;
    11.  
    12.    //This is still inside the update function.
    13. }
    This is the exact same as if you would write it like this:

    Code (CSharp):
    1. void Update()
    2. {
    3.     if (value)
    4.         return; //The same as above, inside the Update function.
    5. }
     
    Last edited: Nov 16, 2016
  18. ShatterGlassGames

    ShatterGlassGames

    Joined:
    Jan 14, 2016
    Posts:
    135
    I know there could be several ways to make this work. That's why programming is great. I do have to say that the sound now works fine with the small fix melle suggested. The sound plays 1 time and doesn't loop anymore. Below is the portion of the script i updates with melles info.


    void Update()
    {
    if (inWater)
    {
    if (time > 0)
    {
    time -= Time.deltaTime;
    if (audio.isPlaying)
    return;

    if (time <= 0) {
    audio.PlayOneShot (DrownDeathSfx, 1F);
    }
    }
    }
    else
    {
    if (time >= timeAmt)
    return;

    time += regenSpeed;
    }
    fillImg.fillAmount = time / timeAmt;
    }
     
  19. melle

    melle

    Joined:
    Nov 6, 2016
    Posts:
    16
    Thanks for replying. Have a great day.
     
    ShatterGlassGames likes this.
  20. AtomicCabbage33

    AtomicCabbage33

    Joined:
    Aug 31, 2015
    Posts:
    141
    @melle well seeing as my note is placed directly next to the function, I would assume that you had the initiative to realise that the function needs to be placed outside the Update() function. And what, so your saying that a function that isn't inside the update function will still behave like it is, makes sense that :')
     
  21. melle

    melle

    Joined:
    Nov 6, 2016
    Posts:
    16
    I see now, you don't understand. Calling methods in the update function will make the function to be ran every frame. It may be outside the method, it will behave the same! If you don't understand, please watch some basic C# tutorials.
     
  22. AtomicCabbage33

    AtomicCabbage33

    Joined:
    Aug 31, 2015
    Posts:
    141
    If it is not inside the Update function, it will not be ran every frame lmao I don't know if your just arrogant or genuinely stupid. The only exception to this rule is OnGUI which gets called everyframe
     
  23. melle

    melle

    Joined:
    Nov 6, 2016
    Posts:
    16
    If you call it in the Update function like you did, It WILL be ran every frame.

    Code (CSharp):
    1. void Update()
    2. {
    3.     RanEveryFrame();
    4. }
    5.  
    6. void RanEveryFrame()
    7. {
    8.     //Ran every frame.
    9. }
     
  24. AtomicCabbage33

    AtomicCabbage33

    Joined:
    Aug 31, 2015
    Posts:
    141
    If you refer to the plain green text next to it (a comment) you will discover that I told him not to put it in the Update function. Do you understand the concept of a comment or what? I could have just included two different snippets of code yes, but for the sake of saving time I thought I would just add it into his and then write an extremely obvious comment next to it clearly stating that it is not meant to go inside that function
     
  25. melle

    melle

    Joined:
    Nov 6, 2016
    Posts:
    16
    Your comment was next to the function self, not the call. You are in-correct.

    Code (CSharp):
    1. void Update()
    2. {
    3.     Method();
    4. }
    5.  
    6. void Method() //Don't put the method in the update function.
    7. {
    8.     //Code
    9. }
    Don't you understand? Your comment makes no sense, the function is not litterally in the update function, it's called from the update function. It would've made more sense if you did this:

    Code (CSharp):
    1. void Update()
    2. {
    3.     Method();//Don't put the call in the update method, the function will be ran every frame.
    4. }
    5.  
    6. void Method()
    7. {
    8.     //Code
    9. }
     
  26. AtomicCabbage33

    AtomicCabbage33

    Joined:
    Aug 31, 2015
    Posts:
    141
    Code (CSharp):
    1. //place this outside the update function
    2. //place this outside the update function
    3. //place this outside the update function
    4. //place this outside the update function
    5. //place this outside the update function
    6. //place this outside the update function
    7.  
     
  27. AtomicCabbage33

    AtomicCabbage33

    Joined:
    Aug 31, 2015
    Posts:
    141
    Well yes, because the function needs to be placed outside of Update, not the call :')
     
  28. melle

    melle

    Joined:
    Nov 6, 2016
    Posts:
    16
    So what were you trying to achieve with this comment? Saying it shouldn't be in the Update method has nothing to do with this topic at all, if the guy who posted this question would try out your solution it wouldn't simply work as the function you commented about is ran every frame, thus playing the sound again every frame.

    Your post and comment both make no sense, try to explain it more, or leave it.