|
JLI Spieleprogrammierung
|
Vorheriges Thema anzeigen :: Nächstes Thema anzeigen |
Autor |
Nachricht |
Hazel JLI MVP
Alter: 39 Anmeldedatum: 19.07.2002 Beiträge: 1761
Medaillen: Keine
|
Verfasst am: 10.09.2003, 20:12 Titel: Problem mit Sprite/Tile Kollisionsbehandlung |
|
|
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 |
|
|
TheMillenium Dark JLI'ler
Anmeldedatum: 21.07.2002 Beiträge: 1427 Wohnort: World Medaillen: Keine
|
Verfasst am: 10.09.2003, 20:38 Titel: |
|
|
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.
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 |
|
|
Hazel JLI MVP
Alter: 39 Anmeldedatum: 19.07.2002 Beiträge: 1761
Medaillen: Keine
|
Verfasst am: 11.09.2003, 13:02 Titel: |
|
|
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 |
|
|
TheMillenium Dark JLI'ler
Anmeldedatum: 21.07.2002 Beiträge: 1427 Wohnort: World Medaillen: Keine
|
Verfasst am: 11.09.2003, 15:47 Titel: |
|
|
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! _________________ The source of all power is in its destiny... |
|
Nach oben |
|
|
Hazel JLI MVP
Alter: 39 Anmeldedatum: 19.07.2002 Beiträge: 1761
Medaillen: Keine
|
Verfasst am: 11.09.2003, 16:02 Titel: |
|
|
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 |
|
|
Hazel JLI MVP
Alter: 39 Anmeldedatum: 19.07.2002 Beiträge: 1761
Medaillen: Keine
|
Verfasst am: 11.09.2003, 17:56 Titel: |
|
|
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 |
|
|
|
|
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
|