Grid the landscape, and shortcircuit checks on the collision array if there are no nearby checked in collisions to be collided with. This is a big win for fire's ammoshove in particular. Also add a +2 that seemed missing in the check, and update fire accordingly.
authornemo
Thu, 01 Jul 2010 17:00:14 -0400
changeset 3603 b6b1989744ef
parent 3602 99c93fa258d6
child 3604 b07b75753c6c
Grid the landscape, and shortcircuit checks on the collision array if there are no nearby checked in collisions to be collided with. This is a big win for fire's ammoshove in particular. Also add a +2 that seemed missing in the check, and update fire accordingly.
hedgewars/GSHandlers.inc
hedgewars/uCollisions.pas
hedgewars/uLand.pas
hedgewars/uLandGraphics.pas
--- a/hedgewars/GSHandlers.inc	Thu Jul 01 14:17:22 2010 -0400
+++ b/hedgewars/GSHandlers.inc	Thu Jul 01 17:00:14 2010 -0400
@@ -1752,7 +1752,7 @@
     begin
         if (Gear^.State and gsttmpFlag) <> 0 then
         begin
-            Gear^.Radius := 9;
+            Gear^.Radius := 7;
             AmmoShove(Gear, 2, 30);
             Gear^.Radius := 1
         end;
@@ -1768,7 +1768,7 @@
             // Standard fire
             if (Gear^.State and gsttmpFlag) = 0 then
             begin
-                Gear^.Radius := 9;
+                Gear^.Radius := 7;
                 AmmoShove(Gear, 4, 100);
                 Gear^.Radius := 1;
                 doMakeExplosion(gX, gY, 4, EXPLNoDamage);
--- a/hedgewars/uCollisions.pas	Thu Jul 01 14:17:22 2010 -0400
+++ b/hedgewars/uCollisions.pas	Thu Jul 01 17:00:14 2010 -0400
@@ -65,6 +65,8 @@
     ga: TGearArray;
 
 procedure AddGearCI(Gear: PGear);
+var i, j, k, tr: LongInt;
+    tmpVals: array[0..8] of byte;
 begin
 if Gear^.CollisionIndex >= 0 then exit;
 TryDo(Count <= MAXRECTSINDEX, 'Collision rects array overflow', true);
@@ -73,19 +75,53 @@
     X:= hwRound(Gear^.X);
     Y:= hwRound(Gear^.Y);
     Radius:= Gear^.Radius;
-    ChangeRoundInLand(X, Y, Radius - 1, true);
-    cGear:= Gear
+    tr:= Radius - 1;
+    ChangeRoundInLand(X, Y, tr, true);
+    cGear:= Gear;
+    k:= 0;
+    for i:= -1 to 1 do
+        for j:= -1 to 1 do
+            begin
+            tmpVals[k]:= LandCollided[(Y + tr*i) div 32, (X + tr*i) div 32];
+            inc(k);
+            end;
+    k:= 0;
+    for i:= -1 to 1 do
+        for j:= -1 to 1 do
+            begin
+            if LandCollided[(Y + tr*i) div 32, (X + tr*i) div 32] < 255 then LandCollided[(Y + tr*i) div 32, (X + tr*i) div 32]:= tmpVals[k] + 1;
+            inc(k)
+            end
     end;
 Gear^.CollisionIndex:= Count;
 inc(Count)
 end;
 
 procedure DeleteCI(Gear: PGear);
+var i, j, k, tr: LongInt;
+    tmpVals: array[0..8] of byte;
 begin
 if Gear^.CollisionIndex >= 0 then
     begin
     with cinfos[Gear^.CollisionIndex] do
-        ChangeRoundInLand(X, Y, Radius - 1, false);
+        begin
+        tr:= Radius - 1;
+        ChangeRoundInLand(X, Y, tr, false);
+        k:= 0;
+        for i:= -1 to 1 do
+            for j:= -1 to 1 do
+                begin
+                tmpVals[k]:= LandCollided[(Y + tr*i) div 32, (X + tr*i) div 32];
+                inc(k);
+                end;
+        k:= 0;
+        for i:= -1 to 1 do
+            for j:= -1 to 1 do
+                begin
+                if LandCollided[(Y + tr*i) div 32, (X + tr*i) div 32] > 0 then LandCollided[(Y + tr*i) div 32, (X + tr*i) div 32]:= tmpVals[k] - 1;
+                inc(k)
+                end
+        end;
     cinfos[Gear^.CollisionIndex]:= cinfos[Pred(Count)];
     cinfos[Gear^.CollisionIndex].cGear^.CollisionIndex:= Gear^.CollisionIndex;
     Gear^.CollisionIndex:= -1;
@@ -94,7 +130,7 @@
 end;
 
 function CheckGearsCollision(Gear: PGear): PGearArray;
-var mx, my: LongInt;
+var mx, my, xP, xN, x0, yP, yN, y0, tr: LongInt;
     i: Longword;
 begin
 CheckGearsCollision:= @ga;
