简体   繁体   中英

AndEngine: Getting a NullPointerException on UpdateThread when adding a Sprite

Getting a NullPointerException on UpdateThread when adding a Sprite

I'm creating my first game in AndEngine and I am simply trying to add a Sprite to my GameScene class. I've been tinkering with it for hours now as my application kept crashing after my splash screen, which is supposed to load my GameScene afterwards. I've narrowed it down to these of code in my drawPanel() method:

selectPanel[0] = new Sprite(0, 0, resourceManager.ballTextureRegionArray[0], vbom) {
    @Override
    protected void preDraw(GLState pGLState, Camera pCamera) {
        super.preDraw(pGLState, pCamera);
        pGLState.enableDither();
    }
};
selectPanel[0].setPosition(240, 400);
attachChild(selectPanel[0]);

Here is my ResourceManager class where I loaded the ball texture:

    ballTexture = new BitmapTextureAtlas(act.getTextureManager(), 64, 576);

    ballTextureRegionArray[0] = BitmapTextureAtlasTextureRegionFactory
            .createFromAsset(ballTexture, act, "red_ball.png", 0, 0);
    ballTextureRegionArray[1] = BitmapTextureAtlasTextureRegionFactory
            .createFromAsset(ballTexture, act, "blue_ball.png", 0, 64);
    ballTextureRegionArray[2] = BitmapTextureAtlasTextureRegionFactory
            .createFromAsset(ballTexture, act, "green_ball.png", 0, 128);
    ballTextureRegionArray[3] = BitmapTextureAtlasTextureRegionFactory
            .createFromAsset(ballTexture, act, "purple_ball.png", 0, 192);
    ballTextureRegionArray[4] = BitmapTextureAtlasTextureRegionFactory
            .createFromAsset(ballTexture, act, "yellow_ball.png", 0, 256);
    ballTextureRegionArray[5] = BitmapTextureAtlasTextureRegionFactory
            .createFromAsset(ballTexture, act, "orange_ball.png", 0, 320);
    ballTextureRegionArray[6] = BitmapTextureAtlasTextureRegionFactory
            .createFromAsset(ballTexture, act, "black_ball.png", 0, 384);
    ballTextureRegionArray[7] = BitmapTextureAtlasTextureRegionFactory
            .createFromAsset(ballTexture, act, "white_ball.png", 0, 448);
    ballTextureRegionArray[8] = BitmapTextureAtlasTextureRegionFactory
            .createFromAsset(ballTexture, act, "select_ball.png", 0, 512);

    ballTexture.load(); // load ballTexture to the scene

... and of course the error.

11-28 17:44:44.750: E/AndroidRuntime(2119): FATAL EXCEPTION: UpdateThread
11-28 17:44:44.750: E/AndroidRuntime(2119): java.lang.NullPointerException
11-28 17:44:44.750: E/AndroidRuntime(2119):     at   com.eklypze.android.mastermdhd.GameScene.drawPanel(GameScene.java:188)
11-28 17:44:44.750: E/AndroidRuntime(2119):     at     com.eklypze.android.mastermdhd.GameScene.createScene(GameScene.java:68)
11-28 17:44:44.750: E/AndroidRuntime(2119):     at     com.eklypze.android.mastermdhd.BaseScene.<init>(BaseScene.java:38)
11-28 17:44:44.750: E/AndroidRuntime(2119):     at com.eklypze.android.mastermdhd.GameScene.<init>(GameScene.java:28)
11-28 17:44:44.750: E/AndroidRuntime(2119):     at com.eklypze.android.mastermdhd.SceneManager.createGameScene(SceneManager.java:120)
11-28 17:44:44.750: E/AndroidRuntime(2119):     at com.eklypze.android.mastermdhd.BaseActivity$1.onTimePassed(BaseActivity.java:84)
11-28 17:44:44.750: E/AndroidRuntime(2119):     at org.andengine.engine.handler.timer.TimerHandler.onUpdate(TimerHandler.java:94)
11-28 17:44:44.750: E/AndroidRuntime(2119):     at org.andengine.engine.handler.UpdateHandlerList.onUpdate(UpdateHandlerList.java:47)
11-28 17:44:44.750: E/AndroidRuntime(2119):     at org.andengine.engine.Engine.onUpdateUpdateHandlers(Engine.java:618)
11-28 17:44:44.750: E/AndroidRuntime(2119):     at org.andengine.engine.Engine.onUpdate(Engine.java:605)
11-28 17:44:44.750: E/AndroidRuntime(2119):     at org.andengine.engine.Engine.onTickUpdate(Engine.java:568)
11-28 17:44:44.750: E/AndroidRuntime(2119):     at org.andengine.engine.Engine$UpdateThread.run(Engine.java:858)

