我正在使用LibGDX为Android开发游戏。我添加了捏缩放和平移。我的问题是如何避免走出游戏区域。实际上,你可以在游戏区域外平移到黑暗中。当我完全缩小时,我知道如何处理它,我只是说:
if(camera.zoom == 1.0f) ;
else {
}
但是,如果放大,我该如何做到这一点。我知道这并不复杂,我似乎无法弄明白。创建后,我将相机设置在屏幕中间。我知道如何平移,我正在使用camera.translate(-input.deltaX,-input.deltaY,0),我只需要在此调用之前进行测试,看看该位置是否在游戏区域之外。当我放大时,如何测试我是否在屏幕边缘?
答案 0 :(得分:7)
您可以使用
之一camera.frustum.boundsInFrustum(BoundingBox box)
camera.frustum.pointInFrustum(Vector3 point)
camera.frustum.sphereInFrustum(Vector3 point, float radius)
检查点/盒子/球体是否在相机视图内。 我通常做的是在我的世界周围定义4个盒子,玩家不应该被允许看到。如果移动相机并且其中一个盒子在平截头体中,我将相机移回前一个位置。
编辑:AAvering已在代码below中实现此功能。
答案 1 :(得分: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
是相机所在的最右侧位置。
我猜你丢失的关键部分是按照缩放级别缩放相机尺寸。
答案 2 :(得分:6)
感谢Matsemann的想法,这是我使用的实现。
制作一个自定义MyCamera类,扩展OrthographicCamera并添加以下代码:
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);
}
}
现在,在您自定义的sceene或您使用的内容(在我的情况下,它是一个自定义的Board类)调用:
camera.setWorldBounds()
在您的GestureListener.pan方法中,您可以调用
camera.translateSafe(x, y);
它应该让你的相机处于界限
答案 3 :(得分:4)
这是我的解决方案:
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
。答案 4 :(得分:3)
我没有足够的声誉来撰写评论,因此我将指出一些以前的答案。
AAverin用Matsemann的想法制作的边界框的解决方案并不好,因为当你靠近一个边缘(边界)并尝试对角平移时,它会令人烦恼地减速,在这种情况下,你正在平移到一边超出边界和其他边界正确的方向。
我强烈建议您从
中提供的handleInput方法的底部尝试解决方案https://github.com/libgdx/libgdx/wiki/Orthographic-camera
那个工作顺利,前面的一些答案看起来像那个,但是这个答案使用MathUtils.clamp,这是一个直截了当且更清洁。
答案 5 :(得分:1)
给出的CustomCamera类并不能很好地工作。我使用它来将一个捏合手势映射到zoomSafe,并且当在边界边缘时,相机会从左到右反复弹跳/闪烁。平移相机也无法正常工作。如果你试图沿边界边缘平移,它就不会在任何地方平移,好像边缘是粘性的#34;这是因为它只是转换回最后一个位置而不是仅调整它在边界外的坐标。
答案 6 :(得分:0)
完美的课程,(部分归功于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);
}
}
}