Příklad a zdroják ke stažení (724k)
Pro detekci kolizí jsem použil předchozí příklad, jen jsem přidal pár procedur. Možná existují daleko lepší algoritmy pro detekci kolizí, ale já jsem si vymyslel jednoduché výpočty, bez goniometrických funkcí a jinejch složitostí a zdá se, že to funguje. Pokud někdo znáte lepší způsob výpočtů, napište mi prosím, rád se přiučím.No a teď k věci.
Do 'public' jsem přidal tyto proměnné.
public ... Xtrue, Ytrue, Ztrue: array [1..6] of boolean; //kolizní hodnoty PxLast, PyLast, PzLast: array [1..6] of double; //poslední pozice kamery před kolizí end;Vytvořil jsem nové procedury.procedure InitCollision; procedure Collision;No a teď se pokusím každou proceduru trochu popsat.
procedure TForm1.InitCollision;Proměnné jsou:
var Ax, Ay, Az, Bx, By, Bz, Cx, Cy, Cz, Dx, Dy, Dz: double; //Body objektu Px, Py, Pz: double; //Pozice kamery Xdiff, Ydiff, Zdiff, Cdiff, Fdiff : boolean; //Kolizní hodnoty i: integer; //Počet objektůTeď převedu hodnoty pozice kamery do proměných 'Px, Py, Pz'.//pozice kamery Px := X; Py := -Y; Pz := -Z;Znaménka minus jsou tam proto, aby odpovídala 'Y,Z' souřadnice kamery 'Y,Z' souřadnici objektu.Nyní převedu hodnoty všech šesti objektů do proměných 'Ax' až 'Dz'.
for i := 1 to 6 do begin //stena 1 if i = 1 then begin //pozice bodu A Ax := VertexPointer[0].X; Ay := VertexPointer[0].Y; Az := VertexPointer[0].Z; //pozice bodu B Bx := VertexPointer[1].X; By := VertexPointer[1].Y; Bz := VertexPointer[1].Z; //pozice bodu C Cx := VertexPointer[2].X; Cy := VertexPointer[2].Y; Cz := VertexPointer[2].Z; //pozice bodu D Dx := VertexPointer[5].X; Dy := VertexPointer[5].Y; Dz := VertexPointer[5].Z; end; //stena 2 if i = 2 then begin //pozice bodu A Ax := VertexPointer2[0].X; Ay := VertexPointer2[0].Y; Az := VertexPointer2[0].Z; //pozice bodu B Bx := VertexPointer2[1].X; By := VertexPointer2[1].Y; Bz := VertexPointer2[1].Z; //pozice bodu C Cx := VertexPointer2[2].X; Cy := VertexPointer2[2].Y; Cz := VertexPointer2[2].Z; //pozice bodu D Dx := VertexPointer2[5].X; Dy := VertexPointer2[5].Y; Dz := VertexPointer2[5].Z; end; //stena 3 if i = 3 then begin //pozice bodu A Ax := VertexPointer3[0].X; Ay := VertexPointer3[0].Y; Az := VertexPointer3[0].Z; //pozice bodu B Bx := VertexPointer3[1].X; By := VertexPointer3[1].Y; Bz := VertexPointer3[1].Z; //pozice bodu C Cx := VertexPointer3[2].X; Cy := VertexPointer3[2].Y; Cz := VertexPointer3[2].Z; //pozice bodu D Dx := VertexPointer3[5].X; Dy := VertexPointer3[5].Y; Dz := VertexPointer3[5].Z; end; //stena 4 if i = 4 then begin //pozice bodu A Ax := VertexPointer4[0].X; Ay := VertexPointer4[0].Y; Az := VertexPointer4[0].Z; //pozice bodu B Bx := VertexPointer4[1].X; By := VertexPointer4[1].Y; Bz := VertexPointer4[1].Z; //pozice bodu C Cx := VertexPointer4[2].X; Cy := VertexPointer4[2].Y; Cz := VertexPointer4[2].Z; //pozice bodu D Dx := VertexPointer4[5].X; Dy := VertexPointer4[5].Y; Dz := VertexPointer4[5].Z; end; //strop if i = 5 then begin //pozice bodu A Ax := VertexPointer5[0].X; Ay := VertexPointer5[0].Y; Az := VertexPointer5[0].Z; //pozice bodu B Bx := VertexPointer5[1].X; By := VertexPointer5[1].Y; Bz := VertexPointer5[1].Z; //pozice bodu C Cx := VertexPointer5[2].X; Cy := VertexPointer5[2].Y; Cz := VertexPointer5[2].Z; //pozice bodu D Dx := VertexPointer5[5].X; Dy := VertexPointer5[5].Y; Dz := VertexPointer5[5].Z; end; //podlaha if i = 6 then begin //pozice bodu A Ax := VertexPointer6[0].X; Ay := VertexPointer6[0].Y; Az := VertexPointer6[0].Z; //pozice bodu B Bx := VertexPointer6[1].X; By := VertexPointer6[1].Y; Bz := VertexPointer6[1].Z; //pozice bodu C Cx := VertexPointer6[2].X; Cy := VertexPointer6[2].Y; Cz := VertexPointer6[2].Z; //pozice bodu D Dx := VertexPointer6[5].X; Dy := VertexPointer6[5].Y; Dz := VertexPointer6[5].Z; end;No a teď, když mám všechny hodnoty, které potřebuju, roztřídim objekty podle vzdáleností jednotlivých bodů od sebe.//rozdíly vzdálenosti bodů if Ax <= Bx then Xdiff := True else Xdiff := False; if Cy <= Ay then Ydiff := True else Ydiff := False; if Dz <= Cz then Zdiff := True else Zdiff := False;Objekty takto třídím, abych věděl, jak jsou orientovány v prostoru a podle toho mohl později vypočítat kolizi mezi objektem a kamerou. Pro každou orientaci se totiž počítá kolize trochu jinak.No a teď následuje hlavní výpočet.
//výpočet //X hodnota if Xdiff then begin if ((Bx - Ax) <= 0) then begin //zruší nulovou hodnotu Ax := Ax - 0.5; Bx := Bx + 0.5; end; if ((Px >= Ax)and(Px <= Bx)) or ((Px >= Cx)and(Px <= Dx)) then Xtrue[i] := True else Xtrue[i] := False; end; if not Xdiff then begin if ((Px >= Bx)and(Px <= Ax)) or ((Px >= Dx)and(Px <= Cx)) then Xtrue[i] := True else Xtrue[i] := False; end; //Y hodnota if Ydiff then begin if ((Ay - Cy) <= 0) then begin //zruší nulovou hodnotu Ay := Ay + 0.5; Cy := Cy - 0.5; end; if ((Py <= Ay)and(Py >= Cy)) or ((Py <= By)and(Py >= Dy)) then Ytrue[i] := True else Ytrue[i] := False; end; if not Ydiff then begin if ((Py <= Cy)and(Py >= Ay)) or ((Py <= Dy)and(Py >= By)) then Ytrue[i] := True else Ytrue[i] := False; end; //Z hodnota if Zdiff then begin if ((Az - Bz) <= 0) then begin //zruší nulovou hodnotu Bz := Bz - 0.5; Az := Az + 0.5 end; if (((Pz <= Az)and(Pz >= Bz)) or ((Pz <= Cz)and(Pz >= Dz))) //stěny or (((Pz >= Az)and(Pz <= Cz)) or ((Pz >= Bz)and(Pz <= Dz))) then //podlaha a strop Ztrue[i] := True else Ztrue[i] := False; end; if not Zdiff then begin if ((Pz <= Bz)and(Pz >= Az)) or ((Pz <= Dz)and(Pz >= Cz)) then Ztrue[i] := True else Ztrue[i] := False; end;Vyznáte se v tom? Já teda moc ne.
Nejdřív počítám 'X' souřadnice bodů objektu vůči kameře. Když se kamera nachází mezi těmito body vyplivne to hodnotu 'Xtrue[i] := True;', což znamená, že se zapíná kolize mezi objektem a kamerou na 'X' souřadnici. To samé se provede na souřadnici 'Y' a 'Z'. Procedura tedy vyplivne hodnoty 'Xtrue[i]', 'Ytrue[i]', 'Ztrue[i]', se kterými pak dále pracuji.Nakonec načtu poslední pozici kamery před následnou kolizí.
//poslední pozice kamery před kolizí if (Xtrue[i] = False) or (Ytrue[i] = False) or (Ztrue[i] = False) then begin PxLast[i] := X; PyLast[i] := Y; PzLast[i] := Z; end;Celou proceduru bez mejch poznámek si můžete prohlédnout zde.
procedure TForm1.Collision;U této procedury je jen jedna proměnná:
var i: integer; //počet objektůVýpočet už je jednoduchý.for i := 1 to 6 do begin if Xtrue[i] and Ytrue[i] and Ztrue[i] then begin X := PxLast[i]; Y := PyLast[i]; Z := PzLast[i]; end; end;Pokud všechny tři kolizní hodnoty jsou pravdivé, načte se poslední pozice kamery před kolizí. Pro každý objekt se toto počítá zvlášť.
Na celou proceduru můžete mrknout zde.
Jo, ještě vám řeknu, jak se v prostoru pohybovat.
Takže dopředu, dozadu a otáčení pomocí šipek.
'PageUp'- nahoru
'PageDown' - dolu
'Home' - pohled nahoru
'End' - pohled dolu
'Esc' - konec
'Enter' - FullScreen Mode 640x480 16b
Home