Here is my GameScene.java class:

package com.eklypze.android.mastermdhd;

import java.util.Random;

import javax.microedition.khronos.opengles.GL10;

import org.andengine.engine.camera.Camera;
import org.andengine.entity.modifier.AlphaModifier;
import org.andengine.entity.modifier.LoopEntityModifier;
import org.andengine.entity.scene.background.SpriteBackground;
import org.andengine.entity.sprite.Sprite;
import org.andengine.input.touch.TouchEvent;
import org.andengine.opengl.util.GLState;

import android.util.Log;

import com.eklypze.android.mastermdhd.SceneManager.SceneType;

public class GameScene extends BaseScene {
    /*** DECLARATIONS ***/
    /* Settings */
    protected static final int CAMERA_WIDTH = 480;
    protected static final int CAMERA_HEIGHT = 800;
    /* Sprites */
    Sprite[] selectPanel = new Sprite[8];
    Sprite boardPieces[] = new Sprite[40];
    Sprite bwPegs[] = new Sprite[10];
    Sprite nextSpot; // "next spot" cursor
    Sprite gameoverLose, gameoverWin; // REPLACE with scenes
    /* Game Options */
    private int turn = 0;
    private int turnCounter = 0; // per line turn counter
    private int currentX = 1;
    private int currentY = 13;
    private int[] code = new int[4]; // array to store generated code
    private int[] codeCopy = new int[4]; // for black&white peg use
    private int blackPegs = 0, whitePegs = 0;
    // remember to take currentX-1 as the array indexes
    private int[] currentXValues = new int[4];
    // dummy variable when drawing selectPanel for touch *don't delete*
    private int z = 0;
    Boolean gameOver = false;
    Boolean doublesAllowed = false;

    /************************************
     * ------------INHERITED------------
     ************************************/

    @Override
    /********************************
     * createScene()
     ********************************/
    public void createScene() {
        // create scene with bgSprite background
        setBackground(new SpriteBackground(resourceManager.bgSprite));
        // STEP 1: Start a New Game
        newGame();
        // STEP 2: Draw selectPanel
        drawPanel(); // debugging: game seems to work up until this point

    }

    @Override
    /********************************
     * onBackKeyPressed()
     ********************************/
    public void onBackKeyPressed() {
        System.exit(0);
    }

    @Override
    /********************************
     * getSceneType()
     ********************************/
    public SceneType getSceneType() {
        return SceneType.SCENE_GAME;
    }

    @Override
    /********************************
     * disposeScene()
     ********************************/
    public void disposeScene() {
        this.detachSelf();
        this.dispose();
    }

    /************************************
     * -----------GAME METHODS-----------
     ************************************/

    /********************************
     * newGame()
     * Description: Initialize game
     * settings for a new session.
     ********************************/
    private void newGame() {
        /* [START] Generate New Code Combination
        for (int x = 0; x < 4; x++) {
            Random r = new Random();
            // if doubles is not allowed check if new generated number is
            // a double, if yes, generate another number. NOTE: doubles are
            // defaulted to 'OFF' until feature is added.
            int randomNumber = r.nextInt(8); // why (7-0)+0?
            Log.v("randomR", "Number generated is " + randomNumber);
            code[x] = randomNumber;
            // write to log (debugging)
            Log.v("theCode", "Number generated for " + x + " is: " + code[x]
                    + " (" + resourceManager.ballColours[randomNumber] + ")");
            // if doubles is not allowed check if new generated number is
            // a double, if yes, generate another number. NOTE: doubles are
            // defaulted to 'OFF' until feature is added.
            if (!doublesAllowed && x > 0) {
                for (int y = x - 1; y >= 0; y--) {
                    // Log.v("theY", "y is "+y);
                    if (code[y] == randomNumber) {
                        x--;
                    }
                }
            }
        } [END] Generate New Code Combination */
        code = new int[] { 7, 1, 2, 3 };
        Log.v("theCode", "The Code Is: " + code[0] + "," + code[1] + ","
                + code[2] + "," + code[3] + ".");
        codeCopy = code.clone(); // copies code array for white/black peg use
    }

