No. Don’t look… This is probably the dumbest script you’ve seen.
But it does exactly what I want/need it to do.
I know it’s not the most elegant/efficient way to do it (duh), so can someone assist?
Basically, I want to enable a bool while the player is in a “damaged” state (a state which is the classic “player blinks after being damaged” type of thing).
So, this ienumerator I conjured up enables the bool at the start, does the blinking by flicking on and off the sprite renderer, and then closes with the bool being disabled. I tried a for loop, but it doesn’t work right.
Maybe I did the for loop wrong?
IEnumerator Blink()
{
noDamage = true;
sprite.enabled = false;
yield return new WaitForSeconds(0.07f);
sprite.enabled = true;
yield return new WaitForSeconds(0.13f);
sprite.enabled = false;
yield return new WaitForSeconds(0.07f);
sprite.enabled = true;
yield return new WaitForSeconds(0.13f);
sprite.enabled = false;
yield return new WaitForSeconds(0.07f);
sprite.enabled = true;
yield return new WaitForSeconds(0.13f);
sprite.enabled = false;
yield return new WaitForSeconds(0.07f);
sprite.enabled = true;
yield return new WaitForSeconds(0.13f);
sprite.enabled = false;
yield return new WaitForSeconds(0.07f);
sprite.enabled = true;
yield return new WaitForSeconds(0.13f);
sprite.enabled = false;
yield return new WaitForSeconds(0.07f);
sprite.enabled = true;
yield return new WaitForSeconds(0.13f);
sprite.enabled = false;
yield return new WaitForSeconds(0.07f);
sprite.enabled = true;
yield return new WaitForSeconds(0.13f);
sprite.enabled = false;
yield return new WaitForSeconds(0.07f);
sprite.enabled = true;
yield return new WaitForSeconds(0.13f);
sprite.enabled = false;
yield return new WaitForSeconds(0.07f);
sprite.enabled = true;
yield return null;
noDamage = false;
}
Cache waitforseconds so it doesn’t generate garbage ( at the top have a variavle WaitForSeconds = new WaitForSeconds(0.07f);, which you can simply return)
Loops. You do the same over and over again.
You might be able to have 1 loop with a bool. If the bool is true wait 0.07 and enable and set it false, so next iteration it’s false, waits 0.14 and disables and set bool to true
All that said, you MIGHT want instead to make an invulnerability cooldown timer.
Set the timer to how long you want the thing to blink, count the timer down by Time.deltaTime each frame, use the timer value directly to decide if damage can happen.
Set the sprite enabled to be equal to either “timer is zero, or blink based on time…”
Oh, so you are say, maybe do two ienumator functions? One for the blinking, one for the bool, and have both of them run? (in this case, they run after pressing a button)?
And thanks for the suggestion on “WaitForSeconds =”. I’m still trying to remember that I can save my fingers by just declaring something long to something simplier
Well, my ham fisted way of not running the coroutine twice was this…
public void TakeDamage(int damage)
{
if (noDamage == false)
{
currentHealth -= damage; // current health will be reduced by whatever damage is sent
StartCoroutine(Blink());
}
Thanks for the assistance, I decided to split this scripting into two coroutines, one for the bool enabled/wait/disable, and then a simple ForLoop for the blinking as provided by Kurt
I’m still trying to come to grips with your suggestion here… Since I do want to do methods that are “more correct”, and I get the idea of what you are saying, but I’ve never done a getter property
I offer you a package with 100% of it working, as i understand what you want, with comments.
The code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
// @kurtdekker - goes on the player
public class GonzoDonBonzoMuyBlinko : MonoBehaviour
{
[Header( "I used a GameObject, you could use a sprite.")]
[Header( "Make sure it is NOT this GameObject or its parent!")]
public GameObject VisibleParts;
// when greater than zero, you are blinking and doDamage is false
float InvulnerableTimer;
const float InvulnerableInterval = 0.5f;
const float BlinkRate = 6.0f;
// the entire point of this get-only boolean is so we can have
// a single point of truth as to "can I do damage?" that is based
// only on the InvulnerableTimer.
//
// Having this single point of truth means we cannot "get ot of sync"
bool doDamage
{
get
{
return InvulnerableTimer <= 0;
}
}
void Update ()
{
if (Input.GetKeyDown( KeyCode.D))
{
// always reset the timer
InvulnerableTimer = InvulnerableInterval;
if (doDamage)
{
// TODO do damage here
}
}
// handle invulnerability
if (InvulnerableTimer > 0)
{
InvulnerableTimer -= Time.deltaTime;
}
// blink
bool visible = (InvulnerableTimer <= 0) ||
(((Time.time * BlinkRate) % 1.0f) < 0.35f);
// put your sprite enabler here instead
VisibleParts.SetActive( visible);
// report
Debug.Log( "doDamage = " + doDamage);
}
}
Grab a cup of coffee and work through each part to see how it works… the parts are all super straightforward laid out top to bottom.