Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 13 Next capture
2021 2022 2023
1 capture
13 Jun 22 - 13 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
0
Question by NerdRageStudios · Jul 15, 2014 at 04:38 PM · yield

problems with damage over time script

Hi, I am trying to create a script that is attached to the player that can be triggered when I want to apply damage over time.

The problem is that it seems to remove a random amount from the player, and also does it in about 2 seconds flat.

Can someone tell me what is wrong with my code please?

 using UnityEngine;
 using System.Collections;
 
 public class ScripPlayerOnePoisoned : MonoBehaviour {
 
     public float dmgAmount = 40;
     bool enable;
     ScriptPlayerOneManager script;
 
     // Use this for initialization
     void Start () 
     {
     script = GameObject.Find("PrefabPlayerOne").GetComponent<ScriptPlayerOneManager>();
     }
     
     // Update is called once per frame
     void Update () 
     {
     if (script.playerStatus.playerOnePoisoned == true)
          {
              StartCoroutine(playerOnePoisoned());
              playerOnePoisoned();
          }
     }
 
     public IEnumerator playerOnePoisoned()
     {
 
 
         if (dmgAmount >= 0)
 
         {
             script.playerActualAttributes.playerOneActualHealth -= 1;
             dmgAmount -=1;
 
             yield return new WaitForSeconds(1);
 
         }
 
             script.playerStatus.playerOnePoisoned = false;
         
 
     }
 }
Comment
Add comment
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

2 Replies

· Add your reply
  • Sort: 
avatar image
0
Best Answer

Answer by NerdRageStudios · Jul 15, 2014 at 06:22 PM

Thank you so much for that!

I have implemented the code as you suggest, but if for example I pass 20 as the damage, it goes to -2000 health in like 5 seconds and doesn't stop decreasing?

 using UnityEngine;
 using System.Collections;
 
 public class ScriptPlayerOnePoison : MonoBehaviour
 {
 
     float dmg = 0;
     float dmgDecreaser = 1;                 // How much the dmg gets decreased by
     bool _poisonCoroutineRunning = false;   // Ensures ONE coroutine is running.
     ScriptPlayerOneManager script;
 
     void Start()
     {
         script = GameObject.Find("PrefabPlayerOne").GetComponent<ScriptPlayerOneManager>();
     }
 
     void Update()
     {
         CheckPoison();
     }
 
     void CheckPoison()
     {
         if (!_poisonCoroutineRunning && script.playerStatus.playerOnePoisoned) // IF you're poisoned and you aren't calculating any poison damage
         {
             _poisonCoroutineRunning = true;   // You lock yourself into 1 instance of the coroutine
             StartCoroutine(UpdatePoison());   // You start the coroutine
         }
     }
 
     IEnumerator UpdatePoison()
     {
         while (script.playerStatus.playerOnePoisoned && dmg >= 0)     // While poisoned and the damage taken is greater than 0
         {
             script.playerActualAttributes.playerOneActualHealth -= dmg;        // Drops health
             dmg -= Time.deltaTime * dmgDecreaser;                              // Drops damage
 
             yield return new WaitForSeconds(Time.deltaTime);    // Waits 1 frame
         }// One of the conditions became false if it breaks past here
 
         script.playerStatus.playerOnePoisoned = false;
         _poisonCoroutineRunning = false;
         yield break;
     }
 }
Comment
Add comment · Show 1 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image NerdRageStudios · Jul 15, 2014 at 07:03 PM 0
Share

Ah, ok I got it working now, but I have another problem now which is different so I shall start a new question ins$$anonymous$$d.

