2
votes

Comment retarder une méthode dans Unity et C #?

Je m'appelle Laurenz et ma question est de savoir comment retarder le changement de couleur de mes sprites dans Unity avec c #.

En ce moment, j'ai un générateur aléatoire qui choisit une couleur basée sur un nombre, mais cela se produit à chaque image. Alors maintenant, le vrai défi est de savoir comment le retarder pour qu'il change moins souvent.

public class colorchange : MonoBehaviour
{
    public int color;
    public bool stop = true;
    void Start()
    {

    }

    void Update()
    {

        Debug.Log("Hello");
        color = Random.Range(1, 5);
        if (color == 2)
        {
            gameObject.GetComponent<SpriteRenderer>().color = Color.blue;
        }
        if (color == 3)
        { 
            gameObject.GetComponent<SpriteRenderer>().color = Color.red;
        }
        if (color == 4)
        {
            gameObject.GetComponent<SpriteRenderer>().color = Color.yellow;
        }
    }
}


2 commentaires

Comptez le temps écoulé depuis la dernière exécution (par exemple: en utilisant Time.deltaTime ) et ne changez de couleur que lorsqu'elle dépasse un certain nombre


OP, si vous souhaitez fournir votre propre réponse, veuillez le faire comme une réponse plutôt que comme une modification à la question. Modification annulée.


6 Réponses :


1
votes

Vous pouvez utiliser le compteur de temps et Time.deltaTime:

public class colorchange : MonoBehaviour
{
    public int color;
    public bool stop = true;
    public float delay;
    private float timer;
    void Start()
    {
        timer = delay;
    }

    void Update()
    {
        timer -= Time.deltaTime;
        if (timer <= 0) {
            timer = delay;
            Debug.Log("Hello");
            color = Random.Range(1, 5);
            if (color == 2)
            {
                gameObject.GetComponent<SpriteRenderer>().color = Color.blue;
            }
            if (color == 3)
            { 
                gameObject.GetComponent<SpriteRenderer>().color = Color.red;
            }
            if (color == 4)
            {
                gameObject.GetComponent<SpriteRenderer>().color = Color.yellow;
            }
        }
    }
}


0 commentaires

2
votes

6 commentaires

savez-vous peut-être comment arrêter le changement de couleur si je mets onmousedown ()


@LaurenzKaml J'ai modifié la réponse pour inclure une fonction bascule dans OnMouseDown () Assurez-vous simplement d'avoir un Collider ou GUIElement attaché au même gameobject comme le script.


Vous pourriez alors en fait directement faire de Start un IEnumerator ;) et supprimer une méthode Update vide.


désolé Ruzihm mais je viens de commencer l'unité il y a 1 jour et je ne sais presque rien pourrais-tu me montrer comment.


Collider2D < / code> qui est probablement ce que vous voulez utiliser pour votre gameobject avec un SpriteRenderer. Ce n'est pas le sujet de cet article. Si vous avez besoin d'aide supplémentaire, envisagez de poser une nouvelle question .


Une suggestion, créez un seul objet WaitUntil et retournez , au lieu de nouveau WaitUntil à chaque fois.



0
votes

