2012-04-10 7 views
1

Ich habe eine Frage über gute Praxis bekommen. Ich mache ein einfaches Spiel und ich mache ein paar Sprites.1 Comprehensive timer vs. multiple, ein Timer pro Objekt

Ich habe eine Sprite-Klasse. In dieser Klasse gibt es einen Timer, der alle paar Millisekunden ausgeführt wird.

Jetzt habe ich eine List<Creatures> und jeder der "Kreaturen", bekam ein Sprite-Objekt in ihnen, um die Animation zu starten. Das bedeutet, dass jede Kreatur einen Timer hat, der das Gleiche macht.

Ich entschied mich, das zu ändern und einen Timer zu erstellen, der nur auf der Liste iteriert und die Funktion aufruft, die die Animation für jedes "Geschöpf" erstellt.

Was ist eine gute Praxis?

  1. Geben Sie jeder "Kreatur" einen eigenen Timer.
  2. Erstellen Sie einen "großen" Timer in der Form, die auf der Liste iterieren, und rufen Sie die Funktion auf, die die Animation von jedem Objekt erstellt.
  3. Eine andere Art und Weise

Antwort

5

Ich habe eine Sprite-Klasse. In dieser Klasse gibt es einen Timer, der alle paar Millisekunden ausgeführt wird.

Leider ist es in Wirklichkeit nicht. Sie sind begrenzt durch die Auflösung des (nicht leistungsfähigen) Systemtakts, der in der Nähe von ~ 15   ms liegt. Sie können also ein Intervall von 1 festlegen, wenn Sie möchten, aber das ist nicht das, was Sie tatsächlich erhalten.

Zurück zum Thema, für ein Spiel sollte alles auf der gleichen Uhr laufen. Für jeden Tick gibt es eine Schleife, die den logischen Zustand des Spiels (Positionen und Whatnot) und dann die Anzeige (Animationsrahmen, Blit auf dem Bildschirm usw.) aktualisiert. Sie werden wahrscheinlich Probleme bekommen, wenn Sie sie auf verschiedenen Timern haben, da es extrem schwierig wird, den Zustand Ihrer Objekte zu koordinieren, wenn sie parallel aktualisiert werden.

Auch erkennen Sie, dass Sie die Aktualisierungsrate normalisieren müssen, um sicherzustellen, dass die Dinge nicht zu schnell oder zu langsam aktualisiert werden (abhängig davon, wie lange es dauert, bis ein Frame gerendert wird). Sie müssen das Delta zwischen dem letzten Update und dem neuen Update überprüfen und entsprechend handeln.

5

Wenn sie laufen alle im gleichen Intervall, ist ein großer Timer definitiv der Weg zu gehen.

Auch wenn sie in unterschiedlichen Intervallen laufen, ist oft ein großer Timer (mit Logik, der festlegt, welche Sub-Handler feuern) immer noch der beste.

Einige Bibliotheken fügen diese Logik intern hinzu und fordern nur einen einzelnen Timer vom Betriebssystem an. Sie haben nicht genau gesagt, welchen Timer (.NET hat mindestens vier) Sie verwenden, also würde ich Ihnen empfehlen, nur einen zentralen Timer zu verwenden.

+0

Im Verwenden von System.Windows.Forms.Timer – samy

+0

@samy: Stellen Sie fest, dass dieser Zeitgeber den 'Tick'-Ereignisdelegaten auf dem UI-Thread ausführt. –

1

Am besten wird eine Game-Schleife implementiert, die verfolgt, wie viel Zeit seit der letzten Schleifeniteration verstrichen ist, und diese verstrichene Zeit an alle Entitäten weitergibt, die sich selbst aktualisieren müssen. B. OpenTk implementiert several events, die bei jedem Durchlauf durch die Spielschleife (z. B. OnUpdateFrame, OnRenderFrame) auftreten.

Jedes dieser Ereignisse ist ein Argument vom Typ FrameEventArgs geleitet, die eine einzelne Eigenschaft der Zeit hat:

/// <summary> 
/// Gets a <see cref="System.Double"/> that indicates how many seconds of time elapsed since the previous event. 
/// </summary> 
public double Time 
{ 
    get { return elapsed; } 
    internal set 
    { 
     if (value <= 0) 
      throw new ArgumentOutOfRangeException(); 
     elapsed = value; 
    } 
} 

auf der Grundlage der Zeit verstrichen ist, können Sie herausfinden, was Animationsrahmen im Sprit zu machen. Der zusätzliche Vorteil besteht darin, dass Sie, wenn Sie diese Zeit abfragen, herausfinden können, wie viele Frames pro Sekunde Sie gerade ausführen, und Entscheidungen auf dieser Grundlage treffen (das Rendering eines Frames überspringen, die Render-Komplexität verringern usw.). .