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.