Einzelnen Beitrag anzeigen

nuclearping

Registriert seit: 7. Jun 2008
708 Beiträge
 
Delphi 10.2 Tokyo Professional
 
#6

AW: [Andorra2D] Ein paar Fragen - Kollisionen und Timer

  Alt 20. Sep 2012, 20:48
„Spatial Hashing“ heißt glaube ich einfach nur, dass man das Spielfeld in ein grobes Gitter einteilt und dann für jede Zelle speichert, welche Objekte darin liegen. Dann testet man nur Objekte, die sich mindestens eine Zelle teilen, gegeneinander. Das ist denke ich für bewegliche Objekte eindeutig die bessere Variante, da die Datenstruktur flach ist, sodass der Overhead bei Änderungen nicht zu groß wird. Außerdem ist es einfacher zu implementieren. So weit ich weiß, verwaltet Andorra2D Sprites intern allerdings schon in so einer Struktur, zumindest schrieb Andreas (Entwickler von Andorra2D) mir das vor Jahren hier im Forum.

Entscheidend für die Effizienz dieses Verfahrens ist aber die Größe der Zellen. Ich weiß nicht, ob Andorra2D die Größe automatisch ermittelt, aber ich würde mal mit verschiedenen Größen experimentieren.
Ja, nach dem, was ich über das Hashing gelesen habe, denke ich auch, dass das wohl in dem Fall die bessere Variante wäre. Hab mir die Andorra-Codes zur Kollision noch nicht genau angeschaut, aber wenn es ein ähnliches Verfahren verwendet, kann man's sicher optimieren. Man merkt zB auch einen Perfomanceverlust, wenn viele Objekte da sind, aber ALLE stehen und sich nichts und niemand bewegt. Aber ich will jetzt bei weitem nicht an Andorra rummeckern, die Engine ist echt top und läuft super

Mir gehts hauptsächlich um das Prinzip eventueller Performancegewinne, um die Spielengine so skalierbar wie möglich zu halten und nicht künstlich den Spielverlauf zu limitieren, weil sonst die Kollisionsprüfung alles in den Keller ziehen würde.

Ich hab mir auch schon ein paar grobe Gedanken über ein mögliches alternatives System gemacht, was auch mit Zellen und Gewichtungen arbeiten würde. Wobei die Zellen je nach "Inhalt" ein Gewicht bekommen. Also könnte man ein Gitter aus 16x16 pro Zelle erstellen. Ein 96x96 Sprite würde 4 Zellen ausfüllen, wobei das Zentrum das höchste Gewicht bekommt und nach aussen hin das Gewicht abnimmt. Je nach Bewegung der Sprites verteilt man die Gewichtung in den Zellen neu und addiert diese Gewichtung mit (zB je nach Bewegungsrichtung) benachbarten Zellen. Überschreitet das Ergebnis einen bestimmten Schwellwert findet eine Kollision statt, sonst nicht. Keine Ahnung, ob und wie gut das aufgehen würde und wie performant das wäre. Aber interessant finde ich es schon.

Zum 2.:
Die beste Lösung ist imo pro Sprite (oder ggf. global) eine Liste zu führen mit Tupeln bestehend aus „Zeitpunkt“ und „Ereignis“. Bei jedem Tick ermittelst du dann die Ereignisse deren Zeitpunkt in der Vergangenheit liegt, führst diese aus und löscht sie aus der Liste. Das wäre also quasi eine „GetTickCount“-Lösung, auch wenn ich nicht unbedingt direkt GetTickCount verwenden würde. Ich meine Andorra stellt den Sprites die aktuelle Zeit sowieso bereit oder bietet zumindest eine Kapselung (TAdPerformanceCounter?) an. Habe aber schon lange nicht mehr damit gearbeitet, daher ohne Gewähr...
Ja, genau so hab ich's jetzt auch gemacht. In der GameEngine eine globale TList angelegt, die einen eigenen Timer-Record verwaltet:
Delphi-Quellcode:
type
  TTimerRecord = record
    Duration,
    Interval: Integer;
    StartTicks: Cardinal;
    IntervalStartTicks: Cardinal;
    PassedTicks: Cardinal;
    TicksLeft: Integer;
    Enabled: Boolean;
    Finished: Boolean;
    FreeOnTimeOut: Boolean;
    Data: Integer;
    OnInterval: TNotifyEvent;
    OnTerminate: TNotifyEvent;
  end;
  PTimerRecord = ^TTimerRecord;
Im Haupt-Render-Event der GameEngine wird UpdateTimers aufgerufen, der die ganzen Timer durchgeht, TickCounts aktualisiert und ggf. entsprechende Events ausführt, Timer wieder aus der Liste entfernt, wenn sie nicht mehr gebraucht werden, etc. Läuft butterweich.
  Mit Zitat antworten Zitat