0

When running my game, I am getting a null pointer exception. I didn't have this issue until after I created an attack class. Sometimes I can spam the attack button until all the enemies are destroyed, other times the exception is thrown nearly immediately (most of the time it happens when colliding with a wall or enemy). There are three main classes involved with attacks: Level1State, Champion, and Attack. Please help me find the error, I've been searching/testing for days.

Why does this happen? How does it become null sometimes while other times it works fine? Also, how can this be addressed?

As far as this being a duplicate question, every situation seems to be different. I have reviewed the other posts but have yet to find a solution to my problem spefically.

Exception in thread "LWJGL Application" java.lang.NullPointerException
at com.badlogic.gdx.graphics.g2d.SpriteBatch.switchTexture(SpriteBatch.java:1056)
at com.badlogic.gdx.graphics.g2d.SpriteBatch.draw(SpriteBatch.java:565)
at com.badlogic.gdx.graphics.g2d.Sprite.draw(Sprite.java:515)
at com.foxdonut.eiu.sprites.Champion.draw(Champion.java:225)
at com.foxdonut.eiu.states.Level1State.render(Level1State.java:172)
at com.badlogic.gdx.Game.render(Game.java:46)
at com.foxdonut.eiu.EIUGame.render(EIUGame.java:43)
at com.badlogic.gdx.backends.lwjgl.LwjglApplication.mainLoop(LwjglApplication.java:225)
at com.badlogic.gdx.backends.lwjgl.LwjglApplication$1.run(LwjglApplication.java:126)

Champion.Java (Line 225 is the very last line in this file)

