looking for good way to make colisions with slopes and gravity

i have several collision methods, between rectangles, poing circles, etc, etc, but im struggling when im making some 2d games with gravity, some times the sprite is stuck ( because of gravity ) and if i want to implement slopes as well im not making sprite to over those slopes.
any guidance will be appreciated.

Have you considered using a physics engine like Box2D?

yes, but Box2D increases learning curve and for simple games sometimes with box collisions is necessary, for now I want to understand how collision works in deep, to implement better engines like Box2D, I have been implemented gravity, but when I want to move my sprite to the left it get stuck, If I quit gravity force once im touching the ground, it wont fall if im a platform. im figuring out that.

yeah no need to do this with Box2D :slight_smile: it’s terrifying to me to see how many people just use box2d for all the simple stuff, that’s overkill on math!

this article has good info on any collision detection in platforms:
https://www.gamedev.net/articles/programming/general-and-gameplay-programming/the-guide-to-implementing-2d-platformers-r2936

one extra tip I would give: The order is important, so make sure to do one-direction at a time.
in code that means:

  1. move X to new location
  2. detect horizontal walls (if moved into a wall, revert to correct location in front of wall)
  3. move Y to new location
  4. detect vertical walls (and correct if needed)

a problem often seen with new devs is doing this:

  1. move X,Y to new location
  2. detect horizontal walls
  3. detect vertical walls

which makes a lot of little bugs happen like suddenly jumping a few pixels, or moving half into tiles, etc.

but most is explained in that article :slight_smile:

you know what, now you mention that is what is happening, im moving two axis instead of one, and actually that is happening because the collision is first evaluation X axis and then Y( it get stuck when I move that on left ), and actually I have like a week seesking the correct way to implement that, lets see you article and thanks so much @orangepascal

simply i cannot do gravity correctly, i have the next things:

( Sprite ) player width:24, height;32

array of tiles:
0 means free
1 means solid tile ( it will make collision with this )
tile width and height are 16 px

int [] tileColisionMap = {
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,

 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
 
 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
 0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,

 0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
 0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
 0,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0   
 };

on the update loop i have the next things
{
input : i can move the sprite 2 pixels left and other 2 pixels right

//process gravity for the player
// jump value = 5 &
jumpvalue = -5;
jumpValue += gravity;
gravity = 0.37f;

     //every tick the jump get a limit
            if( jumpValue >= jumpForce )
            {
                jumpValue = jumpForce;
            }
        y += jumpValue;

//after set gravity im checking a collision against each solid tile
//defined in above array

//this check tile colision against player
//basically is puting the solid tiles of the whole level
//enemies, usable objects and players may check this colisions
if( Collision.getInstance().checkColsionTile(
player,
tileColisionMap,
columns,
rows,
tileWidth,
tileHeigth ).equals( Config.COLISION_BOTTOM ) )
{
player.setJump( false );
// player.setY( player.getY( ) - player.getJumpValue() );
System.out.println("::: inside collision "+player.getY() );
}//

}

inside that method we have the next code:


public  String checkColsionTile(Sprite spr,
                int[] colisionMap,
                int cols, 
                int rows, 
                int tileWidth, 
                int tileHeight)
        {
            String side= Config.COLISION_NONE;
            String aux="";
            if(cols <=0 || rows <= 0)
            {
                //arrojar excepcion aqui
            return side;
            }
        
        int mapIndex = 0;
        int totalTiles = cols * rows;
        
        int tilewidth = tileWidth;
        int tileHeigth = tileHeight;
      
      //for de renglones
         for( int i = 0;i < rows; i++ )
            {
                int tiley = i * tileHeigth;
            
                    //for de columnas
                    for( int j = 0 ; j < cols ; j++ )
                    {
                        
                        
                   //@TODO check here if the tile to compute is
                    //near the sprite to collide, to avoid extra process...
                        
                        
                    if( colisionMap[ mapIndex ] == 1)
                     {
                         int tilex = j * tilewidth;
                         
                        side = blockRectangle(spr, tilex, tiley, tilewidth,tileHeigth);
                        if (side.equals(Config.COLISION_BOTTOM))
                        {
                        aux=Config.COLISION_BOTTOM;
                        }
                      
                     }//if validacion si se checa colision
                 
                      if( mapIndex < totalTiles )
                      mapIndex++;
                      
                      
                    }//for cols
            }//for rows
      
//          System.out.println("-checkColsionTile se regreso SIDE: "+side);
        
          if(!aux.equals(""))
          {
          side=aux;
          }
          
          return side;
        }//checkcolisiontile
        


