Du bist nicht angemeldet.

Stilllegung des Forums
Das Forum wurde am 05.06.2023 nach über 20 Jahren stillgelegt (weitere Informationen und ein kleiner Rückblick).
Registrierungen, Anmeldungen und Postings sind nicht mehr möglich. Öffentliche Inhalte sind weiterhin zugänglich.
Das Team von spieleprogrammierer.de bedankt sich bei der Community für die vielen schönen Jahre.
Wenn du eine deutschsprachige Spieleentwickler-Community suchst, schau doch mal im Discord und auf ZFX vorbei!

Werbeanzeige

1

27.03.2009, 15:45

[SDL] Objekte überspringen Kollisionsbereich!

Hi Leute :),

ich bin neu hier im Forum, deshalb erstmal ein herzliches Hallo an alle Mitglieder, manche kennen mich vielleicht schon aus dem #sppro Channel ;).

Nun zu meinem Problem:
Ich arbeite gerade an meinem ersten kleinen Projekt, weches ich mit Hilfe der SDL und der IDE MSVS2008 umsetze. Die erste richtige Schwierigkeit taucht jetzt bei der Kollisionsabfrage und den Pixelsprüngen auf, die jedes Objekt pro Frame hinter sich legen. Ja, das dürft im Wesentlichen meine Situation einrahmen; aber keine Angst, ich habe mir eine genaue, anschauliche und verständliche Beschreibung überlegt.

Ansetzten werde ich jetzt erst einmal mit der Ausgangsituation,
welche ihr diesem Bild entnehmen könnt:


(Link)


Zu sehen ist ein Objekt (blauer Block) welches sich geradlinig auf einen Bereich (rot) zubewegt (grüner Pfeil), in welchem eine Kollisionsabfrage stattfinden soll. Damit sich das Ganze aufs Wesentliche beschränkt füllt dieser Bereich die komplette X -Achse aus. Das Objekt bewegt sich pro Frame um eine bestimmte Anzahl an Pixel (abhänging von der Geschwindigkeit des Rechners, Timer!) in Richtung des Kollisionsbereiches.

Die ideale Vorstellung,
die eigentlich eintreffen sollte sieht so aus:


(Link)


Der Block kollidiert also anhand von folgendem Code:

C-/C++-Quelltext

1
2
3
4
if
((RectBlock.y-1) > (RectKollision.y) &&
(RectBlock.y + RectBlock.h -1) < (RectKollision.y + RectKollision.h))
{ /*... */}


oder alternativ:

C-/C++-Quelltext

1
2
3
4
if
((RectBlock.y) == (RectKollision.y) &&
(RectBlock.y + RectBlock.h) == (RectKollision.y + RectKollision.h))
{ /*... */ }

Anmerkungen: Ankerpunkt ist die linke obere Ecke; RectBlock und RectKollision die Bounding Boxen.

Wie gesagt, so sollte es eigentlich sein... leider ist es aber nicht so.

Das Grundproblem ist hier folgendes: Der Block kann ab einem bestimmten Pixelsprung pro Frame (natürlich auch abhängig von dem verwendetem Rechner) den Kollisionsbereich einfach überspringen! Hier ist das besonders offensichtlich dargestellt, da er genau in die Fläche passen muss (siehe Code), weil er die gleiche Höhe besitzt (siehe Skizze, 'X'). Wie ich das genau meine, stellt dieses Bild anschaulich dar:


(Link)



Lösungsansätze:

Um dieses Problem zu lösen, habe ich dieses Kollisionsfeld unsichtbar in der Kollisionsabfrage vergrößert:

C-/C++-Quelltext

1
2
3
4
if
((RectBlock.y) > (RectKollision.y -10) &&  //unsichtbare Erhöhung um 10 Pixel

(RectBlock.y + RectBlock.h) < (RectKollision.y + RectKollision.h))
{ /*...  */}