public class Champion extends Sprite{
public enum champState {STANDING, RUNNING, JUMPING, FALLING, ATTACK, RUN_ATTACK}
public champState currentState;
public champState previousState;
public World world;
public Body b2body;
private TextureAtlas atlas;
private Level1State screen;
private Array<Attack> attacks;

// Champion States
private TextureRegion champStand;
private TextureRegion champAttack;
private Animation<TextureRegion> champRun;
private Animation<TextureRegion> champJump;
private Animation<TextureRegion> champRunAttack;

private boolean runningRight;
private float champStateTimer;   // how long in state

private Config config = Config.getInstance();

public Champion(Level1State screen){            
    atlas = new TextureAtlas("champion.pack");
    this.screen = screen;
    this.world = screen.getWorld();

    // Initialize states
    currentState = champState.JUMPING;
    previousState = champState.JUMPING;
    champStateTimer = 0;
    runningRight = true;

    // Create an array of texture regions to pass the constructor for the animation
    Array<TextureRegion> frames = new Array<TextureRegion>();

    // Run right animation
    // start x, start y, dimensions(x,y)
    for(int i = 1; i < 4; i++)
        frames.add(new TextureRegion(atlas.findRegion("champ"), i * 27, 5, 27, 25));
    champRun = new Animation<TextureRegion>(0.1f, frames);
    frames.clear();

    // Jump Animation
    for(int i = 4; i < 5; i++)
        frames.add(new TextureRegion(atlas.findRegion("champ"), 108, 0, 27, 30));
    champJump = new Animation<TextureRegion>(0.1f, frames);
    frames.clear();

    // Standing still
    champStand = new TextureRegion(atlas.findRegion("champ"), 0, 5, 27, 25);
    setBounds(0, 0, 27 / EIUGame.PPM, 25 / EIUGame.PPM);
    setRegion(champStand);

    // Standing still and attacking
    champAttack = new TextureRegion(atlas.findRegion("champ"), 0, 31, 27, 25);
    setBounds(0, 0, 27 / EIUGame.PPM, 25 / EIUGame.PPM);
    setRegion(champAttack);

    // Running and attacking
    for(int i = 1; i < 4; i++)
        frames.add(new TextureRegion(atlas.findRegion("champ"), i * 27, 31, 27, 25));
    champRunAttack = new Animation<TextureRegion>(0.1f, frames);
    frames.clear();

    defineChampion();

    setBounds(0, 0, 27 / EIUGame.PPM, 25 / EIUGame.PPM);
    setRegion(champStand);

    attacks = new Array<Attack>();
}

public void update(float dt){
    setPosition(b2body.getPosition().x -getWidth() / 2, b2body.getPosition().y - getHeight() / 2);
    setRegion(getFrame(dt));

    for(Attack atk : attacks){
        atk.update(dt);
        if(atk.isDestroyed())
            attacks.removeValue(atk, true);
    }
}

public TextureRegion getFrame(float dt){
    currentState = getState();

    TextureRegion region;
    switch(currentState){
        case STANDING:
            region = champStand;
            break;
        case JUMPING:
            region = (TextureRegion) champJump.getKeyFrame(champStateTimer, true);
            break;
        case RUNNING:
            region = (TextureRegion) champRun.getKeyFrame(champStateTimer, true);
            break;
        case FALLING:
            region = champStand;
            break;
        case ATTACK:
            region = champAttack;
            break;
        case RUN_ATTACK:
            region = (TextureRegion) champRunAttack.getKeyFrame(champStateTimer, true);
            break;
        default:
            region = champStand;
            break;
    }
    // Given that the sprite initially is facing right
    // If there is no x-axis velocity, or is running left, and region is not flipped (facing right)
    if((b2body.getLinearVelocity().x < 0 || !runningRight) && !region.isFlipX()){
        region.flip(true,  false);
        runningRight = false;
    }
    // If moving on x-axis or is running right, and region is flipped (facing left)
    else if((b2body.getLinearVelocity().x > 0 || runningRight) && region.isFlipX()){
        region.flip(true,  false);
        runningRight = true;
    }

    champStateTimer = currentState == previousState ? champStateTimer + dt : 0;
    previousState = currentState;
    return region;
}

// Returns the state of the character
public champState getState(){

    if(b2body.getLinearVelocity().y > 0 || (b2body.getLinearVelocity().y < 0 && previousState == champState.JUMPING))
        return champState.JUMPING;

    else if(b2body.getLinearVelocity().y < 0)
        return champState.FALLING;

    else if(Gdx.input.isKeyPressed(config.getAttackInt()) && (b2body.getLinearVelocity().x != 0))
        return champState.RUN_ATTACK;

    else if(b2body.getLinearVelocity().x != 0)
        return champState.RUNNING;

    else if(Gdx.input.isKeyJustPressed(config.getAttackInt()) && (b2body.getLinearVelocity().x == 0))
        return champState.ATTACK;

    else
        return champState.STANDING;
}

public void defineChampion(){
    BodyDef bdef = new BodyDef();                         // Define body

    bdef.position.set(196 / EIUGame.PPM, 128 / EIUGame.PPM); 
    bdef.type = BodyDef.BodyType.DynamicBody;             // Make character movable
    b2body = world.createBody(bdef);                      // Create the body

    FixtureDef fdef = new FixtureDef();                   // Define Fixture
    PolygonShape pShape = new PolygonShape(); 

    // Create a rectangle using an array of 4 vertices
    Vector2[] vertex = new Vector2[4];
    vertex[0] = new Vector2( 7,  9).scl(1 / EIUGame.PPM);
    vertex[1] = new Vector2( 7, -9).scl(1 / EIUGame.PPM);
    vertex[2] = new Vector2(-7, -9).scl(1 / EIUGame.PPM);
    vertex[3] = new Vector2(-7,  9).scl(1 / EIUGame.PPM); 

    pShape.set(vertex);

    fdef.filter.categoryBits = EIUGame.CHAMP_BIT;         // What we are
    fdef.filter.maskBits = EIUGame.GROUND_BIT         |   // What we can collide with
                           EIUGame.MEM_CHIP_BLUE_BIT  |
                           EIUGame.MEM_CHIP_GREEN_BIT |
                           EIUGame.MEM_CHIP_RED_BIT   |
                           EIUGame.ENEMY_BIT          |
                           EIUGame.ENEMY_HEAD_BIT     |
                           EIUGame.DEATH_BIT;

    fdef.shape = pShape;                                  // Define shape of fixture as polygon
    b2body.createFixture(fdef).setUserData(this);         // Create Fixture in body

    EdgeShape head = new EdgeShape();                     // Line between 2 different points
                                                          // A contact "sensor"
    // Relative to Box2D body Center
    // A point offset by -1 and 10 above head
    // A point offset by  1 and 10 above head
    head.set(new Vector2(-1 / EIUGame.PPM, 10 / EIUGame.PPM),
             new Vector2( 1 / EIUGame.PPM, 10 / EIUGame.PPM));

    fdef.shape = head;                                    // Set shape
    fdef.isSensor = true;                                 // Doesn't allow collision
                                                          //   Allows for query of data

    b2body.createFixture(fdef).setUserData("head");       // Uniquely sets fixture as "head"
}

public void attack(){
    attacks.add(new Attack(screen, b2body.getPosition().x, b2body.getPosition().y, runningRight ? true : false));
}

public void draw(Batch batch){
    super.draw(batch);
    for(Attack atk : attacks)
        atk.draw(batch);
}

}

