Search code examples
androidnullpointerexceptionandengineontouch

andEngine Null Exception on Touch


I am new on Android devolopment and today encouraged a problem. When i click on a button which switches the scenes, it gives me a Null Pointer Exception. Stangely, it keeps crashing even if i comment out the "setScene" line from the touch event. Here is my full code..

GameActivity.java: (The base class for game activity - not the game scene)

public class GameActivity extends BaseGameActivity {

	static final int CAMERA_WIDTH = 480;
    static final int CAMERA_HEIGHT = 800;
    Camera mCamera = new Camera(0, 0, CAMERA_WIDTH, CAMERA_HEIGHT);
    
    static SceneManager sceneManager;
	    	
	 @Override
	public void onCreateResources(
			OnCreateResourcesCallback pOnCreateResourcesCallback)
			throws Exception {
		 sceneManager = new SceneManager(this, mEngine, mCamera);
		   sceneManager.loadSplashSceneResources();
		   pOnCreateResourcesCallback.onCreateResourcesFinished();
		
	}
... Just to make you see sceneManager is not null ...

MenuScene.java: Where the "Play" Button located in.. The game crashes on click

public class MenuScene extends mScene{
//mScene is a class extends Scene and has abstract methods such as //"LoadResources". I call the methods on the loading screen 
	BitmapTextureAtlas LogoAtlas;
	TextureRegion LogoRegion;
	Sprite LogoSprite;
	Rectangle StartGame;
	
	public MenuScene(BaseGameActivity activity) {
		super(activity);
		// TODO Auto-generated constructor stub
	}

	@Override
	public void LoadResources() {
		// TODO Auto-generated method stub
		LogoAtlas=new BitmapTextureAtlas(activity.getTextureManager(),300, 300); 
		LogoRegion=BitmapTextureAtlasTextureRegionFactory.createFromAsset(LogoAtlas, activity, "Logo.png", 0, 0);
		LogoAtlas.load();
	}

	@Override
	public void CreateSceneObjects() {
		// TODO Auto-generated method stub
		this.setBackground(new Background(new Color(1f,1f,1f)));
		LogoSprite=new Sprite(80, 30, LogoRegion, activity.getVertexBufferObjectManager()){
			 @Override		
		      protected void preDraw(GLState pGLState, Camera pCamera)
		
		      {
		         super.preDraw(pGLState, pCamera);
		        pGLState.enableDither();
		        this.setCullingEnabled(true);
				      
		      }
		};
		LogoSprite.registerEntityModifier(new MoveYModifier(0.6f, 200, 10){
			@Override
	        protected void onModifierFinished(IEntity pItem)
	        {
	                super.onModifierFinished(pItem);
	                StartGame=SpriteFactory.CreateNextSceneButton(120, 350, "Play", new Color(0.95f,0f,0f), activity,SceneType.GAME);
	        		MenuScene.this.attachChild(StartGame);
	        }
		});
		
		this.registerTouchArea(StartGame);
		this.attachChild(LogoSprite);
		
	}
	@Override 
	public void DestroyScene(){
				
	}
	
	
}

SceneManager.java: (The class that handles scene events and shows a "loading" scene.. )

public class SceneManager {
	public SceneType currentScene;
	
	
	public enum SceneType
	{
		SPLASH,MENU,GAME
	}

	private BaseGameActivity activity;
	private Engine engine;
	private Camera camera;
	mScene Scn_splash,Scn_menu,Scn_Game; 
	
	public SceneManager(BaseGameActivity activity,Engine mEngine, Camera mCamera) {
		this.activity = activity;
		this.engine = mEngine;
		this.camera = mCamera;
		
		
	}

	public void loadSplashSceneResources() {
			Scn_splash=new SplashScene(activity);
			Scn_splash.LoadResources();
			Scn_splash.CreateSceneObjects();
			
	}

	public void loadGameSceneResources() {
		
	}

	public Scene createSplashScene() {
		
		return Scn_splash;
	
	}

	//Method creates all of the Game Scenes
	public void createGameScenes() {
		Scn_menu=new MenuScene(activity);
		Scn_menu.LoadResources();
		Scn_menu.CreateSceneObjects();
		Scn_Game=new GameScene(activity);
		Scn_Game.LoadResources();
		Scn_Game.CreateSceneObjects();
	}
	//Method allows you to get the currently active scene
	public SceneType getCurrentScene() {
		return null;
		
	}

