JLI Spieleprogrammierung Foren-Übersicht JLI Spieleprogrammierung

 
 FAQFAQ   SuchenSuchen   MitgliederlisteMitgliederliste   BenutzergruppenBenutzergruppen 
 medals.php?sid=b2ebf57997b1fcc6282aaf922219cecaMedaillen   RegistrierenRegistrieren   ProfilProfil   Einloggen, um private Nachrichten zu lesenEinloggen, um private Nachrichten zu lesen   LoginLogin 

Problem mit Sprite/Tile Kollisionsbehandlung

 
Neues Thema eröffnen   Neue Antwort erstellen    JLI Spieleprogrammierung Foren-Übersicht -> Entwicklung
Vorheriges Thema anzeigen :: Nächstes Thema anzeigen  
Autor Nachricht
Hazel
JLI MVP
JLI MVP


Alter: 39
Anmeldedatum: 19.07.2002
Beiträge: 1761

Medaillen: Keine

BeitragVerfasst am: 10.09.2003, 20:12    Titel: Problem mit Sprite/Tile Kollisionsbehandlung Antworten mit Zitat

So, ich sitze jetzt schon eine Ewigkeit davor... entweder ich bin blind oder das Problem ist doch nicht ganz so trivial...

Ich habe nun eine annähernd perfekte Sprite/Tile Kollisionsabfrage / -behandlung geschrieben aber ein kleines Problem ist da noch... wenn man an der rechten und linken Seite einer Wand, die aus mehr als einem Tile besteht, von unten nach oben entlanggleitet und dabei gleichzeitig gegen die Wand lenkt, bleibt man an der Grenze zwischen den Tiles hängen. Das gleiche passiert auch auf der oberen Seite einer Wand, wenn man von rechts nach links gleitet. Folgende Skizze soll das mal verdeutlichen:


Die fetten Linien sind jeweils die Grenzen an denen das Problem auftritt... das seltsame ist, dass es wirklich nur Links, Rechts und Oben so ist... die untere Seite ist voll und ganz verschont. =/

Hier ist der Quellcode der Funktion:
Code:

void MoveObj(obj & a)
{
   // Funktion verlassen wenn wir uns nicht bewegen
   if(Equal(a.dx, 0))
      if(Equal(a.dy, 0))
         return;

   // Objekt bewegen
   a.x += a.dx;
   a.y += a.dy;

   // Zu testendes Levelareal ausrechnen
   int i1 = a.x;
   int j1 = a.y;
   int i2 = i1 + a.w - 1;
   int j2 = j1 + a.h - 1;

   // Von Pixelspace in Tilespace umwandeln(ein Tile hat 32x32 Pixel)
   i1 /= 32;
   i2 /= 32;

   j1 /= 32;
   j2 /= 32;

   sprintf(buf2, "i1: %i, i2: %i, j1: %i, j2: %i", i1, i2, j2, j2);

   // Durch dieses Areal iterieren...
   for(int i = i1; i <= i2; ++i)
   {
      for(int j = j1; j <= j2; ++j)
      {
         // Wenn kein Tile gesetzt ist können wir fortfahren
         if(level[i][j] == false)
            continue;

         int coll = IntersectEx(a.x, a.y, a.w, a.h,      // Objekt Bounding Box
                           i * 32, j * 32, 32, 32); // Tile Bounding Box

         if(coll)
         {
            // Kollsion mit der rechten oberen Ecke eines Tiles
            if((coll & DOWN) && (coll & LEFT))
            {
               // Mittelpunkt vom Object bestimmen
               float a_mid_x = a.x + (a.w / 2);
               float a_mid_y = a.y + (a.h / 2);

               // Mittelpunkt vom Tile
               float t_mid_x = i * 32 + 16;
               float t_mid_y = j * 32 + 16;

               // Abstand der Mittelpunkte
               float x_dist = fabs(a_mid_x - t_mid_x);
               float y_dist = fabs(a_mid_y - t_mid_y);

               // Hier Fallunterscheidung!!!
               if(x_dist < y_dist)
                  a.y = j * 32 - a.h;
               else
                  a.x = i * 32 + 32;

               continue;
            }

            // Links oben
            if((coll & DOWN) && (coll & RIGHT))
            {
               float a_mid_x = a.x + (a.w / 2);
               float a_mid_y = a.y + (a.h / 2);

               float t_mid_x = i * 32 + 16;
               float t_mid_y = j * 32 + 16;

               float x_dist = fabs(a_mid_x - t_mid_x);
               float y_dist = fabs(a_mid_y - t_mid_y);

               if(x_dist < y_dist)
                  a.y = j * 32 - a.h;                           
               else
                  a.x = i * 32 - a.w;                  

               continue;                  
            }

            // Rechts unten
            if((coll & UP) && (coll & LEFT))
            {
               float a_mid_x = a.x + (a.w / 2);
               float a_mid_y = a.y + (a.h / 2);

               float t_mid_x = i * 32 + 16;
               float t_mid_y = j * 32 + 16;

               float x_dist = fabs(a_mid_x - t_mid_x);
               float y_dist = fabs(a_mid_y - t_mid_y);

               if(x_dist > y_dist)
                  a.x = i * 32 + 32;                  
               else
                  a.y = j * 32 + 32;                  

               continue;
            }

            // Links unten
            if((coll & UP) && (coll & RIGHT))
            {
               float a_mid_x = a.x + (a.w / 2);
               float a_mid_y = a.y + (a.h / 2);

               float t_mid_x = i * 32 + 16;
               float t_mid_y = j * 32 + 16;

               float x_dist = fabs(a_mid_x - t_mid_x);
               float y_dist = fabs(a_mid_y - t_mid_y);

               if(x_dist > y_dist)   
                  a.x = i * 32 - a.w;
               else
                  a.y = j * 32 + 32;                  

               continue;
            }

            // Wenn wir auf keiner Ecke sind brauchen wir auch keine Fallunterscheidung.
            if(coll & DOWN)
            {
               a.y = j * 32 - a.h;
            }

            if(coll & UP)
            {
               a.y = j * 32 + 32;
            }
            
            if(coll & RIGHT)
            {
               a.x = i * 32 - a.w;
            }

            if(coll & LEFT)
            {
               a.x = i * 32 + 32;
            }            
         }
      }
   }
}


