hedgewars/uCollisions.pas
changeset 3408 56e636b83cb4
parent 3407 dcc129c4352e
child 3411 30d0d780d605
--- 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;