Attack.Java

public class Attack extends Sprite{

Level1State screen;
World world;
TextureAtlas attackRightAtlas;
TextureAtlas attackLeftAtlas;
Array<TextureRegion> frames;
Animation <TextureRegion> attackRightAnimation;
Animation <TextureRegion> attackLeftAnimation;
TextureRegion region;
float stateTime;
boolean destroyed;
boolean setToDestroy;
boolean attackRight;

Body b2body;

public Attack(Level1State screen, float x, float y, boolean attackRight){

    this.attackRight = attackRight;
    this.screen = screen;
    this.world = screen.getWorld();

    if (attackRight){
        frames = new Array<TextureRegion>();
        attackRightAtlas = new TextureAtlas("attack/attackRight.pack");

        for (int i = 0; i < 3; i++)
            frames.add(new TextureRegion(attackRightAtlas.findRegion("attackRight"), i * 24, 0, 24, 25));

        attackRightAnimation = new Animation<TextureRegion>(0.1f, frames);
        //setRegion(attackRightAnimation.getKeyFrame(0));

        frames.clear();

        stateTime = 0;
        region = (TextureRegion) attackRightAnimation.getKeyFrame(stateTime, true);
    }
    else{
        frames = new Array<TextureRegion>();
        attackLeftAtlas = new TextureAtlas("attack/attackLeft.pack");

        for (int i = 0; i < 3; i++)
            frames.add(new TextureRegion(attackLeftAtlas.findRegion("attackLeft"), i * 24, 0, 24, 25));

        attackLeftAnimation = new Animation<TextureRegion>(0.1f, frames);
        //setRegion(attackLeftAnimation.getKeyFrame(0));

        frames.clear();

        stateTime = 0;
        region = (TextureRegion) attackLeftAnimation.getKeyFrame(stateTime, true);
    }

    setBounds(x, y, 24 / EIUGame.PPM, 25 / EIUGame.PPM);

    setToDestroy = false;
    destroyed = false;

    defineAttack();
}

public void defineAttack(){
    BodyDef bdef = new BodyDef();
    // Offset the attack so it appears to the side of the character
    bdef.position.set(attackRight ? getX() + 13.5f / EIUGame.PPM : getX() - 13.5f / EIUGame.PPM, getY());
    bdef.type = BodyDef.BodyType.DynamicBody;

    bdef.gravityScale = 0;

    if(!world.isLocked())
        b2body = world.createBody(bdef);

    FixtureDef fdef = new FixtureDef();                   // Define Fixture

    CircleShape shape = new CircleShape();
    shape.setRadius(5 / EIUGame.PPM);

    fdef.filter.categoryBits = EIUGame.ATTACK_BIT;        // What fixture is
    fdef.filter.maskBits = EIUGame.GROUND_BIT         |   // What fixture can collide with
                           EIUGame.MEM_CHIP_BLUE_BIT  |
                           EIUGame.MEM_CHIP_GREEN_BIT |
                           EIUGame.MEM_CHIP_RED_BIT   |
                           EIUGame.ENEMY_BIT;

    fdef.shape = shape;
    fdef.restitution = 1;
    fdef.friction = 0;

    b2body.createFixture(fdef).setUserData(this);
    b2body.setLinearVelocity(new Vector2(attackRight ? 3 : -3, 0));
}

public void update(float dt){
    stateTime += dt;

    if(setToDestroy && !destroyed){
        world.destroyBody(b2body);
        destroyed = true;
        stateTime = 0; 
    }
    else if (!destroyed){
        if (attackRight)
            setRegion(attackRightAnimation.getKeyFrame(stateTime, true));
        else
            setRegion(attackLeftAnimation.getKeyFrame(stateTime, true));

        setPosition(b2body.getPosition().x - getWidth() / 2, b2body.getPosition().y - getHeight() / 2);

        if((stateTime > 2  || setToDestroy) && !destroyed) {
            world.destroyBody(b2body);
            destroyed = true;
        }
        if(b2body.getLinearVelocity().y > 2f)
            b2body.setLinearVelocity(b2body.getLinearVelocity().x, 2f);
        if((attackRight && b2body.getLinearVelocity().x < 0) || (!attackRight && b2body.getLinearVelocity().x > 0))
            setToDestroy();
    }

}

public void setToDestroy(){
    setToDestroy = true;
}

public boolean isDestroyed(){
    return destroyed;
}

}

