unit uPolygon;
interface
uses
AdPhysics,
Vectors,
Math;
type
// Array mit den Vertices des Polygons
TV2fArray =
array of TVector2f;
// Polygon Klasse
TPolygon =
class(TPhysicalBoxSprite)
private
fposition: TVector2f;
// Position
fvertices: TV2fArray;
// Vertices (Objektkoordinaten)
function GetVertex(n: integer): TVector2f;
// Liefert die Objektkoordinaten
function GetVertexAbs(n: integer): TVector2f;
// Liefert die absoluten Koordinaten
procedure SetVertex(n: integer; Value: TVector2f);
// Setzt die Objektkoordinaten
function GetCount: integer;
// Liefert length(fvertices)
public
procedure AddVertex(v: TVector2f);
// Fügt ein Vertex hinzu
procedure AddVertexAbs(v: TVector2f);
// Fügt ein Vertex mit Weltkoordinaten hinzu
procedure RemoveVertex(n: integer);
// Entfernt ein Vertex
property position: TVector2f
read fposition
write fposition;
// Position
property vertices[n: integer]: TVector2f
read GetVertex
write SetVertex;
// Vertex Koordinaten
property vertices_abs[n: integer]: TVector2f
read GetVertexAbs;
// Vertex Weltkoordinaten
property Count: integer
read GetCount;
// siehe GetCount
end;
TPolygonArray =
array of TPolygon;
function BrickBallIntersect(A, B: TPolygon;
var MTD: TVector2f): boolean;
implementation
function CreateAxis(P: TPolygon): TV2fArray;
var
i, l : integer;
tmp : TVector2f;
begin
for i := 0
to (P.count - 1)
do
begin
l := i + 1;
if l > (P.count - 1)
then
l := 0;
// Berechnung der Seitenfläche
tmp := v2f_sub(P.vertices[l], P.vertices[i]);
// Berechnet die Normale der Seitenfläche
setlength(result, length(result) + 1);
result[high(result)] := v2f_normalize(to_v2f(-tmp.y, tmp.x));
end;
end;
procedure ProjectOntoAxis(P: TPolygon; proj: TVector2f;
var pmin, pmax: extended);
var
i : integer;
dp : extended;
begin // Projeziert den ersten Wert
pmin := v2f_dotproduct(P.vertices[0], proj);
pmax := pmin;
// Findet den kleinsten und größten projezierten Wert für die Gerade für P
for i := 1
to (P.count - 1)
do
begin
// projezieren
dp := v2f_dotproduct(P.vertices[i], proj);
if dp < pmin
then
pmin :=
dp;
if dp > pmax
then
pmax :=
dp;
end;
end;
function CollisionCheck(A, B: TPolygon;
var axis: TVector2f; voffset: TVector2f): boolean;
var
foffset,
amin, amax,
bmin, bmax,
d1, d2, depth : extended;
begin
ProjectOntoAxis(A, axis, amin, amax);
ProjectOntoAxis(B, axis, bmin, bmax);
foffset := v2f_dotproduct(voffset, axis);
amin := amin + foffset;
amax := amax + foffset;
d1 := amin - bmax;
d2 := bmin - amax;
// Wenn es keine Überschneidung gibt, abbrechen -> keine Kollision
if (d1 > 0)
or (d2 > 0)
then
begin
result := false;
exit;
end;
// Ansonsten den Verschiebungsvektor bestimmen
depth := max(d1, d2);
axis := v2f_scale(axis, abs(depth));
result := true;
end;
function BrickBallIntersect(A, B: TPolygon;
var MTD: TVector2f): boolean;
var
axis : TV2fArray;
voffset : TVector2f;
i : integer;
begin
MTD := to_v2f(0, 0);
// Offset berechnen
voffset := v2f_sub(A.position, B.position);
// Alle Achsen für A
axis := CreateAxis(A);
// Alle Achsen für B
axis := CreateAxis(B);
// Projezieren der Polygone
for i := 0
to high(axis)
do
if not CollisionCheck(A, B, axis[i], voffset)
then
begin
result := false;
exit;
end;
// MTD bestimmen
MTD := axis[0];
for i := 1
to high(axis)
do
if v2f_length(axis[i]) < v2f_length(MTD)
then
MTD := axis[i];
if v2f_dotproduct(voffset, MTD) < 0
then
MTD := v2f_scale(MTD, -1);
// Kollision
result := true;
end;
{ TPolygon }
procedure TPolygon.AddVertex(v: TVector2f);
begin
setlength(fvertices, length(fvertices) + 1);
fvertices[high(fvertices)] := v2f_sub(v, position);
end;
procedure TPolygon.AddVertexAbs(v: TVector2f);
begin
setlength(fvertices, length(fvertices) + 1);
fvertices[high(fvertices)] := v;
end;
function TPolygon.GetCount: integer;
begin
result := length(fvertices);
end;
function TPolygon.GetVertex(n: integer): TVector2f;
var
acos, asin : extended;
begin
sincos(degtorad(angle), asin, acos);
result.x := fvertices[n].x * acos + fvertices[n].y * -asin;
result.y := fvertices[n].x * asin + fvertices[n].y * acos;
end;
function TPolygon.GetVertexAbs(n: integer): TVector2f;
begin
result := v2f_add(fvertices[n], fposition);
end;
procedure TPolygon.RemoveVertex(n: integer);
var
i : integer;
begin
for i := n
to high(fvertices) - 1
do
fvertices[i] := fvertices[i + 1];
setlength(fvertices, length(fvertices) - 1);
end;
procedure TPolygon.SetVertex(n: integer; Value: TVector2f);
begin
fvertices[n] := Value;
end;
end.