LibGDX kamerayı TiledMap sınırları içinde tutar


9

Ben iyi render basit bir TiledMap var. Bir oyuncu atlamalı (Box2D ile) ve kameram oyuncu etrafında:

cam.position.set(
    player.position().x * Game.PPM + Game.V_WIDTH / 4,
    player.position().y * Game.PPM,
    0
);
cam.update();

Ancak, kamera TiledMap'i "hareket ettirir". Kameramı TiledMap üzerinde nasıl tutabilirim, bu yüzden haritamın kenarlarına yakın olduğumda, kamera kaydırmayı durdurur ve oynatıcı kameranın kenarına doğru hareket eder?

Yanıtlar:


12

Tamam, burada iki dikdörtgen ile çalışıyorsunuz. İçinde daha büyük bir statik (harita) ve daha küçük bir hareket eden (kamera). İstediğiniz şey, daha küçük dikdörtgenin sınırlarının daha büyük dikdörtgenin iç sınırlarının dışına çıkmasına izin vermemektir.

// These values likely need to be scaled according to your world coordinates.
// The left boundary of the map (x)
int mapLeft = 0;
// The right boundary of the map (x + width)
int mapRight = 0 + map.getWidth();
// The bottom boundary of the map (y)
int mapBottom = 0;
// The top boundary of the map (y + height)
int mapTop = 0 + map.getHeight();
// The camera dimensions, halved
float cameraHalfWidth = cam.viewportWidth * .5f;
float cameraHalfHeight = cam.viewportHeight * .5f;

// Move camera after player as normal

float cameraLeft = cam.position.x - cameraHalfWidth;
float cameraRight = cam.position.x + cameraHalfWidth;
float cameraBottom = cam.position.y - cameraHalfHeight;
float cameraTop = cam.position.y + cameraHalfHeight;

// Horizontal axis
if(map.getWidth() < cam.viewportWidth)
{
    cam.position.x = mapRight / 2;
}
else if(cameraLeft <= mapLeft)
{
    cam.position.x = mapLeft + cameraHalfWidth;
}
else if(cameraRight >= mapRight)
{
    cam.position.x = mapRight - cameraHalfWidth;
}

// Vertical axis
if(map.getHeight() < cam.viewportHeight)
{
    cam.position.y = mapTop / 2;
}
else if(cameraBottom <= mapBottom)
{
    cam.position.y = mapBottom + cameraHalfHeight;
}
else if(cameraTop >= mapTop)
{
    cam.position.y = mapTop - cameraHalfHeight;
}

Yani mantık oldukça basit. Küçük kutuyu büyük kutunun içinde tutun. Bu fikri anladıktan sonra bu kodu daraltmaktan çekinmeyin. İsterseniz, kamera konumu izlemenizde bir dizi iç içe Min / Maks ifadesine bile taşıyabilirsiniz.


1
Daha önce yatmalıyım. Bunun gibi bir şey uyguladım, ama işe yaramadı. Ama setPosition()sınırları düzeltmek güzel bir yöntem çağırmak yerine , hala cam konumunu doğrudan ayarlıyordu (örneğin cam.position.set()) Bu bir cazibe gibi çalışır! Açıklama için teşekkürler!
Ariejan

7

Kamera konumunu kolayca harita sınırlarına şu şekilde bağlayabilirsiniz:

camera.position.x = MathUtils.clamp(camera.position.x, camViewportHalfX, mapWidth - camViewportHalfX);
camera.position.y = MathUtils.clamp(camera.position.y, camViewportHalfY, mapHeight - camViewportHalfY);

Nedir camViewportHalfXve camViewportHalfY?
Cypher

@Cypher: X ve Y eksenlerinin görünümünün yarısı kadardır.
Matthias

Yani camViewportHalfXbuna eşdeğer olur camera.viewportWidth / 2mu?
Cypher

0

Taşımak için Camerade TiledMapsınırları, OrthogonalTiledMapRendererkullanılmıştır.

