CONNEXION
  • RetourJeux
    • Sorties
    • Hit Parade
    • Les + populaires
    • Les + attendus
    • Soluces
    • Tous les Jeux
    • Gaming
  • RetourActu Gaming
    • News
    • Astuces
    • Tests
    • Previews
    • Toute l'actu gaming
  • RetourBons plans
    • Bons plans
    • Bons plans Smartphone
    • Bons plans Hardware
    • Bons plans Image et Son
    • Bons plans Amazon
    • Bons plans Cdiscount
    • Bons plans Decathlon
    • Bons plans Fnac
    • Tous les Bons plans
  • RetourJVTech
    • Actus High-Tech
    • Intelligence Artificielle
    • Smartphones
    • Mobilité urbaine
    • Hardware
    • Image et son
    • Tutoriels
    • Tests produits High-Tech
    • Guides d'achat High-Tech
    • JVTech
  • RetourCulture
    • Actus Culture
    • Culture
  • RetourVidéos
    • A la une
    • Gaming Live
    • Vidéos Tests
    • Vidéos Previews
    • Gameplay
    • Trailers
    • Chroniques
    • Replay Web TV
    • Toutes les vidéos
  • RetourForums
    • Hardware PC
    • PS5
    • Switch 2
    • Xbox Series
    • Switch
    • Pokemon pocket
    • FC 25 Ultimate Team
    • League of Legends
    • Tous les Forums
  • PC
  • PS5
  • Xbox Series
  • Switch 2
  • PS4
  • One
  • Switch
  • iOS
  • Android
  • MMO
  • RPG
  • FPS
En ce moment Genshin Impact Valhalla Breath of the wild Animal Crossing GTA 5 Red dead 2
Liste des sujets

Problème classe Timer

nikobelic
nikobelic
Niveau 10
28 juillet 2015 à 21:12:23

Petite question.
J'ai crée une classe Timer que je peux utiliser dans tous mes scripts (pour faire... des timers quoi...)
Dans la classe Timer j'ai mis la fonction Update(); (et j'ai bien fais hériter Timer de Monobehaviour), pourtant, quand je crée un Timer dans un script, il n'appelle pas la fonction Update à chaque frame :(

Je ne vois pas trop comment faire pour que soit le cas, si c'est possible, ou alors j'ai manqué quelque chose ?

Voilà le code au cazou :

using UnityEngine;
using System.Collections;


public class Timer : MonoBehaviour
{
    private bool _running;
    private float _elsapsedlSecond;

    public Timer()
    {
        _running = false;
        _elsapsedlSecond = 0;
    }

    public Timer(bool startRunning)
    {
        _running = startRunning;
    }

    public float elsapsedlSecond { get { return _elsapsedlSecond; } }
    public bool running { get { return _running; } }
    public void start()
    {
        _running = true;
    }
    public void pause()
    {
        _running = false;
    }
    public void reset() 
    {
        _elsapsedlSecond = 0;
    }

    void Update() 
    {
        Debug.Log("coucou");
        if (_running)
        {
            _elsapsedlSecond += Time.deltaTime;
        }
        
    }
    
}

Merci d'avance.

TheRealMarco
TheRealMarco
Niveau 14
29 juillet 2015 à 00:02:39

Il me semble, que l'autre script ne doit pas appeler la fonction update. L'autre script doit hérité de ta classe Timer.

public class AutreScript : Timer{

Sinon tu fais une fonction public void onUpdate() que tu appelles dans la méthode héritée Update de ta classe.
Explication :
void Update { monTimer.onUpdate(); }

Pseudo supprimé
Pseudo supprimé 29 juillet 2015 à 13:36:45

Hello nikobelic,

Comme d'autre te l'on déjà mentionné, la classe que tu as créée est fonctionnelle, toutefois tu semble mélanger la notion d'une classe qui étant dérivée de "MonoBehaviour" qui est en fait une classe de composant qui ne peut s’exécuter qu'au travers d'un GameObject qui le contient et celle d'une classe de base en C#.

D'ailleurs le fait d'avoir nommé deux constructeurs en démontre cette petite incompréhension.

Dans la pratique pour que ton Update soit appelé il faut que ce script soit attaché au moins à un GameObject instancié dans ta scène. C'est ce GameObject qui créer ta classe et appelle ton Update.

Dans ce cas ton constructeur de base qui surcharge celui de "MonoBehaviour" sera bien sur appelé à la création de l'objet, mais hormis le fait que cette nécessite est très rare à devant être mise en oeuvre, et le problème majeur dans ton écriture est de ne pas appeler aussi le constructeur de base.

La bonne méthode d'écriture devait être :

public class Timer : MonoBehaviour
{
    public Timer():base()
    {
        // Tes initialisations
    }
}

Passons à ton deuxième constructeur.
Sur le même principe puisque tu créer une classe dérivée la bonne méthode est aussi d'appeler le constructeur de base. Tu peut simplifier en appelant toi même ton propre constructeur qui fait le boulot correctement.

public Timer(bool startRunning) : this()
{
    // Autres init
}

Bon cela ne règle pas le problème de fond que quoi qu'il en soit puisque en aucun cas tu ne pourra utiliser ce deuxième constructeur de façon directe, ni le premier bien sur (c'est un crash assuré).

