Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Keep libgdx camera inside boundaries when panning and zooming

Tags:

android

libgdx

I am developing a game for Android using LibGDX. I have added pinch zoom and pan. My issue is how to keep from going outside of the play area. As it is, you can pan outside of the play area into blackness. When zoomed out fully I know how to deal with it, I just said:

if(camera.zoom == 1.0f) ;
else {

}

But, if zoomed in, how do I accomplish this. I know this is not that complicated, I just can't seem to figure it out. Upon creation I set the camera to the middle of the screen. I know how to pan, I am using camera.translate(-input.deltaX, -input.deltaY, 0), I just need to test before this call to see if the position is outside of the play area. When I am zoomed in, how do I test if I am at the edge of the screen?

like image 894
weaverx9x9 Avatar asked Aug 20 '12 14:08

weaverx9x9


4 Answers

I don't have enough reputation to write comments, so I'll point to some previous answers.

AAverin's solution with bounding box that's made with Matsemann's idea isn't good because it annoyingly slows when you are near the one edge (boundary) and trying to translate diagonally in which case you are panning to one side out of bounds and other in proper direction.

I strongly suggest that you try solution from the bottom of handleInput method presented at

https://github.com/libgdx/libgdx/wiki/Orthographic-camera

That one works smoothly, and some of the previous answers look like that one but this one uses MathUtils.clamp wihch is a straight forward and much cleaner.

like image 170
ssbljk Avatar answered Oct 26 '22 05:10

ssbljk


You can use one of

camera.frustum.boundsInFrustum(BoundingBox box) 
camera.frustum.pointInFrustum(Vector3 point)
camera.frustum.sphereInFrustum(Vector3 point, float radius)

to check if a point/box/sphere is within your camera's view. What I normally do is define 4 boxes around my world where the player should not be allowed to see. If the camera is moved and one of the boxes is in the frustum, I move the camera back to the previous position.

Edit: AAvering has implemented this in code below.

like image 36
Matsemann Avatar answered Nov 19 '22 09:11

Matsemann


Credit goes to Matsemann for idea, here is the implementation I used.

Make a custom MyCamera class extending OrthographicCamera and add the following code:

BoundingBox left, right, top, bottom = null;

public void setWorldBounds(int left, int bottom, int width, int height) {
    int top = bottom + height;
    int right = left + width;

    this.left = new BoundingBox(new Vector3(left - 2, 0, 0), new Vector3(left -1, top, 0));
    this.right = new BoundingBox(new Vector3(right + 1, 0, 0), new Vector3(right + 2, top, 0));
    this.top = new BoundingBox(new Vector3(0, top + 1, 0), new Vector3(right, top + 2, 0));
    this.bottom = new BoundingBox(new Vector3(0, bottom - 1, 0), new Vector3(right, bottom - 2, 0));
}

Vector3 lastPosition = new Vector3();
@Override
public void translate(float x, float y) {
    lastPosition.set(position.x, position.y, 0);
    super.translate(x, y);
}

public void translateSafe(float x, float y) {
    translate(x, y);
    update();
    ensureBounds();
    update();
}

public void ensureBounds() {
    if (frustum.boundsInFrustum(left) || frustum.boundsInFrustum(right) || frustum.boundsInFrustum(top) || frustum.boundsInFrustum(bottom)) {
        position.set(lastPosition);
    }
}

Now, in you custom sceene or whathever you use (in my case it was a custom Board class) call:

camera.setWorldBounds()

and in your GestureListener.pan method you can call

camera.translateSafe(x, y);

it should keep your camera in bounds

like image 8
AAverin Avatar answered Nov 19 '22 09:11

AAverin


Here's the code I call after the position of the camera is updated due to panning or zooming in my 2D game using an orthographic camera. It corrects the camera position so that it doesn't show anything outside the borders of the play area.

float camX = camera.position.x;
float camY = camera.position.y;

Vector2 camMin = new Vector2(camera.viewportWidth, camera.viewportHeight);
camMin.scl(camera.zoom/2); //bring to center and scale by the zoom level
Vector2 camMax = new Vector2(borderWidth, borderHeight);
camMax.sub(camMin); //bring to center

//keep camera within borders
camX = Math.min(camMax.x, Math.max(camX, camMin.x));
camY = Math.min(camMax.y, Math.max(camY, camMin.y));

camera.position.set(camX, camY, camera.position.z);

camMin is the lowest left corner that the camera can be without showing anything outside of the play area and is also the offset from a corner of the camera to the center.

camMax is the opposite highest right location the camera can be in.

The key part I'm guessing you're missing is scaling the camera size by the zoom level.

like image 6
Sean Clifford Avatar answered Nov 19 '22 08:11

Sean Clifford