hedgewars/uCollisions.pas
changeset 9706 5178d2263521
parent 9305 8e5140875ab5
child 9708 7d146637cb81
equal deleted inserted replaced
9704:055fee9da6a0 9706:5178d2263521
    36 procedure AddCI(Gear: PGear);
    36 procedure AddCI(Gear: PGear);
    37 procedure DeleteCI(Gear: PGear);
    37 procedure DeleteCI(Gear: PGear);
    38 
    38 
    39 function  CheckGearsCollision(Gear: PGear): PGearArray;
    39 function  CheckGearsCollision(Gear: PGear): PGearArray;
    40 
    40 
    41 function  TestCollisionXwithGear(Gear: PGear; Dir: LongInt): boolean;
    41 function  TestCollisionXwithGear(Gear: PGear; Dir: LongInt): Word;
    42 function  TestCollisionYwithGear(Gear: PGear; Dir: LongInt): Word;
    42 function  TestCollisionYwithGear(Gear: PGear; Dir: LongInt): Word;
    43 
    43 
    44 function  TestCollisionXKick(Gear: PGear; Dir: LongInt): boolean;
    44 function  TestCollisionXKick(Gear: PGear; Dir: LongInt): Word;
    45 function  TestCollisionYKick(Gear: PGear; Dir: LongInt): boolean;
    45 function  TestCollisionYKick(Gear: PGear; Dir: LongInt): Word;
    46 
    46 
    47 function  TestCollisionX(Gear: PGear; Dir: LongInt): boolean;
    47 function  TestCollisionX(Gear: PGear; Dir: LongInt): Word;
    48 function  TestCollisionY(Gear: PGear; Dir: LongInt): boolean;
    48 function  TestCollisionY(Gear: PGear; Dir: LongInt): Word;
    49 
    49 
    50 function  TestCollisionXwithXYShift(Gear: PGear; ShiftX: hwFloat; ShiftY: LongInt; Dir: LongInt): boolean; inline;
    50 function  TestCollisionXwithXYShift(Gear: PGear; ShiftX: hwFloat; ShiftY: LongInt; Dir: LongInt): Word; inline;
    51 function  TestCollisionXwithXYShift(Gear: PGear; ShiftX: hwFloat; ShiftY: LongInt; Dir: LongInt; withGear: boolean): boolean;
    51 function  TestCollisionXwithXYShift(Gear: PGear; ShiftX: hwFloat; ShiftY: LongInt; Dir: LongInt; withGear: boolean): Word;
    52 function  TestCollisionYwithXYShift(Gear: PGear; ShiftX, ShiftY: LongInt; Dir: LongInt): boolean; inline;
    52 function  TestCollisionYwithXYShift(Gear: PGear; ShiftX, ShiftY: LongInt; Dir: LongInt): Word; inline;
    53 function  TestCollisionYwithXYShift(Gear: PGear; ShiftX, ShiftY: LongInt; Dir: LongInt; withGear: boolean): boolean;
    53 function  TestCollisionYwithXYShift(Gear: PGear; ShiftX, ShiftY: LongInt; Dir: LongInt; withGear: boolean): Word;
    54 
    54 
    55 function  TestRectancleForObstacle(x1, y1, x2, y2: LongInt; landOnly: boolean): boolean;
    55 function  TestRectancleForObstacle(x1, y1, x2, y2: LongInt; landOnly: boolean): boolean;
    56 
    56 
    57 // returns: negative sign if going downhill to left, value is steepness (noslope/error = _0, 45° = _0_5)
    57 // returns: negative sign if going downhill to left, value is steepness (noslope/error = _0, 45° = _0_5)
    58 function  CalcSlopeBelowGear(Gear: PGear): hwFloat;
    58 function  CalcSlopeBelowGear(Gear: PGear): hwFloat;
    59 function  CalcSlopeNearGear(Gear: PGear; dirX, dirY: LongInt): hwFloat;
    59 function  CalcSlopeNearGear(Gear: PGear; dirX, dirY: LongInt): hwFloat;
    60 function  CalcSlopeTangent(Gear: PGear; collisionX, collisionY: LongInt; var outDeltaX, outDeltaY: LongInt; TestWord: LongWord): Boolean;
    60 function  CalcSlopeTangent(Gear: PGear; collisionX, collisionY: LongInt; var outDeltaX, outDeltaY: LongInt; TestWord: LongWord): boolean;
    61 
    61 
    62 implementation
    62 implementation
    63 uses uConsts, uLandGraphics, uVariables, uDebug, uGearsList;
    63 uses uConsts, uLandGraphics, uVariables, uDebug, uGearsList;
    64 
    64 
    65 type TCollisionEntry = record
    65 type TCollisionEntry = record
   133                 ga.ar[ga.Count]:= cinfos[i].cGear;
   133                 ga.ar[ga.Count]:= cinfos[i].cGear;
   134                 inc(ga.Count)
   134                 inc(ga.Count)
   135                 end
   135                 end
   136 end;
   136 end;
   137 
   137 
   138 function TestCollisionXwithGear(Gear: PGear; Dir: LongInt): boolean;
   138 function TestCollisionXwithGear(Gear: PGear; Dir: LongInt): Word;
   139 var x, y, i: LongInt;
   139 var x, y, i: LongInt;
   140 begin
   140 begin
   141 // Special case to emulate the old intersect gear clearing, but with a bit of slop for pixel overlap
   141 // Special case to emulate the old intersect gear clearing, but with a bit of slop for pixel overlap
   142 if (Gear^.CollisionMask = lfNotCurrentMask) and (Gear^.Kind <> gtHedgehog) and (Gear^.Hedgehog <> nil) and (Gear^.Hedgehog^.Gear <> nil) and
   142 if (Gear^.CollisionMask = lfNotCurrentMask) and (Gear^.Kind <> gtHedgehog) and (Gear^.Hedgehog <> nil) and (Gear^.Hedgehog^.Gear <> nil) and
   143     ((hwRound(Gear^.Hedgehog^.Gear^.X) + Gear^.Hedgehog^.Gear^.Radius + 16 < hwRound(Gear^.X) - Gear^.Radius) or
   143     ((hwRound(Gear^.Hedgehog^.Gear^.X) + Gear^.Hedgehog^.Gear^.Radius + 16 < hwRound(Gear^.X) - Gear^.Radius) or
   148 if Dir < 0 then
   148 if Dir < 0 then
   149     x:= x - Gear^.Radius
   149     x:= x - Gear^.Radius
   150 else
   150 else
   151     x:= x + Gear^.Radius;
   151     x:= x + Gear^.Radius;
   152 
   152 
   153 TestCollisionXwithGear:= true;
       
   154 if (x and LAND_WIDTH_MASK) = 0 then
   153 if (x and LAND_WIDTH_MASK) = 0 then
   155     begin
   154     begin
   156     y:= hwRound(Gear^.Y) - Gear^.Radius + 1;
   155     y:= hwRound(Gear^.Y) - Gear^.Radius + 1;
   157     i:= y + Gear^.Radius * 2 - 2;
   156     i:= y + Gear^.Radius * 2 - 2;
   158     repeat
   157     repeat
   159         if (y and LAND_HEIGHT_MASK) = 0 then
   158         if (y and LAND_HEIGHT_MASK) = 0 then
   160             if Land[y, x] and Gear^.CollisionMask <> 0 then
   159             if Land[y, x] and Gear^.CollisionMask <> 0 then
   161                 exit;
   160                 exit(Land[y, x]);
   162         inc(y)
   161         inc(y)
   163     until (y > i);
   162     until (y > i);
   164     end;
   163     end;
   165 TestCollisionXwithGear:= false
   164 TestCollisionXwithGear:= 0
   166 end;
   165 end;
   167 
   166 
   168 function TestCollisionYwithGear(Gear: PGear; Dir: LongInt): Word;
   167 function TestCollisionYwithGear(Gear: PGear; Dir: LongInt): Word;
   169 var x, y, i: LongInt;
   168 var x, y, i: LongInt;
   170 begin
   169 begin
   187     repeat
   186     repeat
   188         if (x and LAND_WIDTH_MASK) = 0 then
   187         if (x and LAND_WIDTH_MASK) = 0 then
   189             if Land[y, x] and Gear^.CollisionMask <> 0 then
   188             if Land[y, x] and Gear^.CollisionMask <> 0 then
   190                 begin
   189                 begin
   191                 TestCollisionYwithGear:= Land[y, x];
   190                 TestCollisionYwithGear:= Land[y, x];
   192                 exit;
   191                 exit(Land[y, x]);
   193                 end;
   192                 end;
   194         inc(x)
   193         inc(x)
   195     until (x > i);
   194     until (x > i);
   196     end;
   195     end;
   197 TestCollisionYwithGear:= 0
   196 TestCollisionYwithGear:= 0
   198 end;
   197 end;
   199 
   198 
   200 function TestCollisionXKick(Gear: PGear; Dir: LongInt): boolean;
   199 function TestCollisionXKick(Gear: PGear; Dir: LongInt): Word;
   201 var x, y, mx, my, i: LongInt;
   200 var x, y, mx, my, i: LongInt;
   202     flag: boolean;
   201     pixel: Word;
   203 begin
   202 begin
   204 flag:= false;
   203 pixel:= 0;
   205 x:= hwRound(Gear^.X);
   204 x:= hwRound(Gear^.X);
   206 if Dir < 0 then
   205 if Dir < 0 then
   207     x:= x - Gear^.Radius
   206     x:= x - Gear^.Radius
   208 else
   207 else
   209     x:= x + Gear^.Radius;
   208     x:= x + Gear^.Radius;
   210 
   209 
   211 TestCollisionXKick:= true;
       
   212 if (x and LAND_WIDTH_MASK) = 0 then
   210 if (x and LAND_WIDTH_MASK) = 0 then
   213     begin
   211     begin
   214     y:= hwRound(Gear^.Y) - Gear^.Radius + 1;
   212     y:= hwRound(Gear^.Y) - Gear^.Radius + 1;
   215     i:= y + Gear^.Radius * 2 - 2;
   213     i:= y + Gear^.Radius * 2 - 2;
   216     repeat
   214     repeat
   217         if (y and LAND_HEIGHT_MASK) = 0 then
   215         if (y and LAND_HEIGHT_MASK) = 0 then
   218             if Land[y, x] > 255 then
   216             if Land[y, x] > 255 then
   219                 exit
   217                 exit(Land[y, x])
   220             else if Land[y, x] <> 0 then
   218             else if Land[y, x] <> 0 then
   221                 flag:= true;
   219                 pixel:= Land[y, x];
   222     inc(y)
   220     inc(y)
   223     until (y > i);
   221     until (y > i);
   224     end;
   222     end;
   225 TestCollisionXKick:= flag;
   223 TestCollisionXKick:= pixel;
   226 
   224 
   227 if flag then
   225 if pixel <> 0 then
   228     begin
   226     begin
   229     if hwAbs(Gear^.dX) < cHHKick then
   227     if hwAbs(Gear^.dX) < cHHKick then
   230         exit;
   228         exit;
   231     if (Gear^.State and gstHHJumping <> 0)
   229     if (Gear^.State and gstHHJumping <> 0)
   232     and (hwAbs(Gear^.dX) < _0_4) then
   230     and (hwAbs(Gear^.dX) < _0_4) then
   253                         State:= State or gstMoving;
   251                         State:= State or gstMoving;
   254                         if Kind = gtKnife then State:= State and (not gstCollision);
   252                         if Kind = gtKnife then State:= State and (not gstCollision);
   255                         Active:= true
   253                         Active:= true
   256                         end;
   254                         end;
   257                     DeleteCI(cGear);
   255                     DeleteCI(cGear);
   258                     TestCollisionXKick:= false;
   256                     exit(0);
   259                     exit;
       
   260                     end
   257                     end
   261     end
   258     end
   262 end;
   259 end;
   263 
   260 
   264 function TestCollisionYKick(Gear: PGear; Dir: LongInt): boolean;
   261 function TestCollisionYKick(Gear: PGear; Dir: LongInt): Word;
   265 var x, y, mx, my,  myr, i: LongInt;
   262 var x, y, mx, my,  myr, i: LongInt;
   266     flag: boolean;
   263     pixel: Word;
   267 begin
   264 begin
   268 flag:= false;
   265 pixel:= 0;
   269 y:= hwRound(Gear^.Y);
   266 y:= hwRound(Gear^.Y);
   270 if Dir < 0 then
   267 if Dir < 0 then
   271     y:= y - Gear^.Radius
   268     y:= y - Gear^.Radius
   272 else
   269 else
   273     y:= y + Gear^.Radius;
   270     y:= y + Gear^.Radius;
   274 
   271 
   275 TestCollisionYKick:= true;
       
   276 if (y and LAND_HEIGHT_MASK) = 0 then
   272 if (y and LAND_HEIGHT_MASK) = 0 then
   277     begin
   273     begin
   278     x:= hwRound(Gear^.X) - Gear^.Radius + 1;
   274     x:= hwRound(Gear^.X) - Gear^.Radius + 1;
   279     i:= x + Gear^.Radius * 2 - 2;
   275     i:= x + Gear^.Radius * 2 - 2;
   280     repeat
   276     repeat
   281     if (x and LAND_WIDTH_MASK) = 0 then
   277     if (x and LAND_WIDTH_MASK) = 0 then
   282         if Land[y, x] > 0 then
   278         if Land[y, x] > 0 then
   283             if Land[y, x] > 255 then
   279             if Land[y, x] > 255 then
   284                 exit
   280                 exit(Land[y, x])
   285             else if Land[y, x] <> 0 then
   281             else if Land[y, x] <> 0 then
   286                 flag:= true;
   282                 pixel:= Land[y, x];
   287     inc(x)
   283     inc(x)
   288     until (x > i);
   284     until (x > i);
   289     end;
   285     end;
   290 TestCollisionYKick:= flag;
   286 TestCollisionYKick:= pixel;
   291 
   287 
   292 if flag then
   288 if pixel <> 0 then
   293     begin
   289     begin
   294     if hwAbs(Gear^.dY) < cHHKick then
   290     if hwAbs(Gear^.dY) < cHHKick then
   295         exit;
   291         exit;
   296     if (Gear^.State and gstHHJumping <> 0) and (not Gear^.dY.isNegative) and (Gear^.dY < _0_4) then
   292     if (Gear^.State and gstHHJumping <> 0) and (not Gear^.dY.isNegative) and (Gear^.dY < _0_4) then
   297         exit;
   293         exit;
   316                         State:= State or gstMoving;
   312                         State:= State or gstMoving;
   317                         if Kind = gtKnife then State:= State and (not gstCollision);
   313                         if Kind = gtKnife then State:= State and (not gstCollision);
   318                         Active:= true
   314                         Active:= true
   319                         end;
   315                         end;
   320                     DeleteCI(cGear);
   316                     DeleteCI(cGear);
   321                     TestCollisionYKick:= false;
   317                     exit(0)
   322                     exit
       
   323                     end
   318                     end
   324     end
   319     end
   325 end;
   320 end;
   326 
   321 
   327 function TestCollisionXwithXYShift(Gear: PGear; ShiftX: hwFloat; ShiftY: LongInt; Dir: LongInt): boolean; inline;
   322 function TestCollisionXwithXYShift(Gear: PGear; ShiftX: hwFloat; ShiftY: LongInt; Dir: LongInt): Word; inline;
   328 begin
   323 begin
   329     TestCollisionXwithXYShift:= TestCollisionXwithXYShift(Gear, ShiftX, ShiftY, Dir, true);
   324     TestCollisionXwithXYShift:= TestCollisionXwithXYShift(Gear, ShiftX, ShiftY, Dir, true);
   330 end;
   325 end;
   331 
   326 
   332 function TestCollisionXwithXYShift(Gear: PGear; ShiftX: hwFloat; ShiftY: LongInt; Dir: LongInt; withGear: boolean): boolean;
   327 function TestCollisionXwithXYShift(Gear: PGear; ShiftX: hwFloat; ShiftY: LongInt; Dir: LongInt; withGear: boolean): Word;
   333 begin
   328 begin
   334 Gear^.X:= Gear^.X + ShiftX;
   329 Gear^.X:= Gear^.X + ShiftX;
   335 Gear^.Y:= Gear^.Y + int2hwFloat(ShiftY);
   330 Gear^.Y:= Gear^.Y + int2hwFloat(ShiftY);
   336 if withGear then 
   331 if withGear then 
   337     TestCollisionXwithXYShift:= TestCollisionXwithGear(Gear, Dir)
   332     TestCollisionXwithXYShift:= TestCollisionXwithGear(Gear, Dir)
   338 else TestCollisionXwithXYShift:= TestCollisionX(Gear, Dir);
   333 else TestCollisionXwithXYShift:= TestCollisionX(Gear, Dir);
   339 Gear^.X:= Gear^.X - ShiftX;
   334 Gear^.X:= Gear^.X - ShiftX;
   340 Gear^.Y:= Gear^.Y - int2hwFloat(ShiftY)
   335 Gear^.Y:= Gear^.Y - int2hwFloat(ShiftY)
   341 end;
   336 end;
   342 
   337 
   343 function TestCollisionX(Gear: PGear; Dir: LongInt): boolean;
   338 function TestCollisionX(Gear: PGear; Dir: LongInt): Word;
   344 var x, y, i: LongInt;
   339 var x, y, i: LongInt;
   345 begin
   340 begin
   346 x:= hwRound(Gear^.X);
   341 x:= hwRound(Gear^.X);
   347 if Dir < 0 then
   342 if Dir < 0 then
   348     x:= x - Gear^.Radius
   343     x:= x - Gear^.Radius
   349 else
   344 else
   350     x:= x + Gear^.Radius;
   345     x:= x + Gear^.Radius;
   351 
   346 
   352 TestCollisionX:= true;
       
   353 if (x and LAND_WIDTH_MASK) = 0 then
   347 if (x and LAND_WIDTH_MASK) = 0 then
   354     begin
   348     begin
   355     y:= hwRound(Gear^.Y) - Gear^.Radius + 1;
   349     y:= hwRound(Gear^.Y) - Gear^.Radius + 1;
   356     i:= y + Gear^.Radius * 2 - 2;
   350     i:= y + Gear^.Radius * 2 - 2;
   357     repeat
   351     repeat
   358         if (y and LAND_HEIGHT_MASK) = 0 then
   352         if (y and LAND_HEIGHT_MASK) = 0 then
   359             if Land[y, x] > 255 then
   353             if Land[y, x] > 255 then
   360                 exit;
   354                 exit(Land[y, x]);
   361     inc(y)
   355     inc(y)
   362     until (y > i);
   356     until (y > i);
   363     end;
   357     end;
   364 TestCollisionX:= false
   358 TestCollisionX:= 0
   365 end;
   359 end;
   366 
   360 
   367 function TestCollisionY(Gear: PGear; Dir: LongInt): boolean;
   361 function TestCollisionY(Gear: PGear; Dir: LongInt): Word;
   368 var x, y, i: LongInt;
   362 var x, y, i: LongInt;
   369 begin
   363 begin
   370 y:= hwRound(Gear^.Y);
   364 y:= hwRound(Gear^.Y);
   371 if Dir < 0 then
   365 if Dir < 0 then
   372     y:= y - Gear^.Radius
   366     y:= y - Gear^.Radius
   373 else
   367 else
   374     y:= y + Gear^.Radius;
   368     y:= y + Gear^.Radius;
   375 
   369 
   376 TestCollisionY:= true;
       
   377 if (y and LAND_HEIGHT_MASK) = 0 then
   370 if (y and LAND_HEIGHT_MASK) = 0 then
   378     begin
   371     begin
   379     x:= hwRound(Gear^.X) - Gear^.Radius + 1;
   372     x:= hwRound(Gear^.X) - Gear^.Radius + 1;
   380     i:= x + Gear^.Radius * 2 - 2;
   373     i:= x + Gear^.Radius * 2 - 2;
   381     repeat
   374     repeat
   382         if (x and LAND_WIDTH_MASK) = 0 then
   375         if (x and LAND_WIDTH_MASK) = 0 then
   383             if Land[y, x] > 255 then
   376             if Land[y, x] > 255 then
   384                 exit;
   377                 exit(Land[y, x]);
   385     inc(x)
   378     inc(x)
   386     until (x > i);
   379     until (x > i);
   387     end;
   380     end;
   388 TestCollisionY:= false
   381 TestCollisionY:= 0
   389 end;
   382 end;
   390 
   383 
   391 function TestCollisionYwithXYShift(Gear: PGear; ShiftX, ShiftY: LongInt; Dir: LongInt): boolean; inline;
   384 function TestCollisionYwithXYShift(Gear: PGear; ShiftX, ShiftY: LongInt; Dir: LongInt): Word; inline;
   392 begin
   385 begin
   393     TestCollisionYwithXYShift:= TestCollisionYwithXYShift(Gear, ShiftX, ShiftY, Dir, true);
   386     TestCollisionYwithXYShift:= TestCollisionYwithXYShift(Gear, ShiftX, ShiftY, Dir, true);
   394 end;
   387 end;
   395 
   388 
   396 function TestCollisionYwithXYShift(Gear: PGear; ShiftX, ShiftY: LongInt; Dir: LongInt; withGear: boolean): boolean;
   389 function TestCollisionYwithXYShift(Gear: PGear; ShiftX, ShiftY: LongInt; Dir: LongInt; withGear: boolean): Word;
   397 begin
   390 begin
   398 Gear^.X:= Gear^.X + int2hwFloat(ShiftX);
   391 Gear^.X:= Gear^.X + int2hwFloat(ShiftX);
   399 Gear^.Y:= Gear^.Y + int2hwFloat(ShiftY);
   392 Gear^.Y:= Gear^.Y + int2hwFloat(ShiftY);
   400 
   393 
   401 if withGear then
   394 if withGear then
   402   TestCollisionYwithXYShift:= TestCollisionYwithGear(Gear, Dir) <> 0
   395   TestCollisionYwithXYShift:= TestCollisionYwithGear(Gear, Dir)
   403 else
   396 else
   404   TestCollisionYwithXYShift:= TestCollisionY(Gear, Dir);
   397   TestCollisionYwithXYShift:= TestCollisionY(Gear, Dir);
   405   
   398   
   406 Gear^.X:= Gear^.X - int2hwFloat(ShiftX);
   399 Gear^.X:= Gear^.X - int2hwFloat(ShiftX);
   407 Gear^.Y:= Gear^.Y - int2hwFloat(ShiftY)
   400 Gear^.Y:= Gear^.Y - int2hwFloat(ShiftY)