On va laisser le problème du deuxième constructeur, regardons déjà les choses à comprendre dans le premier s'il est bien écrit.

Un petit script affecté à un GameObject pour permettre de comprendre :

using UnityEngine;

public class Heritage : MonoBehaviour
{
    private int _var_0;
    public int VAR_1 = 1;

    public Heritage()
        : base()
    {
        Debug.Log("Constructor");
    }
    private void Awake()
    {
        Debug.Log("Awake");
    }
    private void Start()
    {
        Debug.Log("Start");
    }
    private void OnEnable()
    {
        Debug.Log("OnEnable");
    }
}

Si tu examine ta console debug tu remarque que ton constructeur est bien appelé. Il est appelé plusieurs fois même, c'est normal car quand tu passe du mode editor en mode run, l'inspecteur d'objet lui aussi doit de nouveau instancier ta classe. Attention cela peut être très très gênant et source de bugs difficile à traquer, si tu utilise une ressource non partageable (par exemple file) à la création et tu la libère pas à la destruction de l'objet.

On peut vérifier le truc en rajoutant un destructeur à notre classe.

    ~Heritage()
    {
        Debug.Log("Destructor");
    }

La tu peut remarquer dans la console, qu'il est difficile de maîtriser ce qui se passe en coulisse d'une façon séquentielle dans le cadre d'un "MonoBehaviour".

Le deuxième point que je souhaite te souligner dans le cadre d'une surcharge du constructeur de base d'un "MonoBehaviour", c'est en ce qui concerne les champs publics présent dans l'inspecteur d'objets (je parle de champs et non de propriétés).
Ceux ci sont sérialisé avec le GameObject et sont dé sérialisés juste avant le Awake().
En gros si dans notre constructeur nous modifions ce type de champ, cela n'aura aucun effet.
Exemple :

    public int VAR_1 = 1;

    public Heritage()
        : base()
    {
        VAR_1 = 12;
    }

    private void Awake()
    {
        Debug.Log(VAR_1);
    }

Tu remarquera que VAR_1 contient toujours la valeur 1 !!!

En gros pour conclure, surcharger un constructeur n'a que peut d’intérêt dans le cas d'un descendant de "MonoBehaviour", sauf cas très très particulier qui dépasse ton besoin exprimé.

A mon sens, ta demande que nomme Timer et qui ressemble plus à un chronomètre peut être écrit dans une classe très basique et unitaire.
Le fait même d'utiliser l'Update pour calculer le temps écouler n'est pas vraiment optimum en terme de temps de traitement (une fois par trame... oufff).

Voici à titre d'exemple une classe utilisable qui fait le boulot, et qui ressemble plus a ce que tu souhaitais réaliser :

using UnityEngine;

public class MyTimer
{

    private float _startTime;
    private float _lastTime;
    private bool _running;

    public float Counter
    {
        get
        {
            if (_running)
                return Time.realtimeSinceStartup - _startTime;
            else
                return _lastTime;
        }
    }

    public MyTimer()
    {
        _running = false;
        _lastTime = 0f;
    }

    public MyTimer(bool startRunning)
    {
        _running = startRunning;
        if (_running)
            Start();
    }

    public void Start()
    {
        _running = true;
        _startTime = Time.realtimeSinceStartup;
    }

    public void Pause()
    {
        _running = false;
        _lastTime = Time.realtimeSinceStartup - _startTime;
    }
    

    public void Reset()
    {
        _startTime = Time.realtimeSinceStartup;
        _lastTime = 0f;
    }
}

Pour l'utiliser rien de plus simple, un script de démo lié à un GameObject :

using UnityEngine;

public class GuiTimer : MonoBehaviour {

    private MyTimer _mytimer;
    
    private void Awake()
    {
        _mytimer = new MyTimer();
        // autre possibilité
        // _mytimer = new MyTimer(true ou false);
    }

    private void OnGUI()
    {
        if (_mytimer == null)
            return;

        GUILayout.BeginVertical("box");
        if (GUILayout.Button("Start timer"))
            _mytimer.Start();
        if (GUILayout.Button("Pause timer"))
            _mytimer.Pause();
        if (GUILayout.Button("Reset timer"))
            _mytimer.Reset();
        GUILayout.EndVertical();

        GUILayout.Label(string.Format("Compteur : {0}", _mytimer.Counter));
    }

}

Bon ben voilà, si des choses doivent être développée dans ce que je vient d'exposé, n'hésite pas.

Bonne continuation.

nikobelic
nikobelic
Niveau 10
29 juillet 2015 à 21:19:50

Merci pour ta réponse, si je comprend bien, il ne faut jamais faire hériter une classe de monobehaviour si on ne compte pas l'utiliser sur un Game Object ?

Pseudo supprimé
Pseudo supprimé 29 juillet 2015 à 22:14:55

Exactement.

Une recherche dans Google du type "unity monobehaviour constructor" te donneras le même type d'information que vient de développer.

A+

Sous forums
  • Aide à l'achat Mac
  • Macintosh
  • Création de sites web
  • Création de Jeux
  • Linux
  • Programmation
  • Internet
  • Steam Deck
  • Hardware
La vidéo du moment