Level1State.Java (Error on line 172 is within render method) ----Line 172: champ.draw(mapRenderer.getBatch());

public class Level1State implements Screen {

private MusicAndSoundManager msm = MusicAndSoundManager.getInstance();
private Config config = Config.getInstance();   
private TextureAtlas atlas;
private OrthographicCamera gameCam, parallaxCam;
private Viewport gamePort;


private GamePad gamepad;

private Hud hud;    
private PauseState pause;

private TmxMapLoader maploader;                     // Loads a tilemap
private TiledMap map;                               // Reference to map itself
private OrthogonalTiledMapRenderer mapRenderer;     // Renders our map to screen
private Champion champ;

// Box2D variables
private World world;
private Box2DDebugRenderer b2dr;   // Shows outlines of fixtures and bodies in box2D world
private B2DWorldCreator creator;

private int backgroundLayer = 0;
private int foregroundLayer = 1;

private TiledMapImageLayer imgLayer;
private TiledMapTileLayer tileLayer;

public Level1State(EIUGame game) {
    gamepad = new GamePad();
    atlas = new TextureAtlas("champion.pack");

    gameCam = new OrthographicCamera();         // Centered on and follows the player
    parallaxCam = new OrthographicCamera();     // Follows the player at a slower rate and moves the background

    // Create a FitViewport to maintain virtual aspect ratio for the gameport and the parallax camera
    gamePort = new FitViewport(EIUGame.V_WIDTH / EIUGame.PPM, EIUGame.V_HEIGHT / EIUGame.PPM, gameCam);
    parallaxCam.setToOrtho(false, EIUGame.V_WIDTH / EIUGame.PPM, EIUGame.V_HEIGHT / EIUGame.PPM);

    // Center the camera at the gamePort
    gameCam.position.set(gamePort.getWorldWidth() / 2 +32f, gamePort.getWorldHeight() / 2, 0);

    // Map loading and layer definitions to specify what we are drawing for the map //
    maploader = new TmxMapLoader();
    map = maploader.load("TestLevel.tmx");

    imgLayer = (TiledMapImageLayer)map.getLayers().get(backgroundLayer);
    tileLayer = (TiledMapTileLayer)map.getLayers().get(foregroundLayer);

    // Pass our tile map to a MapRenderer so that we can manipulate the batch for drawing and update purposes
    mapRenderer = new OrthogonalTiledMapRenderer(map, 1 / EIUGame.PPM); 

    hud = new Hud(game.batch);                  // Add an instance of the game HUD      

    // Box2D initialization
    // Gravity set to -10, set bodies to "rest" that don't need physics calculations
    world = new World(new Vector2(0,-10), true);
    b2dr = new Box2DDebugRenderer(); 

    creator = new B2DWorldCreator(this);            // Create Box2D map

    // Create Champion in game world
    champ = new Champion(this); 

    // Contact listener for hitting head on objects
    world.setContactListener(new WorldContactListener());

    pause = new PauseState(game);
    pause.addPauseToStage(hud.stage);

    // Since we have multiple input processors to work with it'll be best to use a multiplexer
    InputMultiplexer multiplexer = new InputMultiplexer();
    multiplexer.addProcessor(hud.getStage());
    multiplexer.addProcessor(gamepad.getStage());
    Gdx.input.setInputProcessor(multiplexer);
}

// Simple method to return atlas
public TextureAtlas getAtlas(){
    return atlas;
}

@Override
public void show() {}

// Updating of Game World
public void update(float dt){


    // Clear the game screen with black            // Move to render
    Gdx.gl.glClearColor(0, 0, 0, 1);
    Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);

