In Spielen kommen ständig Objekte und gehen wieder, Schüsse, Partikel, Bruchstücke, manchmal hundert Stück gleichzeitig. In modernen Sprachen ist das new und free oder eine dynamische Liste. In MMBasic gibt es weder das eine noch das andere als praktikable Spiel-Lösung. Selbst wenn es das gäbe, wäre eine Allokation pro Frame zu teuer. Wie ich für mein Spiel ein Pool-Pattern aufgebaut habe, das in keinem Tutorial auftaucht, mir aber den Game-Loop rettet.
Object Pool
Mein Ansatz ist ein fester Pool: ich reserviere am Anfang die maximale Zahl Objekte, die je gleichzeitig leben sollen, einmal komplett. Dazu gibt es ein aactive-Flag pro Slot. Aktiv wird über das Flag gesetzt, nicht über das Erzeugen oder Zerstören.
CONST MAX_PARTICLES = 200
DIM FLOAT px(MAX_PARTICLES-1), py(MAX_PARTICLES-1)
DIM FLOAT pvx(MAX_PARTICLES-1), pvy(MAX_PARTICLES-1)
DIM INTEGER plife(MAX_PARTICLES-1), pactive(MAX_PARTICLES-1)
Beim Reset: MATH SET 0, pactive(). Damit sind alle Slots auf einen Schlag frei, ohne FOR-Schleife.
Einen freien Slot finden
Wenn ein neuer Schuss oder Partikel rein soll, suche ich den ersten freien Slot:
FUNCTION FindFreeSlot() AS INTEGER
LOCAL INTEGER i
FOR i = 0 TO MAX_PARTICLES - 1
IF NOT pactive(i) THEN
FindFreeSlot = i
EXIT FUNCTION
END IF
NEXT i
FindFreeSlot = -1
END FUNCTION
Liefert -1, wenn der Pool voll ist. Dann wird der neue Partikel halt verworfen, das fällt im Spielbild nicht auf.
Updaten heißt aktive Slots durchgehen
Im Game-Loop iteriere ich einfach über alle Slots und prüfe das Flag:
FOR i = 0 TO MAX_PARTICLES - 1
IF pactive(i) THEN
INC px(i), pvx(i)
INC py(i), pvy(i)
INC plife(i), -1
IF plife(i) <= 0 THEN
pactive(i) = 0
ELSE
PIXEL px(i), py(i), COL_WHITE
END IF
END IF
NEXT i
Beim Auslaufen wird pactive einfach wieder 0, der Slot ist frei und kann beim nächsten Aufruf von FindFreeSlot wiederverwendet werden.
Der Speicherverbrauch ist konstant, weil der Pool von Anfang an seine volle Größe hat — keine Überraschungen mitten im Spiel. Pro Frame fällt keine Allokation an, das Setzen eines Flags plus ein paar Werte ist billig genug für eine 60-fps-Schleife. Und das aactive-Schema überträgt sich auf jede Pool-Art: bei mir laufen Asteroiden, Schüsse, UFO-Schüsse und Partikel jeweils auf eigenen Pools mit derselben Logik. Für kurzlebige Spielobjekte in MMBasic ist das Pool-Pattern für mich nicht eine von vielen Optionen, sondern faktisch die einzig sinnvolle.