Vous pouvez gérer cela avec une simple coroutine. Si vous ne savez pas comment faire, jetez un œil à ce lien ( https://docs.unity3d.com /ScriptReference/WaitForSeconds.html ) sur la documentation officielle de l'API Unity.

Si vous ne souhaitez pas travailler avec des coroutines, vous pouvez utiliser la méthode InvokeRepating d'Unity. Créez une nouvelle fonction pour changer la couleur et invoquez-la toutes les x secondes. Voici le lien pour la méthode InvokeRepating également https://docs.unity3d.com/ScriptReference/MonoBehaviour .InvokeRepeating.html

ps: Dans ce cas, utiliser Switch pour déterminer l'entier de couleur est plus efficace que d'utiliser if et else if pour chaque code couleur. C'est plus efficace et plus facile à mettre à l'échelle.


0 commentaires

-1
votes

Il existe plusieurs façons de faire ce que vous voulez.

Minuterie

Vous pouvez utiliser une minuterie pour changer la couleur toutes les x heures.

Il existe au moins deux façons de procéder:

1

public class colorchange : MonoBehaviour
{
    public int color;
    public bool stop = true;

    private SpriteRenderer _mySpriteRenderer;
    private float _randomChance = 0.2F;

    void Start()
    {
        _mySpriteRenderer = GetComponent<SpriteRenderer>();
    }

    void Update()
    {
        if (Random.Range(0F, 1F) < _randomChance)
        {
            color = Random.Range(1, 5);

            if (color == 2)
            {
                _mySpriteRenderer.color = Color.blue;
            }
            if (color == 3)
            { 
                _mySpriteRenderer.color = Color.red;
            }
            if (color == 4)
            {
                _mySpriteRenderer.color = Color.yellow;
            }
        }
    }
}

Remarque: strong> vous pouvez mettre en cache votre composant SpriteRenderer pour éviter l'appel GetComponent à chaque fois. Voir ici

2

public class colorchange : MonoBehaviour
{
    public int color;
    public bool stop = true;

    private SpriteRenderer _mySpriteRenderer;
    private float _timeBetweenChanges = 0.5F;

    void Start()
    {
        _mySpriteRenderer = GetComponent<SpriteRenderer>();
        InvokeRepeating("ChangeColor", 0F, _timeBetweenChanges);
    }

    void Update()
    {
        // You don't need Update here, you can safly remove it unless you need it for anything else
    }

    void ChangeColor()
    {
        color = Random.Range(1, 5);
        if (color == 2)
        {
            _mySpriteRenderer.color = Color.blue;
        }
        if (color == 3)
        { 
            _mySpriteRenderer.color = Color.red;
        }
        if (color == 4)
        {
            _mySpriteRenderer.color = Color.yellow;
        }
    }
}

Aléatoire

Vous pouvez utiliser un RNG pour dériver si vous souhaitez changer de couleur ce cadre ou pas. Cela implique que vous ne pouvez pas définir combien de fois par sec / min / en général vous allez changer la couleur.

public class colorchange : MonoBehaviour
{
    public int color;
    public bool stop = true;

    private SpriteRenderer _mySpriteRenderer;
    private float _timeBetweenChanges = 0.5F;
    private float _lastChange = 0f;

    void Start()
    {
        _mySpriteRenderer = GetComponent<SpriteRenderer>();
    }

    void Update()
    {
        if (Time.time - _lastChange >= _timeBetweenChanges)
        {
            _lastChange = Time.time;
            color = Random.Range(1, 5);

            if (color == 2)
            {
                _mySpriteRenderer.color = Color.blue;
            }
            if (color == 3)
            { 
                _mySpriteRenderer.color = Color.red;
            }
            if (color == 4)
            {
                _mySpriteRenderer.color = Color.yellow;
            }
        }
    }
}

Ici, vous avez 20


0 commentaires

0
votes

Une autre alternative à Coroutines ou à un une simple minuterie dans Update consisterait à utiliser InvokeRepeating et arrêtez-le en utilisant AnnulerInvoquer . Dans un cas d'utilisation comme le vôtre, je trouve cette méthode plus facile à implémenter et à contrôler:

public float Interval = 1;

[SerializeField] private SpriteRenderer spriteRenderer;

private void Awake()
{
    // DO THIS ONLY ONCE
    if(!spriteRenderer) spriteRenderer = GetComponent<SpriteRenderer>();
}

// Automatically called when this component or GameObject gets enabled
private void OnEnable ()
{
    // Start invoking every Interval seconds
    InvokeRepeating(nameof(ChangeColor), Interval, Interval);
}

// Automatically called when this component or GameObject gets disabled
private void OnDisable()
{
    // Stop the repeated invoking 
    CancelInvoke();
}

private void ChangeColor()
{
    Debug.Log("Hello");
    color = Random.Range(1, 5);

    // You should also use a switch case here
    switch(color)
    {
        case 2:
            spriteRenderer.color = Color.blue;
            break;

        case 3:
            spriteRenderer.color = Color.red;
            break;

        case 4:
             spriteRenderer.color = Color.yellow;
             break;
    }
}

Ensuite, vous pouvez simplement activer et désactiver le changement de couleur en activant et en désactivant ce composant.

Ou bien déplacez simplement les lignes de code correspondantes de OnEnable et OnDisable à des méthodes publiques comme public void StartColorChange et public void StopColorChange .


0 commentaires

1
votes

Cela peut être fait de plusieurs manières. Avant de vous montrer les choses spécifiques, voici une structure de base, commune à tous les codes d'exemple, que je vais utiliser:

//Since unlike code in Update, coroutines need to be started and stopped, we start it when the script is enabled
private void OnEnable() {
    StartCoroutine(ChangeColorContinuously());
}

//This is automatically stopped by unity when the script is disabled
private IEnumerator ChangeColorContinuously() {
    while (true) {
        yield return new WaitForSeconds(_colorChangeInterval);
        ChangeColor();
    }
}

Voici quelques-unes des principales, par ordre de à quel point ils sont intuitifs, à mon avis:


Modèle de minuterie:

Deux saveurs pour cela.

1) Peut être un accumulateur pour le temps écoulé (comme dans le code ci-dessous), ou l'inverse, et décrémenter de l'intervalle à zéro:

//Replaces _elapsed
private float _timestamp;

private void Start() {
    //...
    _timestamp = Time.time; //Initial timestamp
}

private void Update() {
    if (Time.time < _timestamp + _colorChangeInterval)
        return;
    ChangeColor();
    _timestamp = Time.time;
}

Ou 2) Peut être un déclencheur de vérification d'horodatage depuis le dernier ou jusqu'au suivant (comme ci-dessous), horodatage:

private float _elapsed;

private void Update() {
    _elapsed += Time.deltaTime;

    if (_elapsed < _colorChangeInterval)
        return;
    ChangeColor();
    _elapsed %= _colorChangeInterval;
}

Coroutine & WaitForSeconds:

Ceci est la procédure recommandée lorsque vous devez retarder ou séquencer le code dans l'unité.

Notez qu'il existe d'autres types de méthodes d'attente fournies par unity, comme WaitWhile , WaitUntil , etc ...

public class ColorChanger : MonoBehaviour {
    //Avoid Find and GetComponent methods in performance-critical contexts like Update and FixedUpdate
    //Store the value once in the beginning. This is called 'caching'
    public SpriteRenderer _renderer;

    //Don't hard-code stuff like this
    public Color[] _colors;

    public float _colorChangeInterval = 0.5f;

    //Convenience property to access _renderer.color
    public Color Color {
        get => _renderer.color;
        set => _renderer.color = value;
    }

    private void Start() {
        //Attempts to find the SpriteRenderer in the object if it wasn't set in the inspector
        if (!_renderer)
            _renderer = GetComponent<SpriteRenderer>();
    }

    //This piece of code does a specific thing, so it's best to put it in a method
    public void ChangeColor() {
        if (_colors.Length < 1)
            Debug.LogError($"You forgot to set {nameof(_colors)} in the Inspector. Shame! Shame!");
        Color = _colors[Random.Range(0, _colors.Length - 1)];
    }
}

Ne pas faire d'Async Await!

Eh bien, cela peut être fait, mais cela comporte de nombreux pièges et est très recommandé pour les débutants.

Et ce n'est pas prévu pour remplacer les Coroutines de toute façon.


Ne faites pas InvokeRepeating!

C'est une méthode qui repose sur les chaînes magiques et la réflexion. Utile pour des configurations rapides et faciles par exemple de code, mais si cela est possible (et c'est possible, grâce aux méthodes ci-dessus) doit être évité comme le fléau du code de production.


0 commentaires