Trochu jsem zdokonalil předešlý tutorial na detekci kolizí.
Vytvořil jsem jednoduchou místnost se sloupem. V místnosti
skáče koule a odráží se od stěn. Přidal jsem i detekci kolize kamery se stěnama. Aplikace běží v odděleném procesu 'Thread', který jsem
trochu vylepšil. Procedury aktivující 'Thread' jsou
obsaženy v unitě RenderThread
Algoritmus pro detekci kolizí je stejný. Všechny funkce jsou v unitě K3dMath.pas . Do této unity jsem jen připsal algoritmus na normalizaci vektoru,
kterou budu potřebovat při výpočtu kolize koule se stěnama.
V předešlém tutorialu kolidovala čára s jedním trojúhelníkem. Kolize však funguje vlastně jen v jedné souřadnici. Já však potřebuji, aby kolize
fungovaly ve všech souřadnicích, proto jsem vytvořil tři čáry 'LineX, LineY, LineZ'.
Pokud chci, aby kolidovala koule, místo čar vykreslím kouli. Pokud chci, aby kolidovala kamera, přepočítám pozici čar tak, aby souřadnice
průsečíku čar a pozice kamery byly totožné. Čáry opět nevykresluji.
Kolizi koule počítám takto:
Nejdříve vypočítám, kolizi všech tří čar.
|
//LineX
bCollidedLineX := IntersectedPolygon(Point1[val], Point2[val], Point3[val] , pLineX1, pLineX2);
if bCollidedLineX
then begin
LineX := True;
end;
//LineY
bCollidedLineY := IntersectedPolygon(Point1[val], Point2[val], Point3[val] , pLineY1, pLineY2);
if bCollidedLineY
then begin
LineY := True;
end;
//LineZ
bCollidedLineZ := IntersectedPolygon(Point1[val], Point2[val], Point3[val] , pLineZ1, pLineZ2);
if bCollidedLineZ
then begin
LineZ := True;
end;
Pokud koliduje alespoň jedna z čar.
|
if LineX or LineY or LineZ then begin
Coll := True;
end else begin
Coll := False;
end;
Změním vektor pohybu koule.
|
if Coll then begin
if FirstColl then begin
FirstColl := False;
TriVector := CalcCollVector(Point1[val], Point2[val], Point3[val]);
NewVector.x := (LineVector.x - TriVector.x);
NewVector.y := (LineVector.y - TriVector.y);
NewVector.z := (LineVector.z - TriVector.z);
LineVector := NormalizeVector(NewVector);
MoveSpeedLine := 0.06;
end; //konec FirstColl
end else begin
FirstColl := True;
MoveSpeedLine := 0.05;
end;
Proměnnou 'FirstColl' tam mám proto, aby se kolize počítala jen při prvním střetu čáry se stěnou. Změní se vektor pohybu čar (koule)
a pokud čáry neopustí prostor stěny, kolize se dále nepočítají.
Výpočet funguje takto:
Nejdříve se vypočítá vektor stěny (trojúhelníka)
TriVector := CalcCollVector(Point1[val], Point2[val], Point3[val]);
a potom nový vektor odečtením vektoru stěny od stávajícího vektoru pohybu čar.
NewVector.x := (LineVector.x - TriVector.x);
NewVector.y := (LineVector.y - TriVector.y);
NewVector.z := (LineVector.z - TriVector.z);
Nakonec převedu nový vektor do vektoru pohybu čar.
LineVector := NormalizeVector(NewVector);
|
Pokud počítám kolizi kamery se stěnama, tak si nejdříve vypočítám průsečík čar, aby jeho souřadnice byly
totožné s pozicí kamery.
|
//Line X
LineX1.x := Tran.X - 2;
LineX1.y := Tran.Y;
LineX1.z := Tran.Z;
LineX2.x := Tran.X + 2;
LineX2.y := Tran.Y;
LineX2.z := Tran.Z;
//Line Y
LineY1.x := Tran.X;
LineY1.y := Tran.Y - 2;
LineY1.z := Tran.Z;
LineY2.x := Tran.X;
LineY2.y := Tran.Y + 2;
LineY2.z := Tran.Z;
//Line Z
LineZ1.x := Tran.X;
LineZ1.y := Tran.Y;
LineZ1.z := Tran.Z - 2;
LineZ2.x := Tran.X;
LineZ2.y := Tran.Y;
LineZ2.z := Tran.Z + 2;
Výpočet kolize čar je stejný jako u koule
|
//LineX
bCollidedLineX := IntersectedPolygon(Point1[val], Point2[val], Point3[val] , LineX1, LineX2);
if bCollidedLineX
then begin
bLineX := True;
end;
//LineY
bCollidedLineY := IntersectedPolygon(Point1[val], Point2[val], Point3[val] , LineY1, LineY2);
if bCollidedLineY
then begin
bLineY := True;
end;
//LineZ
bCollidedLineZ := IntersectedPolygon(Point1[val], Point2[val], Point3[val] , LineZ1, LineZ2);
if bCollidedLineZ
then begin
bLineZ := True;
end;
Pokud koliduje alespoň jedna z čar.
|
if bLineX or bLineY or bLineZ then begin
Coll := True;
end else begin
Coll := False;
end;
Vrátím kameru zpět ve směru vektoru kolizní stěny.
|
if Coll then begin
TriVector := CalcCollVector(Point1[val], Point2[val], Point3[val]);
Tran.x := Tran.x - (TriVector.x * MoveSpeed);
Tran.y := Tran.y - (TriVector.y * MoveSpeed);
Tran.z := Tran.z - (TriVector.z * MoveSpeed);
end;
Kouli vytvořím voláním procedury 'DrawSphere'
|
procedure DrawSphere;
var
qObj: PGLUquadricObj;
X,Y,Z: TGLFloat;
begin
if Sphere then begin
glEnable(GL_LIGHTING);
X := pLineZ1.x;
Y := pLineZ1.y;
Z := pLineZ1.z + 2;
glPushMatrix;
glTranslatef(X,Y,Z); //pozice kamery
glColor3f(1, 1, 1);
glBindTexture(GL_TEXTURE_2D, TextureBin[21]);
glEnable(GL_TEXTURE_2D);
qobj := gluNewQuadric(); //vytvori novy objekt
gluQuadricTexture(qobj,GL_true); //otexturuje
gluQuadricDrawStyle(qobj, GLU_FILL); //typ zobrazeni
gluQuadricOrientation(qobj,GLU_OUTSIDE); //vnejsi strana odrazi svetlo
gluQuadricNormals(qobj, GLU_SMOOTH); //volba stinováni
gluSphere(qobj, 2, 20, 20); //zobrazi kouli s polomerem 2 a siti 20x20
glPopMatrix;
end;
end;
Koule se pohybuje podle pozice čar, které definuji v proceduře 'DrawLine'
|
procedure DrawLine;
begin
glDisable(GL_TEXTURE_2D);
glDisable(GL_LIGHTING);
if LineZ or LineX or LineY then begin
glColor3f(1, 0, 0); // Make the line RED if we collided with the triangle's plane
end else begin
glColor3f(1, 1, 0); // Make the line YELLOW if we didn't collide
end;
LineZ := False;
LineX := False;
LineY := False;
//Move collision lines
pLineX1.x := pLineX1.x + (LineVector.x * MoveSpeedLine);
pLineX1.y := pLineX1.y + (LineVector.y * MoveSpeedLine);
pLineX1.z := pLineX1.z + (LineVector.z * MoveSpeedLine);
pLineX2.x := pLineX2.x + (LineVector.x * MoveSpeedLine);
pLineX2.y := pLineX2.y + (LineVector.y * MoveSpeedLine);
pLineX2.z := pLineX2.z + (LineVector.z * MoveSpeedLine);
pLineY1.x := pLineY1.x + (LineVector.x * MoveSpeedLine);
pLineY1.y := pLineY1.y + (LineVector.y * MoveSpeedLine);
pLineY1.z := pLineY1.z + (LineVector.z * MoveSpeedLine);
pLineY2.x := pLineY2.x + (LineVector.x * MoveSpeedLine);
pLineY2.y := pLineY2.y + (LineVector.y * MoveSpeedLine);
pLineY2.z := pLineY2.z + (LineVector.z * MoveSpeedLine);
pLineZ1.x := pLineZ1.x + (LineVector.x * MoveSpeedLine);
pLineZ1.y := pLineZ1.y + (LineVector.y * MoveSpeedLine);
pLineZ1.z := pLineZ1.z + (LineVector.z * MoveSpeedLine);
pLineZ2.x := pLineZ2.x + (LineVector.x * MoveSpeedLine);
pLineZ2.y := pLineZ2.y + (LineVector.y * MoveSpeedLine);
pLineZ2.z := pLineZ2.z + (LineVector.z * MoveSpeedLine);
if Lines then begin
glPushMatrix;
glBegin(GL_LINES); // This is our BEGIN to draw LineX
glVertex3f(pLineX1.x, pLineX1.y, pLineX1.z);
glVertex3f(pLineX2.x, pLineX2.y, pLineX2.z);
glEnd;
glBegin(GL_LINES); // This is our BEGIN to draw Line Y
glVertex3f(pLineY1.x, pLineY1.y, pLineY1.z);
glVertex3f(pLineY2.x, pLineY2.y, pLineY2.z);
glEnd;
glBegin(GL_LINES); // This is our BEGIN to draw LineZ
glVertex3f(pLineZ1.x, pLineZ1.y, pLineZ1.z);
glVertex3f(pLineZ2.x, pLineZ2.y, pLineZ2.z);
glEnd;
glPopMatrix;
end;
end;
Tlačítkem 'L' zobrazím místo koule čáry, tlačítkem 'S' zobrazím kouli.
Kamera se pohybuje prostorem pomocí šipek, pokud zmáčknu mezerník a šipku doleva, nebo doprava, kamera se neotáčí, ale posouvá.
Tlačítky 'PageUp, PageDown' kamera lítá nahoru dolu. Tlačítky 'Home, End' kouká kamera nahoru dolu.
|
Home