I am currently working with Libgdx for Android and Desktop development and I ran into some trouble. (nothing specific with Libgdx). This is just a user error (aka I've been trying to fix this for 2 hours now and I'm completely stumped). So this is whats up: I created a class so I can simply use a string to load a Texture (to use as a spritesheet)
public class Animator{
private int FRAME_Y;
private int FRAME_X;
private Animation walk_down, walk_left, walk_right, walk_up, walk_spin;
private Animation MainAnimation;
private static Texture Sheet;
static TextureRegion[] walkRegion_down, walkRegion_left, walkRegion_right, walkRegion_up, walkRegion_spin;
private SpriteBatch spriteBatch;
static TextureRegion currentFrame;
static float stateTime;
private TextureRegion test;
private TextureRegion MainRegion;
public Animator(String location, int Y, int X, boolean flipped) {
this.FRAME_Y = Y;
this.FRAME_X = X;
Sheet = new Texture(Gdx.files.internal(location));
int frameWidth = Sheet.getWidth() / FRAME_Y;
int frameHeight = Sheet.getHeight() / FRAME_X;
TextureRegion[][] tmp = TextureRegion.split(Sheet, frameWidth, frameHeight);
MainRegion = new TextureRegion(Sheet, 0, 0, frameWidth, frameHeight);
MainAnimation = new Animation(0.2f, MainRegion, MainRegion);
spriteBatch = new SpriteBatch();
stateTime = 0f;
return;
}
public static void render(Animator G, float x, float y) {
SpriteBatch spriteBatch1 = new SpriteBatch();
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT);
stateTime += Gdx.graphics.getDeltaTime();
currentFrame = G.MainAnimation.getKeyFrame(stateTime);
spriteBatch1.begin();
spriteBatch1.draw(currentFrame, x, y);
spriteBatch1.end();
}}
Both of the funcitons are being used in this class / / / to create new Objects
public class LetSurviveMain extends Game{
//public static Entity player1;
public static Animator test, test2;
#Override
public void create () {
//Map = new TmxMapLoader().load("Tutorial.tmx");
//GameStart.show();
Animator test = new Animator("Animations/test.png", 4, 4, false);
Animator test2 = new Animator("Animations/test2.png", 4, 4, false);
}
#Override
public void render () {
//GameStart.render();
Animator.render(test, 150, 150);
Animator.render(test2, 250, 200);
}}
The exact console error is:
Exception in thread "LWJGL Application" java.lang.NullPointerException
at com.tlog.evil.Animator.render(Animator.java:71)
at com.tlog.evil.LetSurviveMain.render(LetSurviveMain.java:24)
at com.badlogic.gdx.backends.lwjgl.LwjglApplication.mainLoop(LwjglApplication.java:206)
at com.badlogic.gdx.backends.lwjgl.LwjglApplication$1.run(LwjglApplication.java:114)
And it points to line 71 in my Animator class, which is this:
currentFrame = G.MainAnimation.getKeyFrame(stateTime);
As I knew it would be an easy fix (just me over thinking it) Here is what I did:
Just removed the Animator In front of the assignement, as I already created one in the class. (the render method was referring to something that was never set.
Thanks guys!
Related
I'm reading a book about game development: Beginning Java Game Development with LibGDX.
There was a class named CheesePlease3 that I copied from the book, it presented the Stage class, and Actor class, I had to make a subclass from the Actor class, named BaseActor.
I did everything correctly, basically copy-pasted the whole thing, and it doesn't draw any object.
So my question is why? What is wrong?
Maybe the code itself a little bit long but easy to read.
Here is the CheesePlease3 class:
public class CheesePlease3 extends Game {
public Stage mainStage;
private BaseActor mouse;
private BaseActor cheese;
private BaseActor floor;
private BaseActor winText;
#Override
public void create () {
mainStage = new Stage();
floor = new BaseActor();
floor.setTexture(new Texture("floor.png"));
floor.setPosition(0, 0);
mainStage.addActor(floor);
cheese = new BaseActor();
cheese.setTexture(new Texture("cheese.png"));
cheese.setPosition(300, 300);
mainStage.addActor(cheese);
mouse = new BaseActor();
mouse.setTexture(new Texture("mouse.png"));
mouse.setPosition(200, 200);
mainStage.addActor(mouse);
winText = new BaseActor();
winText.setTexture(new Texture("youWon.png"));
winText.setPosition(150, 150);
winText.setVisible(false);
mainStage.addActor(winText);
}
#Override
public void render(){
// process input
mouse.velocityX = 0;
mouse.velocityY = 0;
if (Gdx.input.isKeyPressed(Input.Keys.LEFT))
mouse.velocityX -= 100;
if (Gdx.input.isKeyPressed(Input.Keys.RIGHT))
mouse.velocityX += 100;
if (Gdx.input.isKeyPressed(Input.Keys.UP))
mouse.velocityY -= 100;
if (Gdx.input.isKeyPressed(Input.Keys.DOWN))
mouse.velocityY += 100;
// update
float dt = Gdx.graphics.getDeltaTime();
mainStage.act(dt);
// check win condition: Mouse must be overlapping cheese
Rectangle mouseRectangle = mouse.getBoundingRectangle();
Rectangle cheeseRectangle = cheese.getBoundingRectangle();
if (mouseRectangle.contains(cheeseRectangle))
winText.setVisible(true);
// draw graphics
Gdx.gl.glClearColor(0.8f, 0.8f, 1, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
mainStage.draw();
}
And here is the BaseActor class:
public class BaseActor extends Actor {
public TextureRegion region;
public Rectangle boundary;
public float velocityX;
public float velocityY;
public BaseActor(){
super();
region = new TextureRegion();
boundary = new Rectangle();
velocityX = 0;
velocityY = 0;
}
public void setTexture (Texture t){
int w = t.getWidth();
int h = t.getHeight();
setWidth(w);
setHeight(h);
region.setRegion(t);
}
public Rectangle getBoundingRectangle(){
return boundary.set(getX(), getY(), getWidth(), getHeight());
}
#Override
public void act (float dt){
super.act(dt);
moveBy(velocityX * dt, velocityY * dt);
}
public void drawBatch (Batch batch, float parentAlpha){
Color c = getColor();
batch.setColor(c.r, c.g, c.b, c.a);
if (isVisible())
batch.draw(region, getX(), getY(), getOriginX(), getOriginY(),
getWidth(), getHeight(), getScaleX(), getScaleY(), getRotation());
}
And here is the DesktopLauncher:
public static void main (String[] arg) {
LwjglApplicationConfiguration config = new LwjglApplicationConfiguration();
new LwjglApplication(new CheesePlease3(), config);
config.title = "Mouse - Cheese";
}
The BaseActor has to override the draw method.
I assume the drawBatch method should be renamed to draw.
Ps.:
The movement for up and down is inverted.
Im trying to do a little game in LibGdx, right now i have a spaceship that can move with a touchpad in every directions and the camera follows it.
Im tryng to accomplish a parallax background made of stars that moves depending of where the spaceship is going.
Here it is the code, Im giving you all the class just to be sure to not mess up, for im new with this programming code.
public class TouchPadTest extends OrthographicCamera implements ApplicationListener {
public static final int WIDTH=480;
public static final int HEIGHT=800;
private OrthographicCamera camera;
private Stage stage;
private SpriteBatch batch;
private Touchpad touchpad;
private TouchpadStyle touchpadStyle;
private Skin touchpadSkin;
private Drawable touchBackground;
private Drawable touchKnob;
private Texture blockTexture;
private Sprite blockSprite;
private float blockSpeed;
public void create() {
batch = new SpriteBatch();
//Create camera
float aspectRatio = (float) Gdx.graphics.getWidth() / (float) Gdx.graphics.getHeight();
camera = new OrthographicCamera();
camera.setToOrtho(false, TouchPadTest.WIDTH, TouchPadTest.HEIGHT);
//Create a touchpad skin
touchpadSkin = new Skin();
//Set background image
touchpadSkin.add("touchBackground", new Texture("data/touchBackground.png"));
//Set knob image
touchpadSkin.add("touchKnob", new Texture("data/touchKnob.png"));
//Create TouchPad Style
touchpadStyle = new TouchpadStyle();
//Create Drawable's from TouchPad skin
touchBackground = touchpadSkin.getDrawable("touchBackground");
touchKnob = touchpadSkin.getDrawable("touchKnob");
//Apply the Drawables to the TouchPad Style
touchpadStyle.background = touchBackground;
touchpadStyle.knob = touchKnob;
//Create new TouchPad with the created style
touchpad = new Touchpad(10, touchpadStyle);
//setBounds(x,y,width,height)
touchpad.setBounds(15, 15, 200, 200);
//Create a Stage and add TouchPad
stage = new Stage(new FitViewport(Gdx.graphics.getWidth(),Gdx.graphics.getHeight()));
stage.addActor(touchpad);
Gdx.input.setInputProcessor(stage);
//Create block sprite
blockTexture = new Texture(Gdx.files.internal("data/shuttle2.png"));
blockSprite = new Sprite(blockTexture);
//Set position to centre of the screen
blockSprite.setPosition(Gdx.graphics.getWidth()/2-blockSprite.getWidth()/2, Gdx.graphics.getHeight()/2-blockSprite.getHeight()/2);
blockSpeed=5;
}
public void movePlayer(){
Vector2 v = new Vector2(touchpad.getKnobPercentX(), touchpad.getKnobPercentY());
float angle = v.angle();
if (touchpad.isTouched()){
blockSprite.setRotation(angle);
}
blockSprite.setX(blockSprite.getX() + touchpad.getKnobPercentX()*blockSpeed);
blockSprite.setY(blockSprite.getY() + touchpad.getKnobPercentY()*blockSpeed);
//Draw
camera.position.set(blockSprite.getX() + blockSprite.getWidth() / 2, blockSprite.getY() + blockSprite.getHeight() / 2, 0);
camera.update();
batch.setProjectionMatrix(camera.combined);
}
public void renderBackground() {
//---------------PARALLAX BACKGROUND---------------------//
}
public void dispose() {
}
public void render() {
Gdx.gl.glClearColor(0/255f,5/255f,15/255f,1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
//Move blockSprite with TouchPad
movePlayer();
batch.begin();
renderBackground();
blockSprite.draw(batch);
batch.end();
stage.act(Gdx.graphics.getDeltaTime());
stage.draw();
}
#Override
public void pause() {
}
#Override
public void resume() {
}
#Override
public void resize(int width, int height) {
}
}
For a better exemple, this is the kind of result that i want to achieve: https://www.youtube.com/watch?v=zA91SaOR-Io, if you can help me it will be amazing. Thank You.
This working example of a 3 layer parallax background was adapted from the LibGdx Parallax test and should give you an idea on how to implement a parallax effect. The three images used are all 1024x1024px.
import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.InputProcessor;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.math.Matrix4;
import com.badlogic.gdx.math.Vector3;
public class Test extends ApplicationAdapter implements InputProcessor{
private SpriteBatch batch;
private ParallaxCamera camera;
private Texture bgClose;
private Texture bgMid;
private Texture bgFar;
final Vector3 curr = new Vector3();
final Vector3 last = new Vector3(-1, -1, -1);
final Vector3 delta = new Vector3();
#Override
public void create () {
bgClose = new Texture(Gdx.files.internal("starbg-close.png"));
bgMid = new Texture(Gdx.files.internal("starbg-mid.png"));
bgFar = new Texture(Gdx.files.internal("starbg-far.png"));
camera = new ParallaxCamera(1920,1080);
batch = new SpriteBatch();
Gdx.input.setInputProcessor(this);
}
#Override
public void render () {
//clear screen
Gdx.gl.glClearColor(0f, 0f, 0f, 1f);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
// background layer, no parallax, centered around origin
batch.setProjectionMatrix(camera.calculateParallaxMatrix(0, 0));
batch.disableBlending();
batch.begin();
batch.draw(bgFar, -(int)(bgFar.getWidth() / 2), -(int)(bgFar.getHeight() / 2));
batch.end();
batch.enableBlending();
batch.setProjectionMatrix(camera.calculateParallaxMatrix(0.25f, 0.25f));
batch.begin();
for (int i = 0; i < 9; i++) {
batch.draw(bgMid, i * bgClose.getWidth() - 512, -512);
}
batch.end();
batch.setProjectionMatrix(camera.calculateParallaxMatrix(.5f, .5f));
batch.begin();
for (int i = 0; i < 9; i++) {
batch.draw(bgClose, i * bgClose.getWidth() - 512, -512);
}
batch.end();
}
//.. omitted empty methods ..//
#Override
public boolean touchUp(int screenX, int screenY, int pointer, int button) {
last.set(-1, -1, -1);
return false;
}
#Override
public boolean touchDragged(int x, int y, int pointer) {
camera.unproject(curr.set(x, y, 0));
if (!(last.x == -1 && last.y == -1 && last.z == -1)) {
camera.unproject(delta.set(last.x, last.y, 0));
delta.sub(curr);
camera.position.add(delta.x, delta.y, 0);
}
last.set(x, y, 0);
return false;
}
private class ParallaxCamera extends OrthographicCamera {
Matrix4 parallaxView = new Matrix4();
Matrix4 parallaxCombined = new Matrix4();
Vector3 tmp = new Vector3();
Vector3 tmp2 = new Vector3();
public ParallaxCamera (float viewportWidth, float viewportHeight) {
super(viewportWidth, viewportHeight);
}
public Matrix4 calculateParallaxMatrix (float parallaxX, float parallaxY) {
update();
tmp.set(position);
tmp.x *= parallaxX;
tmp.y *= parallaxY;
parallaxView.setToLookAt(tmp, tmp2.set(tmp).add(direction), up);
parallaxCombined.set(projection);
Matrix4.mul(parallaxCombined.val, parallaxView.val);
return parallaxCombined;
}
}
}
I'm learning libgdx and currently doing a flappy bird demo. For fun I tried to implement when the score reached a certain number the bird sprite texture will update and change to another color. Instead of using the spritebatch and changing the color through tinting I wanted to create a new texture(png file).
The problem is since it is a sprite it needs to be animated so the wings will flap. When I try and update the texture at runtime it will only work but the animation wont play.
Here is my bird class:
public class Bird {
private static final int GRAVITY = -15;
private static final int MOVEMENT = 100;
private Vector3 position;
private Vector3 velocity;
private Rectangle bounds;
private Animation birdAnimation;
private Texture birdTexture;
private TextureRegion textureRegion;
private Sound flap;
public Bird(int x, int y){
position = new Vector3(x, y, 0);
velocity = new Vector3(0, 0, 0);
textureRegion = new TextureRegion(returnTexture());
birdAnimation = new Animation(textureRegion, 3, 0.5f);
bounds = new Rectangle(x, y, returnTexture().getWidth() / 3, returnTexture().getHeight());
flap = Gdx.audio.newSound(Gdx.files.internal("sfx_wing.ogg"));
}
public void update(float dt){
textureRegion = new TextureRegion(returnTexture());
birdAnimation = new Animation(textureRegion, 3, 0.5f);
birdAnimation.update(dt);
if(position.y > 0){
velocity.add(0, GRAVITY, 0);
}
velocity.scl(dt);
position.add(MOVEMENT * dt, velocity.y, 0);
if(position.y < 0){
position.y = 0;
}
velocity.scl(1/dt);
bounds.setPosition(position.x, position.y);
}
public TextureRegion getTexture() {
return birdAnimation.getFrame();
}
public Texture returnTexture(){
if(PlayState.score > 1){
return birdTexture = new Texture("birdanimation1.png");
}else{
return birdTexture = new Texture("birdanimation.png");
}
}
public Vector3 getPosition() {
return position;
}
public void jump(){
velocity.y = 250;
flap.play(0.15f);
}
public Rectangle getBounds(){
return bounds;
}
public void dispose(){
returnTexture().dispose();
flap.dispose();
}
}
Here is my animation class:
public class Animation {
private Array<TextureRegion> frames;
private float maxFrameTime;
private float currentFrameTime;
private int frameCount;
private int frame;
public Animation(TextureRegion region, int frameCount, float cycleTime){
frames = new Array<TextureRegion>();
int frameWidth = region.getRegionWidth() / frameCount;
for(int i = 0; i < frameCount; i++){
frames.add(new TextureRegion(region, i * frameWidth, 0, frameWidth, region.getRegionHeight()));
}
this.frameCount = frameCount;
maxFrameTime = cycleTime / frameCount;
frame = 0;
}
public void update(float dt){
currentFrameTime += dt;
if(currentFrameTime > maxFrameTime){
frame++;
currentFrameTime = 0;
}
if(frame >= frameCount){
frame = 0;
}
}
public TextureRegion getFrame(){
return frames.get(frame);
}
}
Here's my render code in my play state:
#Override
public void render(SpriteBatch sb) {
sb.setProjectionMatrix(cam.combined);
sb.begin();
sb.draw(bg, cam.position.x - (cam.viewportWidth /2), 0);
sb.draw(bird.getTexture(), bird.getPosition().x, bird.getPosition().y);
for(Tube tube : tubes){
sb.draw(tube.getTopTube(), tube.getPosTopTube().x, tube.getPosTopTube().y);
sb.draw(tube.getBottomTube(), tube.getPosBotTube().x, tube.getPosBotTube().y);
}
sb.draw(ground, groundPos1.x, groundPos1.y);
sb.draw(ground, groundPos2.x, groundPos2.y);
font.draw(sb, text, cam.position.x - gl.width / 2, cam.position.y + 200);
sb.end();
}
If you need any other classes just ask. I'm probably making a stupid mistake or just coding it entirely wrong for what I'm trying to achieve.
Thanks, Jackson
You need to NOT load your textures every single frame.
libgdx has its own Animation class so you don't need to make your own.
Here is an example on animation from libgdx's github:
2D Animation
To make it simple, just have 2 animaitons on Bird and switch between them when you need to.
i'm creating a 2D platform game with Android Studio and LibGDX.
Right now, I'm implementing an on-screen controller to move the character, but when I start the launcher, it closes automatically.
When I run the launcher, this is what the console shows:
Exception in thread "LWJGL Application" java.lang.IllegalArgumentException: batch cannot be null.
at com.badlogic.gdx.scenes.scene2d.Stage.<init>(Stage.java:108)
at com.globapps.supermarioclon.Tools.Controles.<init>(Controles.java:30)
at com.globapps.supermarioclon.Screens.PantallaJuego.<init>(PantallaJuego.java:57)
at com.globapps.supermarioclon.MarioBros.create(MarioBros.java:34)
at com.badlogic.gdx.backends.lwjgl.LwjglApplication.mainLoop(LwjglApplication.java:147)
at com.badlogic.gdx.backends.lwjgl.LwjglApplication$1.run(LwjglApplication.java:124)
This is the code from the controller class:
public class Controles {
Viewport viewport;
Stage stage;
boolean salto, izquierda, derecha;
OrthographicCamera cam;
public Controles() {
cam = new OrthographicCamera();
viewport = new FitViewport(800, 480, cam);
stage = new Stage(viewport, PantallaJuego.batch);
Gdx.input.setInputProcessor(stage);
Table table1 = new Table();
Table table2 = new Table();
table1.left().bottom();
table2.right().bottom();
Image flechaizquierda = new Image(new Texture("flechaIzquierda.png"));
flechaizquierda.setSize(50, 50);
flechaizquierda.addListener(new InputListener() {
#Override
public boolean touchDown(InputEvent event, float x, float y, int pointer, int button) {
izquierda = true;
return true;
}
#Override
public void touchUp(InputEvent event, float x, float y, int pointer, int button) {
izquierda = false;
}
});
final Image flechaderecha = new Image(new Texture("flechaDerecha.png"));
flechaderecha.setSize(50, 50);
flechaderecha.addListener(new InputListener() {
#Override
public boolean touchDown(InputEvent event, float x, float y, int pointer, int button) {
derecha = true;
return true;
}
#Override
public void touchUp(InputEvent event, float x, float y, int pointer, int button) {
derecha = false;
}
});
Image flechasalto = new Image(new Texture("flechaIzquierda.png"));
flechasalto.setSize(50, 50);
flechasalto.addListener(new InputListener() {
#Override
public boolean touchDown(InputEvent event, float x, float y, int pointer, int button) {
salto = true;
return true;
}
#Override
public void touchUp(InputEvent event, float x, float y, int pointer, int button) {
}
});
table1.add();
table1.add(flechaizquierda).size(flechaizquierda.getWidth(), flechaizquierda.getHeight());
table1.add();
table1.row().pad(0, 5, 0, 5);
table1.add();
table1.add(flechaderecha).size(flechaderecha.getWidth(), flechaderecha.getHeight());
table2.add();
table2.add(flechasalto).size(flechasalto.getWidth(), flechasalto.getHeight());
table2.row().padRight(5);
table2.add();
stage.addActor(table1);
stage.addActor(table2);
}
public void draw() {
stage.draw();
}
public boolean isDerecha() {
return derecha;
}
public boolean isIzquierda() {
return izquierda;
}
public boolean isSalto() {
return salto;
}
public void resize(int ancho, int alto) {
viewport.update(ancho, alto);
}
}
And this is the PlayScreen class:
public class PantallaJuego extends ApplicationAdapter implements Screen {
private MarioBros game;
public static SpriteBatch batch;
private TextureAtlas atlas;
private OrthographicCamera gamecam, cam;
private Viewport gamePort, viewport;
private HUD hud;
private TmxMapLoader maploader;
private TiledMap map;
private OrthogonalTiledMapRenderer renderer;
private World world;
private Box2DDebugRenderer b2dr;
Controles controles;
private Mario player;
private Music musica;
public PantallaJuego(MarioBros game) {
atlas = new TextureAtlas("MarioyEnemigos.pack");
this.game = game;
gamecam = new OrthographicCamera();
gamePort = new FitViewport(MarioBros.V_WIDTH / MarioBros.PPM, MarioBros.V_HEIGHT / MarioBros.PPM, gamecam);
hud = new HUD(game.batch);
controles = new Controles();
batch = new SpriteBatch();
maploader = new TmxMapLoader();
map = maploader.load("nivel1mario.tmx");
renderer = new OrthogonalTiledMapRenderer(map, 1/MarioBros.PPM);
gamecam.position.set(gamePort.getWorldWidth()/2, gamePort.getWorldHeight()/2, 0);
world = new World(new Vector2(0,-10), true);
b2dr = new Box2DDebugRenderer();
player = new Mario(world, this);
new B2WorldCreator(world, map);
world.setContactListener(new WorldContactListener());
musica = MarioBros.manager.get("Audio/Música/Super Mario World - Overworld Theme Music (FULL VERSION).mp3", Music.class);
musica.setLooping(true);
musica.play();
}
public TextureAtlas getAtlas() {
return atlas;
}
#Override
public void show() {
}
public void handleInput(float dt) {
if(controles.isDerecha())
player.b2body.applyLinearImpulse(new Vector2(0.1f, 0), player.b2body.getWorldCenter(), true);
if(controles.isSalto())
MarioBros.manager.get("Audio/Sonidos/Super Mario Bros- Mario Jump Sound Effect.mp3", Sound.class).play();
player.b2body.applyLinearImpulse(new Vector2(0, 4f), player.b2body.getWorldCenter(), true);
if(controles.isIzquierda())
player.b2body.applyLinearImpulse(new Vector2(-0.1f, 0), player.b2body.getWorldCenter(), true);
}
public void update(float dt) {
handleInput(dt);
world.step(1 / 60f, 6, 2);
gamecam.position.x = player.b2body.getPosition().x;
cam.position.set(viewport.getWorldWidth() / 2, viewport.getWorldHeight() / 2, 0);
player.update(dt);
hud.update(dt);
if(Gdx.app.getType() == Application.ApplicationType.Android)
controles.draw();
gamecam.update();
cam.update();
renderer.setView(gamecam);
}
#Override
public void render(float delta) {
update(delta);
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
renderer.render();
b2dr.render(world, cam.combined);
b2dr.render(world, gamecam.combined);
game.batch.setProjectionMatrix(gamecam.combined);
game.batch.begin();
player.draw(game.batch);
game.batch.end();
game.batch.setProjectionMatrix(hud.stage.getCamera().combined);
hud.stage.draw();
}
If someone could help me, I'd be very grateful. Thank you.
I think you should instantiate your batch in PantallaJueago class before instantiating controles field.
public PantallaJuego(MarioBros game) {
atlas = new TextureAtlas("MarioyEnemigos.pack");
this.game = game;
gamecam = new OrthographicCamera();
gamePort = new FitViewport(MarioBros.V_WIDTH / MarioBros.PPM, MarioBros.V_HEIGHT / MarioBros.PPM, gamecam);
hud = new HUD(game.batch);
batch = new SpriteBatch();
controles = new Controles();
Because it is null while you instantiating your "controles". You are getting this error for your line
stage = new Stage(viewport, PantallaJuego.batch);
PantallaJuego.batch is null.
Well you should learn some more of the basics before you continue. This is related to a a NullPointerException and is usually very easy to fix. It tells you that you are trying to access a method or variable in nothing since you did not initialize it. Let's take your stack and find whats wrong.
Exception in thread "LWJGL Application" java.lang.IllegalArgumentException: batch cannot be null.
//Great! So let's fix this.
at com.badlogic.gdx.scenes.scene2d.Stage.<init>(Stage.java:108)
//This is a LibGDX class so there is probably nothing wrong with this
at com.globapps.supermarioclon.Tools.Controles.<init>(Controles.java:30)
//This is your class so let's go to this specific line, you can double click it.
stage = new Stage(viewport, PantallaJuego.batch);
//So either viewport or batch is null in this line.
//You can put a breakpoint here and run a debug,
//your program will stop on this line and you can hover
//to see what is in the variables. You will see that batch
// is null. Why, you may ask.
In the constructor of your main class you first set new Controles()
controles = new Controles();
Now the constructor of Controles will run and comes to this line:
stage = new Stage(viewport, PantallaJuego.batch);
And since your code did not reach batch = new SpriteBatch(); in PantallaJuego batch is still null and since stage does not accept that it will throw a NullPointer. A quick fix is to turn around new SpriteBatch() and new Controles().
The reason I say you should start learning the basics first is because your code is very poorly formed. You should format your code in a neat way and use much smaller methods since right now certain methods and constructors do all kind of stuff and it is very hard to read. Apart from this you are picking up very bad habits like making a global from that SpriteBatch (public static). There is really no need for this and it is partly responsible for your failure here.
Have a look at What is a NullPointerException, and how do I fix it? although your error is not a NullPointerException it is very related. Stage() does a check of it's own for it to be null and throws another exception before it tries to access it and get a nullpointer then.
Hello I am currently programming a LibGDX game based on physics with a ball that must stay on a platform, I have set up the physics components for the ball, but when I try updating the sprite for the ball based on the physic body's position it is giving me a null pointer exception.
I have spent 1 whole day trying to fix the problem through researching and looking at other peoples' code but cannot find my error. Thank you for your time and any input that you can give. Below I have typed the code from my Render class, Ball GameObject class, Asset class, and Exception.
Ball GameObject Class:
public class Ball {
public static World physicsWorld;
public static BodyDef ballBodyDef;
public static Body ballBody;
public static CircleShape ballShape;
public static FixtureDef ballFixtureDef;
public static Fixture ballFixture;
public Ball() {
physicsWorld = new World(new Vector2(0, -9.8f), true);
ballBodyDef = new BodyDef();
ballBodyDef.position.set(Assets.ballSprite.getX(),
Assets.ballSprite.getY());
ballBodyDef.type = BodyDef.BodyType.DynamicBody;
ballBody = physicsWorld.createBody(ballBodyDef);
ballShape = new CircleShape();
ballShape.setRadius(6f);
ballFixtureDef = new FixtureDef();
ballFixtureDef.density = 1.0f;
ballFixtureDef.friction = 0.2f;
ballFixtureDef.restitution = 0.4f;
ballFixture = ballBody.createFixture(ballFixtureDef);
}
public void dispose() {
physicsWorld.dispose();
ballShape.dispose();
}
public BodyDef getBallBodyDef() {
return ballBodyDef;
}
public void setBallBodyDef(BodyDef ballBodyDef) {
this.ballBodyDef = ballBodyDef;
}
public Body getBallBody() {
return ballBody;
}
public void setBallBody(Body ballBody) {
this.ballBody = ballBody;
}
public CircleShape getBallShape() {
return ballShape;
}
public void setBallShape(CircleShape ballShape) {
this.ballShape = ballShape;
}
public FixtureDef getBallFixtureDef() {
return ballFixtureDef;
}
public void setBallFixtureDef(FixtureDef ballFixtureDef) {
this.ballFixtureDef = ballFixtureDef;
}
public Fixture getBallFixture() {
return ballFixture;
}
public void setBallFixture(Fixture ballFixture) {
this.ballFixture = ballFixture;
}
}
Render Class:
public class GameRenderer {
private GameWorld myWorld;
private OrthographicCamera cam;
int width = Gdx.graphics.getWidth();
int height = Gdx.graphics.getHeight();
private SpriteBatch batch;
public GameRenderer(GameWorld world, int gameHeight, int midPointY) {
myWorld = world;
cam = new OrthographicCamera();
cam.setToOrtho(true, width, height);
batch = new SpriteBatch();
batch.setProjectionMatrix(cam.combined);
}
public void render(float delta) {
Gdx.app.log("GameRenderer", "render");
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
Ball.physicsWorld.step(Gdx.graphics.getDeltaTime(), 6, 2);
Assets.ballSprite.setPosition(Ball.ballBody.getPosition().x,
Ball.ballBody.getPosition().y);
batch.begin();
batch.draw(Assets.skySprite, 0, 0, 1920, 1080);
batch.draw(Assets.ballSprite, Assets.ballSprite.getX(),
Assets.ballSprite.getY());
batch.draw(Assets.platformSprite, Assets.platformSprite.getX(),
Assets.platformSprite.getY());
batch.end();
}
}
Lastly my Assets Class:
public class Assets {
public static Texture skyTexture;
public static Sprite skySprite;
public static Texture ballTexture;
public static Sprite ballSprite;
public static Texture platformTexture;
public static Sprite platformSprite;
public static Button rightTiltButton;
public static TextureAtlas rightButtonAtlas;
public static TextButtonStyle rightButtonStyle;
public static Skin rightButtonSkin;
public static void Load() {
skyTexture = new Texture(Gdx.files.internal("Assets/skybackground.png"));
skyTexture.setFilter(TextureFilter.Linear, TextureFilter.Linear);
skySprite = new Sprite(skyTexture);
skySprite.flip(false, true);
ballTexture = new Texture(
Gdx.files.internal("Assets/ballcharacter.png"));
ballTexture.setFilter(TextureFilter.Linear, TextureFilter.Linear);
ballSprite = new Sprite(ballTexture);
ballSprite.flip(false, true);
ballSprite.setPosition(
Gdx.graphics.getWidth() / 2 - ballSprite.getWidth()/2,
Gdx.graphics.getHeight() / 2 - ballSprite.getHeight()-4);
platformTexture = new Texture(Gdx.files.internal("Assets/platform.png"));
platformTexture.setFilter(TextureFilter.Linear, TextureFilter.Linear);
platformSprite = new Sprite(platformTexture);
platformSprite.flip(false, true);
platformSprite.setPosition(
Gdx.graphics.getWidth() / 2 - platformSprite.getWidth()/2,
Gdx.graphics.getHeight() / 2 - platformSprite.getHeight()/2);
rightButtonSkin = new Skin();
rightButtonAtlas = new TextureAtlas(
Gdx.files.internal("Assets/right_tilt_button.pack"));
rightButtonSkin.addRegions(rightButtonAtlas);
rightButtonStyle = new TextButtonStyle();
rightButtonStyle.up = rightButtonSkin.getDrawable("right_tilt_button");
rightButtonStyle.up = rightButtonSkin
.getDrawable("right_tilt_button_pressed");
rightButtonStyle.up = rightButtonSkin.getDrawable("right_tilt_button");
rightButtonStyle.over = rightButtonSkin
.getDrawable("right_tilt_button_pressed");
rightButtonStyle.down = rightButtonSkin
.getDrawable("right_tilt_button_pressed");
rightTiltButton = new Button(rightButtonStyle);
}
public static void dispose() {
skyTexture.dispose();
rightButtonAtlas.dispose();
rightButtonSkin.dispose();
ballTexture.dispose();
}
}
NullPointerException:
Exception in thread "LWJGL Application" java.lang.NullPointerException
at com.manumade.tiltr.tiltrhelpers.GameRenderer.render (GameRenderer.java:36)
at com.manumade.tiltr.screens.GameScreen.render(GameScreen.java:39)
at com.badlogic.gdx.Game.render(Game.java:46)
at com.badlogic.gdx.backends.lwjgl.LwjglApplication.mainLoop(LwjglApplication.java:208)
at com.badlogic.gdx.backends.lwjgl.LwjglApplication$1.run(LwjglApplication.java:114)
Looking at your code and stack trace there seems to be a problem on one of this lines:
batch.draw(Assets.skySprite, 0, 0, 1920, 1080);
batch.draw(Assets.ballSprite, Assets.ballSprite.getX(),
Assets.ballSprite.getY());
batch.draw(Assets.platformSprite, Assets.platformSprite.getX(),
Assets.platformSprite.getY());
From the stack trace that you provided we can see that the error is happening on line 36:
at com.manumade.tiltr.tiltrhelpers.GameRenderer.render (GameRenderer.java:36)
Look at your GameRenderer class and see what object gets called on that line. When you receive a NullPointerException it means that you are trying to call a method or acess a variable on a object that does not point to anything (The object might never be created.)
I would assume that either:
The SpriteBatch is NULL
Assets.skySprite is NULL
Assets.ballSprite is NULL
Assets.platformerSprite is NULL
So look at the way those object get instantiated. Also make sure that you are actually initializing them before performing anything on those objects. Your render() method might be called before you actually initialize the Sprite objects in your Assets class.
It looks like a problem with drawing one of your sprites (based on the exception line number). Try replacing the sprites you have used with other ones (obviously it will look silly), and see if any of them work.
Once you know which sprites work and which ones don't, you can try and narrow down what might be different about them. I have had similar problems caused by using non-power of two textures, for example.
I see that you call:
Assets.ballSprite.setPosition(Ball.ballBody.getPosition().x,
Ball.ballBody.getPosition().y);
batch.begin();
batch.draw(Assets.skySprite, 0, 0, 1920, 1080);
batch.draw(Assets.ballSprite,
Assets.ballSprite.getX(),
Assets.ballSprite.getY());
batch.draw(Assets.platformSprite,
Assets.platformSprite.getX(),
Assets.platformSprite.getY());
batch.end();
Assets.skySprite,
Assets.ballSprite,
Assets.platformSprite
but I can not see that you call Assets.load ();
before using the above why is null, because they are not initialized only declared or I think that's the error.
try calling Assets.Load (); before that used in render method, for example inside of the your public GameRenderer(...); method.
could try to read about it AssetsManager :
https://github.com/libgdx/libgdx/wiki/Managing-your-assets
and create a loading of assets before entering the playing area.(but it's just an idea).
could look at, www some tutorial about it AssetManager.
P.S: which is the line: (GameRenderer.java:36),
sure that the staticas variables used for example in Ball, are initialized before being used in render.