Dies löst in 85% der auftretenden Fälle das Problem, allerdings ist es somit sehr fehleranfällig und äußerst ungenau. Hierbei muss ich noch sagen, dass ich mich auf eine exakte Abfrage verlassen müssen kann, da diese Situation ab Programmstart sehr häufig eintritt, besser gesagt absolut essentiell ist, und ich auch darauf reagieren muss. Bleibt die Kollsionserkennung aus, so gibt es folglich auch keine Reaktion.

Des Weiteren habe ich mir auch schon überlegt, es mit Hilfe der Bewegungsrichtung des Balles zu lösen. Dies führt jedoch auch nur zu sehr ungenauen Resultaten.

Bevor ihr mir versucht zu helfen...
...möchte ich euch bitten, dass ihr wirklich im Rahmenbereich meines aktuellen Wissensspektrums antwortet. Ich bin bis jetzt nur Anfänger, habe seit einiger Zeit Heikos Kalistas Buch ausgelesen und mich seit wenigen Wochen mit der SDL beschäftigt. Links könnten auch äußerst hilfreich sein :D!

Im Grunde bin ich mir sicher, dass es eine passende Lösung gibt, ich weiß nur nicht, wo ich diese finde. Suche und kurzes Durchstöbern der FAQs haben mich allerdings nicht weitergebracht... (möglicherweise gibt es aber auch schon einen passenden Thread hier, bin wie gesagt neu).

Dann schon mal vielen Dank im Voraus!

Anonymous

unregistriert

2

27.03.2009, 16:03

Prüfe erstmal anhand eines Bewegungsrechtecks.

Also:

C-/C++-Quelltext

1
2
3
4
5
6
7
rect = 
{
neues_x,
neues_y,
altes_x + breite,
altes_y + höhe
};


Dadurch wird ein Rechteck erzeugt, dass genau so groß ist wie die Bewegung im Frame. Das kannst du testen :)

n0_0ne

1x Contest-Sieger

  • Private Nachricht senden

3

27.03.2009, 16:47

Interessantes Problem, und ein cooler Lösungsansatz. Allerdings frage ich mich, welches Rect da vergrößert werden soll? das der "Kollisionszone" oder das des Objects?
Weil wenn man das Rect der Kollisionszone ändert, geht das ja nur, wenn es sich nur um ein Object handelt, welches kollidieren kann. Und bei Objekten ist es denke ich nicht so einfach, wie dein Code es vermuten lässt, oder? Man muss doch nämlich das Objekt (also das Rect davon) immer in die entgegengesetze Bewegungsrichtung vergrößern, damit man weiß, wo es auch zwischen zwei Frames gewesen ist. Wenn man das so aber macht, wird es möglicherweise zu groß werden für die Kollisionszone, was zur Folge hätte, dass du die Kollision nicht mit

C-/C++-Quelltext

1
2
((RectBlock.y-1) > (RectKollision.y) &&
(RectBlock.y + RectBlock.h -1) < (RectKollision.y + RectKollision.h))

sondern mit

C-/C++-Quelltext

1
2
((RectBlock.y) < (RectKollision.y) &&
(RectBlock.y + RectBlock.h) > (RectKollision.y + RectKollision.h))

Wenn es also die gesamte Kollisionszone erfasst, war es zwischen zwei Frames irgendwann mal genau darauf... oder denke ich hier zu kompliziert/falsch?

Anonymous

unregistriert

4

27.03.2009, 16:51

Es handelt sich um das Objekt. Obwohl Kollisionszone und Objekt eigentlich das selbe sein sollten.

Wenn eine Kollision statt gefunden hat, dann weißt du auch genau aus welcher Richtung die Kollision kam da "Alt - Neu = Richtung". Und daran kann man sehr gut ansetzen, damit das Objekt an der jeweiligen Stelle der Kollisionszone "nicht durch kommt" und als Positions-Koordinate des Objekts die Korrdinaten der Kollisionszone setzen kann und ggf. + Dimension der Zone oder - Dimension des Objekts, je nach "Seite".

Probiert es einfach aus :)

5

27.03.2009, 17:24

Hi unsigned long und n0_0ne :)!

