Sunday, May 3, 2015

opengl - Camera scrolling and game boundaries


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!



Answer



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

No comments:

Post a Comment

Simple past, Present perfect Past perfect

Can you tell me which form of the following sentences is the correct one please? Imagine two friends discussing the gym... I was in a good s...