@@ -102,15 +138,31 @@
 if Count = 0 then exit;
 mx:= hwRound(Gear^.X);
 my:= hwRound(Gear^.Y);
+tr:= Gear^.Radius - 1;
+xP:= (mx + tr) div 32;
+xN:= (mx - tr) div 32;
+yP:= (my + tr) div 32;
+yN:= (my - tr) div 32;
+x0:= mx div 32;
+y0:= my div 32;
 
-for i:= 0 to Pred(Count) do
-    with cinfos[i] do
-        if (Gear <> cGear) and
-            (sqr(mx - x) + sqr(my - y) <= sqr(Radius + Gear^.Radius)) then
-                begin
-                ga.ar[ga.Count]:= cinfos[i].cGear;
-                inc(ga.Count)
-                end
+if (LandCollided[yN, xN] <> 0) or
+   (LandCollided[yN, x0] <> 0) or
+   (LandCollided[yN, xP] <> 0) or
+   (LandCollided[y0, xN] <> 0) or
+   (LandCollided[y0, x0] <> 0) or
+   (LandCollided[y0, xP] <> 0) or
+   (LandCollided[yP, xN] <> 0) or
+   (LandCollided[yP, x0] <> 0) or
+   (LandCollided[yP, xP] <> 0) then 
+    for i:= 0 to Pred(Count) do
+        with cinfos[i] do
+            if (Gear <> cGear) and
+                (sqr(mx - x) + sqr(my - y) <= sqr(Radius + Gear^.Radius + 2)) then
+                    begin
+                    ga.ar[ga.Count]:= cinfos[i].cGear;
+                    inc(ga.Count)
+                    end
 end;
 
 function TestCollisionXwithGear(Gear: PGear; Dir: LongInt): boolean;
@@ -176,7 +228,7 @@
 end;
 
 function TestCollisionXKick(Gear: PGear; Dir: LongInt): boolean;
-var x, y, mx, my, i: LongInt;
+var x, y, mx, my, i, xP, xN, x0, yP, yN, y0, tr: LongInt;
     flag: boolean;
 begin
 flag:= false;
@@ -204,31 +256,47 @@
 
    mx:= hwRound(Gear^.X);
    my:= hwRound(Gear^.Y);
+   tr:= Gear^.Radius - 1;
+   xP:= (mx + tr) div 32;
+   xN:= (mx - tr) div 32;
+   yP:= (my + tr) div 32;
+   yN:= (my - tr) div 32;
+   x0:= mx div 32;
+   y0:= my div 32;
 
-   for i:= 0 to Pred(Count) do
-    with cinfos[i] do
-      if (Gear <> cGear) and
-         (sqr(mx - x) + sqr(my - y) <= sqr(Radius + Gear^.Radius + 2)) and
-         ((mx > x) xor (Dir > 0)) then
-         if ((cGear^.Kind in [gtHedgehog, gtMine]) and ((Gear^.State and gstNotKickable) = 0)) or
-            // only apply X kick if the barrel is knocked over
-            ((cGear^.Kind = gtExplosives) and ((cGear^.State and gsttmpflag) <> 0)) then
-             begin
-             with cGear^ do
-                  begin
-                  dX:= Gear^.dX;
-                  dY:= Gear^.dY * _0_5;
-                  State:= State or gstMoving;
-                  Active:= true
-                  end;
-             DeleteCI(cGear);
-             exit(false)
-             end
-   end
+   if (LandCollided[yN, xN] <> 0) or
+      (LandCollided[yN, x0] <> 0) or
+      (LandCollided[yN, xP] <> 0) or
+      (LandCollided[y0, xN] <> 0) or
+      (LandCollided[y0, x0] <> 0) or
+      (LandCollided[y0, xP] <> 0) or
+      (LandCollided[yP, xN] <> 0) or
+      (LandCollided[yP, x0] <> 0) or
+      (LandCollided[yP, xP] <> 0) then 
+      for i:= 0 to Pred(Count) do
+       with cinfos[i] do
+         if (Gear <> cGear) and
+            (sqr(mx - x) + sqr(my - y) <= sqr(Radius + Gear^.Radius + 2)) and
+            ((mx > x) xor (Dir > 0)) then
+            if ((cGear^.Kind in [gtHedgehog, gtMine]) and ((Gear^.State and gstNotKickable) = 0)) or
+               // only apply X kick if the barrel is knocked over
+               ((cGear^.Kind = gtExplosives) and ((cGear^.State and gsttmpflag) <> 0)) then
+                begin
+                with cGear^ do
+                     begin
+                     dX:= Gear^.dX;
+                     dY:= Gear^.dY * _0_5;
+                     State:= State or gstMoving;
+                     Active:= true
+                     end;
+                DeleteCI(cGear);
+                exit(false)
+                end
+      end
 end;
 
 function TestCollisionYKick(Gear: PGear; Dir: LongInt): boolean;
