hedgewars/uCollisions.pas
changeset 53 0e27949850e3
parent 38 c1ec4b15d70e
child 54 839fd258ae6f
--- a/hedgewars/uCollisions.pas	Sun Jan 15 23:56:47 2006 +0000
+++ b/hedgewars/uCollisions.pas	Thu Jan 19 21:12:20 2006 +0000
@@ -35,98 +35,93 @@
 interface
 uses uGears;
 {$INCLUDE options.inc}
+const cMaxGearArrayInd = 255;
 
-type TCollisionEntry = record
-                       X, Y, HWidth, HHeight: integer;
-                       cGear: PGear;
-                       end;
+type TDirection = record
+                  dX, dY: integer
+                  end;
+     PGearArray = ^TGearArray;
+     TGearArray = record
+                  ar: array[0..cMaxGearArrayInd] of PGear;
+                  Count: Longword
+                  end;
 
-procedure AddGearCR(Gear: PGear);
-procedure UpdateCR(NewX, NewY: integer; Index: Longword);
-procedure DeleteCR(Gear: PGear);
-function  CheckGearsCollision(Gear: PGear; Dir: integer; forX: boolean): PGear;
+procedure FillRoundInLand(X, Y, Radius: integer; Value: Longword);
+procedure AddGearCI(Gear: PGear);
+procedure DeleteCI(Gear: PGear);
+function CheckGearsCollision(Gear: PGear): PGearArray;
 function  HHTestCollisionYwithGear(Gear: PGear; Dir: integer): boolean;
 function TestCollisionXwithGear(Gear: PGear; Dir: integer): boolean;
 function TestCollisionYwithGear(Gear: PGear; Dir: integer): boolean;
 function TestCollisionXwithXYShift(Gear: PGear; ShiftX, ShiftY: integer; Dir: integer): boolean;
 function TestCollisionYwithXYShift(Gear: PGear; ShiftX, ShiftY: integer; Dir: integer): boolean;
-function TestCollisionY(Gear: PGear; Dir: integer): boolean;
 
 implementation
 uses uMisc, uConsts, uLand;
 
+type TCollisionEntry = record
+                       X, Y, Radius: integer;
+                       cGear: PGear;
+                       end;
+                       
 const MAXRECTSINDEX = 255;
 var Count: Longword = 0;
-    crects: array[0..MAXRECTSINDEX] of TCollisionEntry;
+    cinfos: array[0..MAXRECTSINDEX] of TCollisionEntry;
+    ga: TGearArray;
 
-procedure AddGearCR(Gear: PGear);
+procedure FillRoundInLand(X, Y, Radius: integer; Value: Longword);
+var ty, tx: integer;
 begin
+for ty:= max(-Radius, -y) to min(radius, 1023 - y) do
+    for tx:= max(0, round(x-radius*sqrt(1-sqr(ty/radius)))) to min(2047,round(x+radius*sqrt(1-sqr(ty/radius)))) do
+        Land[ty + y, tx]:= Value;
+end;
+
+procedure AddGearCI(Gear: PGear);
+begin
+if Gear.CollIndex < High(Longword) then exit; 
 TryDo(Count <= MAXRECTSINDEX, 'Collision rects array overflow', true);
-with crects[Count] do
+with cinfos[Count] do
      begin
      X:= round(Gear.X);
      Y:= round(Gear.Y);
-     HWidth:= Gear.HalfWidth;
-     HHeight:= Gear.HalfHeight;
+     Radius:= Gear.Radius;
+     FillRoundInLand(X, Y, Radius, $FF);
      cGear:= Gear
      end;
 Gear.CollIndex:= Count;
 inc(Count)
 end;
 
-procedure UpdateCR(NewX, NewY: integer; Index: Longword);
+procedure DeleteCI(Gear: PGear);
 begin
-with crects[Index] do
-     begin
-     X:= NewX;
-     Y:= NewY
-     end
+if Gear.CollIndex < Count then
+   begin
+   with cinfos[Gear.CollIndex] do FillRoundInLand(X, Y, Radius, 0);
+   cinfos[Gear.CollIndex]:= cinfos[Pred(Count)];
+   cinfos[Gear.CollIndex].cGear.CollIndex:= Gear.CollIndex;
+   Gear.CollIndex:= High(Longword);
+   dec(Count)
+   end;
 end;
 
-procedure DeleteCR(Gear: PGear);
-begin
-if Gear.CollIndex < Pred(Count) then
-   begin
-   crects[Gear.CollIndex]:= crects[Pred(Count)];
-   crects[Gear.CollIndex].cGear.CollIndex:= Gear.CollIndex
-   end;
-Gear.CollIndex:= High(Longword);
-dec(Count)
-end;
-
-function CheckGearsCollision(Gear: PGear; Dir: integer; forX: boolean): PGear;
-var x1, x2, y1, y2: integer;
+function CheckGearsCollision(Gear: PGear): PGearArray;
+var mx, my: integer;
     i: Longword;
 begin
-Result:= nil;
+Result:= @ga;
+ga.Count:= 0;
 if Count = 0 then exit;
