You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

libGDX如何实现任意屏幕尺寸下全屏显示背景并保持图片宽高比

实现背景等比例铺满全屏的解决方法

问题原因

你当前的代码有两个核心问题:

  1. 只按照屏幕高度计算背景宽度,当屏幕宽高比小于背景原始宽高比(540:720=0.75)时,比如横屏状态下屏幕宽高比通常大于1,计算出来的背景宽度会小于屏幕实际宽度,就会出现侧边白边。
  2. 背景的大小、位置只在类初始化时计算一次,窗口大小变化(resize触发)时没有同步更新背景参数。

实现逻辑

要保证背景等比例铺满全屏且无黑边,核心是取宽、高两个方向的最大缩放系数,确保缩放后的背景尺寸完全覆盖屏幕,多余部分居中裁剪:

  • 分别计算「屏幕宽度/背景原始宽度」、「屏幕高度/背景原始高度」两个缩放值
  • 取更大的缩放值作为最终缩放系数,保证缩放后的背景宽、高都不小于屏幕对应尺寸
  • 将缩放后的背景居中放置,超出屏幕的部分会被自动裁剪

修改后的代码

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.scenes.scene2d.Stage;
import com.badlogic.gdx.scenes.scene2d.ui.Image;
import com.badlogic.gdx.scenes.scene2d.utils.TextureRegionDrawable;
import com.badlogic.gdx.utils.viewport.ScreenViewport;

public class MainMenuScreen implements Screen, InputProcessor {
    final MyGame game;
    private Texture backgroundTexture;
    private TextureRegionDrawable backgroundDrawable;
    private Stage stageBackground;
    private Image backgroundImage;
    // 缓存背景原始宽高,避免重复读取
    private float bgOriginalWidth;
    private float bgOriginalHeight;

    public MainMenuScreen(MyGame game) {
        this.game = game;
        // 修复重复创建Texture的问题,避免资源泄漏
        backgroundTexture = new Texture(game.backgroundFileName);
        backgroundDrawable = new TextureRegionDrawable(new TextureRegion(backgroundTexture));
        bgOriginalWidth = backgroundDrawable.getRegion().getRegionWidth();
        bgOriginalHeight = backgroundDrawable.getRegion().getRegionHeight();
        
        // ScreenViewport即可满足需求,直接对应屏幕像素坐标
        stageBackground = new Stage(new ScreenViewport());
        backgroundImage = new Image(backgroundDrawable);
        stageBackground.addActor(backgroundImage);
        
        // 初始化时调用一次resize,适配初始窗口大小
        resize(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
    }

    @Override
    public void render(float delta) {
        // 清屏避免画面残留,可根据需求调整清屏颜色
        Gdx.gl.glClearColor(0,0,0,1);
        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
        
        stageBackground.getViewport().apply();
        stageBackground.draw();
    }

    @Override
    public void resize(int width, int height) {
        // 先更新viewport
        stageBackground.getViewport().update(width, height, true);
        
        // 计算两个方向的缩放系数
        float scaleX = (float) width / bgOriginalWidth;
        float scaleY = (float) height / bgOriginalHeight;
        // 取较大的缩放系数,保证背景完全覆盖屏幕
        float finalScale = Math.max(scaleX, scaleY);
        
        // 计算缩放后的背景尺寸
        float scaledWidth = bgOriginalWidth * finalScale;
        float scaledHeight = bgOriginalHeight * finalScale;
        
        // 更新背景大小和位置,居中放置,超出屏幕部分自动裁剪
        backgroundImage.setSize(scaledWidth, scaledHeight);
        backgroundImage.setPosition(
            (width - scaledWidth) / 2f,
            (height - scaledHeight) / 2f
        );
    }

    // 补充资源销毁逻辑,避免内存泄漏
    @Override
    public void dispose() {
        stageBackground.dispose();
        backgroundTexture.dispose();
    }

    // 其他Screen和InputProcessor的接口方法按你原有逻辑实现即可
}

额外注意事项

  • 如果你的游戏其他UI有独立的Viewport,不要和背景的Viewport混淆,渲染时分别apply各自的Viewport即可
  • 安卓端横竖屏切换时会自动触发resize方法,无需额外处理
  • 记得在AndroidManifest里配置横竖屏切换的configChanges属性,避免Activity重建导致的资源重加载

内容的提问来源于stack exchange,提问作者user2342558

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.12 10:51:00