-var x, y, mx, my, i: LongInt;
+var x, y, mx, my, i, xP, xN, x0, yP, yN, y0, tr: LongInt;
     flag: boolean;
 begin
 flag:= false;
@@ -258,25 +326,41 @@
 
    mx:= hwRound(Gear^.X);
    my:= hwRound(Gear^.Y);
+   tr:= Gear^.Radius - 1;
+   xP:= (mx + tr) div 32;
+   xN:= (mx - tr) div 32;
+   yP:= (my + tr) div 32;
+   yN:= (my - tr) div 32;
+   x0:= mx div 32;
+   y0:= my div 32;
 
-   for i:= 0 to Pred(Count) do
-    with cinfos[i] do
-      if (Gear <> cGear) and
-         (sqr(mx - x) + sqr(my - y) <= sqr(Radius + Gear^.Radius + 2)) and
-         ((my > y) xor (Dir > 0)) then
-         if (cGear^.Kind in [gtHedgehog, gtMine, gtExplosives]) and ((Gear^.State and gstNotKickable) = 0) then
-             begin
-             with cGear^ do
-                  begin
-                  if (Kind <> gtExplosives) or ((State and gsttmpflag) <> 0) then dX:= Gear^.dX * _0_5;
-                  dY:= Gear^.dY;
-                  State:= State or gstMoving;
-                  Active:= true
-                  end;
-             DeleteCI(cGear);
-             exit(false)
-             end
-   end
+   if (LandCollided[yN, xN] <> 0) or
+      (LandCollided[yN, x0] <> 0) or
+      (LandCollided[yN, xP] <> 0) or
+      (LandCollided[y0, xN] <> 0) or
+      (LandCollided[y0, x0] <> 0) or
+      (LandCollided[y0, xP] <> 0) or
+      (LandCollided[yP, xN] <> 0) or
+      (LandCollided[yP, x0] <> 0) or
+      (LandCollided[yP, xP] <> 0) then 
+      for i:= 0 to Pred(Count) do
+       with cinfos[i] do
+         if (Gear <> cGear) and
+            (sqr(mx - x) + sqr(my - y) <= sqr(Radius + Gear^.Radius + 2)) and
+            ((my > y) xor (Dir > 0)) then
+            if (cGear^.Kind in [gtHedgehog, gtMine, gtExplosives]) and ((Gear^.State and gstNotKickable) = 0) then
+                begin
+                with cGear^ do
+                     begin
+                     if (Kind <> gtExplosives) or ((State and gsttmpflag) <> 0) then dX:= Gear^.dX * _0_5;
+                     dY:= Gear^.dY;
+                     State:= State or gstMoving;
+                     Active:= true
+                     end;
+                DeleteCI(cGear);
+                exit(false)
+                end
+      end
 end;
 
 function TestCollisionXwithXYShift(Gear: PGear; ShiftX: hwFloat; ShiftY: LongInt; Dir: LongInt): boolean;
--- a/hedgewars/uLand.pas	Thu Jul 01 14:17:22 2010 -0400
+++ b/hedgewars/uLand.pas	Thu Jul 01 17:00:14 2010 -0400
@@ -35,7 +35,8 @@
 
 var Land: TCollisionArray;
     LandPixels: TLandArray;
-    LandDirty: TDirtyTag;
+// LandCollided is reusing DirtyTag size because currently the largest Radius we have is 32px (Piano)
+    LandDirty, LandCollided: TDirtyTag;
     hasBorder: boolean; 
     hasGirders: boolean;  
     isMap: boolean;  
--- a/hedgewars/uLandGraphics.pas	Thu Jul 01 14:17:22 2010 -0400
+++ b/hedgewars/uLandGraphics.pas	Thu Jul 01 17:00:14 2010 -0400
@@ -83,19 +83,19 @@
    begin
    if ((y + dy) and LAND_HEIGHT_MASK) = 0 then
       for i:= max(x - dx, 0) to min(x + dx, LAND_WIDTH - 1) do
-          if (Land[y + dy, i] < 256) then
+          if (Land[y + dy, i] < 255) then
               inc(Land[y + dy, i]);
    if ((y - dy) and LAND_HEIGHT_MASK) = 0 then
       for i:= max(x - dx, 0) to min(x + dx, LAND_WIDTH - 1) do
-          if (Land[y - dy, i] < 256) then
+          if (Land[y - dy, i] < 255) then
               inc(Land[y - dy, i]);
    if ((y + dx) and LAND_HEIGHT_MASK) = 0 then
       for i:= max(x - dy, 0) to min(x + dy, LAND_WIDTH - 1) do
-          if (Land[y + dx, i] < 256) then
+          if (Land[y + dx, i] < 255) then
               inc(Land[y + dx, i]);
    if ((y - dx) and LAND_HEIGHT_MASK) = 0 then
       for i:= max(x - dy, 0) to min(x + dy, LAND_WIDTH - 1) do
-          if (Land[y - dx, i] < 256) then
+          if (Land[y - dx, i] < 255) then
               inc(Land[y - dx, i]);
    end
 end;