#Blinking indicator in Unity (every 2 seconds)

1 messages · Page 1 of 1 (latest)

half token
#

boop

atomic hatch
#

Either swap the Sprite or make the Color darker

#

if you have a Sprite Renderer then just Reference it instead of the GameObject visualCueE

#

it has the field Color, just modify it

half token
#

Yeah I have that. Would I swap the sprite using an animation cycle or literally replace it?

I was using a timer to decide when to change the color

`` void Update()
{
if (playerInRange)
visualCueE.SetActive(true);
if (Input.GetKeyDown("E"))
tristanIsCrouching = true;

    else
        visualCueE.SetActive(false);
    Debug.Log("Tristan is crouching" + tristanIsCrouching);


    if (this.playerInRange)
    {

        buttonETimer += Time.deltaTime;
    }

    if (this.buttonETimer >= 2f)
    {

//darker here

}

    if(this.buttonETimer >= 4f)
    {
        //change it back here
        this.buttonETimer = 0f;
    }``

Logic is when the timer is >2f or seconds, the sprite is changed to the darker color and then back after that

atomic hatch
#

I'd just completely swap the Sprite/Color in the Sprite Renderer

#

But most likely just the Color since I can just define it in the code, no need to reference any additional sprites

#

With Colors you could even make a short Lerp so the transition would look nicer

atomic hatch
#
spriteRendererReference.Color = someNewColor;
```To swap the color
#
spriteRendererReference.Color = Color.Lerp(firstColor, secondColor, progress01);
``` to lerp the color
#

you can either lerp it over time in update or make a coroutine which would be cleaner and better to understand

#
private IEnumerator LerpSpriteColor(Color start, Color end, float lerpTime)
{
  for (float t = 0; t < lerpTime; t += Time.deltaTime)
  {
    float progress = t / lerpTime;
    spriteRendererReference.Color = Color.Lerp(start, end, progress);
    yield return null;
  }
  spriteRendererReference.Color = end;
}

Which can be called and stored like this:

Coroutine coroutine = StartCoroutine(LerpSpriteColor(Color.white, Color.black, 0.5f));
#

The start Color can be always your current Color (in case you have to stop the coroutine early StopCoroutine(coroutine) and start a new one), and the end Color can be the one you want to lerp into based on the current situation.

half token
atomic hatch
#

lerping is basically

c = a + (b - a) * p
#

it returns a transitioning into b by p% where p is in range [0 ; 1] (where 0 is a, 1 is b and 0.5 is the midpoint between a and b)

#

Also in this case it's just a linear lerp, you can always apply some fancy functions to get a fancy looking progress (easiest example is ease-in/ease-out which basically transforms linear arguments into non-linear return values)

half token
#

thanks!

half token
atomic hatch
#

it just goes from A to B and stops at B, unless interrupted (then it stops somewhere in the middle)

half token
#

I see, to make it return to A would I have to reset the time to 0 after it hits B?

atomic hatch
#

Same as if I had a position A(0 , 0) and B(0 , 1) and wanted to lerp it during 1 second
If I interrupted it after 0.7 seconds it would just stop at (0, 0.7) and stay there

atomic hatch
#

or make another lerp back to A

half token
#

I see, so I would just copy the previous lerp from A to B but make it go from B to A

atomic hatch
#

the time in the coroutine is just how long it should take (t is how much time already elapsed)

atomic hatch
half token
#

I see

atomic hatch
#

also

#

if you want to lerp again, after A-B to B-A ten you can just make another coroutine which does both of them one after another

half token
#

so would that mean endless coroutines or do i make a while loop?

#

like while InRange

#

loop the coroutine endlessly?

atomic hatch
#
private IEnumerator Lerp_AB_BA_Color(Color A, Color B, float timeAB, float timeBA)
{
  yield return LerpSpriteColor(A, B, timeAB);
  yield return LerpSpriteColor(B, A, timeBA);
}
#

No need for endless coroutine, just start it when needed

#

a coroutine is like an update function

half token
#

i see

atomic hatch
#

but is stops when you tell it to stop and continues next frame / time period

#

and after reaching the end it won't run anymore

half token
#

so in this case it needs to stop when the player is out of range

#

return means going back to the start of the code right?

#

and executing it again

atomic hatch
#

yield return stuff
is the way a coroutine says "wait until this thing ends"

#

yield return null
basically waits for nothing, so it continues the next frame

half token
#

i see

atomic hatch
#
int i = 0;
yield return new WaitForSeconds(seconds);
Debug.Log(i); // Will print 0 after 'seconds' seconds
half token
#

i see

atomic hatch
#

The lerping function I wrote earlier basically waits for one frame, same as the update loop does, so it just changes the color over time and then stops

#

without yield return null it wouldn't stop at all and just run all the loops at once, resulting in an instant transition from one color to another

half token
#

I see

#

how do i write color?

#

I did it like this but its not really working. RGB format

atomic hatch
half token
#

private IEnumerator LerpSpriteColor(Color start, Color end, float lerpTime) { for (float t = 0; t < lerpTime; t += Time.deltaTime) { float progress = t / lerpTime; (71,82,69).Color = Color.Lerp(start, end, progress); yield return null; }

atomic hatch
half token
#

i see

#

117.Color

Like this?

atomic hatch
#

just do new Color(r / 255, g / 255, b / 255); to set a color

atomic hatch
#

(71,82,69).Color isn't a valid thing

half token
#

i see

atomic hatch
#

if you want to change the color of the sprite then you have to reference the renderer in the inspector and use it's Color field

half token
atomic hatch
#
[SerializeField] private SpriteRenderer _spriteRenderer; // To be set in inspector
#

and then just

_spriteRenderer.Color = the_color_you_want;
half token
#

ahhhh

half token
atomic hatch
#

this is just to create a new Color variable (also it's a constructor, not a method)

#

you could probably do stuff like idk

#
private Color _baseColor = new Color(1, 1, 1);
private Color _blackColor = new Color(0, 0, 0);
private const float TRANSITION_TIME = 0.5f;
private Coroutine _coroutine;

// ... somewhere in the code ...
_coroutine = StartCoroutine(LerpSpriteColor(_baseColor, _blackColor, TRANSITION_TIME));
atomic hatch
#

this constructor basically expects values in range [0 ; 1] so if you have RGB values in range [0 ; 255] then you'd have to "transform" them into the 01 range by just dividing the values by 255

half token
#

Argument 1: cannot convert from 'double' to 'float'RoslynCS1503

#

private Color endColor = new Color(0.2, 0.2, 0.2);

#

This line seems to assume its a double

atomic hatch
#

You have to add f after the number to tell it that it's a float value

half token
#

OH

atomic hatch
#
private Color endColor = new Color(0.2f, 0.2f, 0.2f);
half token
#

I am so stupid

atomic hatch
#

you can also write a _coroutine = null; at the end of your coroutines if you store them

#

since if one coroutine ends and your code tries to "stop" it before starting a new one, then bad things could happen

#

and with null it just ignores it

#

at least I think so

half token
#

store them?

atomic hatch
#

yeah

#

You can store a coroutine 'instance' so that you can later interrupt it

#
Coroutine _coroutine = StartCoroutine(MyCoroutine());
...
StopCoroutine(_coroutine);
_coroutine = StartCoroutine(NewCoroutine());
half token
#

i see

atomic hatch
#

Same as storing a GameObject

#

if it's already destroyed and try to Destroy it again then your computer explodes

half token
#

ahhh okay i might have to store it because i need to stop the blinking once the pc moves away from the collider

atomic hatch
#

This ^

half token
#

``using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Ebuttonblink : MonoBehaviour
{

[Header("Visual Cue E")]
[SerializeField] GameObject visualCueE;
[SerializeField] private SpriteRenderer spriteRendererE;
bool playerInRange;
bool tristanIsCrouching = false;
private Color baseColor = new Color(1, 1, 1);
private Color endColor = new Color(0.2f, 0.2f, 0.2f);
private const float transitionTime = 0.5f;
private Coroutine coroutineE;

void Awake()
{
    playerInRange = false;
    visualCueE.SetActive(false);
}
void OnTriggerEnter2D(Collider2D collider)
{
    if (collider.gameObject.tag == "Player")
        playerInRange = true;


}

void Update()
{





    if (playerInRange)
        visualCueE.SetActive(true);
    if (Input.GetKeyDown("E"))
        tristanIsCrouching = true;



    else
        visualCueE.SetActive(false);
    Debug.Log("Tristan is crouching" + tristanIsCrouching);


    void OnTriggerExit2D(Collider2D collider)
    {

        playerInRange = false;
    }


}

IEnumerator BlinkButtonE()
{

    coroutine(baseColor, endColor, transitionTime, transitionTime);
{
        yield return LerpSpriteColor(baseColor, endColor, transitionTime);
        yield return LerpSpriteColor(endColor, baseColor, transitionTime);
    }

    yield return new WaitForSeconds(1f);
}

}
``

Here's what I got

#

I'm not sure how to assign values to coroutine and LerpSpriteColor

atomic hatch
#
private IEnumerator LerpSpriteColor(Color start, Color end, float lerpTime)
{
  for (float t = 0; t < lerpTime; t += Time.deltaTime)
  {
    float progress = t / lerpTime;
    spriteRendererReference.Color = Color.Lerp(start, end, progress);
    yield return null;
  }
  spriteRendererReference.Color = end;
}

private IEnumerator BlinkOnce(Color A, Color B, float timeAB, float timeBA)
{
  yield return LerpSpriteColor(A, B, timeAB);
  yield return LerpSpriteColor(B, A, timeBA);
}

private IEnumerator BlinkForEternity(Color A, Color B, float timeAB, float timeBA)
{
  while (true) yield return BlinkOnce(A, B, timeAB, timeBA);
}

...
Coroutine coroutine = StartCoroutine(BlinkForEternity(A,B,T1,T2));
...
// out of reach
StopCoroutine(coroutine);
coroutine = StartCoroutine(LerpSpriteColor(currentColor, baseColor, T3));
half token
#

Ohhh

atomic hatch
half token
#

I'm sorry I'm kind of confused , what does it do here?

I understand the first block, but the blinkonce part is a little confusing for me

#

They seem to be doing the same thing, all 3 paragraphs, unless I'm wrong

atomic hatch
#

the blink once part

#

first lerps the color from A to B

#

then from B to A

#

and stops

#

LerpSpriteColor only lerps from A to B

half token
#

I see

#

So these are 3 different ways to do the same thing?

atomic hatch
#

BlinkForEternity infinitely calls the BlinkOnce coroutine as soon as the previous one ends resulting in: A-B B-A, A-B B-A, ...

atomic hatch
#

As I said

#

the first one only goes from A to B

#

the second one uses the first one twice to go from A to B to A

#

and the third one uses the second one to go from A to B to A over and over again

#

if I used the first one with the arguments (black, white, 1) it would go from black to white over the time of 1 second and stop at white

#

if I used the second one with arguments (black, white, 1, 2) it would go from black to white over the time of 1 second and then from white to black over the time of 2 seconds

half token
#

I see

#

Okay I understand now

atomic hatch
#

and if I used the third one it would do the second one but over and over again

half token
#

Ahhhhh

atomic hatch
#

Basically using already existing small do-one-thing coroutines to make bigger do-several-things coroutines

half token
#

what do i do when the program keeps printing

The name 'LerpSpriteColor' does not exist in the current contextRoslynCS0103```
#

I dont know what value to assign this, the original color?

atomic hatch
#

it means that it doesn't recognise the coroutine you want to use in the place you want to use it

#

show code

half token
#

oki

#
using System.Collections.Generic;
using UnityEngine;

public class Ebuttonblink : MonoBehaviour
{

    [Header("Visual Cue E")]
    [SerializeField] GameObject visualCueE;
    [SerializeField] private SpriteRenderer spriteRendererE;
    bool playerInRange;
    bool tristanIsCrouching = false;
    private Color baseColor = new Color(1, 1, 1);
    private Color endColor = new Color(0.2f, 0.2f, 0.2f);
    private const float transitionTime = 0.5f;
    private Coroutine coroutineE;

    void Awake()
    {
        playerInRange = false;
        visualCueE.SetActive(false);
    }
    void OnTriggerEnter2D(Collider2D collider)
    {
        if (collider.gameObject.tag == "Player")
            playerInRange = true;


    }

    void Update()
    {





        if (playerInRange)
            visualCueE.SetActive(true);
        if (Input.GetKeyDown("E"))
            tristanIsCrouching = true;



        else
            visualCueE.SetActive(false);
        Debug.Log("Tristan is crouching" + tristanIsCrouching);


        void OnTriggerExit2D(Collider2D collider)
        {

            playerInRange = false;
        }


    }

#
    {
        for (float t = 0; t < lerpTime; t += Time.deltaTime)
        {
            float progress = t / lerpTime;
            spriteRendererReference.Color = Color.Lerp(start, end, progress);
            yield return null;
        }
        spriteRendererReference.Color = end;
    }

    private IEnumerator BlinkOnce(Color A, Color B, float timeAB, float timeBA)
    {
        yield return LerpSpriteColor(A, B, timeAB);
        yield return LerpSpriteColor(B, A, timeBA);
    }

    private IEnumerator BlinkForEternity(Color A, Color B, float timeAB, float timeBA)
    {
        while (true) yield return BlinkOnce(A, B, timeAB, timeBA);
    }


    Coroutine coroutine = StartCoroutine(BlinkForEternity(A, B, T1, T2));


    StopCoroutine(coroutine);
  coroutine = StartCoroutine(LerpSpriteColor(currentColor, baseColor, T3));

}
atomic hatch
#

but format it using
```cs
int i = 0;
```
since it's hard to read

half token
#

oh i ran out of discord space, ill use pastebin next time

atomic hatch
#

just add cs

#

```cs
code

#

nwm, I'll just do it myself

half token
#

oh i see now

#

holdon

atomic hatch
#
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Ebuttonblink : MonoBehaviour
{
    [Header("Visual Cue E")]
    [SerializeField] GameObject visualCueE;
    [SerializeField] private SpriteRenderer spriteRendererE;
    bool playerInRange;
    bool tristanIsCrouching = false;
    private Color baseColor = new Color(1, 1, 1);
    private Color endColor = new Color(0.2f, 0.2f, 0.2f);
    private const float transitionTime = 0.5f;
    private Coroutine coroutineE;

    void Awake()
    {
        playerInRange = false;
        visualCueE.SetActive(false);
    }

    void OnTriggerEnter2D(Collider2D collider)
    {
        if (collider.gameObject.tag == "Player")
            playerInRange = true;
    }

    void Update()
    {
        if (playerInRange)
            visualCueE.SetActive(true);
        if (Input.GetKeyDown("E"))
            tristanIsCrouching = true;
        else
            visualCueE.SetActive(false);
        Debug.Log("Tristan is crouching" + tristanIsCrouching);


        void OnTriggerExit2D(Collider2D collider)
        {
            playerInRange = false;
        }
    }
#
    private IEnumerator LerpSpriteColor(Color start, Color end, float lerpTime)
    {
        for (float t = 0; t < lerpTime; t += Time.deltaTime)
        {
            float progress = t / lerpTime;
            spriteRendererReference.Color = Color.Lerp(start, end, progress);
            yield return null;
        }
        spriteRendererReference.Color = end;
    }

    private IEnumerator BlinkOnce(Color A, Color B, float timeAB, float timeBA)
    {
        yield return LerpSpriteColor(A, B, timeAB);
        yield return LerpSpriteColor(B, A, timeBA);
    }

    private IEnumerator BlinkForEternity(Color A, Color B, float timeAB, float timeBA)
    {
        while (true) yield return BlinkOnce(A, B, timeAB, timeBA);
    }
    Coroutine coroutine = StartCoroutine(BlinkForEternity(A, B, T1, T2));
    StopCoroutine(coroutine);
  coroutine = StartCoroutine(LerpSpriteColor(currentColor, baseColor, T3));
}
#

Ok, dear god

#

first of all, you have your OnTriggerExit2D inside Update

#

second of all, don't just copy paste, it obviously won't work, I just provided examples

#

last three lines should just go away

half token
atomic hatch
#

no

half token
#

damn, TIL

atomic hatch
#

if it's inside another method then it's considered to be a local method, only existing within that one method

half token
#

oh

atomic hatch
#

OnTriggerEnter2D has to be available straight from within your class in order to call it

half token
#

i see

atomic hatch
#

basically take it outside of update please

#
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Ebuttonblink : MonoBehaviour
{
    [Header("Visual Cue E")]
    [SerializeField] GameObject visualCueE;
    [SerializeField] private SpriteRenderer spriteRendererE;
    bool playerInRange;
    bool tristanIsCrouching = false;
    private Color baseColor = new Color(1, 1, 1);
    private Color endColor = new Color(0.2f, 0.2f, 0.2f);
    private const float transitionTime = 0.5f;
    private Coroutine coroutineE;

    void Awake()
    {
        playerInRange = false;
        visualCueE.SetActive(false);
    }

    void OnTriggerEnter2D(Collider2D collider)
    {
        if (collider.gameObject.tag == "Player")
            playerInRange = true;
    }

    void OnTriggerExit2D(Collider2D collider)
    {
        if (collider.gameObject.tag == "Player")
            playerInRange = false;
    }

    void Update()
    {
        if (playerInRange)
            visualCueE.SetActive(true);
        if (Input.GetKeyDown("E"))
            tristanIsCrouching = true;
        else
            visualCueE.SetActive(false);
        Debug.Log("Tristan is crouching " + tristanIsCrouching);
    }
#

Like this basically

#

keep it clean.

half token
atomic hatch
#
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Ebuttonblink : MonoBehaviour
{
    [Header("Visual Cue E")]
    [SerializeField] GameObject visualCueE;
    [SerializeField] private SpriteRenderer spriteRendererE;
    bool playerInRange;
    bool tristanIsCrouching = false;
    private Color baseColor = new Color(1, 1, 1);
    private Color endColor = new Color(0.2f, 0.2f, 0.2f);
    private const float transitionTime = 0.5f;
    private Coroutine coroutineE;

    void Awake()
    {
        playerInRange = false;
        visualCueE.SetActive(false);
    }

    void OnTriggerEnter2D(Collider2D collider)
    {
        if (collider.gameObject.tag == "Player")
            playerInRange = true;
    }

    void OnTriggerExit2D(Collider2D collider)
    {
        if (collider.gameObject.tag == "Player")
            playerInRange = false;
    }

    void Update()
    {
        if (playerInRange)
            visualCueE.SetActive(true);
        if (Input.GetKeyDown("E"))
            tristanIsCrouching = true;
        else
            visualCueE.SetActive(false);
        Debug.Log("Tristan is crouching " + tristanIsCrouching);
    }

    private IEnumerator LerpSpriteColor(Color A, Color B, float lerpTime)
    {
        for (float t = 0; t < lerpTime; t += Time.deltaTime)
        {
            float p = t / lerpTime;
            spriteRendererE.Color = Color.Lerp(A, B, p);
            yield return null;
        }
        spriteRendererE.Color = end;
    }

    private IEnumerator BlinkOnce(Color A, Color B, float timeAB, float timeBA)
    {
        yield return LerpSpriteColor(A, B, timeAB);
        yield return LerpSpriteColor(B, A, timeBA);
    }

    private IEnumerator BlinkForEternity(Color A, Color B, float timeAB, float timeBA)
    {
        while (true) yield return BlinkOnce(A, B, timeAB, timeBA);
    }

That should be your whole code (except for calling the coroutines)

#

ah, not exactly

#

now it's good

#

Also, if you want it to be easier and not store the coroutine at all

#

you can just use the method StopAllCoroutines() and simply start the coroutines using StartCoroutine(MyCoroutine(params)); without the need to store it in your coroutineE

half token
#

i see

atomic hatch
#

Now I suppose

#

it probably should look like this

half token
#

'SpriteRenderer' does not contain a definition for 'Color' and no accessible extension method 'Color' accepting a first argument of type 'SpriteRenderer' could be found (are you missing a using directive or an assembly reference?)RoslynCS1061




The name 'end' does not exist in the current contextRoslynCS0103
#

Got these 2 problems, how should I label spriterenderer?

atomic hatch
#

oh, my bad

#

it's not a Color field, it's named "color"

#

small letter

#

renderer.color = ...

#

as for the second one I forgot to rename it, should be B instead of end

half token
#

AH

atomic hatch
#
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Ebuttonblink : MonoBehaviour
{
    [Header("Visual Cue E")]
    [SerializeField] GameObject visualCueE;
    [SerializeField] private SpriteRenderer spriteRendererE;
    bool playerInRange;
    bool tristanIsCrouching = false;
    private Color baseColor = new Color(1, 1, 1);
    private Color endColor = new Color(0.2f, 0.2f, 0.2f);
    private const float transitionTime = 0.5f;
    private Coroutine coroutineE;

    void Awake()
    {
        playerInRange = false;
        visualCueE.SetActive(false);
    }

    void OnTriggerEnter2D(Collider2D collider)
    {
        if (collider.gameObject.tag == "Player")
            playerInRange = true;
    }

    void OnTriggerExit2D(Collider2D collider)
    {
        if (collider.gameObject.tag == "Player")
            playerInRange = false;
    }

    void Update()
    {
        if (playerInRange)
            visualCueE.SetActive(true);
        if (Input.GetKeyDown("E"))
            tristanIsCrouching = true;
        else
            visualCueE.SetActive(false);
        Debug.Log("Tristan is crouching " + tristanIsCrouching);
    }

    private IEnumerator LerpSpriteColor(Color A, Color B, float lerpTime)
    {
        for (float t = 0; t < lerpTime; t += Time.deltaTime)
        {
            float p = t / lerpTime;
            spriteRendererE.color = Color.Lerp(A, B, p);
            yield return null;
        }
        spriteRendererE.color = B;
    }

    private IEnumerator BlinkOnce(Color A, Color B, float timeAB, float timeBA)
    {
        yield return LerpSpriteColor(A, B, timeAB);
        yield return LerpSpriteColor(B, A, timeBA);
    }

    private IEnumerator BlinkForEternity(Color A, Color B, float timeAB, float timeBA)
    {
        while (true) yield return BlinkOnce(A, B, timeAB, timeBA);
    }
#

Also I believe there is no need for half of your update method

#

you don't need to check if he's in range and then activate it, just do it within OnTriggerEnter2D

half token
#

I see

atomic hatch
#

it will be activated once, not million times

#

same with deactivating it

half token
#

ahh

atomic hatch
#

OnTriggerExit2D can handle it

half token
#

I'm curious, why is it that we use an IEnum here, not a foreach loop to Lerp

atomic hatch
#

IEnumerator coroutime does thing across time

#

you use foreach if you have an array or a list of elements

#

that's not a case here

#

you don't loop through any different variables

#

you just want to delay the transition by using time

half token
#

I see

#

So because they're not a type of variables or elements, and the code is just trying to lerp from A to B

#

an IEnum is used

atomic hatch
#

yeah

half token
#

Last couple things, just to clarify, yield return null is used when you want the code to continue at the next frame without waiting

#

While yield return WaitForSeconds(x) means the game should wait for x seconds before displaying/executing the next line of code?

atomic hatch
#

yield return new WaitForSeconds(x);
And yes

half token
#

i see

#

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Ebuttonblink : MonoBehaviour
{

    [Header("Visual Cue E")]
    [SerializeField] GameObject visualCueE;
    [SerializeField] private SpriteRenderer spriteRendererE;
    bool playerInRange;
    bool tristanIsCrouching = false;
    Color A = new Color(1, 1, 1);
    Color B = new Color(0.2f, 0.2f, 0.2f);
    const float transitionTime = 0.5f;
    Coroutine coroutineE;
    float lerpTime = 2f;

    void Awake()
    {
        playerInRange = false;
        visualCueE.SetActive(false);
    }
    void OnTriggerEnter2D(Collider2D collider)
    {
        if (collider.gameObject.tag == "Player")
            playerInRange = true;


    }
    void OnTriggerExit2D(Collider2D collider)
    {

        playerInRange = false;
    }

    void Update()
    {
        //if (playerInRange)
            //visualCueE.SetActive(true);
        if (Input.GetKeyDown("e"))
            tristanIsCrouching = true;
        //else
            //visualCueE.SetActive(false);
        Debug.Log("Tristan is crouching " + tristanIsCrouching);
    }

    private IEnumerator LerpSpriteColor(Color A, Color B, float lerpTime)
    {
        for (float t = 0; t < lerpTime; t += Time.deltaTime)
        {
            float p = t / lerpTime;
            spriteRendererE.color = Color.Lerp(A, B, p);
            yield return null;
        }
        spriteRendererE.color = B;
    }

    private IEnumerator BlinkOnce(Color A, Color B, float timeAB, float timeBA)
    {
        yield return LerpSpriteColor(A, B, timeAB);
        yield return LerpSpriteColor(B, A, timeBA);
    }

    private IEnumerator BlinkForEternity(Color A, Color B, float timeAB, float timeBA)
    {
        while (true) yield return BlinkOnce(A, B, timeAB, timeBA);
    }
    }```
atomic hatch
#

write visualCueE.SetActive(true); inside OnTriggerEnter2D when the tag is correct

#

also instead of writing collider.gameObject.tag == "Player"
I'd be better if you did collider.CompareTag("Player")

half token
#

Ahhhhh

#

Why?

atomic hatch
#

and if you don't want to check for the tag at all, then just go into physics2d setting in your project settings and deactivate all collisions between your Ebuttonblink layer leaving just the player layer (that is, if they have different unique layers), so if OnTriggerEnter2D is ever called then it's 100% the player

atomic hatch
half token
#

I see

half token
atomic hatch
#

As long as you know what you're doing, no

#

But for now you can just keep the tag check

half token
#

Well I am still new to this so I'm afraid I'll mess up in future if other collisions are needed

atomic hatch
#

So stick to tag checking for now

half token
#

Oki

atomic hatch
#

But it becomes useful once there are a lot of different things an object can collide with

half token
#

I see

atomic hatch
#

Because you never start the coroutine.

#

just write StartCoroutine(BlinkForEternity(A, B, transitionTime, transitionTime)); inside OnTriggerEnter2D and StopAllCoroutines() within OnTriggerExit2D if the tag is correct

half token
#

ohhhh

#

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Ebuttonblink : MonoBehaviour
{

    [Header("Visual Cue E")]
    [SerializeField] GameObject visualCueE;
    [SerializeField] private SpriteRenderer spriteRendererE;
    bool playerInRange;
    bool tristanIsCrouching = false;
    Color A = new Color(0.4f, 0.5f, 0.3f);
    Color B = new Color(0.2f, 0.2f, 0.2f);
    const float transitionTime = 0.5f;
    Coroutine coroutineE;
    float lerpTime = 2f;

    void Awake()
    {
        playerInRange = false;
        visualCueE.SetActive(false);
    }
    void OnTriggerEnter2D(Collider2D collider)
    {
        visualCueE.SetActive(true);
        if (collider.CompareTag("Player"))
            playerInRange = true;
            StartCoroutine(BlinkForEternity(A, B, transitionTime, transitionTime));

    }
    void OnTriggerExit2D(Collider2D collider)
    {

        playerInRange = false;
        StopAllCoroutines();
    }

    void Update()
    {
        //if (playerInRange)
        //visualCueE.SetActive(true);
        if (Input.GetKeyDown("e"))
            tristanIsCrouching = true;
        //else
        //visualCueE.SetActive(false);
        Debug.Log("Tristan is crouching " + tristanIsCrouching);
    }

    private IEnumerator LerpSpriteColor(Color A, Color B, float lerpTime)
    {
        for (float t = 0; t < lerpTime; t += Time.deltaTime)
        {
            float p = t / lerpTime;
            spriteRendererE.color = Color.Lerp(A, B, p);
            yield return null;
        }
        spriteRendererE.color = B;
    }

    private IEnumerator BlinkOnce(Color A, Color B, float timeAB, float timeBA)
    {
        yield return LerpSpriteColor(A, B, timeAB);
        yield return LerpSpriteColor(B, A, timeBA);
    }

    private IEnumerator BlinkForEternity(Color A, Color B, float timeAB, float timeBA)
    {
        while (true) yield return BlinkOnce(A, B, timeAB, timeBA);
    }
}

Still no blink

#
StartCoroutine(BlinkForEternity(A, B, transitionTime, transitionTime));```


Should this be placed outside the if(collider.CompareTag)?
atomic hatch
#
    void OnTriggerEnter2D(Collider2D collider)
    {
        if (collider.CompareTag("Player"))
        {
            visualCueE.SetActive(true);
            playerInRange = true;
            StartCoroutine(BlinkForEternity(A, B, transitionTime, transitionTime));
        }
    }

    void OnTriggerExit2D(Collider2D collider)
    {
        if (collider.CompareTag("Player"))
        {
            visualCueE.SetActive(false);
            playerInRange = false;
            StopAllCoroutines();
        }
    }```
#

Also, check if it even runs the method

#

but if the button appears then it should be ok

half token
#

Ah it is working now

#

thank you so much

atomic hatch
#

np

#

Also check out some C# tutorials, even the basic ones

#

Since I saw you struggle with a few stuff here

half token
#

oki!

atomic hatch
#

Might be good to learn all the basics for smoother future unity learning process

half token
#

I am ok with basic C# but coroutines and ienums make me confused

#

polymorphoisms too, those things I think I need to study more

atomic hatch
#

Don't worry, you'll get used to these

#

Better be scared of multithreading

#

(I still have to force myself to start learning this)

half token
#

yikes

#

thanks anyway! CrabRave

atomic hatch
#

And polymorphism isn't that bad either, it's just a bunch of "base" classes which basically exist to specify some methods to be overriden by other classes so that you can store different class instances by using their base class, and still be able to call their unique methods with custom behaviour

#
public abstract class MoveBase : MonoBehaviour
{
  public virtual void UpdatePosition() {}
}

public class EnemyMove : MoveBase
{
  public override void UpdatePosition() { custom behaviour... }
}

...
MoveBase[] moveArray = new MoveBase[10];
moveArray[0] = some_EnemyMove_instance;
moveArray[0].UpdatePosition(); // goes through MoveBase to EnemyMove and calls the custom behaviouir
#

Also it might be better to just an interface in this scenario, depends on the situation

half token
atomic hatch
#

I believe that an interface is best to use when you just want to implement different behaviours for the same 'type' of object, for example weapons

#

As for polymorphism, I don't really know

#

Haven't been using it that much

half token
#

I, so like Interfaces are just stuff you can assign to, and call later?

#

So I can assign IDamagable to a car, house and person and when I throw a bomb I can just called the IDamagable instead of tagging every single object

atomic hatch
#

Interface basically demands you to implement the same methods and fields that it also has, but with your own behaviour to it

#

So you can call for example an IDamagable method from any given object, be it car, door, neighbours cat

#

Without having to reference different scripts such as Car, Door or Cat

half token
#

I see, Interfaces are usually empty right? So They just get called when needed

atomic hatch
#

You define what an interface contains, as well as you call any method or property from that interface when needed

#

easiest example would be

#

for example

#

OnTriggerEnter2D

#

collider.CompareTag("Damagable")

half token
#

Yeah

atomic hatch
#

if yes then
collider.gameObject.GetComponent<IDamagable>().DealDamage(1);

#

or something like that, depends on how you do things

#

it will call the customly implemented DealDamage(int damage) method within any script that implemented it

half token
#

Ah, so everything from <IDamagable> contains all methods boxed into IDamagable interface

atomic hatch
#

for example

public interface IDamagable
{
  private int _health { get; set; }
  
  public void DealDamage() {}
}

public class Cat : MonoBehaviour, IDamagable // Will throw error until implemented
{
  private int _health { get; set; } = 7;
  
  public void DealDamage() { --_health; }
}

public class Dog : MonoBehaviour, IDamagable
{
  private int _health { get; set; } = 3;
  
  public void DealDamage() { _health -= 2; }
}
half token
#

Ahhh so it kinda makes you inherit all methods from the interface

atomic hatch
#

Maybe inherit isn't the right word

#

Since inherited methods are already implemented

half token
#

I see

atomic hatch
#

and an interface basically reminds you to implement them from zero

half token
#

From zero?

atomic hatch
#

Meaning that there isn't any base inherited method

#

you just have to implement your own following the "instruction provided by the interface"

half token
#

I see

atomic hatch
#

Like using MonoBehaviour (class) makes you inherit all it's members, an IDamagable (interface) makes you create them by yourself, no inheritance

half token
#

So no variables to be inherited, just the empty methods

#

or do we not even inherit those empty methods and have to make them oursevles, so the Interface is essentially a fancy tagging system?

atomic hatch
#

Nothing from the interface will be inherited, you basically have to copy everything from the interface and then maybe add your custom behaviour to the properties/methods

#

It just ensures that this method/property exists, it doesn't care what it does, it just has to be callable

half token
#

I see

#

So it's just a fancy tagging system?

atomic hatch
#

I'd call it "inheritance" but with extra steps and safety, lol

#

You do call it however you want

#

The main idea is that is just ensures the creation of certain methods and properties

half token
#

I see

half token
#

I don't really understand this

atomic hatch
#

You code won't compile if you don't create the methods and properties that it wants. That's all there is to it

#

It just forces you to include them in your script somewhere (so it's callable via the interface)

half token
#

Ohhhhh

atomic hatch
#

But some tutorials on interfaces would probably explain it better than me lol

half token
#

So fancy tagging system with safeties to ensure you don't forget to put stuff in

#

Thanks!

#

You've been really helpful 🙂

atomic hatch
#

np

#

now back to forcing Unity to render thousands of missiles.