Help with custom Pixel based collision detection procedure

Just starting out? Need help? Post your questions and find answers here.
Hydrate
Enthusiast
Enthusiast
Posts: 436
Joined: Mon May 16, 2005 9:37 pm
Contact:

Help with custom Pixel based collision detection procedure

Post by Hydrate »

I started coding my own pixel by pixel collision procedure to work for me under Linux. I have what seems to be the majority of it there but now I have hit a problem. This particular problem resides in the fact the procedure does not work, and that it always returns 1 whilst the object is in the "box zone" of the other.

Basically I am looking for a fresh set of eyes here to see what I cannot, the code is below:

Code: Select all

Procedure GetMinimum(lval1.l , lval2.l);
  If lval1 < lval2;
    ProcedureReturn lval1;
  Else;
    ProcedureReturn lval2;
  EndIf;
EndProcedure;

Procedure GetMaximum(lval1.l , lval2.l);
  If lval1 > lval2;
    ProcedureReturn lval1;
  Else;
    ProcedureReturn lval2;
  EndIf;
EndProcedure;

Procedure SDLPixelTransparent(sprObject.l, lx.l, ly.l, lTransColour.l);
  Define lw.l = SpriteWidth(sprObject) , lh.l = SpriteHeight(sprObject);
  lTransparent = #False;
  
  If lx < lw And ly < lh ; Make sure the user put the right params in.
      StartDrawing(SpriteOutput(sprObject));
        If Point(lx, ly) =  lTransColour;
          lTransparent = #True;
        EndIf;
      StopDrawing();
  Else;
      lTransparent = #True;
  EndIf;
  
  ProcedureReturn lTransparent;
EndProcedure;

Procedure SDLCollision(sprObject1.l, lx1.l, ly1.l,  sprObject2.l, lx2.l, ly2.l);
  Define lCollision = #True;                                 We assume they are intersecting by default
  Define lw1.l = SpriteWidth(sprObject1) , lh1.l = SpriteHeight(sprObject1) , lw2.l = SpriteWidth(sprObject2) , lh2.l = SpriteHeight(sprObject2);
  
  If lx1 + lw1 < lx2 Or lx1 > lx2 + lw2;              Now we find why they might not be intersecting.
    lCollision = #False;
  ElseIf  ly1 + lh1 < ly2 Or ly2 + lh2 < ly1;
    lCollision = #False;
  EndIf;
  
  ProcedureReturn lCollision;                          Unless they didn't intersect, it will always return true.
EndProcedure;

Procedure SDLPixelCollision(sprObject1.l, lx1.l, ly1.l,  sprObject2.l, lx2.l, ly2.l, lTransColour.l);
  Define lCollision = #False;                          We assume they are not intersecting by default
  Define lw1.l = SpriteWidth(sprObject1) , lh1.l = SpriteHeight(sprObject1) , lw2.l = SpriteWidth(sprObject2) , lh2.l = SpriteHeight(sprObject2);
  Define lStartX.l , lStopX.l , lStartY.l , lStopY.l;
  
  If lx1 + lw1 < lx2 Or lx1 > lx2 + lw2 Or ly1 + lh1 < ly2 Or ly2 + lh2 < ly1;;              Now we find why they might be intersecting.
  Else;
    lStartX.l = GetMinimum(lx1 , lxl2);
    lStartY.l = GetMinimum(ly1 , lyl2);
    
     lStopX.l = GetMaximum(lx1 +  lw1, lxl2 + lw2);
     lStopY.l = GetMaximum(ly1 +  lh1, lyl2 + lh2);
     
     
     For x = lStartX To lStopX;
      For y = lStartY To lStopY;
      
        If SDLPixelTransparent(sprObject1, x + lx1, y + ly1, lTransColour)=0 And SDLPixelTransparent(sprObject2, x + lx2, y + ly2, lTransColour)=0;
          lCollision = #True;
          ProcedureReturn lCollision; 
        EndIf;
        
      Next y;
    Next x;
    
  EndIf;
  ProcedureReturn lCollision;                          Unless they did intersect, it will always return false.
