J'ai un script de compte à rebours de 10 secondes qui s'exécute sur DeltaTime.
Dans ma fonction de mise à jour, j'essaie de le faire imprimer, une seule fois, "Hello" chaque fois qu'il atteint la seconde 8.
Le problème est que deltaTime imprime à plusieurs reprises "Hello" pendant qu'il se bloque à la 8e seconde, plutôt que d'imprimer une seule fois, et je ne sais pas comment arrêter ce comportement.
J'ai continué à essayer d'introduire des déclencheurs dans le bloc if qui mettent à 0 dès que le bloc est entré mais il continue à imprimer continuellement "Bonjour" tant que le minuteur est sur la seconde 8.
Compte à rebours
if (CountdownTimer.switcher == 1)
{
CountdownTimer.switcher = 0;
print("hey");
}
Méthode de mise à jour dans une classe différente
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class CountdownTimer : MonoBehaviour
{
float currentTime = 0f;
float startingTime = 10f;
public int n = 0;
public int switcher = 0;
// Start is called before the first frame update
void Start()
{
currentTime = startingTime;
}
// Update is called once per frame
void Update()
{
currentTime -= 1 * Time.deltaTime; //does it each frame
n = Convert.ToInt32(currentTime);
if (n == 8)
{
switcher = 1;
}
}
}
Des idées sur la façon de faire imprimer ("hey") une seule fois? C'est important car plus tard, je remplacerais le code d'impression par une méthode importante et je dois m'assurer que la méthode ne se produit qu'une seule fois.
3 Réponses :
Étant donné que Updtade () est appelé une fois par image, le sélecteur est réglé sur 1 une fois par image pendant la 8e seconde (et il y a beaucoup d'images en 1 seconde).
Une réponse pourrait être quelque chose comme ceci pour l'empêcher de s'imprimer à nouveau:
if (CountdownTimer.switcher == 1)
{
if (!AlreadyDisplayed)
{
print("hey");
AlreadyDisplayed = true;
}
}
Où Déjà affiché est un booléen défini sur false lorsqu'il est déclaré.
Cela devrait faire ce que vous voulez réaliser. :)
C'est ici que vous souhaitez implémenter un système d'abonné avec événement / écouteur.
Ajoutez un événement au compte à rebours, si le compte à rebours se veut unique, vous pouvez même le rendre statique. De plus, si la mise à jour n'est plus nécessaire après le réglage du commutateur sur 1, vous pouvez la convertir en coroutine
public class MyClass : MonoBehaviour
{
void Start()
{
CountdownTimer.RaiseReady += CountdownTimer_RaiseReady;
}
private void CountdownTimer_RaiseReady()
{
Debug.Log("Done");
// Remove listener though the other class is already clearing it
CountdownTimer.RaiseReady -= CountdownTimer_RaiseReady;
}
}
Tout composant qui a besoin de savoir:
XXX
J'étais en train de tester cette solution et j'ai quelques problèmes. Il semble que la variable currentTime dans UpdateCoroutine ne compte pas à rebours, comme elle le ferait si elle était à l'intérieur d'une méthode Update. Par exemple, si j'ajoute le code de test print ("in"); dans la branche if (n == 8) , il ne l'imprime jamais dans la console. Si je le force à frapper la branche en disant n = 8 , il imprime "in", mais quand même, Debug.Log ("Done") ne s'imprime jamais sur la console. Des idées...? J'ai des problèmes pour mettre en œuvre l'autre solution pour des raisons similaires.
Oui, j'ai raté la boucle while, mon mauvais
La solution fournie par @Everts est plutôt bonne, mais comme vous utilisez unity, je recommanderais quelques ajustements pour mieux jouer avec l'éditeur. Au lieu d'un événement générique, je recommande d'utiliser un UnityEvent de l'espace de noms UnityEngine.Events . Je déconseillerais également la statique en raison de la façon dont l'unité les sérialise à travers les scènes. Il y a des cas limites étranges dans lesquels vous pouvez entrer si vous n'êtes pas familier avec la façon dont l'unité gère leur sérialisation. Si vous avez juste besoin d'envoyer un message à un autre objet de la même scène, je recommanderais en fait un gestionnaire de jeu. Vous pouvez faire un GameObject.Find () en toute sécurité dans onvalidate () et lier vos variables pour éviter une baisse des performances lors de l'exécution de la recherche. Si ces données doivent être transférées vers une autre scène pour ce message, utilisez à la place un ScriptableObject . Cela ressemblerait à quelque chose comme ci-dessous.
Mettez ce composant sur le "Game Manager" de la scène GameObject
public class user : MonoBehaviour
{
[SerializeField, HideInInspector]
private CountingPassthrough timerObject;
private void OnValidate()
{
if(FindObjectOfType<CountingPassthrough>().gameObject.scene == gameObject.scene && FindObjectOfType<CountingPassthrough>() != new UnityEngine.SceneManagement.Scene())
timerObject = FindObjectOfType<CountingPassthrough>();
}
private void OnEnable()
{
timerObject.countdownTimer.timedOut.AddListener(DoSomething);
}
private void OnDisable()
{
timerObject.countdownTimer.timedOut.RemoveListener(DoSomething);
}
private void DoSomething()
{
//do stuff here...
}
}
mettez ce composant sur la scène " Timer "GameObject
public class CountdownTimer : MonoBehaviour
{
public float startingTime = 10f;
public UnityEvent timedOut = new UnityEvent();
private void OnValidate()
{
if(FindObjectOfType<CountingPassthrough>().gameObject.scene == gameObject.scene && FindObjectOfType<CountingPassthrough>() != new UnityEngine.SceneManagement.Scene())
FindObjectOfType<CountingPassthrough>().countdownTimer = this;
}
private void Start()
{
StartCoroutine(TimerCoroutine());
}
// Coroutine is called once per frame
private IEnumerator TimerCoroutine()
{
float currentTime = 0f;
while (currentTime != 0)
{
currentTime = Mathf.Max(0, currentTime - Time.deltaTime);
yield return null;//wait for next frame
}
timedOut.Invoke();
}
}
Placez ce composant sur le GameObject dont vous souhaitez utiliser le minuteur
public class CountingPassthrough : MonoBehaviour
{
public CountdownTimer countdownTimer;
}
Ce flux de travail est également convivial pour les préfabriqués, car vous pouvez encapsuler le find () dans onvalidate () avec if (FindObjectOfType pour éviter de saisir le mauvais élément d'autres scènes chargées. Et encore une fois, si vous en avez besoin pour transporter des données à travers les scènes, alors CountingPassthrough hérite de ScriptableObject au lieu de MonoBehaviour , créez le nouveau ScriptableObject dans votre dossier de projet quelque part, et ignorez ce supplément si vous cochez pour contraindre la correspondance de scène. Ensuite, assurez-vous d'utiliser une fonction pour la trouver qui inclut des actifs si vous utilisez l'approche ScriptableObject inter-scènes.
EDIT: Oublié le boîtier de bord préfabriqué imbriqué dans les versions Unity 2018+. Vous devez l'ajouter pour en tenir compte: && FindObjectOfType J'ai mis à jour l'extrait de code ci-dessus. Désolé pour cela.