hedgewars/uCollisions.pas
changeset 3408 56e636b83cb4
parent 3407 dcc129c4352e
child 3411 30d0d780d605
equal deleted inserted replaced
3407:dcc129c4352e 3408:56e636b83cb4
    47 function  TestCollisionY(Gear: PGear; Dir: LongInt): boolean;
    47 function  TestCollisionY(Gear: PGear; Dir: LongInt): boolean;
    48 
    48 
    49 function  TestCollisionXwithXYShift(Gear: PGear; ShiftX: hwFloat; ShiftY: LongInt; Dir: LongInt): boolean;
    49 function  TestCollisionXwithXYShift(Gear: PGear; ShiftX: hwFloat; ShiftY: LongInt; Dir: LongInt): boolean;
    50 function  TestCollisionYwithXYShift(Gear: PGear; ShiftX, ShiftY: LongInt; Dir: LongInt): boolean;
    50 function  TestCollisionYwithXYShift(Gear: PGear; ShiftX, ShiftY: LongInt; Dir: LongInt): boolean;
    51 
    51 
    52 function  calcSlopeNormal(Gear: PGear; collisionX, collisionY: LongInt; var deltaX, deltaY: LongInt; TestWord: LongWord): Boolean;
    52 function  calcSlopeTangent(Gear: PGear; collisionX, collisionY: LongInt; var deltaX, deltaY: LongInt; TestWord: LongWord): Boolean;
    53 
    53 
    54 implementation
    54 implementation
    55 uses uMisc, uConsts, uLand, uLandGraphics;
    55 uses uMisc, uConsts, uLand, uLandGraphics;
    56 
    56 
    57 type TCollisionEntry = record
    57 type TCollisionEntry = record
   313 Gear^.X:= Gear^.X - int2hwFloat(ShiftX);
   313 Gear^.X:= Gear^.X - int2hwFloat(ShiftX);
   314 Gear^.Y:= Gear^.Y - int2hwFloat(ShiftY)
   314 Gear^.Y:= Gear^.Y - int2hwFloat(ShiftY)
   315 end;
   315 end;
   316 
   316 
   317 
   317 
   318 function calcSlopeNormal(Gear: PGear; collisionX, collisionY: LongInt; var deltaX, deltaY: LongInt; TestWord: LongWord): boolean;
   318 function calcSlopeTangent(Gear: PGear; collisionX, collisionY: LongInt; var deltaX, deltaY: LongInt; TestWord: LongWord): boolean;
   319 var sx, sy, ldx, ldy, rdx, rdy: LongInt;
   319 var ldx, ldy, rdx, rdy: LongInt;
   320     i, j, mx, my : ShortInt;
   320     i, j, mx, my, li, ri, jfr, jto, tmpo : ShortInt;
   321     tmpx, tmpy: LongWord;
   321     tmpx, tmpy: LongWord;
   322     dx, dy, rx, ry: hwFloat;
   322     dx, dy: hwFloat;
   323     leftsteps:  Array[0..4,0..1] of ShortInt;
   323     offset: Array[0..7,0..1] of ShortInt;
   324     rightsteps: Array[0..4,0..1] of ShortInt;
       
   325 
   324 
   326 begin
   325 begin
   327     dx:= Gear^.dX;
   326     dx:= Gear^.dX;
   328     dy:= Gear^.dY;
   327     dy:= Gear^.dY;
       
   328 
       
   329     // we start searching from the direction the gear center is at
       
   330     mx:= hwRound(Gear^.X-dx) - hwRound(Gear^.X);
       
   331     my:= hwRound(Gear^.Y-dy) - hwRound(Gear^.Y);
       
   332 
       
   333     li:= -1;
       
   334     ri:= -1;
   329     
   335     
   330     if Gear^.AdvBounce > 0 then
   336     // go around collision pixel, checking for first/last collisions
       
   337     // this will determinate what angles will be tried to crawl along
       
   338     for i:= 0 to 7 do
   331         begin
   339         begin
   332         rx:= _0_5 + Int2hwFloat(collisionX) - Gear^.X;
   340         offset[i,0]:= mx;
   333         ry:= _0_5 + Int2hwFloat(collisionY) - Gear^.Y;
   341         offset[i,1]:= my;
   334         end
   342         
   335     else
   343         tmpx:= collisionX + mx;
   336         begin
   344         tmpy:= collisionY + my;
   337         rx:= dx;
   345 
   338         ry:= dy;
   346         if (((tmpy) and LAND_HEIGHT_MASK) = 0) and (((tmpx) and LAND_WIDTH_MASK)  = 0) then
   339         end;
   347             if (Land[tmpy,tmpx] > TestWord) then
   340 
   348                 begin
   341     sx:= hwSign(rx);
   349                 // remember the index belonging to the first and last collision (if in 1st half)
   342     sy:= hwSign(ry);
   350                 if (i <> 0) then
   343 
   351                     begin
   344     if rx.QWordValue > ry.QWordValue then
   352                     if (ri = -1) then
   345         begin
   353                         ri:= i
   346         if (ry/rx).QWordValue < _0_5.QWordValue then sy:= 0;
   354                     else
   347         end
   355                         li:= i;
   348     else
   356                     end;
   349         begin
   357                 end;
   350         if (rx/ry).QWordValue < _0_5.QWordValue then sx:= 0;
   358 
   351         end;
   359         if i = 7 then break;
   352 
   360 
   353     mx:= -sx;
   361         // prepare offset for next check (clockwise)
   354     my:= -sy;
       
   355 
       
   356     for i:= 0 to 4 do
       
   357         begin
       
   358         if (mx = -1) and (my <>  1) then my:= my + 1
       
   359         else if (my = 1) and (mx <> 1) then mx:= mx + 1
       
   360         else if (mx = 1) and (my <> -1) then my:= my - 1
       
   361         else mx:= mx - 1;
       
   362 
       
   363         leftsteps[i,0]:= mx;
       
   364         leftsteps[i,1]:= my;
       
   365         end;
       
   366 
       
   367     mx:= -sx;
       
   368     my:= -sy;
       
   369 
       
   370     for i:= 0 to 4 do
       
   371         begin
       
   372         if (mx = -1) and (my <> -1) then my:= my - 1
   362         if (mx = -1) and (my <> -1) then my:= my - 1
   373         else if (my = -1) and (mx <> 1) then mx:= mx + 1
   363         else if (my = -1) and (mx <> 1) then mx:= mx + 1
   374         else if (mx = 1) and (my <> 1) then my:= my + 1
   364         else if (mx = 1) and (my <> 1) then my:= my + 1
   375         else mx:= mx - 1;
   365         else mx:= mx - 1;
   376 
   366 
   377         rightsteps[i,0]:= mx;
       
   378         rightsteps[i,1]:= my;
       
   379         end;
   367         end;
   380 
   368 
   381     ldx:= collisionX;
   369     ldx:= collisionX;
   382     ldy:= collisionY;
   370     ldy:= collisionY;
   383     rdx:= collisionX;
   371     rdx:= collisionX;
   384     rdy:= collisionY;
   372     rdy:= collisionY;
   385 
   373 
   386     for i:= 0 to 4 do
   374     // edge-crawl
       
   375     for i:= 0 to 8 do
   387         begin
   376         begin
   388         tmpx:= collisionX + leftsteps[i,0];
   377         // using mx,my as temporary value buffer here
   389         tmpy:= collisionY + leftsteps[i,1];
   378         
   390         if (((tmpy) and LAND_HEIGHT_MASK) = 0) and (((tmpx) and LAND_WIDTH_MASK)  = 0) then
   379         jfr:= 8+li+1;
   391             if (Land[tmpy,tmpx] > TestWord) then
   380         jto:= 8+li-1;
   392                 begin
   381 
   393                 if i <> 0 then
   382         for j:= jfr downto jto do
   394                     for j:= 0 to 2 do
       
   395                         begin
       
   396                         leftsteps[j,0]:= leftsteps[i+j,0];
       
   397                         leftsteps[j,1]:= leftsteps[i+j,1];
       
   398                         end;
       
   399                 ldx:= tmpx;
       
   400                 ldy:= tmpy;
       
   401                 break;
       
   402                 end;
       
   403         end;
       
   404 
       
   405     for i:= 0 to 4 do
       
   406         begin
       
   407         tmpx:= collisionX + rightsteps[i,0];
       
   408         tmpy:= collisionY + rightsteps[i,1];
       
   409         if (((tmpy) and LAND_HEIGHT_MASK) = 0) and (((tmpx) and LAND_WIDTH_MASK)  = 0) then
       
   410             if (Land[tmpy,tmpx] > TestWord) then
       
   411                 begin
       
   412                 if i <> 0 then
       
   413                     for j:= 0 to 2 do
       
   414                         begin
       
   415                         rightsteps[j,0]:= rightsteps[i+j-1,0];
       
   416                         rightsteps[j,1]:= rightsteps[i+j-1,1];
       
   417                         end;
       
   418                 rdx:= tmpx;
       
   419                 rdy:= tmpy;
       
   420                 break;
       
   421                 end;
       
   422         end;
       
   423 
       
   424     // TODO: avoid redundant checks
       
   425     for i:= 0 to 4 do
       
   426         begin
       
   427         for j:= 0 to 2 do
       
   428             begin
   383             begin
   429             tmpx:= ldx + leftsteps[j,0];
   384             tmpo:= j mod 8;
   430             tmpy:= ldy + leftsteps[j,1];
   385             tmpx:= ldx + offset[tmpo,0];
   431             if (((tmpy) and LAND_HEIGHT_MASK) = 0) and (((tmpx) and LAND_WIDTH_MASK)  = 0) then
   386             tmpy:= ldy + offset[tmpo,1];
   432                 if (Land[tmpy,tmpx] > TestWord) then
   387             if (((tmpy) and LAND_HEIGHT_MASK) = 0) and (((tmpx) and LAND_WIDTH_MASK)  = 0)
       
   388                 and (Land[tmpy,tmpx] > TestWord) then
   433                     begin
   389                     begin
   434                     ldx:= tmpx;
   390                     ldx:= tmpx;
   435                     ldy:= tmpy;
   391                     ldy:= tmpy;
   436                     break;
   392                     break;
   437                     end;
   393                     end;
   438             end;
   394             end;
   439         end;
   395 
   440 
   396         jfr:= 8+ri-1;
   441     for i:= 0 to 4 do
   397         jto:= 8+ri+1;
   442         begin
   398 
   443         for j:= 0 to 2 do
   399         for j:= jfr to jto do
   444             begin
   400             begin
   445             tmpx:= rdx + rightsteps[j,0];
   401             tmpo:= j mod 8;
   446             tmpy:= rdy + rightsteps[j,1];
   402             tmpx:= rdx + offset[tmpo,0];
   447             if (((tmpy) and LAND_HEIGHT_MASK) = 0) and (((tmpx) and LAND_WIDTH_MASK)  = 0) then
   403             tmpy:= rdy + offset[tmpo,1];
   448                 if (Land[tmpy,tmpx] > TestWord) then
   404             if (((tmpy) and LAND_HEIGHT_MASK) = 0) and (((tmpx) and LAND_WIDTH_MASK)  = 0)
       
   405                 and (Land[tmpy,tmpx] > TestWord) then
   449                     begin
   406                     begin
   450                     rdx:= tmpx;
   407                     rdx:= tmpx;
   451                     rdy:= tmpy;
   408                     rdy:= tmpy;
   452                     break;
   409                     break;
   453                     end;
   410                     end;
   455         end;
   412         end;
   456 
   413 
   457     ldx:= rdx - ldx;
   414     ldx:= rdx - ldx;
   458     ldy:= rdy - ldy;
   415     ldy:= rdy - ldy;
   459 
   416 
   460     // rotate vector by 90°
       
   461     rdx:= -ldy;
       
   462     ldy:= ldx;
       
   463     ldx:= rdx;
       
   464     
       
   465     if (ldy <> 0) then tmpy := collisionY + ldy div abs(ldy) else tmpy:= collisionY;
       
   466     if (ldx <> 0) then tmpx := collisionX + ldx div abs(ldx) else tmpx:= collisionX;
       
   467     if ((ldx = 0) and (ldy = 0)) then EXIT(false);
   417     if ((ldx = 0) and (ldy = 0)) then EXIT(false);
   468     
   418 
   469     if ((((tmpy) and LAND_HEIGHT_MASK) = 0) and (((tmpx) and LAND_WIDTH_MASK)  = 0) 
   419 deltaX:= ldx;
   470         and (Land[tmpy,tmpx] > TestWord)) then
   420 deltaY:= ldy;
   471             begin
   421 exit(true);
   472             if (ldy <> 0) then
       
   473                 begin
       
   474                 ldy:= -ldy;
       
   475                 tmpy := collisionY + ldy div abs(ldy);
       
   476                 end;
       
   477             if (ldx <> 0) then
       
   478                 begin
       
   479                 ldx:= -ldx;
       
   480                 tmpx := collisionX + ldx div abs(ldx);
       
   481                 end;
       
   482             
       
   483             if ((((tmpy) and LAND_HEIGHT_MASK) = 0) and (((tmpx) and LAND_WIDTH_MASK)  = 0) 
       
   484                 and (Land[tmpy,tmpx] > TestWord)) then
       
   485                     EXIT(false);
       
   486             end;
       
   487 
       
   488         
       
   489     if (dx*ldx + dy*ldy).isNegative then
       
   490         begin
       
   491         deltaX:= ldx;
       
   492         deltaY:= ldy;
       
   493         EXIT(true);
       
   494         end;
       
   495 exit(false);
       
   496 end;
   422 end;
   497 
   423 
   498 procedure initModule;
   424 procedure initModule;
   499 begin
   425 begin
   500     Count:= 0;
   426     Count:= 0;