IntersectEx liefert die Seiten, an denen die erste Box mit der zweiten kollidiert. Equal prüft, ob 2 Floats gleich sind. Ansonsten sollte der Code selbsterklärend sein. Nur noch eine Sache zur Fallunterscheidung an den Ecken. An den Ecken muss ja erkannt werden, von welcher Seite ein Objekt kam als es mit dem Tile kollidierte, damit man es richtig aus dem Tile herausschieben kann. Die folgende Skizze soll das am Beispiel der rechten oberen Ecke verdeutlichen:


Hier ist das Programm zum ausprobieren:
www.jliforum.de/hazel/trash/collision.exe

Ich weiß nicht mehr weiter... ich glaub ich bin blind. Wäre cool wenn einer den Fehler sieht... ich hoffe die länge des Posts ist nicht allzu abschreckend. ;) Und wer den Fehler findet oder mich drauf bringt kommt mit in die Credits von Bio Hazard ;P (das ist das letzte Problem das gelöst werden muss, bevor ich eine Demo bauen kann...).

Danke im Voraus!
_________________
*click* Dabuu!?
Twitter: http://twitter.com/Ollie_R
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
TheMillenium
Dark JLI'ler



Anmeldedatum: 21.07.2002
Beiträge: 1427
Wohnort: World
Medaillen: Keine

BeitragVerfasst am: 10.09.2003, 20:38    Titel: Antworten mit Zitat

Das Objekt hält immer an so einer Tilegrenze an? So als ob er zwischen den beiden Tiles gefangen ist. Du gehst zwar schön kompliziert an die Sache heran, aber ist in Ordnung, wenn du es dann noch schaffst. Smile
Ja ich hab mir den Code nochmal angesehen und das liegt daran, dass beide Tiles noch eine Kollision mit dem Objekt haben und das hält dieses dann auch schön gefangen...
_________________
The source of all power is in its destiny...
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
Hazel
JLI MVP
JLI MVP


Alter: 39
Anmeldedatum: 19.07.2002
Beiträge: 1761

Medaillen: Keine

BeitragVerfasst am: 11.09.2003, 13:02    Titel: Antworten mit Zitat

