GLB:Objekte und Kollisionsabfrage

Aus PandoraWiki

Wechseln zu: Navigation, Suche

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
        CollRight

hinzu. 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.

Hier gehts zum letzten Teil des Tutorials