For those that want a D$$anonymous$$G over time script, this is what is now working for me...

 using UnityEngine;
 using System.Collections;
 
 public class ScriptPlayerOnePoison : $$anonymous$$onoBehaviour
 {
 
     public float dmgTimer = 10;
     public float dmgAmount = 10;
     float dmgDecreaser = 1;                 // How much the dmg gets decreased by
     bool _poisonCoroutineRunning = false;   // Ensures ONE coroutine is running.
     ScriptPlayerOne$$anonymous$$anager script;
 
     void Start()
     {
         script = GameObject.Find("PrefabPlayerOne").GetComponent<ScriptPlayerOne$$anonymous$$anager>();
     }
 
     void Update()
     {
         CheckPoison();
     }
 
     void CheckPoison()
     {
         if (!_poisonCoroutineRunning && script.playerStatus.playerOnePoisoned) // IF you're poisoned and you aren't calculating any poison damage
         {
             _poisonCoroutineRunning = true;   // You lock yourself into 1 instance of the coroutine
             StartCoroutine(UpdatePoison());   // You start the coroutine
         }
     }
 
     IEnumerator UpdatePoison()
     {
         while (script.playerStatus.playerOnePoisoned && dmgTimer >= 0)     // While poisoned and the damage taken is greater than 0
         {
             script.playerActualAttributes.playerOneActualHealth -= dmgAmount;        // Drops health
             dmgTimer -= dmgDecreaser;                              // Drops damage
 
             yield return new WaitForSeconds(1);    // Waits 1 frame
         }// One of the conditions became false if it breaks past here
 
         script.playerStatus.playerOnePoisoned = false;
         _poisonCoroutineRunning = false;
         yield break;
     }
 }
avatar image
1

Answer by Anti-Social Fred · Jul 15, 2014 at 05:27 PM

I see two main problems.

  1. Multiple instances of coroutines can run. So EVERY FRAME you're telling the damage to decrement by 1 and then wait 1 second. A coroutine shouldn't be used like this.

  2. Wait(X) where X isn't equal to Time.deltaTime can cause problems like this. I suggest:

       float dmg = 0;
         float dmgDecreaser = 1;                 // How much the dmg gets decreased by
         bool _poisonCoroutineRunning = false;   // Ensures ONE coroutine is running.
     
         void Update()
         {
             CheckPoison();
         }
     
         void CheckPoison()
         {
             if (!_poisonCoroutineRunning && script.isPoisoned) // IF you're poisoned and you aren't calculating any poison damage
             {
                 _poisonCoroutineRunning = true;   // You lock yourself into 1 instance of the coroutine
                 StartCoroutine(UpdatePoison());   // You start the coroutine
             }
         }
     
         IEnumerator UpdatePoison()
         {
             while (script.isPoisoned && dmg >= 0 )     // While poisoned and the damage taken is greater than 0
             {
                 script.actualHealth -= dmg;                         // Drops health
                 dmg -= Time.deltaTime * dmgDecreaser;                              // Drops damage
     
                 yield return new WaitForSeconds(Time.deltaTime);    // Waits 1 frame
             }// One of the conditions became false if it breaks past here
     
             script.isPoisoned = false;
             _poisonCoroutineRunning = false;
             yield break;
         }
    
    

This method goes along with Vitor_r's suggestion; just substitute your own values and you should be golden!

As long as your instance of the script variable is poisoned this is run, so every frame the health is decremented by dmg * Time.deltaTime. It is almost always advantageous to use Time.deltaTime instead of a constant value.

I prefer this way as well because the coroutine will automatically stop if you pick up a poison cure, for instance, and set the isPoisoned variable to false.

I don't know how your game works, but another thing that I saw just now was that after you decrement the health and wait, you set the isPoisoned to false, every time, regardless of everything. I'm not sure if you want a one-shot poison, but if that's the case use a regular void() method to decrement health, and then use an IEnumerator as a timer to take off poison after X seconds.

Comment
Add comment · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

24 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

Coroutines and states 1 Answer

Yield Statement Problems 2 Answers

i need to delay an action but my code isnt working 1 Answer

What is wrong with this use of WaitForSeconds? 1 Answer

How to implement a delay between each time my gun fires (using coroutines or otherwise)?... 2 Answers


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges