Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

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;
}

}

share|improve this question
    
Not a bad explanation at all. That's a fairly common collision problem, IMO. –  Seth Battin Oct 24 '12 at 4:26
add comment

1 Answer

up vote 1 down vote accepted

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.

share|improve this answer
    
So how can I detect a collision ahead of time, What is the best way of doing this? –  BleedObsidian Oct 24 '12 at 13:54
    
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. –  Seth Battin Oct 24 '12 at 14:07
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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