如何在libGdx中刷新透明屏幕并解决按钮重复问题
LibGdx透明菜单屏幕按钮重复问题解决
我在开发小型libGdx项目时遇到了透明屏幕的问题:GameMenuScreen作为可全局调用的透明菜单,渲染在GameScreen上方,背景可见,但点击"Save"等按钮后,所有按钮会出现重复残影。推测是屏幕未逐帧刷新导致,但直接用常规的glClear会失去透明度。
问题代码(GameMenuScreen)
public class GameMenuScreen extends ScreenAdapter { private TextureAtlas uiskinAtlas; private Skin skin; private OrthographicCamera camera; private Viewport viewport; private Stage stage; private Table table; private Vector3 position; private SpriteBatch batch; private TextButton continueGame; private TextButton loadGame; private TextButton settings; private TextButton mainMenu; private TextButton quit; private TextButton save; public GameMenuScreen() { uiskinAtlas = GameWindow.manager.get(Paths.uiskinAtlas, TextureAtlas.class); skin = new Skin(Gdx.files.internal(Paths.uiskinJson), uiskinAtlas); camera = new OrthographicCamera(); position = new Vector3(Gdx.graphics.getWidth() / 2, Gdx.graphics.getHeight() / 2, 0); camera.position.set(position); viewport = new ScreenViewport(camera); stage = new Stage(viewport); batch = new SpriteBatch(); table = new Table(); continueGame = new TextButton("Continue Game", skin); loadGame = new TextButton("Load Game", skin); settings = new TextButton("Settings", skin); mainMenu = new TextButton("Main Menu", skin); quit = new TextButton("Quit", skin); save = new TextButton("Save", skin); continueGame.setColor(Color.ROYAL); loadGame.setColor(Color.ROYAL); settings.setColor(Color.ROYAL); mainMenu.setColor(Color.ROYAL); quit.setColor(Color.ROYAL); save.setColor(Color.ROYAL); createUI(); } @Override public void show() { Gdx.input.setInputProcessor(stage); } @Override public void render(float delta) { Gdx.gl.glClearColor(0, 0, 0, 0f); batch.enableBlending(); batch.begin(); continueGame.draw(batch, 0); loadGame.draw(batch, 0); settings.draw(batch, 0); mainMenu.draw(batch, 0); quit.draw(batch, 0); save.draw(batch, 0); batch.end(); stage.act(); stage.draw(); } private void createUI() { table.setFillParent(true); table.center(); setButtonInput(); table.add(continueGame).width(250); table.row().space(5, 5, 0, 0); table.add(loadGame).width(250); table.row().space(5, 5, 0, 0); table.add(save).width(250); table.row().space(5, 5, 0, 0); table.add(settings).width(250); table.row().space(5, 5, 0, 0); table.add(mainMenu).width(250); table.row().space(5, 5, 0, 0); table.add(quit).width(250); table.row().space(5, 5, 0, 0); stage.addActor(table); } private void setButtonInput() { continueGame.addListener(new ClickListener() { @Override public void clicked(InputEvent event, float x, float y) { GameWindow.INSTANCE.setScreen(Screens.getGameScreen()); } }); loadGame.addListener(new ClickListener() { @Override public void clicked(InputEvent event, float x, float y) { Savegame.load(); Screens.getGameScreen().setWorldCreated(false); GameWindow.INSTANCE.setScreen(Screens.getGameScreen()); } }); save.addListener(new ClickListener() { @Override public void clicked(InputEvent event, float x, float y) { Savegame.save(); } }); mainMenu.addListener(new ClickListener() { @Override public void clicked(InputEvent event, float x, float y) { GameWindow.INSTANCE.setScreen(Screens.getMainMenuScreen()); } }); quit.addListener(new ClickListener() { @Override public void clicked(InputEvent event, float x, float y) { Gdx.app.exit(); } }); } @Override public void resize(int width, int height) { viewport.update(width, height); position = new Vector3(viewport.getScreenWidth() / 2, viewport.getScreenHeight() / 2, 0); camera.position.set(position); } }
常规刷新代码的问题
下面的代码会导致屏幕失去透明度:
Gdx.gl.glClearColor(0.35f, 0, 0f, 1); Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
按钮重复现象表现为点击后按钮出现多层重叠的残影。
问题根源与解决方法
问题根源
- 重复绘制按钮:
render方法中既通过batch手动绘制所有按钮,又调用stage.draw()——按钮已经被添加到Table并加入Stage,这导致按钮被绘制两次,点击后按钮状态变化(如按下效果),两次绘制状态不一致就会出现残影。 - 未清理缓冲区:没有调用
glClear(GL20.GL_COLOR_BUFFER_BIT),每一帧画面叠加在前一帧上,加剧残影问题。
解决步骤
- 删除手动绘制按钮的代码:移除
render中batch.begin()到batch.end()之间的所有按钮绘制逻辑,Stage会自动绘制所有添加的Actor。 - 保留透明背景并清理缓冲区:设置透明清除颜色后调用
glClear,既清空缓冲区又不遮挡下方的GameScreen。
修改后的render方法:
@Override public void render(float delta) { // 设置透明清除颜色,alpha值为0 Gdx.gl.glClearColor(0, 0, 0, 0f); // 清空颜色缓冲区,避免画面叠加 Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); // 仅保留Stage的更新与绘制 stage.act(delta); stage.draw(); }
- 额外优化:删除类中的
batch成员变量,因为Stage内部已维护自己的SpriteBatch,无需手动创建。
内容的提问来源于stack exchange,提问作者Morgoth
相关产品推荐
相关产品推荐