    /********************************
     * drawPanel()
     * Description: Draw the panels
     * required for user selection.
     ********************************/
    private void drawPanel() {
        int column = 7; // constant?
        int rowStart = 2;

        /* [START] Draw Selection selectPanel
        for (int i = 0; i < 8; i++) {
            final int j = i;
            selectPanel[i] = new Sprite(grid_xPixel(column),
                    grid_yPixel(rowStart),
                    resourceManager.ballTextureRegionArray[i], vbom) {
                @Override
                /* [START] Touch Detection
                public boolean onAreaTouched(TouchEvent pSceneTouchEvent,
                        float pTouchAreaLocalX, float pTouchAreaLocalY) {
                    switch (pSceneTouchEvent.getAction()) {
                            // On Touch
                            case TouchEvent.ACTION_DOWN:
                                this.setScale(2.0f); // enlarge effect
                                z = j;
                                Log.v("thisIsZ", "Z: " + z);
                                break;
                            // On Move/Drag
                            case TouchEvent.ACTION_MOVE: {
                                /* to be implemented in the future
                                // this.setPosition(pSceneTouchEvent.getX() -
                                // this.getWidth()/2, pSceneTouchEvent.getY() -
                                // this.getHeight()/2);
                                break;
                            }
                            // On Release
                            case TouchEvent.ACTION_UP:
                                // z = j; // not needed
                                makeMove(z);
                                this.setScale(1.0f); // normal size
                                break;
                    }
                    return super.onAreaTouched(pSceneTouchEvent,
                            pTouchAreaLocalX, pTouchAreaLocalY);
                }
                [END] Touch Detection
            }; */

            // selectPanel[0] = new Sprite(200, 400,
            //      resourceManager.ballTextureRegionArray[0], vbom);
            //attachChild(selectPanel[0]);
        //registerTouchArea(selectPanel[i]);
        selectPanel[0] = new Sprite(0, 0, resourceManager.ballTextureRegionArray[0], vbom) {
            @Override
            protected void preDraw(GLState pGLState, Camera pCamera) {
                super.preDraw(pGLState, pCamera);
                pGLState.enableDither();
            }
        };
        selectPanel[0].setPosition(240, 400);
        attachChild(selectPanel[0]);
        //} /* [END] Draw Selection selectPanel */
        // setTouchAreaBindingOnActionDownEnabled(true);
    }

    /********************************
     * makeMove()
     * Description: Allow the player
     * to make their selection and
     * display pegs as a result.
     ********************************/
    private void makeMove(int inColor) {
        boardPieces[turn] = new Sprite(grid_xPixel(currentX),
                grid_yPixelBoard(currentY),
                resourceManager.ballTextureRegionArray[inColor], vbom);
        boardPieces[turn].setScale(0.75f); // set 75% size on board

        // store current line, compare values to code and generate B/W pegs
        currentXValues[currentX - 1] = inColor;
        if (currentXValues[currentX - 1] == codeCopy[currentX - 1]) {
            blackPegs++;
            // dummy variable so this isn't counted again as a white peg
            codeCopy[currentX - 1] = 999;
        }

        for (int i = 0; i < 4; i++) {
            if ((currentXValues[currentX - 1] == codeCopy[i])) {
                whitePegs++;
                // dummy variable so this isn't counted again as a white peg
                codeCopy[i] = 999;
            }
        }

        /* log for debugging */
        Log.v("pegs", "blackPegs: " + blackPegs);
        Log.v("pegs", "whitePegs: " + whitePegs);

        // Draw pieces to scene and advance to next turn & column
        attachChild(boardPieces[turn]);
        currentX++;
        turn++;

        // advance to next row, draw B/W pegs
        if (currentX > 4) {
            currentX = 1;
            currentY--;

            // Draw Pegs
            drawBWPegs(blackPegs, whitePegs);
            turnCounter++;

            // Reset pegs for next line
            blackPegs = 0;
            whitePegs = 0;

            // codeCopy is only used for counting black and white
            // pegs per line to ensure all cases work
            codeCopy = code.clone();
        }

        /* [START] Draw Blinking Cursor in Next Spot */
        nextSpot = new Sprite(grid_xPixel(currentX),
                grid_yPixelBoard(currentY),
                resourceManager.ballTextureRegionArray[8], vbom);
        nextSpot.setScale(0.75f);

        nextSpot.setBlendFunction(GL10.GL_SRC_ALPHA,
                GL10.GL_ONE_MINUS_SRC_ALPHA);
        nextSpot.registerEntityModifier(new LoopEntityModifier(
                new AlphaModifier(2, 0f, 1.0f)));
        attachChild(nextSpot);
        /* [END] Draw Blinking Cursor in Next Spot */

        /* *
         * GAME OVER (LOSE)
         *  If player reaches turn 40 and still has not received
         *  correct code, go to Game Over (Lose) scene.
         * */
        if (turn == 40) {
            // NOTE: I will replace this with a Game Over scene.
            GameOverWin(false);
            Log.v("Game Over", "You Lose");
            gameoverLose = new Sprite(CAMERA_WIDTH / 2 - 256,
                    CAMERA_HEIGHT / 2 - 64, resourceManager.loseTextureRegion,
                    vbom);
            attachChild(gameoverLose);
        }
    }