EndProcedure;
I feel certain that the error is inside the SDLPixelCollision procedure somewhere, I am just not sure where. Any help or advice here would be much appreciated.
.::Image::.
User avatar
Demivec
Addict
Addict
Posts: 4270
Joined: Mon Jul 25, 2005 3:51 pm
Location: Utah, USA

Post by Demivec »

Here's my suggestion modification to SDLPixelCollision(), change the portion between Else and Endif to:

Code: Select all

 lStartX.l = GetMaximum(lx1 , lxl2);
    lStartY.l = GetMaximum(ly1 , lyl2);
    
    lStopX.l = GetMinimum(lx1 +  lw1, lxl2 + lw2);
    lStopY.l = GetMinimum(ly1 +  lh1, lyl2 + lh2);
    
    
    For x = lStartX To lStopX;
      For y = lStartY To lStopY;
        
        If SDLPixelTransparent(sprObject1, x - lx1, y - ly1, lTransColour)= #False And SDLPixelTransparent(sprObject2, x - lx2, y - ly2, lTransColour)= #False;
          lCollision = #True;
          ProcedureReturn lCollision;
        EndIf;
        
      Next y;
    Next x;
Hydrate
Enthusiast
Enthusiast
Posts: 436
Joined: Mon May 16, 2005 9:37 pm
Contact:

Post by Hydrate »

Demivec wrote:Here's my suggestion modification to SDLPixelCollision(), change the portion between Else and Endif to:

Code: Select all

 lStartX.l = GetMaximum(lx1 , lxl2);
    lStartY.l = GetMaximum(ly1 , lyl2);
    
    lStopX.l = GetMinimum(lx1 +  lw1, lxl2 + lw2);
    lStopY.l = GetMinimum(ly1 +  lh1, lyl2 + lh2);
    
    
    For x = lStartX To lStopX;
      For y = lStartY To lStopY;
        
        If SDLPixelTransparent(sprObject1, x - lx1, y - ly1, lTransColour)= #False And SDLPixelTransparent(sprObject2, x - lx2, y - ly2, lTransColour)= #False;
          lCollision = #True;
          ProcedureReturn lCollision;
        EndIf;
        
      Next y;
    Next x;
Thank you for trying to help, though that didnt seem to solve the problem. The issue seems to be somewhere in the calculation of startx, stopx etc I think. I have been playing around with it to no avail. My current code is now as follows (for that section):

Code: Select all

lStartX.l = GetMaximum(lx1 , lxl2);
    lStartY.l = GetMaximum(ly1 , lyl2);
   
    lStopX.l = GetMinimum(lx1 +  lw1, lxl2 + lw2);
    lStopY.l = GetMinimum(ly1 +  lh1, lyl2 + lh2);
   
   
    For x = lStartX To lStopX;
      For y = lStartY To lStopY;
       
        If SDLPixelTransparent(sprObject1, x - lx1, y - ly1, lTransColour)= #False And SDLPixelTransparent(sprObject2, x - lx2, y - ly2, lTransColour)= #False;
          lCollision = #True;
          Break;
        EndIf;
       
      Next y;
      If lCollision = #True : Break : EndIf;
    Next x;
.::Image::.
User avatar
Michael Vogel
Addict
Addict
Posts: 2810
Joined: Thu Feb 09, 2006 11:27 pm
Contact:

Post by Michael Vogel »

Maybe you'll find the problem faster, when you return the values of the x and/or y parameter of the loops...

Then you could recheck the values of the transparency on exactly these coordinates...
It may also help to draw rectangles on the screen and/or sprites to see, which points will be checked at the moment...

Michael
User avatar
Demivec
Addict
Addict
Posts: 4270
Joined: Mon Jul 25, 2005 3:51 pm
Location: Utah, USA

Post by Demivec »

In addition to using incorrect formulas for which regions to check (which has already been corrected) you also used 2 variables with mistyped names (lx12 and ly12). Here's is the corrected code below:

