2
\$\begingroup\$

I am making a platformer game in JBox2D and LWJGL that has a scrolling camera, but I have hit a wall with the boundaries of the camera.

Essentially what I have right now is a Box2D world that is being draw on the screen, a viewport being moved by gluLookAt and several boundaries specified by Box2D edges that also help keep the player from moving out of bounds. It looks a bit like this:

Example Image 1

What I'd like to do is "push" the camera when ever it comes in contact with the edge, but otherwise be centered on the player.

I've tried a couple of methods for this, such as finding the min and max width and height, and simply doing an easy box hit test, and moving the screen accordingly, but that has it's limitations, such as if the world is not in a rectangular shape e.g. Example Image 2

Another method I've tried is doing something where I raytrace from one vertex to another of each edge, and if it comes into contact with the screen, I "push" the screen out of the way, but that hasn't quite worked either

    Fixture fixture = boundary.getFixtureList();
    Vec2 point = null;
    boolean hit = false;
    fixtureLoop:
    for(int i = 0; i < boundary.m_fixtureCount; i++)
    {
        EdgeShape edge = (EdgeShape)fixture.getShape();
        Vec2 origin = new Vec2(edge.m_vertex1.x*Main.OPENGL_SCALE, edge.m_vertex1.y*Main.OPENGL_SCALE);
        Vec2 direction = new Vec2(edge.m_vertex2.x*Main.OPENGL_SCALE, edge.m_vertex2.y*Main.OPENGL_SCALE).sub(origin);
        for(float t = 0; t < 1.0f; t += 0.001f) //Raytrace loop
        {
            point = origin.add(direction.mul(t));
            //See if point is within screen bounds
            if(point.x > screenX-Main.WIDTH/2 && point.x < screenX+Main.WIDTH/2 && point.y > screenY-Main.HEIGHT/2 && point.y < screenY+Main.HEIGHT/2) 
            {
                hit = true;
            }
        }
            //If hit, find closest vertex
        if(hit)
        {
            float shortestDistance = Float.MAX_VALUE;
            Vec2 vertex = new Vec2();
            for(int v = 0; v < screenVertices.length; v++)
            {
                float distance = point.sub(screenVertices[i]).length();
                if(distance < shortestDistance)
                {
                    shortestDistance = distance;
                    vertex = screenVertices[v];
                }
            }
            Vec2 displacement = point.add(vertex.sub(new Vec2(screenX, screenY)));
            screenX = displacement.x;
            screenY = displacement.y;
            break fixtureLoop;
        }
        fixture = fixture.getNext();
    }

What I have here is my attempt that I have played around with WAAAY too much. Essentially what I'm trying to do is detect if and edges are hitting the screen, find the point where they hit, find the closest screen vertex, subtract them to find the displacement between them, and apply it to the screen so that they're no longer in contact: (The screenVertices array is essentially 4 vertices that look like Vec2(screenX+WIDTH/2, screenY+HEIGHT/2), etc)

Example Image 3

I was wondering if anyone could help me out, I'm not sure if I'm having logic problems, code problems, or both. Absolutely any help would be appreciated, thanks!

\$\endgroup\$
1
  • \$\begingroup\$ You should clarify those "limitations". Currently the question doesn't say anything about non-rectangular levels, which is what makes this question interesting. The image provided as a comment to CobaltHex's answer should be included in the question. \$\endgroup\$
    – msell
    Jul 16, 2013 at 7:05

1 Answer 1

2
\$\begingroup\$

If I'm reading correctly, you want the camera to center on the player except when the player is at the edge of the map. Well, to do this you should first get the world coordinates of the screen, and just move the camera to stay centered around the player. However, you will want to clamp the x and y coords of the camera to the boundaries of the map:

//calc camera pos
int camera_x = playerx - (view_width / 2);
int camera_y = playery - (view_height / 2);
camera_x = clamp(camera_x, 0, map_width - view_width);
camera_y = clamp(camera_y, 0, map_height - view_height);

//draw map at camera_x and camera_y regardless of player position
\$\endgroup\$
4
  • \$\begingroup\$ This works, except it has the limitations I was talking about, for example, it doesn't work for maps not shaped like a square: i.imgur.com/tv0BIME.png \$\endgroup\$
    – emptyflash
    Jul 16, 2013 at 6:53
  • \$\begingroup\$ hmm, well then perhaps move the camera with the player's velocity \$\endgroup\$
    – CobaltHex
    Jul 16, 2013 at 6:54
  • \$\begingroup\$ or hmm, thats an interesting request, perhaps have have a directional vector out the length of half of the screen and do a collision check on that for the screen. Or even move the camera only when needed. Maybe player's distance from the center point of the viewport. \$\endgroup\$
    – CobaltHex
    Jul 16, 2013 at 6:55
  • \$\begingroup\$ I'm gonna give the original answer another try, see if I can't make it "look" right. I'll mark this accepted if it works ;) \$\endgroup\$
    – emptyflash
    Jul 16, 2013 at 7:12

You must log in to answer this question.

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