Du bist nicht angemeldet.

Stilllegung des Forums
Das Forum wurde am 05.06.2023 nach über 20 Jahren stillgelegt (weitere Informationen und ein kleiner Rückblick).
Registrierungen, Anmeldungen und Postings sind nicht mehr möglich. Öffentliche Inhalte sind weiterhin zugänglich.
Das Team von spieleprogrammierer.de bedankt sich bei der Community für die vielen schönen Jahre.
Wenn du eine deutschsprachige Spieleentwickler-Community suchst, schau doch mal im Discord und auf ZFX vorbei!

Werbeanzeige

Garzec

Alter Hase

  • »Garzec« ist der Autor dieses Themas

Beiträge: 693

Wohnort: Gießen

  • Private Nachricht senden

1

03.04.2017, 08:27

Wert pro Sekunde in Unity erhöhen

Hi,
ich habe einen Tageszyklus, ein voller Tag hat zum Beispiel 300 Sekunden. Jetzt funktioniert der Code bereits, aber ich finde ihn einfach sehr unsauber. Die while-Schleife hat ja keine wirkliche Bedingung, läuft also endlos. Nun ist meine eigentlich Frage nur, ob jemand eine Idee hat, wie ich bei einer Tagesdauer von beispielsweise 300 Sekunden den Zähler so erhöhen kann, dass der Tag tatsächlich 300 Sekunden andauert.

Vielleicht ist dieser Weg ja richtig, aber die Schleife gefällt mir gar nicht :/

C#-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
void Start()
    {
        cycleData = new DayNightCycleData();
        cycleView = new DayNightCycleView();

        StartCoroutine(HandleTime());
    }

    IEnumerator HandleTime()
    {
        while (true)
        {
            cycleData.CurrentTime++; // Die aktuelle Uhrzeit, tickt von 0 bis 300 hoch

            if (cycleData.CurrentTime >= cycleData.FullCycleInSeconds) // Bei 300 wird der Counter zurückgesetzt
                cycleData.CurrentTime = 0;

            cycleView.UpdateCycle(cycleData); // GUI Aktualisierung

            yield return new WaitForSeconds(1); // Warte 1 Sekunde
        }
    }

Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von »Garzec« (03.04.2017, 09:21)


Sneyke

Frischling

Beiträge: 33

Beruf: Softwareentwickler

  • Private Nachricht senden

2

03.04.2017, 10:23

Warum so kompliziert? In so einem Simplen ding würde ich nicht so dick auffahren bzw. da halte ich Parallelität für unnötig.

Eventuell so:

eine Klasse:

C#-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class DayTime{

   private float actualTime = 0;
   private float dayCycleTimeInSec;


   public DayTime(float dayCycleTimeInSec){
       this.dayCycleTimeInSec = dayCycleTimeInSec;
   }


   public void AddTime(float time){
       
      actualTime += time;
      
      if(time >= dayCycleTimeInSec){
         actualTime -= dayCycleTimeInSec; //Um die Zeit wieder auf null zu setzen, aber die bereits verstrichene Zeit nicht zu verlieren
      }

   }

}



In deiner Unity-Klasse:

C#-Quelltext

1
2
3
4
5
6
7
DayTime dayTime = new DayTime(300f);

public void UpdateBlaBla(){

    dayTime.AddTime(Time.deltaTime);

}

Tixewi

Frischling

Beiträge: 81

Wohnort: Stuttgart

Beruf: Software Developer

  • Private Nachricht senden

3

03.04.2017, 13:43

Du könntest in der Update dein Counter um die Delta Time erhöhen oder was vermutlich besser sein wird, InvokeRepeat verwenden, welches jede Sekunde eine Methode aufruft, in welcher du dann den Counter erhöhst und dann diesen bei 300 zurücksetzt.

Garzec

Alter Hase

  • »Garzec« ist der Autor dieses Themas

Beiträge: 693

Wohnort: Gießen

  • Private Nachricht senden

4

03.04.2017, 15:53

@Sneyke, den Wert mit Time.deltaTime aufzuaddieren, das hatte ich schon. Aber Time.deltaTime liefert ja nicht 1 Sekunde zurück sondern die verstrichene Zeit, seit dem letzten Zeitpunkt. Aus diesem Grunde war ich unsicher, ob ich das wirklich nehmen möchte. Es ist der einfachste Weg und höchstwahrscheinlich auch der beste Weg, ja.

Tixewi

Frischling

Beiträge: 81

Wohnort: Stuttgart

Beruf: Software Developer

  • Private Nachricht senden

5

03.04.2017, 17:00

Wenn du es exakt möchtest bleibt nur noch InvokeRepeat. Im Endeffekt läuft dann auch eine Coroutine im Hintergrund. Diese hat aber keine While-Schleife ^^

Edit: nevermind, das ist exakt das gleiche. Sieht nur ordentlicher aus mit InvokeRepeat. Aber dann passt es eigentlich so, wie du es gemacht hast.

Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von »Tixewi« (03.04.2017, 17:10)


Garzec

Alter Hase

  • »Garzec« ist der Autor dieses Themas

Beiträge: 693

