Upload
fridric-wuthrich
View
108
Download
1
Embed Size (px)
Citation preview
V10 - Kollisionen
Nicolas Matentzoglu
Inhalt der Präsentation
Kollisionserkennung bei Hindernissen
Verhalten der Kugel über verschiedenen Untergründen
Beschreibung der physikalischen Eigenschaften der Untergründe
struct untergrund{int typ;char *name;float daempfung;};
untergrund mein_untergrund[5] = {{ WASSER, "Wasser", 0.6f},{ HOLZ, "Holz", 0.9f},{ STEIN, "Stein", 0.8f},{ GRAS, "Gras", 0.7f},{ ZIEL, "Ziel", 0.9f}};
Beschreibung der physikalischen Eigenschaften der Untergründe
Der Name dient dem Zweck, eine lesbare Ausgabe der Kugelposition in display_info zu erreichen
Daempfung ist der Faktor, um den die Kugelgeschwindigkeit verlangsamt wird, wenn sie auf einen bestimmten Untergrund trifft (Bremswirkung)
Beschreibung der Hindernisse
struct hindernis{int typ;char *name;float faktor;};
hindernis mein_hindernis[3] ={{ 0, "Kegel", 0.9f},{ 1, "Bumper", 2.5f},{ 2, "Markierung", 0}};
Der Faktor gibt an, wie sich der Geschwindigkeitsvektor ändert, wenn die Kugel an ein Hindernis stößt.
Die Positionsinformationen der Kugel
struct posinfo{int innerhalb; // Ist die Kugel noch im Spielfeld?int zeile; // Spielfeldzeileint spalte; // SpielfeldspalteD3DXVECTOR3 mitte; // Mittelpunkt des Spielfeldsfloat aq; // Das Quadrat des Abstands der Kugel vom Mittelpunkt des Feldes
untergrund *ugrnd; // Zeiger auf den Untergrund des Feldes
hindernis *hnd; // Zeiger auf ein evtl. Hindernis};
Abfrage der Positionsinfos: get_info()
(In class spielfeld (public):)
void get_info( D3DXVECTOR3 v, posinfo *p);
v ist die Position, für die wir uns interessieren In unserer Struktur sollen die Ergebnisse eingetragen
werden
Abfrage der Positionsinfos: get_info()
void spielfeld::get_info( D3DXVECTOR3 v, posinfo *p)
{
int h;
p->spalte = (int)floor((v.x + 2*spalten)/4); // Umkehrung der Berechnung
p->zeile = (int)floor((v.z + 2*zeilen)/4); // von verschiebung_x (/z)
p->mitte.x = verschiebung_x( p->spalte); // Anwendung der
p->mitte.y = 0; // Funktionen verschiebung_x (/_y) auf die Spalte (Zeile)
p->mitte.z = verschiebung_z( p->zeile);
p->aq = (v.x-p->mitte.x)*(v.x-p->mitte.x)+(v.z-p->mitte.z)*(v.z-p->mitte.z); // Pythagoras (Quadrat des Abstands vom Mittelpunkt)
p->innerhalb = (p->zeile >= 0) && (p->zeile < zeilen) && (p->spalte >= 0) && ( p->spalte < spalten); // Zeile und Spalte in gültigem Bereich?
Abfrage der Positionsinfos: get_info()
if( p->innerhalb) // wenn die Kugel innerhalb liegt
{
p->ugrnd = mein_untergrund + felder[p->zeile][p->spalte]; // Zeiger auf den Untergrund
h = hind[p->zeile][p->spalte]; // Hindernis zunächst in h
p->hnd = h != NICHTS ? mein_hindernis + h : 0;
// wenn es eins gibt, wird es in p->hnd eingetragen
}
}
Ausgabe der Positionsinformationen
void balance::display_info()
{
posinfo p;
switch( info)
{
... case 2:
mein_spielfeld.get_info( kugelposition, &p);
if( p.innerhalb)
{
... (SIEHE NÄCHSTE FOLIE)
}
else
mein_directx.display_text( 4, "Kugel ausserhalb");
Break; } }
Ausgabe der Positionsinformationen
mein_directx.display_text( 4,
"Zeile %d, Spalte %d, Abstand zur Mitte %f",
p.zeile, p.spalte, sqrtf( p.aq));
// beim dritten Parameter muss noch die Wurzel gezogen werden
mein_directx.display_text( 5,
"Untergrund %s, Hindernis %s",
p.ugrnd->name, // hier wird aus unserer struct der Name geholt
p.hnd ? p.hnd->name : "(kein)"); // wenn da keiner steht...
Die Kollisionsberechnung
Wenn die Kugel in den Bereich eines Kegels tritt, muss der Schnittpunkt der Kugelhülle mit dem Kegelumkreis in der Höhe des Kugelradius berechnet werden
Der genaue Auftreffpunkt ist für uns allerdings erst einmal nicht so wichtig
Die Kollisionsberechnung
Uns interessiert der Punkt, an dem sich beim Aufprall der Mittelpunkt der Kugel befindet
Dazu müssen wir berechnen, wann er versucht, den äußeren Radius (siehe letzte Folie) zu durchbrechen
Da wir den Radius nur nur näherungsweise brauchen, rechnen wir ihn anhand einer Skizze aus (rechts): 1,615
Die Kollisionsberechnung
Um den Schnittpunkt einer Strecke mit einem Kreis zu Berechnen, verwenden wir ein iteratives Verfahren, bei dem, ausgehend von Start und Endpunkt der Strecke, der Abstand zum gesuchten Schnittpunkt mit jedem Verfahrensschritt halbiert wird.
Die Kollisionsberechnung
Wir gehen von einer Strecke aus, die außerhalb des Radius beginnt und innerhalb enden soll.
Annahme: Es gibt nur einen Schnittpunkt der Strecke mit dem Kreis
Iteration: Es wird ein Punkt P auf halber Strecke ermittelt. Liegt P außerhalb des Radius, ist P der neue Anfangspunkt der Strecke, liegt er innerhalb, der neue Endpunkt
Berechnung des Schnittpunkts: void schnittpunkt()
Die Paramter der Funktion void_schnittpunkt()
void schnittpunkt(
D3DXVECTOR3 *s, // Zeiger auf den Vektor in den der
// Schnittpunkt später eingetragen wird
D3DXVECTOR3 start, // Startpunkt der Strecke
D3DXVECTOR3 ziel, // Endpunkt der Strecke
D3DXVECTOR3 m, // Mittelpunkt des Kreises
float rq // Quadrat des Kreisradius, damit bei der Abstandsberechnung
// nicht die Wurzelfunktion verwendet werden muss
)
Berechnung des Schnittpunkts: void schnittpunkt()
void schnittpunkt( ..)
{
D3DXVECTOR3 t;
float aq;
int n;
for( n = 10; n; n—) //max. 10 Iterationen (reicht)
{
// SIEHE NÄCHSTE FOLIE
}
*s = t; //Rückgabe des gefundenen Punkts
}
Berechnung des Schnittpunkts: void schnittpunkt()
t = (start+ziel)/2.0f; // Mittelpunkt zwischen Start und
// Ende wird neuer Testpunkt.
aq = (t.x-m.x)*(t.x-m.x) + (t.z-m.z)*(t.z-m.z); // Bestimmung des Abstandsquadrats t von Kreismittelpunkt.
if( fabs( aq - rq) < 0.01) // liegt t schon nahe genug an der
break; // Kreislinie: Ende des Verfahrens.
if( aq > rq) // je nachdem, ob der Testpunkt außerhalb
start = t;
else // oder innerhalb des Kreises liegt
ziel = t; // wird Start- oder Zielpunkt neu bestimmt.
Kollision: Die Ablenkung der Kugel
Wir müssen den Richtungsvektor an der Normalen am Kollisionspunkt spiegeln
Also: Drehung des Richtungsvektors um 180 Grad um die Normale und Richtungsänderung
Die Ablenkung der Kugel: kugel_rollen()
Berechnung des Zielpunkts, auf den die Kugel (kneu) zusteuert:
D3DXMatrixRotationY( &dreh, -drehung);
// Kompensation der Spielfelddrehung
D3DXVec3TransformNormal( &neu, &kugelgeschwindigkeit, &dreh);
// drehung des Geschwindigkeitsvektors mit dieser Matrix
kneu = kugelposition + neu;
// Addition dieses Vektors mit der aktullen Kugelpsoition
mein_spielfeld.get_info( kneu, &pneu);
// Positioninformation vom Spielfeld einholen
Die Ablenkung der Kugel: kugel_rollen()
if( pneu.innerhalb) // wenn die Kugel im Feld ist
{ //(sonst: kontrollierter Absturz)
if( pneu.hnd && (pneu.aq < 2.6f)) // gibt es ein Hindernis?
// Kommt die Kugel um den Mittelpunkt
{ // des Hindernisses an (1.615hoch2=2.6)?
if( pneu.hnd->typ == MARKIERUNG) // wenn es sich um
{ // eine Markierung handelt...
mein_spielfeld.hind[pneu.zeile][pneu.spalte] = NICHTS;
mein_spielfeld.anzahl_markierungen--; //entferne diese und
} //rechne die Zahl der im Spiel befindlichen Markierungen runter
Die Ablenkung der Kugel: kugel_rollen()
else // wenn es sich nicht um eine Markierung handelt {
schnittpunkt( &s, kugelposition, kneu, pneu.mitte, 2.6f);
neu = s – kugelposition;
rachse = s – pneu.mitte; // Vektor vom Mittelpunkt (kreis) zum Schnittpunkt
rachse.y = 0;
D3DXMatrixRotationAxis( &reflect, &rachse, D3DX_PI); // dreh 180
D3DXVec3TransformNormal( &kugelgeschwindigkeit, &kugelgeschwindigkeit, &reflect); // Kugelgeschw. Mit
// Rotationsmatrix gedreht
kugelgeschwindigkeit = -pneu.hnd->faktor*kugelgeschwindigkeit;// Richtung wir umgekehrt (-) und entsprechend des Faktors verändert
kugelgeschwindigkeit.y = 0;}
Die Ablenkung der Kugel: kugel_rollen()
else if(pneu.ugrnd->typ == WASSER) { //ist der Untergrund Wasser
pneu.mitte.y = -1; // wird die Position der Kugel um eins nach unten verändert.
neu = (pneu.mitte – kugelposition)/4; } // ein Viertel der Strecke zum
// Ruhepunkt (mitte des Feldes) wird noch zurückgelegt
else if((pneu.ugrnd->typ == ZIEL) && (pneu.aq < 1.0f)) { // wenn Ziel
neu = (pneu.mitte – kugelposition)/4; } // das selbe wie gerade
kugelgeschwindigkeit.x = pneu.ugrnd->daempfung* (kugelgeschwindigkeit.x – kippx);
kugelgeschwindigkeit.z = pneu.ugrnd->daempfung*(kugelgeschwindigkeit.z – kippz); }
// Änderung der Kugelgeschwindigkeit entsprechend der
// Materialeigenschaften.
Die Ablenkung der Kugel: kugel_rollen()
else // wenn die Kugel außerhalb des Feldes liegt
{ kugelgeschwindigkeit.x *= 0.95f;
kugelgeschwindigkeit.y -= 0.05f; // kontrollierter Absturz
kugelgeschwindigkeit.z *= 0.95f;
}
kugelposition += neu; // das zuvor berechnete Wegstück hinzu..
D3DXVec3Cross( &kippachse, &neu, &D3DXVECTOR3( 0, 1, 0));
// dann wird die Kugel bewegt
v = D3DXVec3Length( &neu); //Drehung der Kugel wie gehabt
D3DXMatrixRotationAxis( &dreh, &kippachse, -v);
D3DXMatrixMultiply(&kugelrotation, &kugelrotation, &dreh);
}
Ende
Hinweis auf das Referat nächste Woche: Kollisionserkennung und Meshes Kollisionserkennung bei komplizierteren Strukturen