--- a/hedgewars/uCollisions.pas Sun May 02 22:00:50 2010 +0000
+++ b/hedgewars/uCollisions.pas Mon May 03 02:32:17 2010 +0000
@@ -49,7 +49,7 @@
function TestCollisionXwithXYShift(Gear: PGear; ShiftX: hwFloat; ShiftY: LongInt; Dir: LongInt): boolean;
function TestCollisionYwithXYShift(Gear: PGear; ShiftX, ShiftY: LongInt; Dir: LongInt): boolean;
-function calcSlopeNormal(Gear: PGear; collisionX, collisionY: LongInt; var deltaX, deltaY: LongInt; TestWord: LongWord): Boolean;
+function calcSlopeTangent(Gear: PGear; collisionX, collisionY: LongInt; var deltaX, deltaY: LongInt; TestWord: LongWord): Boolean;
implementation
uses uMisc, uConsts, uLand, uLandGraphics;
@@ -315,67 +315,55 @@
end;
-function calcSlopeNormal(Gear: PGear; collisionX, collisionY: LongInt; var deltaX, deltaY: LongInt; TestWord: LongWord): boolean;
-var sx, sy, ldx, ldy, rdx, rdy: LongInt;
- i, j, mx, my : ShortInt;
+function calcSlopeTangent(Gear: PGear; collisionX, collisionY: LongInt; var deltaX, deltaY: LongInt; TestWord: LongWord): boolean;
+var ldx, ldy, rdx, rdy: LongInt;
+ i, j, mx, my, li, ri, jfr, jto, tmpo : ShortInt;
tmpx, tmpy: LongWord;
- dx, dy, rx, ry: hwFloat;
- leftsteps: Array[0..4,0..1] of ShortInt;
- rightsteps: Array[0..4,0..1] of ShortInt;
+ dx, dy: hwFloat;
+ offset: Array[0..7,0..1] of ShortInt;
begin
dx:= Gear^.dX;
dy:= Gear^.dY;
+
+ // we start searching from the direction the gear center is at
+ mx:= hwRound(Gear^.X-dx) - hwRound(Gear^.X);
+ my:= hwRound(Gear^.Y-dy) - hwRound(Gear^.Y);
+
+ li:= -1;
+ ri:= -1;
- if Gear^.AdvBounce > 0 then
- begin
- rx:= _0_5 + Int2hwFloat(collisionX) - Gear^.X;
- ry:= _0_5 + Int2hwFloat(collisionY) - Gear^.Y;
- end
- else
- begin
- rx:= dx;
- ry:= dy;
- end;
-
- sx:= hwSign(rx);
- sy:= hwSign(ry);
-
- if rx.QWordValue > ry.QWordValue then
- begin
- if (ry/rx).QWordValue < _0_5.QWordValue then sy:= 0;
- end
- else
+ // go around collision pixel, checking for first/last collisions
+ // this will determinate what angles will be tried to crawl along
+ for i:= 0 to 7 do
begin
- if (rx/ry).QWordValue < _0_5.QWordValue then sx:= 0;
- end;
-
- mx:= -sx;
- my:= -sy;
+ offset[i,0]:= mx;
+ offset[i,1]:= my;
+
+ tmpx:= collisionX + mx;
+ tmpy:= collisionY + my;
- for i:= 0 to 4 do
- begin
- if (mx = -1) and (my <> 1) then my:= my + 1
- else if (my = 1) and (mx <> 1) then mx:= mx + 1
- else if (mx = 1) and (my <> -1) then my:= my - 1
- else mx:= mx - 1;
+ if (((tmpy) and LAND_HEIGHT_MASK) = 0) and (((tmpx) and LAND_WIDTH_MASK) = 0) then
+ if (Land[tmpy,tmpx] > TestWord) then
+ begin
+ // remember the index belonging to the first and last collision (if in 1st half)
+ if (i <> 0) then
+ begin
+ if (ri = -1) then
+ ri:= i
+ else
+ li:= i;
+ end;
+ end;
- leftsteps[i,0]:= mx;
- leftsteps[i,1]:= my;
- end;
+ if i = 7 then break;
- mx:= -sx;
- my:= -sy;
-
- for i:= 0 to 4 do
- begin
+ // prepare offset for next check (clockwise)
if (mx = -1) and (my <> -1) then my:= my - 1
else if (my = -1) and (mx <> 1) then mx:= mx + 1
else if (mx = 1) and (my <> 1) then my:= my + 1
else mx:= mx - 1;
- rightsteps[i,0]:= mx;
- rightsteps[i,1]:= my;
end;
ldx:= collisionX;
@@ -383,69 +371,38 @@
rdx:= collisionX;
rdy:= collisionY;
- for i:= 0 to 4 do
- begin
- tmpx:= collisionX + leftsteps[i,0];
- tmpy:= collisionY + leftsteps[i,1];
- if (((tmpy) and LAND_HEIGHT_MASK) = 0) and (((tmpx) and LAND_WIDTH_MASK) = 0) then
- if (Land[tmpy,tmpx] > TestWord) then
- begin
- if i <> 0 then
- for j:= 0 to 2 do
- begin
- leftsteps[j,0]:= leftsteps[i+j,0];
- leftsteps[j,1]:= leftsteps[i+j,1];
- end;
- ldx:= tmpx;
- ldy:= tmpy;
- break;
- end;
- end;
-
- for i:= 0 to 4 do
+ // edge-crawl
+ for i:= 0 to 8 do
begin
- tmpx:= collisionX + rightsteps[i,0];
- tmpy:= collisionY + rightsteps[i,1];
- if (((tmpy) and LAND_HEIGHT_MASK) = 0) and (((tmpx) and LAND_WIDTH_MASK) = 0) then
- if (Land[tmpy,tmpx] > TestWord) then
- begin
- if i <> 0 then
- for j:= 0 to 2 do
- begin
- rightsteps[j,0]:= rightsteps[i+j-1,0];
- rightsteps[j,1]:= rightsteps[i+j-1,1];
- end;
- rdx:= tmpx;
- rdy:= tmpy;
- break;
- end;
- end;
+ // using mx,my as temporary value buffer here
+
+ jfr:= 8+li+1;
+ jto:= 8+li-1;
- // TODO: avoid redundant checks
- for i:= 0 to 4 do
- begin
- for j:= 0 to 2 do
+ for j:= jfr downto jto do
begin
- tmpx:= ldx + leftsteps[j,0];
- tmpy:= ldy + leftsteps[j,1];
- if (((tmpy) and LAND_HEIGHT_MASK) = 0) and (((tmpx) and LAND_WIDTH_MASK) = 0) then
- if (Land[tmpy,tmpx] > TestWord) then
+ tmpo:= j mod 8;
+ tmpx:= ldx + offset[tmpo,0];
+ tmpy:= ldy + offset[tmpo,1];
+ if (((tmpy) and LAND_HEIGHT_MASK) = 0) and (((tmpx) and LAND_WIDTH_MASK) = 0)
+ and (Land[tmpy,tmpx] > TestWord) then
begin
ldx:= tmpx;
ldy:= tmpy;
break;
end;
end;
- end;
+
+ jfr:= 8+ri-1;
+ jto:= 8+ri+1;
- for i:= 0 to 4 do
- begin
- for j:= 0 to 2 do
+ for j:= jfr to jto do
begin
- tmpx:= rdx + rightsteps[j,0];
- tmpy:= rdy + rightsteps[j,1];
- if (((tmpy) and LAND_HEIGHT_MASK) = 0) and (((tmpx) and LAND_WIDTH_MASK) = 0) then
- if (Land[tmpy,tmpx] > TestWord) then
+ tmpo:= j mod 8;
+ tmpx:= rdx + offset[tmpo,0];
+ tmpy:= rdy + offset[tmpo,1];
+ if (((tmpy) and LAND_HEIGHT_MASK) = 0) and (((tmpx) and LAND_WIDTH_MASK) = 0)
+ and (Land[tmpy,tmpx] > TestWord) then
begin
rdx:= tmpx;
rdy:= tmpy;
@@ -457,42 +414,11 @@
ldx:= rdx - ldx;
ldy:= rdy - ldy;
- // rotate vector by 90°
- rdx:= -ldy;
- ldy:= ldx;
- ldx:= rdx;
-
- if (ldy <> 0) then tmpy := collisionY + ldy div abs(ldy) else tmpy:= collisionY;
- if (ldx <> 0) then tmpx := collisionX + ldx div abs(ldx) else tmpx:= collisionX;
if ((ldx = 0) and (ldy = 0)) then EXIT(false);
-
- if ((((tmpy) and LAND_HEIGHT_MASK) = 0) and (((tmpx) and LAND_WIDTH_MASK) = 0)
- and (Land[tmpy,tmpx] > TestWord)) then
- begin
- if (ldy <> 0) then
- begin
- ldy:= -ldy;
- tmpy := collisionY + ldy div abs(ldy);
- end;
- if (ldx <> 0) then
- begin
- ldx:= -ldx;
- tmpx := collisionX + ldx div abs(ldx);
- end;
-
- if ((((tmpy) and LAND_HEIGHT_MASK) = 0) and (((tmpx) and LAND_WIDTH_MASK) = 0)
- and (Land[tmpy,tmpx] > TestWord)) then
- EXIT(false);
- end;
-
- if (dx*ldx + dy*ldy).isNegative then
- begin
- deltaX:= ldx;
- deltaY:= ldy;
- EXIT(true);
- end;
-exit(false);
+deltaX:= ldx;
+deltaY:= ldy;
+exit(true);
end;
procedure initModule;