Wohnort: Gießen

  • Private Nachricht senden

6

03.04.2017, 17:22

Also ich kann verstehen, wenn man meinen ursprünglichen Weg als "viel zu komplex" ansieht. Ebenso finde ich die while-Schleife, die immer auf true steht schon fast tödlich. Dennoch funktioniert der Code. Sneyke hat wohl einfach den saubersten Weg geliefert. ;)

Danke

Renegade

Alter Hase

Beiträge: 494

Wohnort: Berlin

Beruf: Certified Unity Developer

  • Private Nachricht senden

7

03.04.2017, 20:03

Hallo Garzec,
dein Weg ist tatsächlich sehr unsauber und produziert Unmengen von Overhead für eine simple Routine. Das liegt nicht nur am allgemeinen Overhead von Coroutinen (2x System-Calls nötig: moveNext und current, sowie eine weitere GC alloc in jedem Frame), sondern auch an der Tatsache das du z.B. dein WaitForSeconds nicht cachest. Um Missverständnisse außerdem aus dem Weg zu räumen: Coroutinen sind NICHT parallel und damit KEINE Threads (in Bezug auf Sneyke's Kommentar). Sie sind lediglich eine Art von State-Machine mit einem eigenständigen Update-Call im selbem Unity-Thread, wobei dieser nach den Kriterien des yield-Objekts in den Code zurück kehrt.

Hier ein Beispiel zum cachen:

C#-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
WaitForSeconds wait = new WaitForSeconds(1.0f);
 
void Start()
{
     StartCoroutine(Coroutine());
}

IEnumerator Coroutine()
{
    //do something...
    yield return wait;
    //do something else after that...
}


Der Weg mit der Update (Sneyke's Vorschlag) finde ich am saubersten. Die InvokeRepeating wäre eine simple Alternativlösung, jedoch finde ich Unity's Weg mit der Suche einer Methode über einen String im selben MonoBehaviour ziemlich schlecht (Wozu die Suche, ich weiß doch wo die Methode liegt?!). InvokeRepeating ist demzufolge auch in keiner Klasse verfügbar die nicht von MonoBehaviour ableitet.

Hier Sneyke's Besipiel erweitert, damit etwas nach einem definierbaren Step aufgerufen wird:

C#-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
class DayTime {

   private float actualTime;
   private float stepTimeForInvoke;
   private float lastInvokedStep;
   private float dayCycleTimeInSec;
   
   private stepCallback;
   private fullDayCallback;

   public DayTime(float dayCycleTimeInSec, float stepTimeForInvoke, Action stepCallback, Action fullDayCallback) {
       this.dayCycleTimeInSec = dayCycleTimeInSec;
       this.stepTimeForInvoke  = stepTimeForInvoke;
       this.stepCallback = stepCallback;
       this.fullDayCallback = fullDayCallback;
   }

   public void AddTime(float time) {
       
      actualTime += time;
      
      if(actualTime >= lastInvokedStep + stepTimeForInvoke) {
         stepCallback?.Invoke();
         lastInvokedStep = actualTime;
      }

      if(time >= dayCycleTimeInSec) {
         fullDayCallback?.Invoke();
         actualTime -= dayCycleTimeInSec;
         float restStepFromLastDay = lastInvokedStep - actualTime;
         lastInvokedStep = restStepFromLastDay;
      }
   }
}


PS: Coroutinen sind laut Entwickler-Blog 5x langsamer als Updates. Wobei eine Vielzahl von Updates in verschieden MonoBehaviours gegenüber einem Array in einem Manager ebenfalls 4x langsamer ist. Verteilte Coroutinen sind also gegenüber einer zentralen Update-Stelle bis zu 20x langsamer. https://blogs.unity3d.com/2015/12/23/1k-update-calls/
Liebe Grüße,
René

Dieser Beitrag wurde bereits 7 mal editiert, zuletzt von »Renegade« (03.04.2017, 20:17)


Garzec

Alter Hase

  • »Garzec« ist der Autor dieses Themas

Beiträge: 693

Wohnort: Gießen

  • Private Nachricht senden

8

03.04.2017, 20:37

Hm das ist ganz schön viel Code :D ich würde erstmal bei Sneykes Vorschlag bleiben. Aber trotzdem vielen Dank :)

Renegade

Alter Hase

Beiträge: 494

Wohnort: Berlin

Beruf: Certified Unity Developer

  • Private Nachricht senden

9

03.04.2017, 21:08

Hallo Garzec,
das ist doch Sneyke's Beispiel! Verstehst du etwas an den 12 Zeilen mehr nicht? Ich erkläre es gerne. So eine Timer-Klasse ist sehr wichtig und gehört meiner Meinung nach eigentlich in jedes gut sortierte Programmiererrepertoire.
Liebe Grüße,
René

Garzec

Alter Hase

  • »Garzec« ist der Autor dieses Themas

Beiträge: 693

Wohnort: Gießen

  • Private Nachricht senden

10

03.04.2017, 22:02

Doch doch, natürlich verstehe ich die Klasse, damit meinte ich nur, die wenigen Zeilen erfüllen, zumindest bei mir, schon ihren Zweck

Werbeanzeige