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

Libgdx中render()方法重复调用问题的解决咨询

LibGDX中SplashScreen的render方法重复调用导致IllegalStateException及重复创建屏幕问题

在基于LibGDX开发的SplashScreen类中,出现render()方法在上一次调用完成前被几乎同时调用两次的情况,触发IllegalStateException异常。即使移除AssetManager相关逻辑,新屏幕仍会被创建两次。现寻求解决该重复渲染问题的方案。

相关代码

public class SplashScreen extends AbstractScreen {

    private float countDown;
    private final GameManager gameManager;
    boolean updating = false;

    public SplashScreen(Main main) {
        super(main);
        gameManager = GameManager.get();

        Label loading = new Label("Loading", new Label.LabelStyle(new BitmapFont(), Color.BLACK));

        Table table = new Table();
        table.setFillParent(true);
        table.center();
        table.add(loading).expand();

        stage.addActor(table);

        countDown = 0.5f;
    }

    @Override
    public void show() {
        super.show();
        main.loadManager();
    }

    @Override
    public void render(float delta) {
        super.render(delta);
        
        if (updating) throw new IllegalStateException();
        
        updating = true;
        
        countDown -= delta;
        if (countDown < 0.0f && gameManager.assetManager.update()) {
            main.onLoadManager();
            ScreenManager.get().showScreen(ScreenManager.ScreenEnum.MAIN_MENU);
        }
        
        updating = false;
    }

}

异常信息

Exception in thread "main" java.lang.IllegalStateException
    at avseygames.convey.screens.SplashScreen.render(SplashScreen.java:51)
    at com.badlogic.gdx.Game.render(Game.java:48)
    at avseygames.convey.Main.render(Main.java:41)
    at com.badlogic.gdx.backends.lwjgl3.Lwjgl3Graphics.renderWindow(Lwjgl3Graphics.java:103)
    at com.badlogic.gdx.backends.lwjgl3.Lwjgl3Graphics.access$000(Lwjgl3Graphics.java:45)
    at com.badlogic.gdx.backends.lwjgl3.Lwjgl3Graphics$1.invoke(Lwjgl3Graphics.java:80)
    at org.lwjgl.glfw.GLFWFramebufferSizeCallbackI.callback(GLFWFramebufferSizeCallbackI.java:44)
    at org.lwjgl.system.JNI.invokePPV(Native Method)
    at org.lwjgl.glfw.GLFW.glfwSetWindowMonitor(GLFW.java:3017)
    at com.badlogic.gdx.backends.lwjgl3.Lwjgl3Graphics.setFullscreenMode(Lwjgl3Graphics.java:446)
    at avseygames.convey.manage.GameManager.setScreenSize(GameManager.java:78)
    at avseygames.convey.Main.onLoadManager(Main.java:28)
    at avseygames.convey.screens.SplashScreen.render(SplashScreen.java:56)
    at com.badlogic.gdx.Game.render(Game.java:48)
    at avseygames.convey.Main.render(Main.java:41)
    at com.badlogic.gdx.backends.lwjgl3.Lwjgl3Window.update(Lwjgl3Window.java:387)
    at com.badlogic.gdx.backends.lwjgl3.Lwjgl3Application.loop(Lwjgl3Application.java:193)
    at com.badlogic.gdx.backends.lwjgl3.Lwjgl3Application.<init>(Lwjgl3Application.java:167)
    at avseygames.convey.DesktopLauncher.main(DesktopLauncher.java:15)

FAILURE: Build failed with an exception.

问题分析与解决方案

从异常栈可以看出,问题根源在于:main.onLoadManager()中调用的setScreenSize最终触发了glfwSetWindowMonitor,而GLFW在窗口尺寸/显示器变更时会同步触发GLFWFramebufferSizeCallback回调,LibGDX的Lwjgl3后端会在该回调中额外调用一次render方法,导致当前SplashScreen的render被重复执行。

修改方案

新增一个标志位标记屏幕切换是否已触发,避免重复执行切换逻辑:

public class SplashScreen extends AbstractScreen {

    private float countDown;
    private final GameManager gameManager;
    private boolean hasTriggeredSwitch = false; // 新增标志位

    public SplashScreen(Main main) {
        super(main);
        gameManager = GameManager.get();

        Label loading = new Label("Loading", new Label.LabelStyle(new BitmapFont(), Color.BLACK));

        Table table = new Table();
        table.setFillParent(true);
        table.center();
        table.add(loading).expand();

        stage.addActor(table);

        countDown = 0.5f;
    }

    @Override
    public void show() {
        super.show();
        main.loadManager();
    }

    @Override
    public void render(float delta) {
        super.render(delta);
        
        if (hasTriggeredSwitch) return; // 已触发切换则直接返回
        
        countDown -= delta;
        if (countDown < 0.0f && gameManager.assetManager.update()) {
            hasTriggeredSwitch = true; // 标记切换已启动
            main.onLoadManager();
            ScreenManager.get().showScreen(ScreenManager.ScreenEnum.MAIN_MENU);
        }
    }
}

额外建议

  • 尽量避免在render方法中执行可能触发窗口变更的操作,此类操作可移至新屏幕的show方法中执行
  • 如果必须在加载完成后调整窗口尺寸,可考虑将尺寸变更逻辑异步处理,避免同步触发渲染回调

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 09:51:21