--- 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)