1
\$\begingroup\$

My game has a bug with collision detection. If you go against the wall and tap forward/back sometimes the game thinks the speed you travelled at is 0 and the game doesn't know how to get you out of the wall. My collision detection works by getting the speed you hit the wall at and if it is positive it moves you back, if it is negative it moves you forward.

It might help if you download it: https://rapidshare.com/files/1550046269/game.zip

Sorry if I explained badly, it's hard to explain.

float maxSpeed = 0.3f;
float minSpeed = -0.2f;
float acceleration = 0.002f;
float deacceleration = 0.001f;

float slowdownSpeed = 0.002f;
float rotateSpeed = 0.08f;
static float currentSpeed = 0;

boolean up = false;
boolean down = false;

boolean noKey = false;

static float rotate = 0;

//Image effect system
static String locationCarNormal;
static String locationCarFront;
static String locationCarBack;
static String locationCarBoth;

static boolean carFront = false;
static boolean carBack = false;

static String imageRef;

boolean collision = false;

public ComponentPlayerMovement(String id, String ScarNormal, String ScarFront, String ScarBack, String ScarBoth)
{
    this.id = id;
    playerBody = new Rectangle(900/2-16, 700/2-16, 32, 32);

    locationCarNormal = ScarNormal;
    locationCarFront = ScarFront;
    locationCarBack = ScarBack;
    locationCarBoth = ScarBoth;

    imageRef = locationCarNormal;
}

@Override
public void update(GameContainer gc, StateBasedGame sbg, int delta) throws SlickException
{
    Input input = gc.getInput();

    playerBody.transform(Transform.createRotateTransform(2));

    float hip = currentSpeed * delta;
    float unstuckspeed = 0.05f * delta;

    if(carBack && !carFront)
    {
        imageRef = locationCarBack;
        ComponentImageRender.updateImage();
    }
    else if(carFront && !carBack)
    {
        imageRef = locationCarFront;
        ComponentImageRender.updateImage();
    }
    else if(carFront && carBack)
    {
        imageRef = locationCarBoth;
        ComponentImageRender.updateImage();
    }

    if(input.isKeyDown(Input.KEY_RIGHT))
    {
        rotate += rotateSpeed * delta;
        owner.setRotation(rotate);
    }

    if(input.isKeyDown(Input.KEY_LEFT))
    {
        rotate -= rotateSpeed * delta;
        owner.setRotation(rotate);
    }

    if(input.isKeyDown(Input.KEY_UP))
    {
        if(!collision)
        {
            up = true;
            noKey = false;

            if(currentSpeed < maxSpeed)
            {
                currentSpeed += acceleration;
            }
            MapCoordStorage.mapX += hip * Math.sin(Math.toRadians(rotate));
            MapCoordStorage.mapY -= hip * Math.cos(Math.toRadians(rotate));
        }
        else
        {
            currentSpeed = 1;
        }
    }
    else if(input.isKeyDown(Input.KEY_DOWN) && !collision)
    {
        down = true;
        noKey = false;

        if(currentSpeed > minSpeed)
        {
            currentSpeed -= slowdownSpeed;
        }
        MapCoordStorage.mapX += hip * Math.sin(Math.toRadians(rotate));
        MapCoordStorage.mapY -= hip * Math.cos(Math.toRadians(rotate));
    }
    else
    {
        noKey = true;
        if(currentSpeed > 0)
        {
            currentSpeed -= deacceleration;
        }
        else if(currentSpeed < 0)
        {
            currentSpeed += acceleration;
        }
        MapCoordStorage.mapX += hip * Math.sin(Math.toRadians(rotate));
        MapCoordStorage.mapY -= hip * Math.cos(Math.toRadians(rotate));
    }

    if(entityCollisionWith())
    {
        collision = true;
        if(currentSpeed > 0 || up)
        {
            up = true;
            currentSpeed = 0;

            carFront = true;

            MapCoordStorage.mapX += unstuckspeed * Math.sin(Math.toRadians(rotate-180));
            MapCoordStorage.mapY -= unstuckspeed * Math.cos(Math.toRadians(rotate-180));
        }
        else if(currentSpeed < 0 || down)
        {
            down = true;
            currentSpeed = 0;

            carBack = true;

            MapCoordStorage.mapX += unstuckspeed * Math.sin(Math.toRadians(rotate));
            MapCoordStorage.mapY -= unstuckspeed * Math.cos(Math.toRadians(rotate));
        }
        else
        {
            currentSpeed = 0;
        }
    }
    else
    {
        collision = false;
        up = false;
        down = false;
    }

    if(currentSpeed >= -0.01f && currentSpeed <= 0.01f && noKey && !collision)
    {
        currentSpeed = 0;
    }
}

public static boolean entityCollisionWith() throws SlickException
{
    for (int i = 0; i < BlockMap.entities.size(); i++)
    {
        Block entity1 = (Block) BlockMap.entities.get(i);
        if (playerBody.intersects(entity1.poly))
        {
            return true;
        }       
    }       
    return false;
}

}

\$\endgroup\$
1
  • \$\begingroup\$ Not a bad explanation at all. That's a fairly common collision problem, IMO. \$\endgroup\$ Oct 24, 2012 at 4:26

1 Answer 1

1
\$\begingroup\$

You might benefit from a collision methodology which detects a collision that is about to happen due to velocity, and truncates motion to the collision point. Your model would not get stuck in that state of colliding in all directions.

Or, a more complicated but better strategy, is to detect an oncoming collision and the fraction of oncoming motion before that collision happens. Move that first fraction, then reverse the velocity's direction and continue moving. This guarantees (in theory only :) ) not getting stuck and provides a very accurate collision, and makes the total motion equal to the inteded motion for that frame.

The simplest answer might be to give your collisions a direction, such that your model can always move away from the center of the bounding box of the object with which it collided. That will require a collision state more complex than a bool, of course.

\$\endgroup\$
2
  • \$\begingroup\$ So how can I detect a collision ahead of time, What is the best way of doing this? \$\endgroup\$ Oct 24, 2012 at 13:54
  • \$\begingroup\$ You could modify your collision detection method to accept an argument that is the object's velocity, and then perform all the collision checks with the object's bounding volume temporarily transformed by that vector. Then run your collision checks before adding velocity to position. \$\endgroup\$ Oct 24, 2012 at 14:07

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .