触摸时出现 andEngine 空异常
andEngine Null Exception on Touch
我是 Android 开发的新手,今天遇到了一个问题。当我点击一个切换场景的按钮时,它给了我一个空指针异常。奇怪的是,即使我从触摸事件中注释掉 "setScene" 行,它仍然会崩溃。这是我的完整代码..
GameActivity.java:(游戏activity的基础class——不是游戏场景)
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: "Play" 按钮位于.. 点击
时游戏崩溃
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:(处理场景事件并显示"loading"场景的class..)
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;
}
}
}
最后是游戏崩溃的行:
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;
}
这是完整的错误代码:
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)
我很抱歉这个问题太长了,但我认为添加相关代码是必不可少的
在 Logo moveModifier 的 onModifierFinished() 中创建 StartGame Rectanlge 不是一个好主意。这意味着 StartGame 在创建 Logo 后立即注册为触摸区域,但仅在修改器的末尾初始化。
准确地说,您在 "StartGame=SpriteFactory.CreateNextSceneButton(..." 之前调用了 "this.registerTouchArea(StartGame)"。通过在 StartGame 为空时注册它,您将导致空指针。
这样的顺序会更好:
创建徽标精灵;
创建开始游戏矩形;
this.registerTouchArea(开始游戏);
StartGame.setVisible(假);
然后编辑 onModifierFinished() 以执行 StartGame.setVisible(true)
我是 Android 开发的新手,今天遇到了一个问题。当我点击一个切换场景的按钮时,它给了我一个空指针异常。奇怪的是,即使我从触摸事件中注释掉 "setScene" 行,它仍然会崩溃。这是我的完整代码..
GameActivity.java:(游戏activity的基础class——不是游戏场景)
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: "Play" 按钮位于.. 点击
时游戏崩溃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:(处理场景事件并显示"loading"场景的class..)
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;
}
}
}
最后是游戏崩溃的行:
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;
}
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)
我很抱歉这个问题太长了,但我认为添加相关代码是必不可少的
在 Logo moveModifier 的 onModifierFinished() 中创建 StartGame Rectanlge 不是一个好主意。这意味着 StartGame 在创建 Logo 后立即注册为触摸区域,但仅在修改器的末尾初始化。
准确地说,您在 "StartGame=SpriteFactory.CreateNextSceneButton(..." 之前调用了 "this.registerTouchArea(StartGame)"。通过在 StartGame 为空时注册它,您将导致空指针。
这样的顺序会更好:
创建徽标精灵;
创建开始游戏矩形;
this.registerTouchArea(开始游戏);
StartGame.setVisible(假);
然后编辑 onModifierFinished() 以执行 StartGame.setVisible(true)