Code: Select all

Procedure SDLPixelCollision(sprObject1.l, lx1.l, ly1.l,  sprObject2.l, lx2.l, ly2.l, lTransColour.l);
  Define lCollision = #False;                          We assume they are not intersecting by default
  Define lw1.l = SpriteWidth(sprObject1) , lh1.l = SpriteHeight(sprObject1) , lw2.l = SpriteWidth(sprObject2) , lh2.l = SpriteHeight(sprObject2);
  Define lStartX.l , lStopX.l , lStartY.l , lStopY.l;
  Define x,y
  
  If lx1 + lw1 < lx2 Or lx1 > lx2 + lw2 Or ly1 + lh1 < ly2 Or ly2 + lh2 < ly1;;              Now we find why they might be intersecting.
  Else;
    lStartX.l = GetMaximum(lx1 , lx2);
    lStartY.l = GetMaximum(ly1 , ly2);
    
    lStopX.l = GetMinimum(lx1 +  lw1, lx2 + lw2);
    lStopY.l = GetMinimum(ly1 +  lh1, ly2 + lh2);
    
    
    For x = lStartX To lStopX;
      For y = lStartY To lStopY;
        
        If SDLPixelTransparent(sprObject1, x - lx1, y - ly1, lTransColour)= #False And SDLPixelTransparent(sprObject2, x - lx2, y - ly2, lTransColour)= #False; 
          lCollision = #True
          Break 2
        EndIf;
        
      Next y;
    Next x;
    
  EndIf;
  ProcedureReturn lCollision;                          Unless they did intersect, it will always return false.
EndProcedure
Use EnableExplicit to help prevent typo problems. :wink:

The procedure has only been tested with images on windows by using macros to substitute image commands for the sprite ones.
Hydrate
Enthusiast
Enthusiast
Posts: 436
Joined: Mon May 16, 2005 9:37 pm
Contact:

Post by Hydrate »

Demivec wrote:In addition to using incorrect formulas for which regions to check (which has already been corrected) you also used 2 variables with mistyped names (lx12 and ly12). Here's is the corrected code below:

Code: Select all

Procedure SDLPixelCollision(sprObject1.l, lx1.l, ly1.l,  sprObject2.l, lx2.l, ly2.l, lTransColour.l);
  Define lCollision = #False;                          We assume they are not intersecting by default
  Define lw1.l = SpriteWidth(sprObject1) , lh1.l = SpriteHeight(sprObject1) , lw2.l = SpriteWidth(sprObject2) , lh2.l = SpriteHeight(sprObject2);
  Define lStartX.l , lStopX.l , lStartY.l , lStopY.l;
  Define x,y
  
  If lx1 + lw1 < lx2 Or lx1 > lx2 + lw2 Or ly1 + lh1 < ly2 Or ly2 + lh2 < ly1;;              Now we find why they might be intersecting.
  Else;
    lStartX.l = GetMaximum(lx1 , lx2);
    lStartY.l = GetMaximum(ly1 , ly2);
    
    lStopX.l = GetMinimum(lx1 +  lw1, lx2 + lw2);
    lStopY.l = GetMinimum(ly1 +  lh1, ly2 + lh2);
    
    
    For x = lStartX To lStopX;
      For y = lStartY To lStopY;
        
        If SDLPixelTransparent(sprObject1, x - lx1, y - ly1, lTransColour)= #False And SDLPixelTransparent(sprObject2, x - lx2, y - ly2, lTransColour)= #False; 
          lCollision = #True
          Break 2
        EndIf;
        
      Next y;
    Next x;
    
  EndIf;
  ProcedureReturn lCollision;                          Unless they did intersect, it will always return false.
EndProcedure
Use EnableExplicit to help prevent typo problems. :wink:

The procedure has only been tested with images on windows by using macros to substitute image commands for the sprite ones.
Perfect, it was the variable names which were the main underlying cause here. Thank you very much indeed. The procedure now appears to work perfectly.
.::Image::.
Post Reply