GLB:Objekte und Kollisionsabfrage
Aus PandoraWiki
Im zweitletzten Teil von diesem Tutorial werden wir zuerst das Hinzufügen von Objekten automatisieren. Danach befassen wir uns mit der Kollisionsabfrage. Der Beispiel-Code zu diesem Tutorial gibt es hier: http://dl.openhandhelds.org/cgi-bin/pandora.cgi?0,0,0,0,46,32
Beim letzten Teil haben wir ja mit
IF ScrollX=128 THEN ObjectADD(ID_ENEMY1,320,120) IF ScrollX=160 THEN ObjectADD(ID_ENEMY2,320,120)
in level00.gbas die Objekte manuell hinzugefügt. In einem fertigen Spiel benötigt man jedoch viel mehr und es wäre sehr umständlich, diese alle einzeln aufzurufen. Deshelb lesen wir die benötigten Daten aus einer vordefinierten Datei level00.evt. Dazu müssen wir unseren bereits vorhandenen Event-Type erweitern.
IX% = 0 ID%[256] Pos%[256] X%[256] Y%[256]
Dabei ist IX ein Zeiger auf den aktuellen Listeneintrag, ID ist die ObjektID, Pos ist die Scrollposition wann das Objekt erscheinen soll und X,Y ist die Position an der das Objekt erscheinen soll. Mit
// init events OPENFILE(1,"./isdo/level00.evt",TRUE) FOR p=0 TO 254 READUWORD 1,VAL Event.POS[p]=VAL NEXT FOR p=0 TO 254 READUWORD 1,VAL Event.ID[p]=VAL NEXT FOR p=0 TO 254 READUWORD 1,VAL Event.X[p]=VAL NEXT FOR p=0 TO 254 READUWORD 1,VAL Event.Y[p]=VAL NEXT
in level00.gbas laden wir diese Daten in unsere Eventliste. Die Abfrage wann ein Objekt erscheinen soll machen wir im Unterprogramm EventHANDLER in library.gbas.
//============================================================================= SUB EventHANDLER: //============================================================================= LOCAL ix%,typ% ix=Event.IX IF ScrollX=Event.POS[ix] SELECT Event.ID[ix] CASE ID_ENEMY1 TO ID_ENEMY2 ObjectADD(Event.ID[ix],Event.X[ix],Event.Y[ix]) ENDSELECT INC Event.IX,1 ENDIF ENDSUB // EventHANDLER
Erst fragen wir den aktuellen Index der Eventliste ab, dann überprüfen wir den Typ und fügen der Szene das entsprechende Objekt hinzu. Der Rest geht dann wie von alleine.
So, und nun die Kollisionsabfrage. Da gibt es verschiedene Möglichkeiten in GLBasic.
- BOXCOLL überprüft, ob sich 2 Rechtecke überlappen
- SPRCOLL überprüft, ob sich einzelne Pixel von 2 Sprites überlappen
Wir benutzen eine Routine, die auf BOXCOLL basiert. Dazu definieren wir für den Spieler, die Schüsse und sowie die Objekte eine sogenannte Kollisionsbox. Diese Box kann auch kleiner oder größer als das Sprite sein. Also fügen wir für die verschiedenen Types jeweils
CollTop
CollBottom
CollLeft
CollRighthinzu. Die Größe der Box bestimmen wir bei den Objekten mit der Funktion
//============================================================================= FUNCTION SetCollBox: ix%,left,top,right,bottom //============================================================================= Object.CollLeft[ix]=Object.PosX[ix]+left Object.CollTop[ix]=Object.PosY[ix]+top Object.CollRight[ix]=Object.PosX[ix]+right Object.CollBottom[ix]=Object.PosY[ix]+bottom
Zu Testzwecken könnt ihr ja mal die folgenden 3 Zeilen auskommentieren und etwas herumexperimentieren. Dann werden die Boxen halbtransparent sichtbar.
//ALPHAMODE 0.5 //DRAWRECT Object.CollLeft[ix],Object.CollTop[ix],Object.PosX[ix]+right-Object.CollLeft[ix],Object.PosY[ix]+bottom-Object.CollTop[ix],0xFFFFFF //ALPHAMODE 0.0
Für den Spieler erstellen wir eine separate Box.
//============================================================================= SUB PlayerHANDLER: //============================================================================= Player.CollTop=Player.PosY Player.CollBottom=Player.PosY+31 Player.CollLeft=Player.PosX Player.CollRight=Player.PosX+16 DRAWSPRITE SPR_PLAYER+(INTEGER((bAND(Player.TIMER,3)/2))),Player.PosX,Player.PosY ENDSUB // PlayerHANDLER
ebenso für die 8 Schüsse im ShotHANDLER.
Shot.CollTop [ix]=Shot.PosY[ix] Shot.CollBottom[ix]=Shot.PosY[ix]+6 Shot.CollLeft [ix]=Shot.PosX[ix] Shot.CollRight [ix]=Shot.PosX[ix]+6
Wichtig ist, dass die Zuweisung der Box bei jeder Positionsänderung gemacht wird.
Nun kommt die Abfrage ob ein Objekt mit dem Spieler oder mit einem Schuss kollidiert.
//============================================================================= FUNCTION CheckCollPlayer: ix% //============================================================================= IF Player.CollTop>Object.CollBottom[ix] OR Player.CollBottom<Object.CollTop[ix] OR Player.CollLeft>Object.CollRight[ix] OR Player.CollRight<Object.CollLeft[ix] RETURN COLL_NONE ELSE RETURN COLL_PLAYER ENDIF RETURN COLL_NONE
Mit ix übergeben wir den Index für das Objekt mit welchem wir prüfen. Falls das Objekt den Spieler berührt geben wir den Wert COLL_PLAYER zurück, ansonsten COLL_NONE. Dasselbe gilt für die Schüsse.
//============================================================================= FUNCTION CheckCollShot: ix% //============================================================================= LOCAL i% FOR i=0 TO Shot.Count-1 IF Shot.State[i] IF Shot.CollTop[i]>Object.CollBottom[ix] OR Shot.CollBottom[i]<Object.CollTop[ix] OR Shot.CollLeft[i]>Object.CollRight[ix] OR Shot.CollRight[i]<Object.CollLeft[ix] RETURN COLL_NONE ELSE Shot.State[i]=0 RETURN COLL_SHOT ENDIF ENDIF NEXT RETURN COLL_NONE ENDFUNCTION // CheckCollShot
Hier geben wir jedoch den Wert COLL_SHOT zurück und löschen gleichzeitig noch den aktuellen Schusseintrag.
Den Befehl zur Kollisionsabfrage geben wir für jedes Objekt in den Scripts. Als Beispiel nehmen wir einmal ID_ENEMY1 in enemies.gbas:
SetCollBox(ix,0,0,15,15)
legt die Größe der Kollisionsbox fest. Dann überprüfen wir ob wir (das ENEMY1) von einem Schuss getroffen wurden.
IF CheckCollShot(ix)=COLL_SHOT Object.State[ix]=0 EffectADD(ID_EFFECT1,Object.PosX[ix],Object.PosY[ix]) ENDIF
Falls ja, löschen wir das Objekt aus der Liste und fügen noch einen Effekt (Explosion) hinzu. Effekte sind genau gleich aufgebaut wie Objekte. Sie benötigen aber keine Kollisionsbox. Der Grund dass wir hier zwischen Effekten und Objekten einen Unterschied machen ist
GOSUB KeyHANDLER GOSUB LayerBGDRAW GOSUB ShotHANDLER GOSUB EventHANDLER GOSUB ObjectHANDLER GOSUB PlayerHANDLER GOSUB LayerFGDRAW GOSUB EffectHANDLER GOSUB StatusDRAW
dass wir die Effekte NACH den Objekten Zeichnen. Sonst sähe man unter Umständen ja die Effekte gar nicht mehr.