Ayrıca beklenmedik bir şekilde davrandığını da fark ettim: Cameraharita sınırlarına ulaşırken, atalet gibi döşeli harita, bazı pikselleri çok fazla hareket ettirir (kaydırmanın hızına bağlıdır).

Bir çözüm olarak , her Cameraharekette, Camerazorla harita sınırlarına yerleştirilir. Bkz. putInMapBounds()Yöntem.

TiledMapKullanılan aksaklıklardan kaçınmak için kullanılır Math.min(float, float).

Bu dinleyiciyi aşağıdakileri işlemek için kullanın Camera:

/**
 * @author Gram <gram7gram@gmail.com>
 */
public class CameraListener extends InputAdapter {

    private final UIStage stage;
    private final Camera camera;
    private final Vector3 curr;
    private final Vector3 last;
    private final Vector3 delta;
    private final int mapWidth;
    private final int mapHeight;

    public CameraListener(UIStage stage) {
        this.stage = stage;
        this.camera = stage.getViewport().getCamera();

        curr = new Vector3();
        last = new Vector3(-1, -1, -1);
        delta = new Vector3();

        TiledMapTileLayer layer = stage.getLevel().getMap().getFirstLayer();
        mapWidth = layer.getWidth() * DDGame.TILE_HEIGHT;
        mapHeight = layer.getHeight() * DDGame.TILE_HEIGHT;
    }

    @Override
    public boolean touchDragged(int x, int y, int pointer) {

        camera.unproject(curr.set(x, y, 0));

        if (!(last.x == -1 && last.y == -1 && last.z == -1)) {
            camera.unproject(delta.set(last.x, last.y, 0));
            delta.sub(curr);
            camera.translate(Math.min(delta.x, 5), Math.min(delta.y, 5), 0);
            if (isInMapBounds()) {
                stage.moveBy(Math.min(delta.x, 5), Math.min(delta.y, 5));
            }
        }

        last.set(x, y, 0);

        putInMapBounds();

        return false;
    }


    private boolean isInMapBounds() {

        return camera.position.x >= camera.viewportWidth / 2f
                && camera.position.x <= mapWidth - camera.viewportWidth / 2f
                && camera.position.y >= camera.viewportHeight / 2f
                && camera.position.y <= mapHeight - camera.viewportHeight / 2f;

    }

    private void putInMapBounds() {

        if (camera.position.x < camera.viewportWidth / 2f)
            camera.position.x = camera.viewportWidth / 2f;
        else if (camera.position.x > mapWidth - camera.viewportWidth / 2f)
            camera.position.x = mapWidth - camera.viewportWidth / 2f;

        if (camera.position.y < camera.viewportHeight / 2f)
            camera.position.y = camera.viewportHeight / 2f;
        else if (camera.position.y > mapHeight - camera.viewportHeight / 2f)
            camera.position.y = mapHeight - camera.viewportHeight / 2f;

        stage.moveTo(
                camera.position.x,
                camera.position.y);

    }

    @Override
    public boolean touchUp(int x, int y, int pointer, int button) {
        last.set(-1, -1, -1);
        Log.info("Camera at " + camera.position.x + ":" + camera.position.y);
        return false;
    }
}

0

Dikkat etmeniz gereken yakınlaştırma faktörünüz varsa, bunun çok daha iyi çalıştığını gördüm:

public void fixBounds() {
    float scaledViewportWidthHalfExtent = viewportWidth * zoom * 0.5f;
    float scaledViewportHeightHalfExtent = viewportHeight * zoom * 0.5f;

    // Horizontal
    if (position.x < scaledViewportWidthHalfExtent)
        position.x = scaledViewportWidthHalfExtent;
    else if (position.x > xmax - scaledViewportWidthHalfExtent)
        position.x = xmax - scaledViewportWidthHalfExtent;

    // Vertical
    if (position.y < scaledViewportHeightHalfExtent)
        position.y = scaledViewportHeightHalfExtent;
    else if (position.y > ymax - scaledViewportHeightHalfExtent)
        position.y = ymax - scaledViewportHeightHalfExtent;
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.