public String blockRectangle(Sprite s1,int x, int y, int width,int height)
	{
            int halfWidth = width / 2;
            int halfHeigth = height / 2;
            int centerX = x + halfWidth;
            int centerY = y + halfHeigth;
            
		String side = Config.COLISION_NONE;        
                
                //get distance vectors
		float vx=s1.getCenterX()-centerX;
		float vy=s1.getCenterY()-centerY;
		
                
		float combinedHalfWidth = s1.getHalfWidth()+halfWidth;
		float combinedHalfHeight = s1.getHalfHeight()+halfHeigth;
            
                
                //collision on x axis
                if( Math.abs(vx) < combinedHalfWidth )
		{
                    //collision on y axis
			if(Math.abs(vy) < combinedHalfHeight)
			{
                            
                            //collision made 
                            
				float overlapX=combinedHalfWidth-Math.abs(vx);
				float overlapY=combinedHalfHeight-Math.abs(vy);
		
                            if( overlapX < overlapY )
                                    {
					
					if( vx > 0 )
					{
                                            s1.setX( s1.getX()+overlapX );
                                            return Config.COLISION_LEFT;
					}
					else
					{
                                            s1.setX( s1.getX()-overlapX );
                                            return Config.COLISION_RIGHT;
					}

                                    }//
                                else
   
				{

                                    if( vy > 0 )
					{
                                            s1.setY( s1.getY()+overlapY );
                                            return Config.COLISION_TOP;
                                        }
                                    else 
					{
                                           s1.setY( s1.getY()  - overlapY );
                                            return Config.COLISION_BOTTOM;
					}

				}
        		


			}//height

                        
		}//width
                
		return side;
		
	}//colision con rectangulos, pero     
        


that collision tile method is supposed to check bottom collision and to put the sprite in the correct place ( must align the player along solid tile )

but the error is that the sprite is stuck when i want to move left

there’s no need to check all tiles every time :slight_smile:

maybe this example helps you get there:


public final static void example()
{
	int tilex;
	int tileY;

	// sprite horizontal position+speed+width
	int x=24;
	int xSpeed=2;
	int width=16;	// can be any size
	
	// sprite vertical position+speed+height
	int y=64;
	int ySpeed=2;
	int height=16; // can be any size
	
	x+=xSpeed;
	
	// for horizontal movement I usually take the waste-height of my character
	// and check on that..  99% of the time that works, in some case you might want to test at the feet or head height
	// remember, this is for horizontal movement, we aren't testing vertical collisions yet!
	tileY = (y + (height / 2) / 16);
	
	// which direction are we moving in?
	if (xSpeed>0)
	{
		// moving to the right, so check if our right edge hits a wall
		tileX = (x+w) / 16;  // we divide our sprite's right-edge by 16 since our tiles are 16x16 pixels wide
		
		if (tilemap[tileX + (tileY * tilemapwidth)] == solidtile)
		{
			// we hit a solid tile!
			// so correct our position, obviously we couldn't move this far to the right
			// we reset the player on the left edge of the tile we just hit, minus the player's width
			x = (tileX * 16) - width;
		}
	}
	else if (xSpeed<0)
	{
		// moving to the left, so check if our left edge hits a wall
		tileX = (x / 16);  // we divide our sprite's left-edge by 16 since our tiles are 16x16 pixels wide
		
		if (tilemap[tileX + (tileY * tilemapwidth)] == solidtile)
		{
			// we hit a solid tile!
			// so correct our position, obviously we couldn't move this far to the left
			// we reset the player on the right edge of the tile we just hit
			x = (tileX * 16)+16;
		}		
	}
}

Now write a function to do vertical testing, almost the same way, except for the Y-axis :slight_smile:

If you have that up and running, you might want to improve your checking by making the vertical function check not on the sprite’s-xAxis-center, but on both the left and right foot… but don’t worry about that too much for now, just try get this up and running!

oh and in case you need some live example, here’s one of my opensource projects:
https://bitbucket.org/orangepixel/planet-busters

now my example is working I had to create another function that is checking if the sprite is in the air and if is, I will process gravity again.