    for (Enemy enemy : creator.getCogs()){
        enemy.update(dt);

        if(!enemy.isDestroyed() && enemy.getX() < champ.getX() + 224 / EIUGame.PPM)
            enemy.b2body.setActive(true);
    }

    config.animateChamp(champ);
    gamepad.animateChamp(champ, pause);

    // Run at 60fps, velocity of 6, position 2
    world.step(1/60f, 6, 2);

    // Update the champion
    champ.update(dt);

    hud.update(dt);

    // Move camera with champion
    parallaxCam.position.x = champ.b2body.getPosition().x/2.00f + 1.1f;     
    parallaxCam.update();       
    mapRenderer.setView(parallaxCam);
    mapRenderer.renderImageLayer(imgLayer);     

    gameCam.position.x = champ.b2body.getPosition().x;      
    gameCam.update();       
    mapRenderer.setView(gameCam);
    mapRenderer.renderTileLayer(tileLayer);

}

@Override
public void render(float delta) {

    if(Gdx.input.isKeyJustPressed(Input.Keys.ESCAPE)) {
        pause.togglePause();                        
    }

    // If the game is paused prevent character movement and HUD updates
    if(!pause.getPauseState()) {

        // Get the batch to begin updating the screen
        mapRenderer.getBatch().begin(); 

        // Handles player movement
        update(delta);

        champ.draw(mapRenderer.getBatch()); 
        for (Enemy enemy : creator.getCogs())
            enemy.draw(mapRenderer.getBatch());

        mapRenderer.getBatch().end();

        //b2dr.render(world, gameCam.combined);
    }
    hud.stage.draw();   
    gamepad.draw();
} 

@Override
public void resize(int width, int height) {
    gamePort.update(width, height);
    gamepad.resize(width, height);
}

public TiledMap getMap(){
    return map;
}

public World getWorld(){
    return world;
}

@Override
public void pause() {}

@Override
public void resume() {}

@Override
public void hide() {}

@Override
public void dispose() {
    map.dispose();
    mapRenderer.dispose();
    world.dispose();
    b2dr.dispose();
    hud.dispose();
    gamepad.dispose();
}

}

I understand this is a lot to go through. However, I've spent a lot of time on this myself and couldn't seem to figure it out. Time to ask experts.

  • Most likely the `batch` in `atk.draw(batch)` is null. – greg-449 Mar 11 '17 at 07:44
  • why does this happen? How does it become null sometimes while other times it works fine? Also, how can this be addressed? –  Mar 11 '17 at 16:41
  • It happens because there are errors in your code somewhere. Go through all the answers in the duplicate question which describe how to diagnose problems like this. Learn how to use the Eclipse debugger. – greg-449 Mar 11 '17 at 16:52

0 Answers0