调整大小后,LibGDX如何保持纵横比?

调整大小后,LibGDX如何保持纵横比?,libgdx,resize,viewport,aspect-ratio,Libgdx,Resize,Viewport,Aspect Ratio,我有点困惑为什么我的FitViewport在调整窗口大小时没有保持纵横比。 我认为它应该始终保持纵横比,然后用黑条填充屏幕中未使用的区域 然而对我来说,它并没有保持纵横比,圆圈变成省略号f.e.(见截图) 创建我的游戏渲染器时的代码(32和18是我的世界单位) 调整窗口大小时编码 public void resize(int width, int height) { Gdx.app.debug(TAG, "Resizing to " + width + " x " + height);

我有点困惑为什么我的FitViewport在调整窗口大小时没有保持纵横比。 我认为它应该始终保持纵横比,然后用黑条填充屏幕中未使用的区域

然而对我来说,它并没有保持纵横比,圆圈变成省略号f.e.(见截图)

创建我的游戏渲染器时的代码(32和18是我的世界单位)

调整窗口大小时编码

 public void resize(int width, int height) {
   Gdx.app.debug(TAG, "Resizing to " + width + " x " + height);
   viewport.update(width, height);
   visibleArea.set(0, 0, viewport.getScreenWidth(), viewport.getScreenHeight());
渲染方法

public void render(float alpha) {
  viewport.calculateScissors(batch.getTransformMatrix(), visibleArea, scissors);
  ScissorStack.pushScissors(scissors);

  viewport.apply();
  setView(camera.combined, visibleArea.x, visibleArea.y, visibleArea.width, visibleArea.height);

  batch.begin();
  // ...
  batch.end();

  ScissorStack.popScissors();
}


好的,问题实际上是我的framebuffer light方法(prepareLightFrameBuffer)也调用了batch.begin();和batch.end()。 这似乎会弄乱视图(或将其重置为其他内容?)。为了解决这个问题,我只需再次应用视口,并在render方法中再次设置视图(注意:我还有一个stage,因此我认为必须在此处以及stage.render()方法中调用viewport.apply()

如果有人感兴趣,下面是游戏渲染器的完整代码。我想它可以简化,但我不是OpenGL/Matrix专家,所以我不知道怎么做:)

package com.lok.game;
导入java.util.Comparator;
导入com.badlogic.ashley.core.ComponentMapper;
导入com.badlogic.ashley.core.Entity;
导入com.badlogic.gdx.Application;
导入com.badlogic.gdx.gdx;
导入com.badlogic.gdx.graphics.Camera;
导入com.badlogic.gdx.graphics.Color;
导入com.badlogic.gdx.graphics.GL20;
导入com.badlogic.gdx.graphics.Pixmap;
导入com.badlogic.gdx.graphics.g2d.TextureAtlas;
导入com.badlogic.gdx.graphics.g2d.TextureAtlas.AtlasRegion;
导入com.badlogic.gdx.graphics.g2d.TextureRegion;
导入com.badlogic.gdx.graphics.glutils.FrameBuffer;
导入com.badlogic.gdx.graphics.glutils.shaperender;
导入com.badlogic.gdx.graphics.glutils.shaperender.ShapeType;
导入com.badlogic.gdx.maps.MapLayer;
导入com.badlogic.gdx.maps.tiled.TiledMapImageLayer;
导入com.badlogic.gdx.maps.tiled.tiledMartileLayer;
导入com.badlogic.gdx.maps.tiled.renders.OrthogonalTiledMapRenderer;
导入com.badlogic.gdx.maps.tiled.tiles.animatedTiledMatpile;
导入com.badlogic.gdx.math.Intersector;
导入com.badlogic.gdx.math.Rectangle;
导入com.badlogic.gdx.scenes.scene2d.utils.ScissorStack;
导入com.badlogic.gdx.utils.Array;
导入com.badlogic.gdx.utils.GdxRuntimeException;
导入com.badlogic.gdx.utils.viewport.FitViewport;
导入com.badlogic.gdx.utils.viewport.viewport;
导入com.lok.game.ecs.components.AnimationComponent;
导入com.lok.game.ecs.components.CollisionComponent;
导入com.lok.game.ecs.components.MapRelationComponent;
导入com.lok.game.ecs.components.SizeComponent;
导入com.lok.game.map.map;
导入com.lok.game.map.map.Portal;
导入com.lok.game.map.MapManager;
公共类GameRenderer扩展了OrthogonalTiledMapRenderer{
private final static String TAG=GameRenderer.class.getName();
私有静态类yPositionComparator实现Comparator{
私有最终组件映射器sizeComponentMapper;
专用yPositionComparator(组件映射器大小组件映射器){
this.sizeComponentMapper=sizeComponentMapper;
}
@凌驾
公共整数比较(实体o1、实体o2){
如果(o1==o2){
返回0;
}else if(o1==null){
返回-1;
}否则如果(o2==null){
返回1;
}
返回sizeComponentMapper.get(o1).boundingRectangle.y>sizeComponentMapper.get(o2).boundingRectangle.y?-1:1;
}
}
专用尺寸组件CameralLockEntitySizeComponent;
私有MapRevelationComponent CameralLockEntityLevel组件;
私人地图;
专用瓷砖底层底层;
私有最终阵列背景层;
专用最终阵列前置层;
私人罗非鱼光照层;
私人最终位置比较器实体比较器;
私有最终组件映射器sizeComponentMapper;
私有最终组件映射器animationComponentMapper;
私人最终摄像机;
私有最终视口;
私人住宅区;
私人最终矩形剪刀;
私人最终定单定单定单定单定单定单定单定单定单定单定单定单定单定单定单定单定单定单定单定单定单定单定单定单定单定单定单定单定单定单定单定单定单定单;
专用帧缓冲区帧缓冲区;
私有最终AtlasRegion lightTexture;
私有最终AtlasRegion阴影纹理;
公共游戏机(){
超级(空,MapManager.WORLD\u UNITS\u PER\u PIXEL);
if(Gdx.app.getLogLevel()==Application.LOG\u调试){
Gdx.app.debug(标记“在调试模式下创建”);
ShaperEnder=新的ShaperEnder();
}否则{
Gdx.app.debug(标记“在非调试模式下创建”);
shaperender=null;
}
视口=新视口(32,18);
camera=viewport.getCamera();
visibleArea=新矩形();
剪刀=新矩形();
this.backgroundLayers=新数组();
this.foregroundLayers=新数组();
this.sizeComponentMapper=ComponentMapper.getFor(SizeComponent.class);
this.animationComponentMapper=ComponentMapper.getFor(AnimationComponent.class);
this.entityComparator=新的yPositionComparator(sizeComponentMapper);
最终TextureAtlas TextureAtlas=AssetManager.getManager().getAsset(“lights/lights.atlas”,TextureAtlas.class);
lightTexture=textureAtlas.findRegion(“灯光”);
shadowTexture=textureAtlas.findRegion(“阴影”);
帧缓冲区=null;
}
公共无效集合映射(映射映射){
this.map=map;
super.setMap(map.getTiledMap());
这个.backgroundLayers.clear();
这是.foregroundLayers.clear();
this.lightMapLayer=null;
对于(MapLayer MapLayer:map.getTiledMap().getLayers()){
如果(映射层)
public void render(float alpha) {
  viewport.calculateScissors(batch.getTransformMatrix(), visibleArea, scissors);
  ScissorStack.pushScissors(scissors);

  viewport.apply();
  setView(camera.combined, visibleArea.x, visibleArea.y, visibleArea.width, visibleArea.height);

  batch.begin();
  // ...
  batch.end();

  ScissorStack.popScissors();
}
package com.lok.game;

import java.util.Comparator;

import com.badlogic.ashley.core.ComponentMapper;
import com.badlogic.ashley.core.Entity;
import com.badlogic.gdx.Application;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.Camera;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.Pixmap;
import com.badlogic.gdx.graphics.g2d.TextureAtlas;
import com.badlogic.gdx.graphics.g2d.TextureAtlas.AtlasRegion;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.graphics.glutils.FrameBuffer;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer.ShapeType;
import com.badlogic.gdx.maps.MapLayer;
import com.badlogic.gdx.maps.tiled.TiledMapImageLayer;
import com.badlogic.gdx.maps.tiled.TiledMapTileLayer;
import com.badlogic.gdx.maps.tiled.renderers.OrthogonalTiledMapRenderer;
import com.badlogic.gdx.maps.tiled.tiles.AnimatedTiledMapTile;
import com.badlogic.gdx.math.Intersector;
import com.badlogic.gdx.math.Rectangle;
import com.badlogic.gdx.scenes.scene2d.utils.ScissorStack;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.GdxRuntimeException;
import com.badlogic.gdx.utils.viewport.FitViewport;
import com.badlogic.gdx.utils.viewport.Viewport;
import com.lok.game.ecs.components.AnimationComponent;
import com.lok.game.ecs.components.CollisionComponent;
import com.lok.game.ecs.components.MapRevelationComponent;
import com.lok.game.ecs.components.SizeComponent;
import com.lok.game.map.Map;
import com.lok.game.map.Map.Portal;
import com.lok.game.map.MapManager;

public class GameRenderer extends OrthogonalTiledMapRenderer {
private final static String TAG = GameRenderer.class.getName();

private static class yPositionComparator implements Comparator<Entity> {
    private final ComponentMapper<SizeComponent> sizeComponentMapper;

    private yPositionComparator(ComponentMapper<SizeComponent> sizeComponentMapper) {
        this.sizeComponentMapper = sizeComponentMapper;
    }

    @Override
    public int compare(Entity o1, Entity o2) {
        if (o1 == o2) {
            return 0;
            } else if (o1 == null) {
            return -1;
            } else if (o2 == null) {
            return 1;
        }

        return sizeComponentMapper.get(o1).boundingRectangle.y > sizeComponentMapper.get(o2).boundingRectangle.y ? -1 : 1;
    }

}

private SizeComponent                  cameraLockEntitySizeComponent;
private MapRevelationComponent              cameraLockEntityRevelationComponent;

private Map                          map;
private TiledMapTileLayer                  groundLayer;
private final Array<TiledMapTileLayer>          backgroundLayers;
private final Array<TiledMapTileLayer>          foregroundLayers;
private TiledMapImageLayer                  lightMapLayer;

private final yPositionComparator              entityComparator;

private final ComponentMapper<SizeComponent>      sizeComponentMapper;
private final ComponentMapper<AnimationComponent> animationComponentMapper;

private final Camera                  camera;
private final Viewport                  viewport;
private final Rectangle                  visibleArea;
private final Rectangle                  scissors;

private final ShapeRenderer                  shapeRenderer;

private FrameBuffer                      frameBuffer;
private final AtlasRegion                  lightTexture;
private final AtlasRegion                  shadowTexture;

public GameRenderer() {
    super(null, MapManager.WORLD_UNITS_PER_PIXEL);

    if (Gdx.app.getLogLevel() == Application.LOG_DEBUG) {
        Gdx.app.debug(TAG, "Creating in debug mode");
        shapeRenderer = new ShapeRenderer();
        } else {
        Gdx.app.debug(TAG, "Creating in non-debug mode");
        shapeRenderer = null;
    }

    viewport = new FitViewport(32, 18);
    camera = viewport.getCamera();
    visibleArea = new Rectangle();
    scissors = new Rectangle();

    this.backgroundLayers = new Array<TiledMapTileLayer>();
    this.foregroundLayers = new Array<TiledMapTileLayer>();

    this.sizeComponentMapper = ComponentMapper.getFor(SizeComponent.class);
    this.animationComponentMapper = ComponentMapper.getFor(AnimationComponent.class);

    this.entityComparator = new yPositionComparator(sizeComponentMapper);

    final TextureAtlas textureAtlas = AssetManager.getManager().getAsset("lights/lights.atlas", TextureAtlas.class);
    lightTexture = textureAtlas.findRegion("light");
    shadowTexture = textureAtlas.findRegion("shadow");
    frameBuffer = null;
}

public void setMap(Map map) {
    this.map = map;
    super.setMap(map.getTiledMap());

    this.backgroundLayers.clear();
    this.foregroundLayers.clear();
    this.lightMapLayer = null;
    for (MapLayer mapLayer : map.getTiledMap().getLayers()) {
        if (mapLayer instanceof TiledMapTileLayer) {
            if ("ground".equals(mapLayer.getName())) {
                groundLayer = (TiledMapTileLayer) mapLayer;
                } else if (mapLayer.getName().startsWith("background")) {
                backgroundLayers.add((TiledMapTileLayer) mapLayer);
                } else {
                foregroundLayers.add((TiledMapTileLayer) mapLayer);
            }
            } else if (mapLayer instanceof TiledMapImageLayer) {
            lightMapLayer = (TiledMapImageLayer) mapLayer;
        }
    }
}

public void resize(int width, int height) {
    Gdx.app.debug(TAG, "Resizing with " + width + "x" + height + " from viewport " + viewport.getScreenWidth() + "x" + viewport.getScreenHeight());
    viewport.update(width, height, false);
    visibleArea.set(0, 0, viewport.getWorldWidth(), viewport.getWorldHeight());
    Gdx.app.debug(TAG, "To viewport " + viewport.getScreenWidth() + "x" + viewport.getScreenHeight());

    if (frameBuffer != null) {
        frameBuffer.dispose();
    }

    try {
        frameBuffer = FrameBuffer.createFrameBuffer(Pixmap.Format.RGBA8888, viewport.getScreenWidth(), viewport.getScreenHeight(), false);
        } catch (GdxRuntimeException e) {
        frameBuffer = FrameBuffer.createFrameBuffer(Pixmap.Format.RGB565, viewport.getScreenWidth(), viewport.getScreenHeight(), false);
    }
}

public void lockCameraToEntity(Entity entity) {
    if (entity == null) {
        cameraLockEntitySizeComponent = null;
        cameraLockEntityRevelationComponent = null;
        } else {
        cameraLockEntityRevelationComponent = entity.getComponent(MapRevelationComponent.class);
        cameraLockEntitySizeComponent = entity.getComponent(SizeComponent.class);

        if (cameraLockEntitySizeComponent == null) {
            throw new GdxRuntimeException("Trying to lock camera to an entity without size component: " + entity);
        }
    }
}

private void interpolateEntities(float alpha) {
    for (Entity entity : map.getEntities()) {
        final SizeComponent sizeComp = sizeComponentMapper.get(entity);

        final float invAlpha = 1.0f - alpha;
        sizeComp.interpolatedPosition.x = sizeComp.interpolatedPosition.x * invAlpha + sizeComp.boundingRectangle.x * alpha;
        sizeComp.interpolatedPosition.y = sizeComp.interpolatedPosition.y * invAlpha + sizeComp.boundingRectangle.y * alpha;
    }
}

public void render(float alpha) {
    AnimatedTiledMapTile.updateAnimationBaseTime();
    interpolateEntities(alpha);
    map.getEntities().sort(entityComparator);

    if (cameraLockEntitySizeComponent != null) {
        camera.position.set(cameraLockEntitySizeComponent.interpolatedPosition, 0);
        visibleArea.setCenter(cameraLockEntitySizeComponent.interpolatedPosition);
    }

    prepareLightFrameBuffer();

    Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
    batch.setBlendFunction(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA);

    viewport.apply();
    setView(camera.combined, visibleArea.x, visibleArea.y, visibleArea.width, visibleArea.height);
    batch.begin();
    viewport.calculateScissors(batch.getTransformMatrix(), visibleArea, scissors);
    ScissorStack.pushScissors(scissors);
    if (groundLayer != null) {
        renderTileLayer(groundLayer);
    }
    for (Entity entity : map.getEntities()) {
        renderEntityShadow(entity);
    }
    for (TiledMapTileLayer layer : backgroundLayers) {
        renderTileLayer(layer);
    }
    for (Entity entity : map.getEntities()) {
        renderEntity(entity);
    }
    for (TiledMapTileLayer layer : foregroundLayers) {
        renderTileLayer(layer);
    }
    batch.end();

    applyLightFrameBuffer();

    if (Gdx.app.getLogLevel() == Application.LOG_DEBUG) {
        renderDebugInformation();
    }

    ScissorStack.popScissors();
}

private void renderEntityShadow(Entity entity) {
    final AnimationComponent animationComp = animationComponentMapper.get(entity);

    if (animationComp.animation != null) {
        final SizeComponent sizeComp = sizeComponentMapper.get(entity);
        if (!viewBounds.overlaps(sizeComp.boundingRectangle)) {
            return;
        }

        if (cameraLockEntityRevelationComponent != null && !Intersector.overlaps(cameraLockEntityRevelationComponent.revelationCircle, sizeComp.boundingRectangle)) {
            return;
        }

        batch.draw(shadowTexture, sizeComp.interpolatedPosition.x, sizeComp.interpolatedPosition.y - sizeComp.boundingRectangle.height * 0.2f, sizeComp.boundingRectangle.width,
        sizeComp.boundingRectangle.height * 0.5f);
    }
}

private void renderEntity(Entity entity) {
    final AnimationComponent animationComp = animationComponentMapper.get(entity);

    if (animationComp.animation != null) {
        final SizeComponent sizeComp = sizeComponentMapper.get(entity);
        if (!viewBounds.overlaps(sizeComp.boundingRectangle)) {
            return;
        }

        if (cameraLockEntityRevelationComponent != null && !Intersector.overlaps(cameraLockEntityRevelationComponent.revelationCircle, sizeComp.boundingRectangle)) {
            return;
        }

        final TextureRegion keyFrame = animationComp.animation.getKeyFrame(animationComp.animationTime, true);
        batch.draw(keyFrame, sizeComp.interpolatedPosition.x, sizeComp.interpolatedPosition.y, sizeComp.boundingRectangle.width, sizeComp.boundingRectangle.height);
    }
}

private void prepareLightFrameBuffer() {
    if (cameraLockEntityRevelationComponent != null) {
        frameBuffer.begin();

        final Color mapBackgroundColor = map.getBackgroundColor();
        Gdx.gl.glClearColor(mapBackgroundColor.r, mapBackgroundColor.g, mapBackgroundColor.b, mapBackgroundColor.a);
        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);

        setView(camera.combined, visibleArea.x, visibleArea.y, visibleArea.width, visibleArea.height);
        batch.begin();
        if (lightMapLayer != null) {
            batch.setBlendFunction(GL20.GL_SRC_ALPHA, GL20.GL_ONE);
            renderImageLayer(lightMapLayer);
        }

        batch.setBlendFunction(GL20.GL_SRC_ALPHA, GL20.GL_ONE);
        final Rectangle boundingRectangle = cameraLockEntitySizeComponent.boundingRectangle;
        batch.draw(lightTexture, cameraLockEntitySizeComponent.interpolatedPosition.x + boundingRectangle.width * 0.5f - cameraLockEntityRevelationComponent.revelationRadius, // x
        cameraLockEntitySizeComponent.interpolatedPosition.y + boundingRectangle.height * 0.5f - cameraLockEntityRevelationComponent.revelationRadius, // y
        cameraLockEntityRevelationComponent.revelationRadius * 2f, cameraLockEntityRevelationComponent.revelationRadius * 2f);

        batch.end();

        frameBuffer.end();
    }
}

private void applyLightFrameBuffer() {
    if (cameraLockEntityRevelationComponent != null) {
        batch.setProjectionMatrix(batch.getProjectionMatrix().idt());
        batch.setBlendFunction(GL20.GL_ZERO, GL20.GL_SRC_COLOR);
        batch.begin();
        batch.draw(frameBuffer.getColorBufferTexture(), -1, 1, 2, -2);
        batch.end();
    }
}

private void renderDebugInformation() {
    shapeRenderer.setProjectionMatrix(camera.combined);
    shapeRenderer.begin(ShapeType.Line);

    shapeRenderer.setColor(Color.RED);
    for (Rectangle rect : map.getCollisionAreas()) {
        shapeRenderer.rect(rect.x, rect.y, rect.width, rect.height);
    }

    for (Entity entity : map.getEntities()) {
        final CollisionComponent collisionComponent = entity.getComponent(CollisionComponent.class);
        final SizeComponent sizeComp = sizeComponentMapper.get(entity);
        if (collisionComponent != null) {
            shapeRenderer.setColor(Color.RED);
            shapeRenderer.rect(sizeComp.interpolatedPosition.x + collisionComponent.rectOffset.x, sizeComp.interpolatedPosition.y + collisionComponent.rectOffset.y,
            collisionComponent.collisionRectangle.width, collisionComponent.collisionRectangle.height);
        }

        if (sizeComp != null) {
            shapeRenderer.setColor(Color.BLUE);
            shapeRenderer.rect(sizeComp.interpolatedPosition.x, sizeComp.interpolatedPosition.y, sizeComp.boundingRectangle.width, sizeComp.boundingRectangle.height);
        }

    }

    shapeRenderer.setColor(Color.BLUE);
    for (Portal portal : map.getPortals()) {
        shapeRenderer.rect(portal.getArea().x, portal.getArea().y, portal.getArea().width, portal.getArea().height);
    }

    if (cameraLockEntityRevelationComponent != null) {
        shapeRenderer.setColor(Color.WHITE);
        shapeRenderer.circle(cameraLockEntitySizeComponent.interpolatedPosition.x + cameraLockEntitySizeComponent.boundingRectangle.width * 0.5f,
        cameraLockEntitySizeComponent.interpolatedPosition.y + cameraLockEntitySizeComponent.boundingRectangle.height * 0.5f,
        cameraLockEntityRevelationComponent.revelationCircle.radius, 64);
    }

    shapeRenderer.end();
}

@Override
public void dispose() {
    Gdx.app.debug(TAG, "Disposing Gamerenderer");
    super.dispose();
    if (shapeRenderer != null) {
        shapeRenderer.dispose();
    }
    if (frameBuffer != null) {
        frameBuffer.dispose();
    }
}
}