0

I'm creating some lines of many diffent rectangles. Both lines and rectangles are created by code. I do some logic with the rectangle's vertices and update that information in my instantiated rectangles. This works really well.

Then on each rectangle I have 2 scripts, one storing data and the other storing a corutine to make the rectangle flash or stop flashing when certain conditions are met after lines and rectangles move possitions.

It does not work, it might have to be done with some other outside scripts and even diccionaries or lists, but as I'm new to coroutines I would like to know if it's possible to do it from each instantiated object by simply checking those bool and int variables as they change during the game.

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

public class rectanguloAnim : MonoBehaviour{
rectangulo rect; //script containing data from this rectangle

Color32 colOrig;
Material material;
IEnumerator currentFlashCoroutine;



void Start()
{
    rect = GetComponent<rectangulo>();
    colOrig = GetComponent<rectangulo>().colorOriginal;
    material = GetComponent<Renderer>().material;
}


void Update()
{
    // this bool and int change when the line and rect are interacted with
    if (rect.isIntermediate == true || rect.activeDirection != 0)
    {
        if (currentFlashCoroutine != null)
        {
            StopCoroutine(currentFlashCoroutine);
        }

        currentFlashCoroutine = ChangeColor(material, colOrig, Color.white);
        StartCoroutine(currentFlashCoroutine);
    }
    else
    {
        if (currentFlashCoroutine != null)
        {
            StopCoroutine(currentFlashCoroutine);
        }
    }


}

IEnumerator ChangeColor(Material toChange, Color32 startColor, Color32 endColor)
{
    float t = 0;
    float colorDuration = Random.Range(2.49f, 6f);

    while (t < colorDuration)
    {
        float timeDuration = Random.Range(.55f, .95f);
        if (t > timeDuration)
        {
            t = 0;
        }

        t += Time.deltaTime;
        toChange.color = Color.Lerp(startColor, endColor, t / colorDuration);
        yield return null;
    }
}

}

hard
  • 23
  • 3

1 Answers1

0

I think you should rather make your field

private Coroutine currentFlashCoroutine;

and then use

currentcurrentFlashCoroutine = StartCoroutine(ChangeColor(material, colOrig, Color.white);

and then do

if(currentFlashCoroutine != null)
{
    StopCoroutine (currentFlashCoroutine);
    currentFlashCoroutine = null;
}

Btw in doubt you could also use StopAllCoroutines since in your use case you seem to anyway only have a single routine in your class ;)


The second issue here is that you are stopping and starting a new routine every frame as long the condition is true.

You would rather do somthing like

void Update()
{
    // this bool and int change when the line and rect are interacted with
    if (rect.isIntermediate || rect.activeDirection != 0)
    {
        // only start a new routine if there is not already one running
        if(currentFlashCoroutine == null)
        {
            currentFlashCoroutine = StartCoroutine(ChangeColor(material, colOrig, Color.white);
        }
    }
    else
    {
        if(currentFlashCoroutine != null)
        {
            StopCoroutine (currentFlashCoroutine);
            currentFlashCoroutine = null;
        }
    }
}

IEnumerator ChangeColor(Material toChange, Color32 startColor, Color32 endColor)
{
    var t = 0f;
    var colorDuration = Random.Range(2.49f, 6f);

    while (t < colorDuration)
    {
        var timeDuration = Random.Range(.55f, .95f);
        if (t > timeDuration)
        {
            t = 0;
        }

        t += Time.deltaTime;
        toChange.color = Color.Lerp(startColor, endColor, t / colorDuration);
        yield return null;
    }

    currentFlashRoutine = null;
}
derHugo
  • 83,094
  • 9
  • 75
  • 115
  • I already tried to rewrite those lines, and coroutine still not even start for any of the objects. I suspect maybe it's a problem from trying to run a corutine from an instantiated object, but still dont know too much about coroutines. – hard Jan 25 '21 at 18:44
  • If your condition becomes true this should work .. did you try to debug if the line is even reached? – derHugo Jan 25 '21 at 18:53
  • Yes, this log the conditions properly: if (rect.esIntermedio == true || rect.activoDireccion != 0) { Debug.Log(rect.esIntermedio.ToString() + ":" + rect.activoDireccion); if (currentFlashCoroutine != null) { StopCoroutine(currentFlashCoroutine); } [rest of the code] – hard Jan 25 '21 at 19:17
  • Again if your conditions are as expected I don't see in the code why this should not work ... how long do the conditions stay true? Maybe it is immediately stopped in the next frame e.g. ? – derHugo Jan 26 '21 at 07:51
  • They only change when I drag a line of rectangles and vertices are checked again. When I drag a line the flags are changing properly but coroutine does not. I read that it's not a good practice to start coroutines in the update method, mybe that's the issue. – hard Jan 26 '21 at 10:36
  • What is ment by that is you should not start a new coroutine every frame! And yes as I understand this might be currently your issue! You are stopping and starting a new routine **every frame** as long as the condition is true .. didn't note this before sorry :D – derHugo Jan 26 '21 at 10:56