peachplayer Geschrieben 21. Januar 2021 Melden Share Geschrieben 21. Januar 2021 Hallo Leute Weiss jemand wie man einen Timer mit Unity machen kann? Habs wie folgt probiert: using System; using System.Collections; using System.Collections.Generic; using System.Globalization; using UnityEngine; using UnityEngine.UI; public class Countdown11 : MonoBehaviour { public float timeStart = 0; public Text textBox; public DateTime time; // Use this for initialization void Start() { textBox.text = timeStart.ToString(); } // Update is called once per frame void Update() { Time.timeScale = 500f; timeStart += Time.deltaTime * Time.timeScale; DateTimeFormatInfo fmt = (new CultureInfo("hr-HR")).DateTimeFormat; var time = new DateTime(Convert.ToInt64(timeStart)); textBox.text = time.ToLongDateString(); Debug.Log(time.ToString("yyyy-MM-ddTHH:mm:ssZ")); } } Leider bleibt die Ausgabe immer bei null stecken, statt dass die Tage vorwärts laufen. Kann mir jemand helfen? Gruss, peachplayer Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
Sascha Geschrieben 21. Januar 2021 Melden Share Geschrieben 21. Januar 2021 Moin, also erstmal solltest du timeScale nicht dafür benutzen. Das ist ein globaler Faktor, der auf Time.deltaTime draufmultipliziert wird, und zwar überall. Die Physik läuft dann auch auf 500-facher Geschwindigkeit. Und du multiplizierst das ja nochmal drauf, also bist du bei 250.000 Steigerung pro Sekunde. Dann benutzt du da new DateTime(long), was als Parameter einen Wert in Zehntel-Millisekunden haben will. Du schmeißt also nicht 250.000, sondern 25 Sekunden pro Sekunde da rein... ganz komischer Umweg. Aber mal zum Anfang... was meinst du mit "Timer"? Meinst du einfach eine Uhr im Spiel, die bei 0 losgeht, wenn das Spiel startet? Oder meinst du so eine Uhr, die weiterläuft, wenn das Spiel geschlossen und wieder geöffnet wurde (bzw. zumindest so tut)? Es sieht irgendwie so aus, als würdest du ein paar Ingame-Jahre verstreichen lassen wollen, wenn irgendwie eine Stunde oder so vergeht... aber ich will eigentlich nicht blind raten. Ein Timer ist erstmal ganz einfach. Nicht timeScale benutzen, sondern einfach einen eigenen Faktor: private float time; [Tooltip("How many ingame seconds pass per real-world second?")] public float factor = 1; private void Update() { time += Time.deltaTime * factor; Debug.Log(time); } Wenn du deinen Sekunden-Wert in Jahre, Monate, Tage, Stunden, Minuten und Sekunden rechnen willst, dann kannst du dafür theoretisch DateTime benutzen, aber damit ist immer ein reales Datum im realen Kalender repräsentiert. Passender wäre vermutlich die TimeSpan-Klasse, und dann so: var timeSpan = new TimeSpan((long)(time * 10000)); 10000, um von den 100-Nanosekunden-Schritten auf Sekunden-Schritte zu kommen. Das solltest du dann mit ToString in eine hübsch lesbare Form kriegen können, wie du es auch schon tust. Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
peachplayer Geschrieben 22. Januar 2021 Autor Melden Share Geschrieben 22. Januar 2021 using System; using System.Collections; using System.Collections.Generic; using System.Globalization; using UnityEngine; using UnityEngine.UI; public class Countdown11 : MonoBehaviour { float cntdnw = 1.0f; public Text disvar; public Button startButton; public Button stoppButton; private void Start() { Button btn1 = startButton.GetComponent<Button>(); Button btn2 = stoppButton.GetComponent<Button>(); } void Update() { if ( (startButton.enabled) && (!stoppButton.enabled)) { cntdnw += Time.deltaTime; double b = System.Math.Round(cntdnw, 2); string dateTimeString = System.String.Format("{0:yyyy-MM-dd-hh}", b); disvar.text = TimeSpan.FromDays(b).ToString(); } if (stoppButton.enabled) Debug.Log("game stopped!"); } } Habe noch 2 Buttons für "start" und "stopp" gemacht. Jedoch funktionieren diese Buttons nicht richtig, d.h. das Spiel kann nicht fortgesetzt werden nach einem stopp. Gruss, peachplayer Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
malzbie Geschrieben 23. Januar 2021 Melden Share Geschrieben 23. Januar 2021 Du fragst ab, ob die Button-Komponente Enabled ist. Das hat ja nichts mit einem Druck auf den Button zu tun. Enabled wird die Komponente immer sein. Es scheint, als hättest du noch keine Erfahrung mit der UI, also den Buttons da drin. Der Button ist ein Gameobjekt und hat eine Button-Komponente ( Das unterscheidet ihn von einem Image, das hat nämlich stattdessen eine Image-Komponente). Die Button-Komponente hat ein OnClick Event, welches dafür da ist, in eine ( oder auch mehrere) Methode(n) eines Scripts hinein zu springen, wenn der Button gedrück wurde. Du brauchst also ein eine public Methode in deinem Script, mit der der Button kommuniziert. z.B. sowas: public void StartCounter(){ // diese Methode soll der Start Button aufrufen // hier kannst du eine Variable setzen oder aber ganzen Code ausführen } public void StopCounter(){ // Diese Methode soll der Stop Button aufrufen // auch hier kannst du alles Möglich drin tun } Du klickst also beim Bereich OnClick() auf das kleine Pluszeichen. Jetzt legst du in den entstandenen Slot das Objekt rein, auf dem dein Script liegt. Nun kannst du beim Dropdown Function dein Script sehen. Gehe mit der Maus über das Script und es öffnet sich ein weiterer Bereich, der dir alle möglichen Dinge anzeigt. Unter anderem auch deine public Methoden. Wähle die gewünschte Methode aus. Schon ist der Button mit dem Script verknüpft. Noch was: Du hast ja in deinem Script die 2 Buttons eingebunden. Ich vermute du setzt per script enable auf true oder false, weil du möchtest, dass die Button nur dann etwas machen sollen wenn das Szenario es auch erlaubt. Buttons enabled man aber nicht. Man sagt ihnen ob sie interagieren dürfen oder nicht. Und dafür gibt es extra einen Zustand der interactable heisst. Und das steuerst du so: StopButton.interactable = true; Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
peachplayer Geschrieben 23. Januar 2021 Autor Melden Share Geschrieben 23. Januar 2021 Danke für die Tipps! Wenn ich das richtig verstanden habe, benötige ich keinen Event-Handler für die Buttons, um auf einen Click zu regarieren? Ein weiteres Problem ist die Anweisung: cntdnw += Time.deltaTime; Muss dieser Befehl nicht zwingend innerhalb der Update()-Funktion aufgeführt werden, damit der Timer überhaupt vorwärts läuft? Gruss, peachplayer Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
Sascha Geschrieben 23. Januar 2021 Melden Share Geschrieben 23. Januar 2021 vor 33 Minuten schrieb peachplayer: Wenn ich das richtig verstanden habe, benötige ich keinen Event-Handler für die Buttons, um auf einen Click zu regarieren? Korrekt. Du kannst entweder die Methode(n) aussuchen, die der Button beim Klick ausführen soll, indem du im Inspektor des Buttons Listeneinträge machst, oder du machst das über Code, mit mybutton.onClick.AddListener. Beides ist valide. Welches von beidem du eher nutzen solltest, hängt von der Situation ab. vor 35 Minuten schrieb peachplayer: Ein weiteres Problem ist die Anweisung: cntdnw += Time.deltaTime; Muss dieser Befehl nicht zwingend innerhalb der Update()-Funktion aufgeführt werden, damit der Timer überhaupt vorwärts läuft? Richtig, du willst das immer wieder ausführen. Aber du willst nicht immer wieder den Button abfragen. Geht auch gar nicht. Was du tun willst, ist einen Schalter umlegen: private bool timerIsActive; public void StartTimer() { timerIsActive = true; } public void PauseTimer() { timerIsActive = false; } private void Update() { if (timerIsActive) { // Do clock stuff } } Du kannst aber auch direkt enabled benutzen: public void StartTimer() { enabled = true; } public void PauseTimer() { enabled = false; } private void Update() { // Do clock stuff } Update wird ja gar nicht erst aufgerufen, wenn enabled false ist. Außerdem kannst du dann schön im Editor manuell das Häckchen an und aus machen zum Debuggen Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
peachplayer Geschrieben 23. Januar 2021 Autor Melden Share Geschrieben 23. Januar 2021 danke für die guten tipps! Jetzt klappt alles wunderbar, ausser das Datum-format für den Countdown fehlt noch, in der Art von "dd:mm:hh", sodass jede Sekunde etwa einem Tag entspricht! Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
peachplayer Geschrieben 23. Januar 2021 Autor Melden Share Geschrieben 23. Januar 2021 Leider funktioniert immer noch nicht alles ganz richtig: public void starttimer() { startButton.enabled = true; stoppButton.enabled = false; stoppButton.interactable = true; } public void stopptimer() { stoppButton.enabled = true; startButton.enabled = false; startButton.interactable = true; } Der Timer kann nach einem 'stop' nicht mehr fortgesetzt werden mit dem 'start' - Button. Weshalb wohl? Gruss, peachplayer Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
malzbie Geschrieben 23. Januar 2021 Melden Share Geschrieben 23. Januar 2021 Was soll denn dein enable.true bzw. enabled.false bewirken? Wieso machst du das? Wenn du eine Komponente über enabled.false abschaltest, dann geht sie auch nicht mehr bis du sie wieder einschaltest. Drückst du den Stop Button, wird der Startbutton disabled. Er ist also deaktiviert und funktioniert nicht mehr. Deswegen kannst du es nicht fortsetzen. Deswegen frage ich dich, warum du enable nutzt. Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
peachplayer Geschrieben 24. Januar 2021 Autor Melden Share Geschrieben 24. Januar 2021 danke für die Tipps! Habs statt mit Button.enabled mit einer boolschen Variable gelöst. Jetzt ist noch das Problem, wie man die virtuelle Systemzeit, also den Timer, für alle Szenen benützen kann. Kann man das ev. mit den PlayerPrefs machen? Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
Sascha Geschrieben 24. Januar 2021 Melden Share Geschrieben 24. Januar 2021 NEIN! Also... doch. Aber bitte nicht. PlayerPrefs speichert Dinge auf der Festplatte. Das ist NICHT dafür da, dass du Dinge in mehreren Szenen zur Verfügung hast. Ist ein bisschen als ob du das Waschbecken abmontierst, um damit in die Küche zu gehen und Suppe reinzufüllen. Geht zwar, aber lass mal lieber. Wenn du Dinge szenenübergreifend machen willst, musst du dir bewusst machen, was ein Szenenwechsel ist. Es werden alle GameObjects gelöscht und die GameObjects der neuen Szene werden geladen. Es geht alles verloren, was auf einem der gelöschten GameObjects hockt... naja, theoretisch zumindest Davon ausgehend gibt es mehrere Sachen, die du machen kannst. An dieser Stelle denke ich, dass ein statisches Feld vermutlich sinnvoll wäre. Ein statisches Feld ist ja eines, das nicht an ein Objekt gebunden ist. Der Wert geht also auch nicht flöten, wenn alle möglichen Objekte gelöscht werden, weil er halt zu keinem davon gehört. Du machst also statt private float zahl; einfach private static float zahl; und schon bleibt der Wert erhalten. Denke aber daran, was static bedeutet und was das für Konsequenzen hat. Du kannst nämlich zum Beispiel keine zwei Timer dieser Art mehr haben, weil ja nicht jedes Timer-Objekt sein eigenes float-Feld bekommt, sondern es programmweit nur noch dieses eine gibt. Wenn static hier nicht die richtige wahl sein sollte (weil du z.B. doch beliebig viele Timer haben können willst), dann könnten noch DontDestroyOnLoad oder ScriptableObjects etwas für dich sein. Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
peachplayer Geschrieben 24. Januar 2021 Autor Melden Share Geschrieben 24. Januar 2021 danke, leider funktioniert das bisher nicht mit der static-Anweisung. Das Datum fängt immer wieder beim Startpunkt an, wenn ich eine andere Szene lade. Habs wie folgt probiert: public static DateTime virtual_time = Anzeige1.dt; Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
chrische5 Geschrieben 24. Januar 2021 Melden Share Geschrieben 24. Januar 2021 Hallo Nutz doch ein Scriptable Object als quasi globale Variable. Chrische Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
Sascha Geschrieben 24. Januar 2021 Melden Share Geschrieben 24. Januar 2021 vor 4 Stunden schrieb peachplayer: Das Datum fängt immer wieder beim Startpunkt an, wenn ich eine andere Szene lade. Dann hast du irgendwo Code, der das zurücksetzt. Vermutlich irgendeine Komponente, die das in Awake, OnEnable oder Start macht. Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
peachplayer Geschrieben 24. Januar 2021 Autor Melden Share Geschrieben 24. Januar 2021 Muss denn die statische Varible im anderen Skript nicht via Update inkrementiert werden, damit das Datum nicht bei Null stehen bleibt? In der Anfangs-Szene wo der Timer generiert wird werden ja nach dem laden der neuen Szene alle GameObjekte und Variablen gelöscht, oder nicht? Output 2. Szene: Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
Sascha Geschrieben 24. Januar 2021 Melden Share Geschrieben 24. Januar 2021 vor einer Stunde schrieb peachplayer: Muss denn die statische Varible im anderen Skript nicht via Update inkrementiert werden, damit das Datum nicht bei Null stehen bleibt? Doch. vor einer Stunde schrieb peachplayer: In der Anfangs-Szene wo der Timer generiert wird Ich glaube, da ist vielleicht der Knackpunkt. Ein statisches Feld existiert nicht auf einem Objekt. Es wird also auch nicht generiert. Es existiert von Anfang des Programms bis zu dessen Ende. Ein stückweit heißen die Dinger auch deswegen "statisch". Der Timer wird also nicht generiert. Es sei denn, du meinst damit das Objekt, das den Wert des Feldes durchgehend erhöht. vor einer Stunde schrieb peachplayer: werden ja nach dem laden der neuen Szene alle GameObjekte und Variablen gelöscht, oder nicht? Die GameObjects, die in der Szene sind, werden gelöscht, ja. Aber eben nicht dein statisches Feld. Das existiert schon vor dem Laden der Szene und bleibt auch danach noch erhalten. Meine Vermutung ist halt, dass du in der zweiten Szene ein Objekt hast, das den Wert des statischen Feldes zurücksetzt. Klar brauchst du zum Weiterzählen auch in der zweiten Szene ein Objekt, das das tut... (wobei man auch mit DontDestroyOnLoad das ursprüngliche behalten könnte... aber das ist schon wieder so ein Thema...) aber dieses Objekt sollte den Wert nicht erstmal wieder auf 0 setzen. Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
peachplayer Geschrieben 25. Januar 2021 Autor Melden Share Geschrieben 25. Januar 2021 Könnte man das Problem eines 'synchronisierten' Timers ev. mit einer eigenen Klasse für den Timer lösen? Gruss, peachplayer Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
Sascha Geschrieben 25. Januar 2021 Melden Share Geschrieben 25. Januar 2021 Ich weiß gerade nicht, welches Problem du meinst. Aber ob du Dinge in Klasse A oder Klasse B tust sollte, wenn nicht sowieso eindeutig ist dass das sein muss, keinen Unterschied machen. Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
peachplayer Geschrieben 25. Januar 2021 Autor Melden Share Geschrieben 25. Januar 2021 ich meine damit, dass der Timer für alle Szenen synchronisiert gültig ist! Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
Sascha Geschrieben 25. Januar 2021 Melden Share Geschrieben 25. Januar 2021 Warum versuchst du, jetzt etwas ganz anderes zu machen? Statische Variable und los! Nur, weil da gerade noch ein Problem zu lösen ist, heißt das nicht, dass man gleich die ganze Idee verwerfen muss... Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
peachplayer Geschrieben 25. Januar 2021 Autor Melden Share Geschrieben 25. Januar 2021 es funktioniert einfach nicht so einfach mit der statischen Variable, d.h. gemäss einem Lehrbuch unterstützt Unity gar keine globalen Variablen. Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
Sascha Geschrieben 25. Januar 2021 Melden Share Geschrieben 25. Januar 2021 Bitte was... natürlich funktioniert das xD Und was dein Lehrbuch sagt... naja, genieße das mit ner Prise Salz. Statische Variablen sind globale Variablen und selbstverständlich unterstützt Unity die. Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
peachplayer Geschrieben 25. Januar 2021 Autor Melden Share Geschrieben 25. Januar 2021 by the way....wie macht man dass dann, dass die Timer-Klasse von MonoBehavoiur ableitet? Hab mal gesehen, das geht mit 'Instanzen'? Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
Sascha Geschrieben 25. Januar 2021 Melden Share Geschrieben 25. Januar 2021 Ich weiß nicht genau, was du gerade machen willst, aber generell einfach public class Klassenname : MonoBehaviour Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
peachplayer Geschrieben 25. Januar 2021 Autor Melden Share Geschrieben 25. Januar 2021 dann wäre das aber eine 'eigene' MonoBehavour-Klasse ohne Zugriff von aussen... Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
Recommended Posts
Archiviert
Dieses Thema ist jetzt archiviert und für weitere Antworten gesperrt.