@n0_0ne:
Beim Lösungsversuch sollte die Länge des Kollisionsbereiches erhöht werden, damit eine Kollision leichter möglich wäre. Bei RectBlock handelt es sich dabei um eine Bounding Box des blauen Block, bei RectKollision um eine Bounding Box, die den rot makierten (Kollisions)Bereich "einzäunt".
Deine vorgeschlagene Lösung würde nicht funktionieren. Grund: Der Block müsste dazu um mindestens 2 Pixel größer sein! Siehe Skizze 1: Block sowie auch die Kollisionsfläche besitzen eine identische Höhe, dargestellt durch das 'X'.

@unsigned long:
Ich kann mit deinem Vorschlag leider nicht viel anfangen. Wenn ich das richtig verstehen, schlägst du in deinem ersten Beitrag vor, eine neue Bounding Box, die du als "Bewegungsrechteck" bezeichnest zu deklarieren und zu initialisieren mit neuen und bereits zuvor verwendeten Variablen. Aber:
Wozu ist dieses Bewegungrechteck nützlich? Oder meinst du damit vielleicht sogar das Rect des Blockes, welches sich auch bewegt?
Inwiefern hiflt das bei dem Problem weiter?
D.h. wie kann es das Überspringen verhindern?
Auf was beziehen sich bei "Alt - Neu = Richtung" die Ausdrücke "Alt" und "Neu"?

Ich denke du musst das ein wenig ausführlicher beschreiben, ansonsten kommen wir auf keinen grünen Zweig ;). Eine Skizze wäre evtl. auch sehr interresant, sofern sie hilfreich wäre!

6

27.03.2009, 17:50

Nennt sich Tunneln, kommt auch in der Natur vor :).

Bewegungsrechteck: Die Bounding Box um den Bereich, den das Objekt waehrend eines Zeitschrittes einnehmen koennte. Ist von Geschwindigkeit und Zeitschritt abhaengig.
If it were not for laughter, there would be no Tao.

Anonymous

unregistriert

7

27.03.2009, 22:32

Ich denke mein Vorredner hat den springenden Punkt erbracht ;)

n0_0ne

1x Contest-Sieger

  • Private Nachricht senden

8

28.03.2009, 07:41

Zitat von »"Eldoradon"«

Grund: Der Block müsste dazu um mindestens 2 Pixel größer sein!

Das stimmt nicht, bzw. nur wenn du mit Integers arbeitest, was du in dem Fall nicht tun solltest.

Edit: Gibt es zu dem Problem eigentlich noch eine genauere Lösung? Weil wenn es mal eine Zeitverzögerung von sagen wir einer Sekunde gibt, dann wird das Bewegungsrechteck sehr groß, aber es war ja nicht die ganze Sekunde über in dem kompletten Rechteck, weshalb es zu Kollisionen kommen wird, wo eig. keine waren.

Anonymous

unregistriert

9

28.03.2009, 10:09

nO_One_
Das ist schon die genauste Möglichkeit und damit kann ich z. B. in meinen 2D Programmen alles bewerkstelligen, selbst bei einer Verzögerung von N Sekunden.

10

29.03.2009, 16:22

Hallo. Ich hab mir das mit dem Bewegungsviereck mal angeschaut, das ist eine gute Idee. Aber ich hab ein kleines Problem, das Viereck zu berechnen. So wie oben angeschrieben (neu_x,neu_y,alt_x+breite,alt_y+höhe) will das irgendwie nicht.

Letzendlich ist mir klar geworden, dass ich bei einer x+y achsen verschiebung nicht wirklich weiß, wie das Rechteck auszusehen hat.

Hierzu ein Beispielbild:
Für Fall1 ist das Bewegungsviereck klar, wie sieht es aber für Fall 2 aus, (tauschen von a=alt n=neu ist auch möglich wie sieht es dann aus. b=bewegungsviereck)


(Link)


Außerdem kann mir vielleicht jemand sagen, wie ich das ganze dann auch Berechnen kann? bzw welche Koordinaten, Breite + Höhe das b haben muss, damit es in jeder Situation funktioniert?

Loki

Werbeanzeige