	//Method allows you to set the currently active scene
	public void setCurrentScene(SceneType scene){
	switch (scene) {
	case MENU:engine.setScene(Scn_menu);
		if(Scn_splash!=null) Scn_splash.DestroyScene();
		break;
	case GAME:engine.setScene(Scn_Game);
		break;
	
	default:
		break;
	}
	}
	
	
}

and finnaly the line where the game crashes:

public class SpriteFactory {
	public static final int DOT_RED =0,DOT_BLACK =1;
	//method that creates buttons for switching scenes..
	public static Rectangle CreateNextSceneButton(final float pX,final float pY,String Text,Color c,final BaseGameActivity activity,final SceneManager.SceneType type){
				
		Rectangle r=new Rectangle(pX, pY, 190, 70, activity.getVertexBufferObjectManager()){
			 @Override
			    protected void preDraw(final GLState pGLState, final Camera pCamera)
			    {
			        super.preDraw(pGLState, pCamera);
			        pGLState.enableDither();
			        this.setCullingEnabled(true);
			    }
			 @Override
			 public boolean onAreaTouched(TouchEvent pSceneTouchEvent,float X,float Y){
				 super.onAreaTouched(pSceneTouchEvent, X, Y);
				 GameActivity.sceneManager.setCurrentScene(type);
//Here is the line where tha game crashes. It also creashes if i comment out the previous line. Namely just clicking on the button is enough to make it crash  
				 return true;
			 }
		};
		WindowManager windowManager = (WindowManager) activity.getSystemService(Context.WINDOW_SERVICE);
		
		Display display = windowManager.getDefaultDisplay();
		DisplayMetrics displayMetrics = new DisplayMetrics();
		display.getMetrics(displayMetrics);
		float density = displayMetrics.density;

		
		int fontSize = (int) (25 * density);

		BitmapTextureAtlas mFontTexture = new BitmapTextureAtlas(activity.getTextureManager(),256, 256, TextureOptions.BILINEAR_PREMULTIPLYALPHA);

        Font mFont = new Font(activity.getFontManager(),mFontTexture, Typeface.create(Typeface.DEFAULT, Typeface.BOLD), fontSize, true, Color.WHITE);
        
        activity.getEngine().getTextureManager().loadTexture(mFontTexture);
        activity.getFontManager().loadFont(mFont);
		Text t=new Text(20, 20, mFont,Text, 30, activity.getVertexBufferObjectManager()){
		    @Override
		    protected void preDraw(final GLState pGLState, final Camera pCamera)
		    {
		        super.preDraw(pGLState, pCamera);
		        pGLState.enableDither();
		        this.setCullingEnabled(true);
		    }
		};
	
		r.setPosition(pX, pY);
	
	 
	 r.attachChild(t);
	 r.setColor(c);
	 t.setY(t.getY()-5);
	
	 	 
	return r;
	}
and this is the full error code:

05-23 12:43:42.921: E/AndroidRuntime(6178): FATAL EXCEPTION: UpdateThread
05-23 12:43:42.921: E/AndroidRuntime(6178): java.lang.NullPointerException
05-23 12:43:42.921: E/AndroidRuntime(6178): 	at org.andengine.entity.scene.Scene.onSceneTouchEvent(Scene.java:356)
05-23 12:43:42.921: E/AndroidRuntime(6178): 	at org.andengine.engine.Engine.onTouchScene(Engine.java:452)
05-23 12:43:42.921: E/AndroidRuntime(6178): 	at org.andengine.engine.Engine.onTouchEvent(Engine.java:438)
05-23 12:43:42.921: E/AndroidRuntime(6178): 	at org.andengine.input.touch.controller.BaseTouchController$TouchEventRunnablePoolItem.run(BaseTouchController.java:102)
05-23 12:43:42.921: E/AndroidRuntime(6178): 	at org.andengine.util.adt.pool.RunnablePoolUpdateHandler.onHandlePoolItem(RunnablePoolUpdateHandler.java:54)
05-23 12:43:42.921: E/AndroidRuntime(6178): 	at org.andengine.util.adt.pool.RunnablePoolUpdateHandler.onHandlePoolItem(RunnablePoolUpdateHandler.java:1)
05-23 12:43:42.921: E/AndroidRuntime(6178): 	at org.andengine.util.adt.pool.PoolUpdateHandler.onUpdate(PoolUpdateHandler.java:88)
05-23 12:43:42.921: E/AndroidRuntime(6178): 	at org.andengine.input.touch.controller.BaseTouchController.onUpdate(BaseTouchController.java:62)
05-23 12:43:42.921: E/AndroidRuntime(6178): 	at org.andengine.engine.Engine.onUpdate(Engine.java:584)
05-23 12:43:42.921: E/AndroidRuntime(6178): 	at org.andengine.engine.LimitedFPSEngine.onUpdate(LimitedFPSEngine.java:56)
05-23 12:43:42.921: E/AndroidRuntime(6178): 	at org.andengine.engine.Engine.onTickUpdate(Engine.java:548)
05-23 12:43:42.921: E/AndroidRuntime(6178): 	at org.andengine.engine.Engine$UpdateThread.run(Engine.java:820)

I am really sory about that the question is too long but I think that adding the relevant codes is essential


Solution

  • It is not a good idea to create the StartGame Rectanlge in the onModifierFinished() of the Logo moveModifier. This means StartGame is registered as a touch area immediately after the Logo is created, but only initialised at the end of the modifier.

    To be precise, you are calling "this.registerTouchArea(StartGame)" before "StartGame=SpriteFactory.CreateNextSceneButton(...". By registering StartGame when it is null, you are causing the null pointer.

    This would be a better order:

    create logo sprite;

    create StartGame Rectangle;

    this.registerTouchArea(StartGame);

    StartGame.setVisible(false);

    and then edit the onModifierFinished() to do StartGame.setVisible(true)