hedgewars/uCollisions.pas
changeset 14006 105793e575d6
parent 13464 7b4643ff60ea
child 14282 6015b74eea55
equal deleted inserted replaced
14005:31bdb759d98b 14006:105793e575d6
    22 interface
    22 interface
    23 uses uFloat, uTypes, uUtils;
    23 uses uFloat, uTypes, uUtils;
    24 
    24 
    25 const cMaxGearArrayInd = 1023;
    25 const cMaxGearArrayInd = 1023;
    26 const cMaxGearHitOrderInd = 1023;
    26 const cMaxGearHitOrderInd = 1023;
       
    27 const cMaxGearProximityCacheInd = 1023;
    27 
    28 
    28 type PGearArray = ^TGearArray;
    29 type PGearArray = ^TGearArray;
    29     TGearArray = record
    30     TGearArray = record
    30         ar: array[0..cMaxGearArrayInd] of PGear;
    31         ar: array[0..cMaxGearArrayInd] of PGear;
    31         cX: array[0..cMaxGearArrayInd] of LongInt;
    32         cX: array[0..cMaxGearArrayInd] of LongInt;
    38         ar: array[0..cMaxGearHitOrderInd] of PGear;
    39         ar: array[0..cMaxGearHitOrderInd] of PGear;
    39         order: array[0..cMaxGearHitOrderInd] of LongInt;
    40         order: array[0..cMaxGearHitOrderInd] of LongInt;
    40         Count: Longword
    41         Count: Longword
    41         end;
    42         end;
    42 
    43 
       
    44 type PGearProximityCache = ^TGearProximityCache;
       
    45     TGearProximityCache = record
       
    46         ar: array[0..cMaxGearProximityCacheInd] of PGear;
       
    47         Count: Longword
       
    48         end;
       
    49 
    43 type TLineCollision = record
    50 type TLineCollision = record
    44         hasCollision: Boolean;
    51         hasCollision: Boolean;
    45         cX, cY: LongInt; //for visual effects only
    52         cX, cY: LongInt; //for visual effects only
    46         end;
    53         end;
    47 
    54 
    51 procedure AddCI(Gear: PGear);
    58 procedure AddCI(Gear: PGear);
    52 procedure DeleteCI(Gear: PGear);
    59 procedure DeleteCI(Gear: PGear);
    53 
    60 
    54 function  CheckGearsCollision(Gear: PGear): PGearArray;
    61 function  CheckGearsCollision(Gear: PGear): PGearArray;
    55 function  CheckAllGearsCollision(SourceGear: PGear): PGearArray;
    62 function  CheckAllGearsCollision(SourceGear: PGear): PGearArray;
       
    63 function  CheckCacheCollision(SourceGear: PGear): PGearArray;
    56 
    64 
    57 function  CheckGearsLineCollision(Gear: PGear; oX, oY, tX, tY: hwFloat): PGearArray;
    65 function  CheckGearsLineCollision(Gear: PGear; oX, oY, tX, tY: hwFloat): PGearArray;
    58 function  CheckAllGearsLineCollision(SourceGear: PGear; oX, oY, tX, tY: hwFloat): PGearArray;
    66 function  CheckAllGearsLineCollision(SourceGear: PGear; oX, oY, tX, tY: hwFloat): PGearArray;
    59 
    67 
    60 function  UpdateHitOrder(Gear: PGear; Order: LongInt): boolean;
    68 function  UpdateHitOrder(Gear: PGear; Order: LongInt): boolean;
    61 procedure ClearHitOrderLeq(MinOrder: LongInt);
    69 procedure ClearHitOrderLeq(MinOrder: LongInt);
    62 procedure ClearHitOrder();
    70 procedure ClearHitOrder();
       
    71 
       
    72 procedure RefillProximityCache(SourceGear: PGear; radius: LongInt);
       
    73 procedure RemoveFromProximityCache(Gear: PGear);
       
    74 procedure ClearProximityCache();
    63 
    75 
    64 function  TestCollisionXwithGear(Gear: PGear; Dir: LongInt): Word;
    76 function  TestCollisionXwithGear(Gear: PGear; Dir: LongInt): Word;
    65 function  TestCollisionYwithGear(Gear: PGear; Dir: LongInt): Word;
    77 function  TestCollisionYwithGear(Gear: PGear; Dir: LongInt): Word;
    66 
    78 
    67 function  TestCollisionXKick(Gear: PGear; Dir: LongInt): Word;
    79 function  TestCollisionXKick(Gear: PGear; Dir: LongInt): Word;
    95 const MAXRECTSINDEX = 1023;
   107 const MAXRECTSINDEX = 1023;
    96 var Count: Longword;
   108 var Count: Longword;
    97     cinfos: array[0..MAXRECTSINDEX] of TCollisionEntry;
   109     cinfos: array[0..MAXRECTSINDEX] of TCollisionEntry;
    98     ga: TGearArray;
   110     ga: TGearArray;
    99     ordera: TGearHitOrder;
   111     ordera: TGearHitOrder;
       
   112     proximitya: TGearProximityCache;
   100 
   113 
   101 procedure AddCI(Gear: PGear);
   114 procedure AddCI(Gear: PGear);
   102 begin
   115 begin
   103 if (Gear^.CollisionIndex >= 0) or (Count > MAXRECTSINDEX) or
   116 if (Gear^.CollisionIndex >= 0) or (Count > MAXRECTSINDEX) or
   104     ((Count > MAXRECTSINDEX-200) and ((Gear^.Kind = gtMine) or (Gear^.Kind = gtSMine) or (Gear^.Kind = gtKnife))) then
   117     ((Count > MAXRECTSINDEX-200) and ((Gear^.Kind = gtMine) or (Gear^.Kind = gtSMine) or (Gear^.Kind = gtKnife))) then
   178         begin
   191         begin
   179             if (Gear <> SourceGear) and
   192             if (Gear <> SourceGear) and
   180                (sqr(mx - hwRound(Gear^.x)) + sqr(my - hwRound(Gear^.y)) <= sqr(Gear^.Radius + tr))then
   193                (sqr(mx - hwRound(Gear^.x)) + sqr(my - hwRound(Gear^.y)) <= sqr(Gear^.Radius + tr))then
   181             begin
   194             begin
   182                 ga.ar[ga.Count]:= Gear;
   195                 ga.ar[ga.Count]:= Gear;
   183                 ga.cX[ga.Count]:= hwround(SourceGear^.X);
   196                 ga.cX[ga.Count]:= mx;
   184                 ga.cY[ga.Count]:= hwround(SourceGear^.Y);
   197                 ga.cY[ga.Count]:= my;
   185                 inc(ga.Count)
   198                 inc(ga.Count)
   186             end;
   199             end;
   187 
   200 
   188             Gear := Gear^.NextGear
   201             Gear := Gear^.NextGear
   189         end;
   202         end;
   285             end;
   298             end;
   286         Gear := Gear^.NextGear
   299         Gear := Gear^.NextGear
   287     end;
   300     end;
   288 end;
   301 end;
   289 
   302 
       
   303 function CheckCacheCollision(SourceGear: PGear): PGearArray;
       
   304 var mx, my, tr, i: LongInt;
       
   305     Gear: PGear;
       
   306 begin
       
   307     CheckCacheCollision:= @ga;
       
   308     ga.Count:= 0;
       
   309 
       
   310     mx:= hwRound(SourceGear^.X);
       
   311     my:= hwRound(SourceGear^.Y);
       
   312 
       
   313     tr:= SourceGear^.Radius + 2;
       
   314 
       
   315     for i:= 0 to proximitya.Count - 1 do
       
   316     begin
       
   317         Gear:= proximitya.ar[i];
       
   318         // Assuming the cache has been filled correctly, it will not contain SourceGear
       
   319         // and other gears won't be far enough for sqr overflow
       
   320         if (sqr(mx - hwRound(Gear^.X)) + sqr(my - hwRound(Gear^.Y)) <= sqr(Gear^.Radius + tr)) then
       
   321         begin
       
   322             ga.ar[ga.Count]:= Gear;
       
   323             ga.cX[ga.Count]:= mx;
       
   324             ga.cY[ga.Count]:= my;
       
   325             inc(ga.Count)
       
   326         end;
       
   327     end;
       
   328 end;
       
   329 
   290 function UpdateHitOrder(Gear: PGear; Order: LongInt): boolean;
   330 function UpdateHitOrder(Gear: PGear; Order: LongInt): boolean;
   291 var i: LongInt;
   331 var i: LongInt;
   292 begin
   332 begin
   293 UpdateHitOrder:= true;
   333 UpdateHitOrder:= true;
   294 for i:= 0 to ordera.Count - 1 do
   334 for i:= 0 to ordera.Count - 1 do
   333 end;
   373 end;
   334 
   374 
   335 procedure ClearHitOrder();
   375 procedure ClearHitOrder();
   336 begin
   376 begin
   337     ordera.Count:= 0;
   377     ordera.Count:= 0;
       
   378 end;
       
   379 
       
   380 procedure RefillProximityCache(SourceGear: PGear; radius: LongInt);
       
   381 var cx, cy, dx, dy, r: LongInt;
       
   382     Gear: PGear;
       
   383 begin
       
   384     proximitya.Count:= 0;
       
   385     cx:= hwRound(SourceGear^.X);
       
   386     cy:= hwRound(SourceGear^.Y);
       
   387     Gear:= GearsList;
       
   388 
       
   389     while (Gear <> nil) and (proximitya.Count <= cMaxGearProximityCacheInd) do
       
   390     begin
       
   391         dx:= abs(hwRound(Gear^.X) - cx);
       
   392         dy:= abs(hwRound(Gear^.Y) - cy);
       
   393         r:= radius + Gear^.radius + 2;
       
   394         if (Gear <> SourceGear) and (max(dx, dy) <= r) and (sqr(dx) + sqr(dy) <= sqr(r)) then
       
   395         begin
       
   396             proximitya.ar[proximitya.Count]:= Gear;
       
   397             inc(proximitya.Count)
       
   398         end;
       
   399         Gear := Gear^.NextGear
       
   400     end;
       
   401 end;
       
   402 
       
   403 procedure RemoveFromProximityCache(Gear: PGear);
       
   404 var i: LongInt;
       
   405 begin
       
   406     i := 0;
       
   407     while i < proximitya.Count do
       
   408         begin
       
   409         if proximitya.ar[i] = Gear then
       
   410             begin
       
   411                 proximitya.ar[i]:= proximitya.ar[proximitya.Count - 1];
       
   412                 dec(proximitya.Count);
       
   413             end
       
   414         else
       
   415             inc(i);
       
   416         end;
       
   417 end;
       
   418 
       
   419 procedure ClearProximityCache();
       
   420 begin
       
   421     proximitya.Count:= 0;
   338 end;
   422 end;
   339 
   423 
   340 function TestCollisionXwithGear(Gear: PGear; Dir: LongInt): Word;
   424 function TestCollisionXwithGear(Gear: PGear; Dir: LongInt): Word;
   341 var x, y, i: LongInt;
   425 var x, y, i: LongInt;
   342 begin
   426 begin