为啥我在更改屏幕并在 Libgdx 中绘制 Sprite 后得到 NPE
Posted
技术标签:
【中文标题】为啥我在更改屏幕并在 Libgdx 中绘制 Sprite 后得到 NPE【英文标题】:Why i get an NPE after changing Screen and Drawing a Sprite in Libgdx为什么我在更改屏幕并在 Libgdx 中绘制 Sprite 后得到 NPE 【发布时间】:2021-02-15 16:41:03 【问题描述】:这是我在这里提出的第一个问题,所以我很抱歉我在这里做错了什么。
我目前正在尝试在 libgdx 中开发我自己的第一个游戏。 所以一开始我有 4 节课。
-
从 Game 扩展而来的 FlipX 类。
StartMenu 一个从 Screen 实现的类。
GameScreen 一个从 Screen 实现的类。
Button 一个从 Sprite 扩展的类。
我希望我可以在这里向您展示一些代码,但让我先解释一下。 当启动类 FlipX 的代码时,我要在其中绘制 SpriteBatch,将屏幕设置为 StartMenu 类。在那里我可以单击从 FlipX 绘制到 SpriteBatch 的 2 个按钮。 这些按钮来自我创建的按钮类,用于将多个纹理存储到一个所谓的按钮。这个按钮类从 Sprite 扩展而来。 当我单击它时,PlayBtn 会将屏幕设置为 GameScreen 类。 当屏幕设置为 GameScreen 后,当 GameScreen 类在同一批次上绘制另一个 Button 时,就会出现问题。 它是 drawBatch() 函数中 GameScreen 的 Line,我在其中绘制 jumpBtn.draw(game.batch)。 当我这样做时,我收到以下错误。
Exception in thread "LWJGL Application" java.lang.NullPointerException
at com.badlogic.gdx.graphics.g2d.SpriteBatch.switchTexture(SpriteBatch.java:1067)
at com.badlogic.gdx.graphics.g2d.SpriteBatch.draw(SpriteBatch.java:558)
at com.badlogic.gdx.graphics.g2d.Sprite.draw(Sprite.java:580)
at de.geecogames.flipx.Screens.GameScreen.drawBatch(GameScreen.java:88)
at de.geecogames.flipx.Screens.GameScreen.render(GameScreen.java:63)
at com.badlogic.gdx.Game.render(Game.java:46)
at de.geecogames.flipx.FlipX.render(FlipX.java:26)
at com.badlogic.gdx.backends.lwjgl.LwjglApplication.mainLoop(LwjglApplication.java:232)
at com.badlogic.gdx.backends.lwjgl.LwjglApplication$1.run(LwjglApplication.java:127)
当我用一个简单的 Sprite 替换 Button 时,不会发生此错误,这很奇怪,因为 Button Class 只是一个扩展 Sprite 的类。 private Sprite jumpBtn = new Sprite(new Texture("game/UpDef.png"));
public class FlipX extends Game
public SpriteBatch batch;
//Filemanager to load Assets from an Asset Manager
public FileManager manager;
StartMenu startMenu;
@Override
public void create ()
manager= new FileManager();
startMenu=new StartMenu(this);
batch = new SpriteBatch();
setScreen(startMenu);
@Override
public void render ()
super.render();
@Override
public void dispose ()
batch.dispose();
public FileManager getFileManager()
return manager;
public class StartMenu implements Screen
private final FlipX game;
private final FileManager fileM;
private final OrthographicCamera camera;
private final FitViewport viewport;
private Sprite img = new Sprite(new Texture("badlogic.jpg"));
private final Button playBtn, exitBtn;
private final Sprite backGround;
private boolean playPressed, exitPressed;
public StartMenu(FlipX game)
this.game = game;
//Get Manager and load Assets
this.fileM = game.getFileManager();
fileM.loadAssetsMenu();
//Testlabel
Label testlabel = new Label(String.format("test"), new Label.LabelStyle(new BitmapFont(), Color.BLACK));
//Get the Assets from Manager
playBtn = new Button(fileM.getTexture(fileM.playBtnDefault), fileM.getTexture(fileM.playBtnHover), fileM.getTexture(fileM.playBtnClick));
exitBtn = new Button(fileM.getTexture(fileM.exitBtnDefault), fileM.getTexture(fileM.exitBtnHover), fileM.getTexture(fileM.exitBtnClick));
backGround = fileM.getSprite(fileM.backgroundMenu);
camera = new OrthographicCamera(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
viewport = new FitViewport(Z.V_WIDTH, Z.V_HEIGHT, camera);
camera.position.set(viewport.getWorldWidth() / 2, viewport.getWorldHeight() / 2, 0);
//Btn Position
playBtn.setPosition(Z.V_WIDTH / 2 - playBtn.getWidth() / 2, Z.V_HEIGHT / 2 - playBtn.getHeight() / 2);
exitBtn.setPosition(Z.V_WIDTH / 2 - exitBtn.getWidth() / 2, Z.V_HEIGHT / 2 - exitBtn.getHeight() / 2 - playBtn.getHeight() - playBtn.getHeight() / 2);
img.setPosition(0, 0);
@Override
public void render(float delta)
update(delta);
clearColor();
drawBatch();
private void update(float dt)
handleInput();
cameraUpdates();
private void clearColor()
Gdx.gl.glClearColor(0, 0.5f, 0.9f, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
private void drawBatch()
game.batch.setProjectionMatrix(camera.combined);
game.batch.begin();
backGround.draw(game.batch);
img.draw(game.batch);
//Buttons
playBtn.draw(game.batch);
exitBtn.draw(game.batch);
game.batch.end();
private void handleInput()
Vector3 realCoords = viewport.unproject(new Vector3(Gdx.input.getX(), Gdx.input.getY(), 0));
if (Gdx.input.isKeyPressed(Input.Keys.K))
float addX = 2;
float addY = 0;
img.setPosition(img.getX() + addX, img.getY() + addY);
if (Gdx.input.isKeyPressed(Input.Keys.UP))
camera.position.y = camera.position.y + 1;
else if (Gdx.input.isKeyPressed(Input.Keys.DOWN))
camera.position.y = camera.position.y - 1;
if (Gdx.input.isKeyPressed(Input.Keys.LEFT))
camera.position.x = camera.position.x - 1;
else if (Gdx.input.isKeyPressed(Input.Keys.RIGHT))
camera.position.x = camera.position.x + 1;
if (Gdx.input.isKeyPressed(Input.Keys.PAGE_UP))
camera.zoom = camera.zoom + 0.1f;
else if (Gdx.input.isKeyPressed(Input.Keys.PAGE_DOWN))
camera.zoom = camera.zoom - 0.1f;
//btn test
if (BasicFunctions.isInside(realCoords.x, realCoords.y, playBtn))
if (Gdx.input.justTouched())
playBtn.setClick();
playPressed = true;
fileM.playSound(fileM.playBtnSound);
else
if (playPressed)
game.setScreen(new GameScreen(game));
playBtn.setHover();
else
playBtn.setNormal();
if (BasicFunctions.isInside(realCoords.x, realCoords.y, exitBtn))
if (Gdx.input.isTouched())
exitBtn.setClick();
exitPressed = true;
else
if (exitPressed)
Gdx.app.exit();
exitBtn.setHover();
else
exitBtn.setNormal();
private void cameraUpdates()
camera.update();
public class GameScreen implements Screen
private final FlipX game;
private final FileManager fileM;
private final OrthographicCamera camera;
private final FitViewport viewport;
private final Button jumpBtn;
private final Sprite background;
public GameScreen(FlipX game)
this.game=game;
this.fileM=game.getFileManager();
fileM.loadAssetsGame();
camera=new OrthographicCamera(Gdx.graphics.getWidth(),Gdx.graphics.getHeight());
viewport = new FitViewport(Z.V_WIDTH,Z.V_HEIGHT,camera);
jumpBtn = new Button(new Texture("game/UpDef.png"),new Texture("game/UpHov.png"),new Texture("game/UpClick.png"));
jumpBtn.setPosition(2,2);
background = fileM.getSprite(fileM.backgroundMenu);
@Override
public void show()
@Override
public void render(float delta)
update(delta);
clearColor();
drawBatch();
private void update(float dt)
handleInput(dt);
private void clearColor()
Gdx.gl.glClearColor(1, 0.5f, 0.9f, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
private void drawBatch()
game.batch.setProjectionMatrix(camera.combined);
game.batch.begin();
background.draw(game.batch);
//Bug here?
jumpBtn.draw(game.batch);
game.batch.end();
private void handleInput(float dt)
Vector3 realCoords = viewport.unproject(new Vector3(Gdx.input.getX(), Gdx.input.getY(), 0));
if(Gdx.input.isTouched())
if(BasicFunctions.isInside(realCoords.x,realCoords.y,jumpBtn))
EzLog.logging("X " + jumpBtn.getX() + " Y " + jumpBtn.getY());
public class Button extends Sprite
private final Texture normal, hover, click;
private float stateTimer;
public Button(Texture normal, Texture hover, Texture click)
this.normal=normal;
this.hover=hover;
this.click=click;
stateTimer=0;
setSize();
private void setSize()
float height,width;
width=normal.getWidth();
height=normal.getHeight();
setBounds(0,0,width*3,height*3);
public void setNormal()
setRegion(normal);
public void setHover()
setRegion(hover);
public void setClick()
setRegion(click);
【问题讨论】:
【参考方案1】:几个小时后,我找到了解决方案。
问题是我的类按钮最多可以保存 3 个纹理。 要绘制其中一个纹理,我们可以使用它的绘制函数,因为 Button 是从 Sprite 扩展而来的。要在 SpriteBatch 上显示它,只需将纹理设置为区域。
setRegion("TextureHere.png")
所以每次我用 playBtn.draw(game.batch) 绘制它时,它都会在我之前用 setPosition(x,y) 给他的位置显示这个纹理
但我实际上从未在构造函数中执行“setRegion()”,因此它会尝试绘制不存在的东西。这就是为什么它说 NullPointerException。由于 SpriteBatch 中的 switchTexture 函数,我只是对错误感到困惑。 在 StartMenu 类中,巧合的是,它只是调用了“setRegion()”,因为它总是在“handleInput”中的条件的 else 部分中使用 Button 类中的函数“setNormal()”调用。
我知道的解决方案如下:
我在构造函数中添加了 setNormal() 函数,所以第一个纹理将始终设置为区域,如果我可以这样说的话,这很有效。
public class Button extends Sprite
private final Texture normal, hover, click;
public Button(Texture normal, Texture hover, Texture click)
this.normal=normal;
this.hover=hover;
this.click=click;
setSize();
setNormal();
private void setSize()
float height,width;
width=normal.getWidth();
height=normal.getHeight();
setBounds(0,0,width*3,height*3);
public void setNormal()
setRegion(normal);
public void setHover()
setRegion(hover);
public void setClick()
setRegion(click);
【讨论】:
以上是关于为啥我在更改屏幕并在 Libgdx 中绘制 Sprite 后得到 NPE的主要内容,如果未能解决你的问题,请参考以下文章