-x1:= round(Gear.X);
-y1:= round(Gear.Y);
-
-if forX then
-   begin
-   x1:= x1 + Dir*Gear.HalfWidth;
-   x2:= x1;
-   y2:= y1 + Gear.HalfHeight - 1;
-   y1:= y1 - Gear.HalfHeight + 1
-   end else
-   begin
-   y1:= y1 + Dir*Gear.HalfHeight;
-   y2:= y1;
-   x2:= x1 + Gear.HalfWidth - 1;
-   x1:= x1 - Gear.HalfWidth + 1
-   end;
+mx:= round(Gear.X);
+my:= round(Gear.Y);
 
 for i:= 0 to Pred(Count) do
-   with crects[i] do
-      if  (Gear.CollIndex <> i)
-         and (x1 <= X + HWidth)
-         and (x2 >= X - HWidth)
-         and (y1 <= Y + HHeight)
-         and (y2 >= Y - HHeight) then
+   with cinfos[i] do
+      if (Gear <> cGear) and
+         (sqrt(sqr(mx - x) + sqr(my - y)) <= Radius + Gear.Radius) then
              begin
-             Result:= crects[i].cGear;
-             exit
+             ga.ar[ga.Count]:= cinfos[i].cGear;
+             inc(ga.Count)
              end;
 end;
 
@@ -135,14 +130,14 @@
 begin
 Result:= false;
 y:= round(Gear.Y);
-if Dir < 0 then y:= y - Gear.HalfHeight
-           else y:= y + Gear.HalfHeight;
+if Dir < 0 then y:= y - Gear.Radius
+           else y:= y + Gear.Radius;
            
 if ((y - Dir) and $FFFFFC00) = 0 then
    begin
    x:= round(Gear.X);
-   if (((x - Gear.HalfWidth) and $FFFFF800) = 0)and(Land[y - Dir, x - Gear.HalfWidth] <> 0)
-    or(((x + Gear.HalfWidth) and $FFFFF800) = 0)and(Land[y - Dir, x + Gear.HalfWidth] <> 0) then
+   if (((x - Gear.Radius) and $FFFFF800) = 0)and(Land[y - Dir, x - Gear.Radius] <> 0)
+    or(((x + Gear.Radius) and $FFFFF800) = 0)and(Land[y - Dir, x + Gear.Radius] <> 0) then
       begin
       Result:= true;
       exit
@@ -151,15 +146,12 @@
 
 if (y and $FFFFFC00) = 0 then
    begin
-   x:= round(Gear.X) - Gear.HalfWidth + 1;
-   i:= x + Gear.HalfWidth * 2 - 2;
+   x:= round(Gear.X) - Gear.Radius + 1;
+   i:= x + Gear.Radius * 2 - 2;
    repeat
      if (x and $FFFFF800) = 0 then Result:= Land[y, x]<>0;
      inc(x)
-   until (x > i) or Result;
-   if Result then exit;
-
-   Result:= CheckGearsCollision(Gear, Dir, false) <> nil
+   until (x > i) or Result
    end
 end;
 
@@ -168,18 +160,16 @@
 begin
 Result:= false;
 x:= round(Gear.X);
-if Dir < 0 then x:= x - Gear.HalfWidth
-           else x:= x + Gear.HalfWidth;
+if Dir < 0 then x:= x - Gear.Radius
+           else x:= x + Gear.Radius;
 if (x and $FFFFF800) = 0 then
    begin
-   y:= round(Gear.Y) - Gear.HalfHeight + 1; {*}
-   i:= y + Gear.HalfHeight * 2 - 2;         {*}
+   y:= round(Gear.Y) - Gear.Radius + 1; {*}
+   i:= y + Gear.Radius * 2 - 2;         {*}
    repeat
      if (y and $FFFFFC00) = 0 then Result:= Land[y, x]<>0;
      inc(y)
    until (y > i) or Result;
-   if Result then exit;
-   Result:= CheckGearsCollision(Gear, Dir, true) <> nil
    end
 end;
 
@@ -197,32 +187,12 @@
 begin
 Result:= false;
 y:= round(Gear.Y);
-if Dir < 0 then y:= y - Gear.HalfHeight
-           else y:= y + Gear.HalfHeight;
+if Dir < 0 then y:= y - Gear.Radius
+           else y:= y + Gear.Radius;
 if (y and $FFFFFC00) = 0 then
    begin
-   x:= round(Gear.X) - Gear.HalfWidth + 1;    {*}
-   i:= x + Gear.HalfWidth * 2 - 2;            {*}
-   repeat
-     if (x and $FFFFF800) = 0 then Result:= Land[y, x]<>0;
-     inc(x)
-   until (x > i) or Result;
-   if Result then exit;
-   Result:= CheckGearsCollision(Gear, Dir, false) <> nil;
-   end
-end;
-
-function TestCollisionY(Gear: PGear; Dir: integer): boolean;
-var x, y, i: integer;
-begin
-Result:= false;
-y:= round(Gear.Y);
-if Dir < 0 then y:= y - Gear.HalfHeight
-           else y:= y + Gear.HalfHeight;
-if (y and $FFFFFC00) = 0 then
-   begin
-   x:= round(Gear.X) - Gear.HalfWidth + 1;    {*}
-   i:= x + Gear.HalfWidth * 2 - 2;            {*}
+   x:= round(Gear.X) - Gear.Radius + 1;    {*}
+   i:= x + Gear.Radius * 2 - 2;            {*}
    repeat
      if (x and $FFFFF800) = 0 then Result:= Land[y, x]<>0;
      inc(x)