    /********************************
     * GameOverWin()
     * Description: Display GameOver
     * image as a result of the user
     * winning the game.
     ********************************/
    private void GameOverWin(boolean win) {
        // clear game
        detachChildren();
        turn = 0;

    }

    /********************************
     * drawBWPegs()
     * Description: Draw the black
     * and white pegs to the scene
     * based on game results.
     ********************************/
    private void drawBWPegs(int numBlack, int numWhite) {
        /* [START] if */
        // do not display if no pegs were counted
        if (numBlack > 0 || numWhite > 0) {
            int pegScore = 0;
            // determine pegScore
            if (numBlack == 1 && numWhite == 0) {
                pegScore = 0;
            } else if (numBlack == 1 && numWhite == 2) {
                pegScore = 1;
            } else if (numBlack == 1 && numWhite == 3) {
                pegScore = 2;
            } else if (numBlack == 0 && numWhite == 1) {
                pegScore = 3;
            } else if (numBlack == 2 && numWhite == 0) {
                pegScore = 4;
            } else if (numBlack == 2 && numWhite == 2) {
                pegScore = 5;
            } else if (numBlack == 0 && numWhite == 2) {
                pegScore = 6;
            } else if (numBlack == 3 && numWhite == 0) {
                pegScore = 7;
            } else if (numBlack == 3 && numWhite == 1) {
                pegScore = 8;
            } else if (numBlack == 0 && numWhite == 3) {
                pegScore = 9;
            } else if (numBlack == 4 && numWhite == 0) {
                pegScore = 10;
            } else if (numBlack == 0 && numWhite == 4) {
                pegScore = 11;
            } /* [END] if */
            // use pegScore to display corresponding image
            bwPegs[turnCounter] = new Sprite(grid_xPixel(5),
                    grid_yPixelBoard(currentY + 1),
                    resourceManager.pegTextureRegionArray[pegScore], vbom);
            bwPegs[turnCounter].setScale(0.80f);
            attachChild(bwPegs[turnCounter]);
        }
    }

    /********************************
     * ---------GRID SYSTEM---------
     ********************************/

    /************************************
     * grid_xPixel()
     * Description: Converts grid
     * coordinates to pixel coordinates
     * based on a 480 by 800 resolution
     * screen. Needs to be updated.
     ************************************/
    private int grid_xPixel(int x) {
        int pixel = 0;
        pixel = x * (CAMERA_WIDTH / 8 + 2) - 32;
        return pixel;
    }

    /************************************
     * grid_yPixel()
     * Description: Y-grid for user
     * selection panel.
     ************************************/
    private int grid_yPixel(int y) {
        int pixel = 0;
        pixel = y * (CAMERA_HEIGHT / 10) - 32;
        return pixel;
    }

    /************************************
     * grid_yPixelBoard()
     * Description: Y-grid for the main
     * game board.
     ************************************/
    private int grid_yPixelBoard(int y) {
        int pixel = 0;
        pixel = y * (CAMERA_HEIGHT / 15) - 32;
        return pixel;
    }
}

I apologize as I'm also new to StackOverflow and don't quite know how to format code properly. Also, if I'm missing important areas of code that are relevant to the question please let me know as I have so many lines of code and don't quite know where to start.

Thanks in advance!

Looking at your code I'd say that ballTextureRegionArray[0] was the null pointer, probably because it wasn't loaded in your resourceManager initialisation.

If your .png files are resources ie in the "res" directory not the "asset" directory you need to load with .createFromResource not .createFromAsset.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM