13

我正在使用 LibGDX 为 Android 开发游戏。我添加了捏缩放和平移。我的问题是如何避免走出游乐区。实际上,您可以在游戏区域外平移到黑暗中。当完全缩小时,我知道如何处理它,我只是说:

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

}

但是,如果放大,我该如何做到这一点。我知道这并不复杂,我只是似乎无法弄清楚。创建后,我将相机设置在屏幕中间。我知道如何平移,我正在使用 camera.translate(-input.deltaX, -input.deltaY, 0),我只需要在此调用之前进行测试以查看位置是否在播放区域之外。当我放大时,如何测试我是否在屏幕边缘?

4

7 回答 7

8

您可以使用其中一种

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

检查点/框/球是否在您的相机视野内。我通常做的是在我的世界中定义 4 个不应该让玩家看到的盒子。如果相机被移动并且其中一个盒子在平截头体中,我将相机移回之前的位置。

编辑:AAvering 在下面的代码中实现了这一点。

于 2012-08-21T16:02:32.613 回答
7

归功于 Matsemann 的想法,这是我使用的实现。

制作一个扩展 OrthographicCamera 的自定义 MyCamera 类并添加以下代码:

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

现在,在您自定义场景或您使用的任何内容中(在我的情况下,它是一个自定义 Board 类)调用:

camera.setWorldBounds()

在您的 GestureListener.pan 方法中,您可以调用

camera.translateSafe(x, y);

它应该让你的相机保持在界限内

于 2014-04-11T15:42:33.280 回答
6

这是由于使用正交相机在我的 2D 游戏中平移或缩放而更新相机位置后我调用的代码。它纠正了相机位置,使其不会显示游戏区域边界之外的任何内容。

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是相机可以在不显示播放区域之外的任何东西的情况下的左下角,也是从相机一角到中心的偏移量。

camMax是相机可以位于的最右侧位置。

我猜您缺少的关键部分是按缩放级别缩放相机尺寸。

于 2013-05-10T04:02:38.920 回答
5

这是我的解决方案:

float minCameraX = camera.zoom * (camera.viewportWidth / 2);
float maxCameraX = worldSize.x - minCameraX;
float minCameraY = camera.zoom * (camera.viewportHeight / 2);
float maxCameraY = worldSize.y - minCameraY;
camera.position.set(Math.min(maxCameraX, Math.max(targetX, minCameraX)),
        Math.min(maxCameraY, Math.max(targetY, minCameraY)),
        0);

在哪里:

  • targetX并且targetY是目标所在位置的世界坐标。
  • worldSize是一个Vector2世界的大小。
于 2013-10-21T21:00:27.017 回答
4

我没有足够的声誉来写评论,所以我会指出一些以前的答案。

AAverin 使用 Matsemann 的想法制作的带有边界框的解决方案并不好,因为当您靠近一个边缘(边界)并尝试对角平移时,它会令人讨厌地减慢速度,在这种情况下,您会平移到边界之外的一侧和正确方向的另一侧.

我强烈建议您尝试从提供的 handleInput 方法底部的解决方案

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

那个工作顺利,以前的一些答案看起来像那个,但这个使用 MathUtils.clamp ,它是一个直截了当且更干净的答案。

于 2014-11-03T09:44:16.220 回答
2

完美的课程,(部分感谢 AAverin)

此类不仅会粘在边界内,它还会在您缩放时捕捉到边界内。

调用这些来设置边界和移动相机。

camera.setWorldBounds()
camera.translateSafe(x, y);

缩放通话时

camera.attemptZoom();

这是课程:

public class CustomCamera extends OrthographicCamera
{
    public CustomCamera() {}

    public CustomCamera(float viewportWidth, float viewportHeight)
    {
        super(viewportWidth, viewportHeight);
    }

    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;
    @Override
    public void translate(float x, float y) {
        lastPosition = new Vector3(position);
        super.translate(x, y);
    }

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

    public void ensureBounds()
    {
        if(isInsideBounds())
        {
            position.set(lastPosition);
        }
    }

    private boolean isInsideBounds()
    {
        if(frustum.boundsInFrustum(left) || frustum.boundsInFrustum(right) || frustum.boundsInFrustum(top) || frustum.boundsInFrustum(bottom))
        {
            return true;
        }
        return false;
    }

    public void attemptZoom(float newZoom)
    {
        this.zoom = newZoom;
        this.snapCameraInView();
    }

    private void snapCameraInView()
    {
        float halfOfCurrentViewportWidth = ((viewportWidth * zoom) / 2f);
        float halfOfCurrentViewportHeight = ((viewportHeight * zoom) / 2f);

        //Check the vertical camera.
        if(position.x - halfOfCurrentViewportWidth < 0f) //Is going off the left side.
        {
            //Snap back.
            float amountGoneOver = position.x - halfOfCurrentViewportWidth;
            position.x += Math.abs(amountGoneOver);
        }
        else if(position.x + halfOfCurrentViewportWidth > viewportWidth)
        {
            //Snap back.
            float amountGoneOver = (viewportWidth - (position.x + halfOfCurrentViewportWidth));
            position.x -= Math.abs(amountGoneOver);
        }

        //Check the horizontal camera.
        if(position.y + halfOfCurrentViewportHeight > viewportHeight)
        {
            float amountGoneOver = (position.y + halfOfCurrentViewportHeight) - viewportHeight;
            position.y -= Math.abs(amountGoneOver);
        }
        else if(position.y - halfOfCurrentViewportHeight < 0f)
        {
            float amountGoneOver = (position.y - halfOfCurrentViewportHeight);
            position.y += Math.abs(amountGoneOver);
        }
    }
}
于 2015-06-06T20:54:05.920 回答
1

给定的 CustomCamera 类不能很好地工作。我用它来将捏合手势映射到 zoomSafe 并且相机在边界边缘时会不断地从左到右弹跳/闪烁。相机在平移时也无法正常工作。如果您尝试沿着边界的边缘平移,它不会在任何地方平移,就好像边缘是“粘性的”一样。这是因为它只是转换回最后一个位置,而不是仅仅调整它超出边界的坐标。

于 2015-11-29T16:45:09.253 回答