1
\$\begingroup\$

I am working on a platformer game for the final year project in HS. However... The collision detection system I use is basically about checking wether a specific part of the character intersects with another block or not.

The collision seems to be working fine except that it causes some bugs such as player king of getting stuck or slowing down when hitting from the sides or gets thrown up when both upper and < or > keys are used.

My question is; How can I improve the collision code in order to avoid such glitches and have sort of 'slippery' collisions?

here is a preview of how the bounds look

enter image description here


and here is a preview of what it actually looks like in game (click for better quality) enter image description here
The code i use for collision detection: (tempObject are blocks that the player is intersecting with)

if(getBoundsTop().intersects(tempObject.getBoundsBottom())){
    y = tempObject.getY() + height;
    velY = 0;
    System.out.println("Top collision");
}

if(getBoundsBottom().intersects(tempObject.getBoundsTop())){
    y = tempObject.getY() - height;
    velY = 0;
    falling = false;
    jumping = false;
    //isOnBlock = true;
} else {
    falling = true;
    //isOnBlock = false;
}

if(getBoundsRight().intersects(tempObject.getBoundsLeft())){
    x = tempObject.getX() - this.width;
}


if(getBoundsLeft().intersects(tempObject.getBoundsRight())){
    x = tempObject.getX() + this.width;
}

and here is are the bound methods:

public Rectangle getBounds() { return new Rectangle( (int)x, (int)y, (int)width, (int)height ); }

    public Rectangle getBoundsTop() {
        return new Rectangle(
                (int)x, 
                (int)y, 
                (int)(width-(width*0.01f)), 
                (int)(height/2)
        );
    }
    public Rectangle getBoundsBottom() {
        return new Rectangle(
                (int)x,
                (int)(y+(height/2)),
                (int)(width-(width*0.01f)),
                (int)(height/2)
        );
    }

    public Rectangle getBoundsLeft() {
        return new Rectangle(
                (int)x,
                (int)y, 
                (int)((int)width*0.15f), 
                (int)height
        );
    }

    public Rectangle getBoundsRight() {
        return new Rectangle(
                (int) 
                ((int)x+(width-(width*0.15f))), 
                (int)y, 
                (int) ((int)width*0.15f), 
                (int)height
        );
    }
\$\endgroup\$
  • 1
    \$\begingroup\$ You could use a single box "collider" for your player, and detect collisions with an algorithm such as SAT that returns collision manifolds. They are a struct/object containing the point(s) of collision and the correcting directions: both are what you're looking for, the easy way. \$\endgroup\$ – liggiorgio Apr 18 '18 at 18:15
0
\$\begingroup\$

I actually had the same problems many years ago when implementing collision detection in Java for my final year project (what a coincidence!). What I did to solve it was to inset the collision boxes by, say, 10% in either direction like so:

image example

The whole image represents the player. The yellow boxes represent vertical collision detection (up / down), the blue boxes represent horizontal collision detection (left / right) and the red areas mark "deadzones" where there is no collision detection.

This will solve the problem where you collide from the side, but the game thinks you've hit the top box so it pushes you down etc. You might have to play with the percentage to inset the boxes since it will change depending on how far your character can reasonably penetrate a surface (so if your player might move 10px inside a surface before collision steps in, inset the sides by 10px in either direction).

\$\endgroup\$
  • \$\begingroup\$ I have tried your method, but as soon as the player hits a corner with either left or right bounds it teleports the player up and whichever side it intersected with. \$\endgroup\$ – Feelsbadman Apr 18 '18 at 20:09
0
\$\begingroup\$

i think you are adding the movement or gravity every thick were you are calculating the position, to make better collisions you have to:

update()

{
 1-move the sprite ( gravity moves the sprite down as well )
 2-check for collision and get the overlapped value
   NOTE: check step 2 with X & Y axis
 3-move back the overlapped value ( so you wont see the sprite going back )
}

here is the function im using:

     /**
 * checks if there is a collision between sprite 1 and certain coordinate
 * and check if the sprite mush be pushed the other or if it must bounce
 * 
 * @param s1
 * @param x
 * @param y
 * @param width
 * @param height
 * @return true if there is a colision and false if not
 * 
 * */
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     
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.