Was passiert, weiß ich ich frag mich nur grad wie man es umgehen kann, möglichst ohne Hacks. ;) Zu kompliziert? Wie hättest du es denn gelöst? Mein vorheriges Beispiel mit den Hotspots fand ich zu ungenau und Problemanfällig. Und vielleicht siehts ja auch nur kompliziert aus, weil es unoptimiert ist und ich den Code mit der Mittepunktberechnung 4x wiederhole(ja, ich hab mit Copy n Paste gearbeitet. ;P).
_________________
*click* Dabuu!?
Twitter: http://twitter.com/Ollie_R
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
TheMillenium
Dark JLI'ler



Anmeldedatum: 21.07.2002
Beiträge: 1427
Wohnort: World
Medaillen: Keine

BeitragVerfasst am: 11.09.2003, 15:47    Titel: Antworten mit Zitat

Naja zu kompliziert finde ich es vor allem, weil es so aufgeblasen ist. Da finde ich es viel cooler wenn man das ganze in 4-5 Zeilen erledigt, dann ist es zwar wirklich "kompliziert" aber schön kompakt.

Ich würde erst mal statt dauert if, if, if mal if else if else if daraus machen, da sparst du bei vielen Objekten schon mal etwas Rechenpower und es könnte auch daran liegen. Zwar hast du bei den Ecken das mit continue gelöst aber nicht unten.
Code:

 if(coll & DOWN)
            {
               a.y = j * 32 - a.h;
            }

            if(coll & UP)
            {
               a.y = j * 32 + 32;
            }
             
            if(coll & RIGHT)
            {
               a.x = i * 32 - a.w;
            }

            if(coll & LEFT)
            {
               a.x = i * 32 + 32;
            }


würde ich so schreiben:
Code:
 if(coll & DOWN)
            {
               a.y = j * 32 - a.h;
            }
else
            if(coll & UP)
            {
               a.y = j * 32 + 32;
            }
else             
            if(coll & RIGHT)
            {
               a.x = i * 32 - a.w;
            }
else
            if(coll & LEFT)
            {
               a.x = i * 32 + 32;
            }


wenn es auf keiner Ecke ist, kann es ja nur auf einer Seite von einem rechteckigen Objekt sein! Wink
_________________
The source of all power is in its destiny...
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
Hazel
JLI MVP
JLI MVP


Alter: 39
Anmeldedatum: 19.07.2002
Beiträge: 1761

Medaillen: Keine

BeitragVerfasst am: 11.09.2003, 16:02    Titel: Antworten mit Zitat

Nein, daran liegt es nicht. Ich hatte das gestern Nacht, kurz nachdem ich den Thread hier geöffnet habe, schon korrigiert. Ich glaube eher, dass es daran liegt, dass man mit zwei Ecken kollidiert. Mal schauen wie ich das am besten überprüfe.. Aber solche Kollisionsabfragen gibt's doch schon seit Ewigkeiten... denke ich mal wieder zu kompliziert?
_________________
*click* Dabuu!?
Twitter: http://twitter.com/Ollie_R
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
Hazel
JLI MVP
JLI MVP


Alter: 39
Anmeldedatum: 19.07.2002
Beiträge: 1761

Medaillen: Keine

BeitragVerfasst am: 11.09.2003, 17:56    Titel: Antworten mit Zitat

Ich habs nun hinbekommen. Es lag daran, dass an den Ecken auch der Fall, wenn x_dist und y_dist gleich sind behandelt werden muss.
_________________
*click* Dabuu!?
Twitter: http://twitter.com/Ollie_R
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
Beiträge der letzten Zeit anzeigen:   
Neues Thema eröffnen   Neue Antwort erstellen    JLI Spieleprogrammierung Foren-Übersicht -> Entwicklung Alle Zeiten sind GMT
Seite 1 von 1

 
Gehe zu:  
Du kannst keine Beiträge in dieses Forum schreiben.
Du kannst auf Beiträge in diesem Forum nicht antworten.
Du kannst deine Beiträge in diesem Forum nicht bearbeiten.
Du kannst deine Beiträge in diesem Forum nicht löschen.
Du kannst an Umfragen in diesem Forum nicht mitmachen.


Powered by phpBB © 2001, 2005 phpBB Group
Deutsche Übersetzung von phpBB.de

Impressum