I have a very basic program, that is supposed to display a label and a text field. I am able to display the text. For the textfield, I can create it without error, but when I add it to the stage and run the program I have this error :
Exception in thread "LWJGL Application" java.lang.NullPointerException
at com.badlogic.gdx.scenes.scene2d.ui.TextField.draw(TextField.java:301)
at com.badlogic.gdx.scenes.scene2d.Group.drawChildren(Group.java:111)
at com.badlogic.gdx.scenes.scene2d.Group.draw(Group.java:58)
at com.badlogic.gdx.scenes.scene2d.Stage.draw(Stage.java:128)
at com.pace.converter.MainMenuScreen.render(MainMenuScreen.java:52)
at com.badlogic.gdx.Game.render(Game.java:46)
at com.pace.converter.MyGdxGame.render(MyGdxGame.java:21)
at com.badlogic.gdx.backends.lwjgl.LwjglApplication.mainLoop(LwjglApplication.java:207)
at com.badlogic.gdx.backends.lwjgl.LwjglApplication$1.run(LwjglApplication.java:114)
As I don't know how to put line numbers in the code block of my comments, here are the lines pointed by the error :
MainMenuScreen.java: 52 is
stage.draw();
MyGdxGame.java: 21 is
super.render();
I don't understand why I have this NullPointerException as I created the TextField before adding it to the stage.
And here is my complete code :
Main activity :
public class MyGdxGame extends Game {
SpriteBatch batch;
AssetManager assets;
#Override
public void create () {
batch = new SpriteBatch();
assets = new AssetManager();
this.setScreen(new LoadingScreen(this));
}
#Override
public void render () {
super.render();
}
public void dispose () {
batch.dispose();
}
}
Main menu screen :
public MainMenuScreen(final MyGdxGame gam) {
game = gam;
camera = new OrthographicCamera();
camera.setToOrtho(false, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
skin = new Skin(Gdx.files.internal("skin.json"));
stage = new Stage();
labelStyle = new LabelStyle(game.assets.get("font1.ttf", BitmapFont.class), Color.WHITE);
labelTest = new Label("Test", labelStyle);
textFieldTest = new TextField("Test", skin);
stage.addActor(labelTest);
stage.addActor(textFieldTest);
}
#Override
public void render(float delta) {
Gdx.gl.glClearColor(0.281f, 0.602f, 0.844f, 0);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
game.batch.setProjectionMatrix(camera.combined);
stage.act();
stage.draw();
}
First off all you need to check some things which could be null.. wrap your code in try-catch blocks
I don't know what is stage but check if it has been initialized or not ?
If stage is not null
then check in your Main menu Screen
skin = new Skin(Gdx.files.internal("skin.json")); // is the skin null ? if the file 'skin.json' couldn't be found then this would be null.. check this
textFieldTest = new TextField("Test", skin); // If skin is null, you're adding it here
as for the super.render(); is it even supposed to be called here ?
Related
So I've recently started tinkering with LibGDX (desktop only, at the moment) in Java. I'm mildly experienced with other type of OGL libraries in other languages (namely SFML in C++) and quite experienced with the Java language itself, so I tackled LibGDX pretty confidently; and while the results were mostly positive, there's a bug that I just can't figure out.
What I want to achieve is simple: draw a map (Tiled .tmx), draw a Sprite (soon-to-be "player") inbetween layers 1 and 2, and render a couple of GUI widgets on top of all that, using a scene2D stage. I've managed to achieve this partially.
Here's my Game class, it's pretty messy from so much switching things around just to try, but it's pretty clear what it attempts to do:
public class Game extends ApplicationAdapter
{
private SpriteBatch batch;
private Texture img;
private Sprite playerSprite;
private TiledMap tiledMap;
private OrthographicCamera camera;
private OrthogonalTiledMapRenderer tiledMapRenderer;
private Stage stage;
#Override
public void create () {
batch = new SpriteBatch();
img = new Texture("trchar000.png");
playerSprite = new Sprite(img, 0, 0, 32, 48);
playerSprite.setPosition(32, 192);
InputHandler.init();
Gdx.input.setInputProcessor(new InputHandler());
stage = new TestStage(playerSprite);
// inputs
InputMultiplexer im = new InputMultiplexer(stage, new InputHandler());
Gdx.input.setInputProcessor(im);
// tiles
camera = new OrthographicCamera();
camera.setToOrtho(false, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
camera.update();
tiledMap = new TmxMapLoader().load("map2.tmx");
tiledMapRenderer = new OrthogonalTiledMapRenderer(tiledMap);
}
#Override
public void render () {
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glBlendFunc(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
camera.update();
tiledMapRenderer.setView(camera);
int[] groundLayers = {0};
int[] topLayers = {1};
// render layer1 -> player -> layer 2
// the .tmx map doesn't have any other layers (just those 2)
tiledMapRenderer.render(groundLayers);
// removing these 3 lines solves the issue, but doesn't render the player
// I've also tried using my regular SpriteBatch instance; same results
// Also, I tried creating a class that extends OrthogonalTiledMapRenderer and overriding the render() method, so that it would draw the player inbetween layers, but again, same results.
tiledMapRenderer.getBatch().begin();
tiledMapRenderer.getBatch().draw(playerSprite, playerSprite.getX(), playerSprite.getY());
tiledMapRenderer.getBatch().end();
tiledMapRenderer.render(topLayers);
batch.begin();
// just to try, I'm rendering the stage here (not calling it's draw() method). Removing this for loop solves the issue, but doesn't render the GUI
for(Actor a : stage.getActors())
a.draw(batch, 1);
batch.end();
}
#Override
public void dispose () {
batch.dispose();
img.dispose();
tiledMapRenderer.dispose();
stage.dispose();
}
}
Also, here's my TestStage class:
public class TestStage extends Stage {
private Skin skin;
private BitmapFont newDefaultFont;
public TestStage(Sprite player)
{
super(new ScreenViewport());
// skin
FreeTypeFontGenerator freeTypeFontGenerator = new FreeTypeFontGenerator(Gdx.files.internal("segoeui.ttf"));
FreeTypeFontGenerator.FreeTypeFontParameter parameter = new FreeTypeFontGenerator.FreeTypeFontParameter();
parameter.size = 14;
newDefaultFont = freeTypeFontGenerator.generateFont(parameter);
skin = new Skin();
skin.add("default-font", newDefaultFont, BitmapFont.class);
FileHandle fileHandle = Gdx.files.internal("uiskin.json");
FileHandle atlasFile = fileHandle.sibling("uiskin.atlas");
if (atlasFile.exists()) {
skin.addRegions(new TextureAtlas(atlasFile));
}
skin.load(fileHandle);
final TextButton button = new TextButton("This is a Button", skin, "default");
button.setPosition(250, 250);
button.setWidth(150);
button.setHeight(40);
final Label lbl = new Label("Test", skin);
this.addActor(lbl);
this.addActor(button);
}
}
Now here's the deal; this is what it looks like if a try to render everything (as shown in my Game class' render() method):
Image 1
The player, GUI, and layer 2 are rendered correctly, but the layer 1 is all bugged out, and I can't figure out why.
Now, here's how it looks like if a don't render the player, removing the line
tiledMapRenderer.getBatch().draw(playerSprite, playerSprite.getX(), playerSprite.getY());
Image 2
Everything renders fine.
Also, here's what it looks like if I decide not to render the stage actors, commenting this loop:
for(Actor a : stage.getActors())
a.draw(batch, 1);
Image 3
Again, everything renders fine.
The only other classes in my project are the default DesktopLauncher class, and an InputProcessor which I'm sure has nothing to do with this.
This is my first question here ever; I just can't figure this out.
Thanks in advance.
This is my code:
game init:
playerAtlas = new TextureAtlas(Gdx.files.internal("spineboy.atlas"));
json = new SkeletonJson(playerAtlas);
playerSkeletonData = json.readSkeletonData(Gdx.files.internal("spineboy.json"));
playerAnimationData = new AnimationStateData(playerSkeletonData);
batch = new SpriteBatch();
skeletonRenderer = new SkeletonRenderer();
skeleton = new Skeleton(playerSkeletonData);
animationState = new AnimationState(playerAnimationData);
animationState.setAnimation(0, "walk", true); // trackIndex, name, loop
render:
animationState.update(Gdx.graphics.getDeltaTime());
animationState.apply(skeleton);
batch.begin();
skeletonRenderer.draw(batch, skeleton);
batch.end();
Gdx.app.log("rendering", "x" +skeleton.getX());
Gdx.app.log("rendering", "y"+skeleton.getY());
skeleton.setPosition(300, 300);
And for some reason, I can't get my animation to show up.
I got this code from here and copied it:
https://gamedev.stackexchange.com/questions/98890/implementing-spine-animations-in-libgdx
I cant figure out why the animation isn't rendering!!
Can anyone please help?
Try this Test Class :
public class SimpleTest1 extends ApplicationAdapter {
OrthographicCamera camera;
SpriteBatch batch;
SkeletonRenderer renderer;
SkeletonRendererDebug debugRenderer;
TextureAtlas atlas;
Skeleton skeleton;
AnimationState state;
public void create () {
camera = new OrthographicCamera();
batch = new SpriteBatch();
renderer = new SkeletonRenderer();
renderer.setPremultipliedAlpha(true); // PMA results in correct blending without outlines.
debugRenderer = new SkeletonRendererDebug();
debugRenderer.setBoundingBoxes(false);
debugRenderer.setRegionAttachments(false);
atlas = new TextureAtlas(Gdx.files.internal("spineboy/spineboy.atlas"));
SkeletonJson json = new SkeletonJson(atlas); // This loads skeleton JSON data, which is stateless.
json.setScale(0.6f); // Load the skeleton at 60% the size it was in Spine.
SkeletonData skeletonData = json.readSkeletonData(Gdx.files.internal("spineboy/spineboy.json"));
skeleton = new Skeleton(skeletonData); // Skeleton holds skeleton state (bone positions, slot attachments, etc).
skeleton.setPosition(250, 20);
AnimationStateData stateData = new AnimationStateData(skeletonData); // Defines mixing (crossfading) between animations.
stateData.setMix("run", "jump", 0.2f);
stateData.setMix("jump", "run", 0.2f);
state = new AnimationState(stateData); // Holds the animation state for a skeleton (current animation, time, etc).
state.setTimeScale(0.5f); // Slow all animations down to 50% speed.
// Queue animations on track 0.
state.setAnimation(0, "run", true);
state.addAnimation(0, "jump", false, 2); // Jump after 2 seconds.
state.addAnimation(0, "run", true, 0); // Run after the jump.
}
public void render () {
state.update(Gdx.graphics.getDeltaTime()); // Update the animation time.
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
state.apply(skeleton); // Poses skeleton using current animations. This sets the bones' local SRT.
skeleton.updateWorldTransform(); // Uses the bones' local SRT to compute their world SRT.
// Configure the camera, SpriteBatch, and SkeletonRendererDebug.
camera.update();
batch.getProjectionMatrix().set(camera.combined);
debugRenderer.getShapeRenderer().setProjectionMatrix(camera.combined);
batch.begin();
renderer.draw(batch, skeleton); // Draw the skeleton images.
batch.end();
debugRenderer.draw(skeleton); // Draw debug lines.
}
public void resize (int width, int height) {
camera.setToOrtho(false); // Update camera with new size.
}
public void dispose () {
atlas.dispose();
}
}
I can't add comments, but there is a some additional info for Abhishek Aryan's post.
Now (oct, 22)you should use:
PolygonSpriteBatch batch;
..
batch = new PolygonSpriteBatch ();
to make his code work.
I am working on an Android game with LibGDX and would like to implement two TextFields to login to a server.
As far as I know I need to use Stage to add a TextField as an Actor like this:
this.stage = new Stage();
TextField txtf = new TextField("", mSkin);
//...
stage.addActor(txtf);
// And then set the stage as InputProcessor
Gdx.input.setInputProcessor(this.stage);
But I already have a custom InputHandler which implements InputProcessor. I don't really know how I can handle a TextField with my InputHandler.
I have created my TextField in my InputHandler like this:
public class InputHandler implements InputProcessor {
public InputHandler(float ratioWidth, float ratioHeight, GameWorld world) {
this.world = world;
this.player = world.getPlayer();
this.ratioWidth = ratioWidth;
this.ratioHeight = ratioHeight;
//...
this.usernameTextField = new TextField("", AssetLoader.defaultSkin);
this.usernameTextField.setPosition(24,73);
this.usernameTextField.setSize(88, 14);
this.passwordTextField = new TextField("", AssetLoader.defaultSkin);
this.passwordTextField.setPosition(24, 102);
this.passwordTextField.setSize(88, 14);
this.actors.add(this.usernameTextField);
this.actors.add(this.passwordTextField);
}
And then I have a method in my InputHandler that can get the TextField for the GameRenderer:
public ArrayList<Actor> getActors() { return this.actors; }
And this is my GameRenderer:
public class GameRenderer {
public GameRenderer(GameWorld world) {
this.world = world;
//...
}
//...
private void drawLogUI() {
for(Actor a : ((InputHandler) Gdx.input.getInputProcessor()).getActors()){
a.draw(batcher, 1);
}
//...
}
public void render(float delta) {
// Initialisation
Gdx.gl.glClearColor(32/255.0f, 72/255.0f, 132/255.0f, 1f);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
batcher.begin();
batcher.enableBlending();
//...
drawLogUI();
//...
batcher.end();
}
//...
}
TextFields are rendering correctly but I can't do anything with them, keyboard doesn't show up, etc. Can someone explain how I can use them in my project ?
You know that you need to use Stage and TextField for your requirement, you created TextField but not adding to stage so you're not using scene2d(stage, actor, textfield..)
Tutorial that you following, don't have stage so he is using InputProcessor for his requirement.
TextField usernameTextField = new TextField("", AssetLoader.defaultSkin);
usernameTextField.setPosition(24,73);
usernameTextField.setSize(88, 14);
stage.add(usernameTextField); // <-- Actor now on stage
Gdx.input.setInputProcessor(stage);
Inside render() method call
stage.draw();
stage.act();
Hello the following code is from my main class trying to call another class i made which implements screen.
if (grumpface.whiteballoon.getBoundingRectangle().overlaps(spriterect)) {
System.out.println("hey");
setScreen(new GameOverScreen());
}
;
here is the class i am calling.
class GameOverScreen implements Screen{
private Stage stage;
// Called automatically once for init objects
#Override
public void show() {
stage = new Stage();
float delta = Gdx.graphics.getDeltaTime();
stage.setDebugAll(true); // Set outlines for Stage elements for easy debug
BitmapFont white = new BitmapFont(Gdx.files.internal("hazey.fnt"), false);
LabelStyle headingStyle = new LabelStyle(white, Color.WHITE);
Label gameoverstring = new Label("game ovaaaa!", headingStyle);
gameoverstring.setPosition(100, 100);
stage.addActor(gameoverstring);
}
// Called every frame so try to put no object creation in it
#Override
public void render(float delta) {
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
System.out.println("hey");
stage.act(delta);
stage.draw();
}
even though i am not returning any stack errors, my program still will not switch screen whenever the event is performed. i can tell the gameoverscreen class is getting called, because whenever the event happens the System.out.println("hey"); is triggered and starts in the console. however, there is no color clear or label drawing like there should be.
Don't use Show() like that. You should initialize your objects in your constructor. maybe try to set screen like that :
((com.badlogic.gdx.Game) Gdx.app.getApplicationListener())
.setScreen(new GameScreen());
We need to see more code to help you
ps i can't comment, but the link : https://code.google.com/p/libgdx-users/wiki/ScreenAndGameClasses is outdated, check it : https://github.com/libgdx/libgdx/wiki
Hey everyone I am really new to libgdx and Open GL so I am having trouble with this sample project I have to do. Here is my code it should be simply displaying a three buttons from a .batch file any help is greatly appreciated. After going through the debugger the only thing I could see was that the call to get draw able returned object[o] but if it didn't find anything why didn't it error out?
public MainScreen() {
spriteBatch = new SpriteBatch();
stage = new Stage(Gdx.graphics.getWidth(), Gdx.graphics.getHeight(), false, spriteBatch);
font = new BitmapFont(Gdx.files.internal("assets/font.fnt"),
Gdx.files.internal("assets/font.png"), false);
buttons = new TextureAtlas("assets/GameButtons.pack");
images = new Skin();
images.addRegions(buttons);
SFXButton = new Button(images.getDrawable("sfxButton"));
SFXButton.setPosition(295, 310);
APIButton = new Button(images.getDrawable("apiButton"));
APIButton.setPosition(405, 310);
GameButton = new Button(images.getDrawable("gameButton"));
GameButton.setPosition(515, 310);
SFXClick = Gdx.audio.newSound(Gdx.files.internal("assets/button_click.wav"));
}
#Override
public void dispose() {
spriteBatch.dispose();
stage.dispose();
}
#Override
public void render(float delta) {
stage.act(delta);
stage.draw();
stage.addActor(SFXButton);
stage.addActor(APIButton);
stage.addActor(GameButton);
spriteBatch.begin();
font.setColor(Color.RED);
font.draw(spriteBatch, "PennyPop", 455 - font.getBounds("PennpyPop").width/2,
460 + font.getBounds("PennyPop").height/2);
if (SFXButton.isPressed())
SFXClick.play();
spriteBatch.end();
}
OUCH! No way you want to add buttons to your stage every render, with 60 FPS and 3 buttons, that would add 180 buttons to your stage per second, and for every second, until you close your app.
public void render(float delta) {
stage.act(delta);
stage.draw();
stage.addActor(SFXButton); //problem here
stage.addActor(APIButton); //and here
stage.addActor(GameButton); //and here
Move the buttons adding to the constructor, see if it will solve the problem.