Autor Beitrag
F34r0fTh3D4rk
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 5284
Erhaltene Danke: 27

Win Vista (32), Win 7 (64)
Eclipse, SciTE, Lazarus
BeitragVerfasst: Sa 09.08.08 16:14 
hi,

Ich brauche gerade einen Code, der mit die Kollision von zwei TRects berechnet. Es soll ausgegeben werden, ob Rechteck A Links, Rechts, Oben oder Unten mit Rechteck B kollidiert. Des weiteren soll ausgegeben werden, wie weit A aus B herausgeschoben werden muss, damit die Kollision nicht mehr stattfindet. Es gibt auch Fälle (die in denen das Schnittrechteck quadratisch ist) in denen keine Seite festzustellen ist. In diesem Fall sollen immer die Horizontalen Seiten (also Rechts oder Links) genommen werden.

Mein bisheriger Versuch sieht so aus (nichtmal getestet):
(gehts nicht auch deutlich einfacher und ohne potentielles Endlosschleifenrisiko?)
ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
function RectRectIntersect(A, B: TRect; var C: TRect): boolean;
begin
  result := (A.Left <= B.Right) AND (A.Right >= B.Left) AND (A.Top <= B.Bottom) AND (A.Bottom >= B.Top);

  if result then
  with C do
  begin
    Left   := max(min(A.Right, B.Left), min(A.Left, B.Right));
    Right  := min(max(A.Right, B.Left), max(A.Left, B.Right));
    Top    := max(min(A.Bottom, B.Top), min(A.Top, B.Bottom));
    Bottom := min(max(A.Bottom, B.Top), max(A.Top, B.Bottom));
  end;
end;

function ResolveCollision(A, B: TRect; var mtd: integer): TCollisionType;
var
  C: TRect;
  w, h: integer;
  function Stuck: TCollisionType;
  var
    Aw, Ah,
    Bw, Bh,
    Ax, Ay,
    Bx, By,
    Cx, Cy: integer;
  begin
    Aw := (A.Right - A.Left);
    Ah := (A.Bottom - A.Top);
    Ax := A.Left + Aw;
    Ay := A.Top + Ah;
    Bw := (B.Right - B.Left);
    Bh := (B.Bottom - B.Top);
    Bx := B.Left + Bw;
    By := B.Top + Bh;
    Cx := Ax - Bx;
    Cy := Ay - By;
    // Horizontal
    if abs(Cx) <= abs(Cy) then
    begin
      mtd := Aw div 2 + Bw div 2;
      if Cx > 0 then
        result := ctRight;
      if Cx < 0 then
        result := ctLeft;
    end else
    // Vertical
    begin
      mtd := Ah div 2 + Bh div 2;
      if Cy > 0 then
        result := ctBottom;
      if Cy < 0 then
        result := ctTop;  
    end;
  end;
  function Vertical: TCollisionType; forward;
  function Horizontal: TCollisionType;
  begin
    mtd := w;
    // Left
    if (A.right >= B.left) and (A.Left <= B.Left) then
    begin
      result := ctLeft;
      exit;
    end;
    // Right
    if (A.Left <= B.Right) and (A.Right >= B.Right) then
    begin
      result := ctRight;
      exit;
    end;
    // A Stuck in B
    if (A.left >= B.Left) and (A.Right <= B.Right) then
      if (A.Top >= B.Top) and (A.Bottom <= B.Bottom) then
        result := Stuck else
          result := Vertical;
  end;
  function Vertical: TCollisionType;
  begin
    mtd := h;
    // Top
    if (A.Bottom >= B.Top) and (A.Top <= B.Top) then
    begin
      result := ctTop;
      exit;
    end;
    // Bottom
    if (A.Top <= B.Bottom) and (A.Bottom >= B.Bottom) then
    begin
      result := ctRight;
      exit;
    end;
    // A Stuck in B
    if (A.Top >= B.Top) and (A.Bottom <= B.Bottom) then
      if (A.left >= B.Left) and (A.Right <= B.Right) then
        result := Stuck else
          result := Horizontal;
  end;
begin
  result := ctNone;
  if RectRectIntersect(A, B, C) then
  begin
    w := C.right - C.Left;
    h := C.bottom - C.Top;
    if (w <= h) then
      result := Horizontal else
        result := Vertical;
  end;
end;


Vielen Dank schonmal ;)

mfg
F34r0fTh3D4rk Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 5284
Erhaltene Danke: 27

Win Vista (32), Win 7 (64)
Eclipse, SciTE, Lazarus
BeitragVerfasst: So 10.08.08 19:51 
Ich werde es wohl erstmal so machen, nur wird dann der mtd nicht immer korrekt berechnet:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
function ResolveCollision(A, B: TRectf; var mtd: single): boolean;
var
  C: TRectf;
  w, h: single;
begin
  result := false;
  if RectRectIntersect(A, B, C) then
  begin
    w := C.right - C.Left;
    h := C.bottom - C.Top;
    if (w <= h) then
      mtd := w else
        mtd := h;
    result := true;    
  end;
end;


mfg