Invoke dans Update

Questions à propos du scripting. Hors Shader, GUI, Audio et Mobile.
ketsuicrea
Messages : 11
Inscription : 30 Déc 2020 13:00

Invoke dans Update

Message par ketsuicrea » 08 Jan 2021 10:48

Bonjour,

Mon but est d'attendre avant d'avoir la possibilité d'instantier un dogPrefab, donc je peux appuyer sur la barre espace mais cette dernière n'instantiera qu'au bout d'un certain temps et pour faire cela j'ai utilisé Invoke avec un temps de 3s mais Ô surprise, pour le premier appel, première prefab à 3s pour la suite lorsque je j'appuie sur espace plusieurs fois alors il y a autant de prefab que d'appui hors je pensais que Invoke attendrait 3s comme spécifié à chaque appel de Update().

du coup je ne comprends pas pourquoi et ne sais comment placer un temps d'attente entre deux prefab?

Code : Tout sélectionner

    void Update()
    {
        // On spacebar press, send dog
     
        Invoke("StartDog",3);
        
    }

    void StartDog()
    {
        if (Input.GetKeyDown(KeyCode.Space))
        {
            Instantiate(dogPrefab, transform.position, dogPrefab.transform.rotation);
        }
    }
Merci pour votre aide, j'espère avoir été assez clair, j'ai bien fait des recherches mais je suis tombé sur des truc type IEemumerator yield and co... mais toujours le même prob.

Ketsui.

Avatar de l’utilisateur
jmhoubre
Messages : 851
Inscription : 05 Oct 2019 22:05

Re: Invoke dans Update

Message par jmhoubre » 08 Jan 2021 13:07

Bonjour,

quand tu lances ton jeu, Update () est appelée à chaque frame (plusieurs dizaines de fois par seconde), et invoque donc ta méthode StartDog (), toujours plusieurs dizaines de fois par seconde. StartDog teste si le joueur appuie sur la touche espace. Si c'est le cas, l'instanciation a lieu.

Cette façon de faire n'est pas efficace : en effet, Unity va lancer StartDog des dizaines de fois en parallèle pendant les 3 secondes d'attente, et ceci pour rien. Je ne suis pas très sûr de la façon dont fonctionne invoke dans le détail, mais j'ai bien l'impression que l'ordre d'exécution de ces dizaines d'Invoke n'est pas déterministe.J'ai fait quelques essais, et ma fonction invoquée s'exécute 0, 1, 2 ou 3 fois à chaque frame :

Code : Tout sélectionner

private int count;
void Update()
{
    count++;
    Invoke ("StartDog", 3);
}

private void StartDog ()
{
    Debug.Log (count);
}
Pour faire ce que tu veux, tu devrais utiliser une coroutine. C'est d'ailleurs préconisé par Unity :
Documentation a écrit :For better performance and maintability, use Coroutines instead.

ketsuicrea
Messages : 11
Inscription : 30 Déc 2020 13:00

Re: Invoke dans Update

Message par ketsuicrea » 08 Jan 2021 14:40

Bonjour,

J'ai en effet vu Coroutines utiliser avec la déclaration d'une méthode IEnumerator mais j'ai bien essayé après quelques copies collés mais comme IEnumerator et autre n'est pas encore clair ce que j'écris compile mais le résultat n'est pas au Rendez-vous. Mais d'après ce que j'ai vu, beaucoup de personnes semblent avoir cette problématique et il y. a presque autant de questions que de réponses donc un sujet pas si évident que cela.

Mais merci pour les explications sur Update c'est encore une chose que je n'ai pas en tête.

Ketsui.

Avatar de l’utilisateur
boubouk50
ModoGenereux
ModoGenereux
Messages : 6185
Inscription : 28 Avr 2014 11:57
Localisation : Saint-Didier-en-Bresse (71)

Re: Invoke dans Update

Message par boubouk50 » 08 Jan 2021 15:58

C'est un problème de compréhension des fonctions de MonoBehaviour puis de la logique qui en découle.
L'update (), comme dit, est appelé à chaque frame (donc 60 fois par secondes quand tu es a 60fps). Donc si tu fais un appel de fonction directement dedans, elle sera appelé à chaque frame (donc 60 fois par secondes).
Ce n'est pas du tout ce que tu veux.
Une coroutine quand a elle est une fonction dans laquelle tu peux gérer le temps à ta guise. Une coroutine qui fait des trucs puis attend la fin de la frame pour recommencer fait donc office d'Update ().
Ici, ce que tu veux c'est avoir un temps d'attente minimum pour avoir accès à une fonction. Que ce soit par l'Update () ou la coroutine, cela ne joue pas avec le temps mais avec une condition d'attente. Un timer en soit.

Tu peux utiliser l'Update () dans lequel un timer (float) va s'incrémenter jusqu'à atteindre 3 secondes pour débloquer une condition (if (timer > 3f)).

Code : Tout sélectionner

[...]
private float timer = 0f;

void Update ()
{
	//Incrémenter le timer
	timer += Time.deltaTime;
	
	//Tester l'attente
	if (timer > 3f)
	{
		if (Input.GetKeyDown(KeyCode.Space))
        	{
        		//Instancier ton prefab
			Instantiate(dogPrefab, transform.position, dogPrefab.transform.rotation);
			
			//Remettre le timer à 0 pour ne plus entrer dans la condition
			timer = 0f;
		}
	}
}
[...]
Tu n'appelles pas une fonction dans 3 secondes, tu attends 3 secondes avant de pouvoir la lancer, c'est totalement différent comme approche.
"Ce n'est pas en améliorant la bougie, que l'on a inventé l'ampoule, c'est en marchant longtemps."
Nétiquette du forum
Savoir faire une recherche
Apprendre la programmation

ketsuicrea
Messages : 11
Inscription : 30 Déc 2020 13:00

Re: Invoke dans Update

Message par ketsuicrea » 08 Jan 2021 21:27

Merci,

Touché en effet, ma compréhension est encore très très bas niveau mais ce type de Challenge proposé à Unity vise à nous questionner, essayer nous planter, chercher sur la toile et apprendre à poser des questions.

Merci pour ces les éclaircissements sur l'Update et pour le code qui fonctionne à merveille. J'avais pourtant dans les tutos précédants d'Unity utilisé la méthode Time.deltaTime mais je n'ai pas su l'utiliser à bon escient dans ce cas.

Petit à petit :)

Encore merci.
Ketsui.

Répondre

Revenir vers « Scripting »