0

作为我大学的最后一年项目,我正在使用 ODK 和 Eclipse 中的 AndEngine GLES1 开发一个 OUYA 游戏。我有一些制作Android游戏的经验,但这是我的第一个OUYA,所以请多多包涵。

我的问题是,在尝试部署到 OUYA 时,它有时会成功,有时会返回 NullPointerException。

我的主要活动扩展了 BaseGameActivity,并且我覆盖了所有必要的方法(onLoadEngine 等)。

所以,首先我创建了一个 Vehicle 类型的成员变量,它扩展了 Sprite:

private Vehicle mVehicle;

我在 onLoadResources 中为此设置了一个 TextureRegion 等,然后在 onLoadScene 中调用 Vehicle 类的构造函数:

mVehicle = new Vehicle(SCREEN_WIDTH/2.0f, SCREEN_HEIGHT/2.0f, mVehicleTexReg);  

mVehicle 实例有一个更新方法,在注册更新处理程序并覆盖 onupdate 后在 onLoadComplete 中调用该方法。我正在使用 onGenericMotionEvent 的覆盖来检测控制器输入并调用适当的车辆功能(旋转、加速等)。

我的问题是:大约每 4 次我尝试运行我的代码中的 3 次我在 onGenericMotionEvent 函数中得到一个 nullpointerexception(指针是我的 mVehicle)。在我看来,onGenericMotionEvent 是在 onLoadScene 有机会建造我的车辆之前触发的。下面是我的整个 MainActivity 类,以及有关问题的 LogCat 输出。这可能真的很愚蠢,但任何帮助将不胜感激。

编码:

package *****.*****.ssr;

import java.util.ArrayList;

import org.anddev.andengine.engine.Engine;
import org.anddev.andengine.engine.camera.Camera;
import org.anddev.andengine.engine.handler.IUpdateHandler;
import org.anddev.andengine.engine.options.EngineOptions;
import org.anddev.andengine.engine.options.EngineOptions.ScreenOrientation;
import org.anddev.andengine.engine.options.resolutionpolicy.RatioResolutionPolicy;
import org.anddev.andengine.entity.scene.Scene;
import org.anddev.andengine.entity.sprite.Sprite;
import org.anddev.andengine.extension.physics.box2d.PhysicsFactory;
import org.anddev.andengine.extension.physics.box2d.PhysicsWorld;
import org.anddev.andengine.extension.physics.box2d.util.Vector2Pool;
import org.anddev.andengine.opengl.texture.TextureOptions;
import org.anddev.andengine.opengl.texture.atlas.bitmap.BitmapTextureAtlas;
import org.anddev.andengine.opengl.texture.atlas.bitmap.BitmapTextureAtlasTextureRegionFactory;
import org.anddev.andengine.opengl.texture.region.TextureRegion;
import org.anddev.andengine.ui.activity.BaseGameActivity;
import org.anddev.andengine.util.Debug;

import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.physics.box2d.FixtureDef;

import tv.ouya.console.api.OuyaController;
//import ie.itcarlow.C00113480.ssr.R.layout;
import android.util.Log;
import android.view.MotionEvent;

public class MainActivity extends BaseGameActivity {

    private static final int SCREEN_WIDTH = 800;
    private static final int SCREEN_HEIGHT = 600;
    private static final int MAP_WIDTH = 800;
    private static final int MAP_HEIGHT = 600;
    private static final int NUM_VEHICLES = 1;

    //private PhysicsWorld mPhysicsWorld;

    //Game Objects
    private Camera mCamera;
    private Vehicle mVehicle;
    private Track mTrack;

    //Construction Values
    private int mTrackRows = 5;
    private int mTrackCols = 5;
    private int mTrackTileSize = 400;
    private String mTrackLayout = "5000216661166611666140003";
    ArrayList<TextureRegion> mTrackTexs;

    //Controller Fields
    private float conDZ = 0.3f;

    //Visual Assets
    private BitmapTextureAtlas mVehicleTex;
    private TextureRegion mVehicleTexReg;
    private BitmapTextureAtlas mTrackStraightTex;
    private TextureRegion mTrackStraightTexReg;
    private BitmapTextureAtlas mTrackBendTex;
    private TextureRegion mTrackBendTexReg;
    private BitmapTextureAtlas mTrackEmptyTex;
    private TextureRegion mTrackEmptyTexReg;

    @Override
    public Engine onLoadEngine() {
        this.mCamera = new Camera(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);       
        //setContentView(layout.game);      
        return new Engine
                (new EngineOptions(true, ScreenOrientation.LANDSCAPE, 
                        new RatioResolutionPolicy(SCREEN_WIDTH, SCREEN_HEIGHT),
                        this.mCamera));     
    }

    @Override
    public void onLoadResources() {
        //asset paths
        BitmapTextureAtlasTextureRegionFactory.setAssetBasePath("vfx/");

        this.mTrackTexs = new ArrayList<TextureRegion>();

        //visuals
        this.mVehicleTex = new BitmapTextureAtlas(64, 64, TextureOptions.BILINEAR);
        this.mVehicleTexReg = BitmapTextureAtlasTextureRegionFactory.createFromAsset(
                this.mVehicleTex, this, "vehicle.png", 0, 0);

        this.mTrackStraightTex = new BitmapTextureAtlas(1024, 1024, TextureOptions.BILINEAR);
        this.mTrackStraightTexReg = BitmapTextureAtlasTextureRegionFactory.createFromAsset(
                this.mTrackStraightTex, this, "straight.png", 0, 0);
        this.mTrackBendTex = new BitmapTextureAtlas(1024, 1024, TextureOptions.BILINEAR);
        this.mTrackBendTexReg = BitmapTextureAtlasTextureRegionFactory.createFromAsset(
                this.mTrackBendTex, this, "bend.png", 0, 0);
        this.mTrackEmptyTex = new BitmapTextureAtlas(1024, 1024, TextureOptions.BILINEAR);
        this.mTrackEmptyTexReg = BitmapTextureAtlasTextureRegionFactory.createFromAsset(
                this.mTrackEmptyTex, this, "empty.png", 0, 0);

        this.mEngine.getTextureManager().loadTextures(this.mVehicleTex, this.mTrackStraightTex,
                this.mTrackBendTex, this.mTrackEmptyTex);

        this.mTrackTexs.add(mTrackStraightTexReg);
        this.mTrackTexs.add(mTrackBendTexReg);
        this.mTrackTexs.add(mTrackEmptyTexReg); 

    }

    @Override
    public Scene onLoadScene() {
        Debug.d("Calling OnloadScene");
        final Scene scene = new Scene(); 
        //final Vector2 v = Vector2Pool.obtain(0,0);
        //mPhysicsWorld = new PhysicsWorld(v, false);
        //Vector2Pool.recycle(v);
        //scene.registerUpdateHandler(mPhysicsWorld);

        ArrayList<ArrayList<Sprite>> trackTexs;
        //create game objects
        mVehicle = new Vehicle(SCREEN_WIDTH/2.0f, SCREEN_HEIGHT/2.0f, mVehicleTexReg);  
        mTrack = new Track(mTrackRows, mTrackCols, mTrackTileSize, mTrackLayout, mTrackTexs);
        //attach to scene
        scene.attachChild(mVehicle);
        trackTexs = mTrack.getSprites();        
        for(int i = 0; i < mTrackRows; i++){
            for(int j = 0; j < mTrackCols; j++){
                scene.attachChild(trackTexs.get(i).get(j));             
            }           
        }       
        //controller setup
        OuyaController.init(this);  
        return scene;
    }

    @Override
    public boolean onGenericMotionEvent(final MotionEvent event){       
        float xOffset = event.getAxisValue(OuyaController.AXIS_LS_X);
        float lOffset = event.getAxisValue(OuyaController.AXIS_L2);
        float rOffset = event.getAxisValue(OuyaController.AXIS_R2);
        if(xOffset >= conDZ || xOffset <= -conDZ) 
            //Debug.d("Rotating");
            mVehicle.rotate(xOffset);
        else {
            mVehicle.rotate(0);         
            //Debug.d("Not Rotating");
        }
        if(rOffset >= conDZ || lOffset >= conDZ){
            if(rOffset > lOffset)
                //Debug.d("Accelerating");
                mVehicle.accelerate(rOffset);
            else if(lOffset > rOffset)
                //Debug.d("Braking");
                mVehicle.brake(lOffset);
            }
        else
            //Debug.d("Not Moving");
            mVehicle.accelerate(0);     
        return true;
    }


    @Override
    public void onLoadComplete() {
        this.mEngine.registerUpdateHandler(new IUpdateHandler(){
            @Override
            public void onUpdate(float pSecondsElapsed){
                OuyaController.startOfFrame();
                mVehicle.update(pSecondsElapsed);   
                mCamera.setCenter(mVehicle.getX(), mVehicle.getY());            
            }
            @Override
            public void reset(){}           
        });     
    }       
}

日志输出:

Enabling debug mode 0

Exception dispatching input event.

Shutting down VM

threadid=1: thread exiting with uncaught exception (group = 0x411fc300)

FATAL EXCEPTION: main

java.lang.NullPointerException

at ie.itcarlow.C00113480.ssr.MainActivity.onGenericMotionEvent(MainActivity.java:155)

at android.app.Activity.dispatchGenericMotionEvent(Activity.java:2459)

at com.android.internal.policy.imp1.PhoneWindowDecorView.dispatchGenericMotionEvent(PhoneWindow.java:1887)

..................

.................

.................
4

2 回答 2

1

我对此一无所知AndEngine,但从您的描述中可以明显看出,它的 API 不保证onLoadScene在处理运动事件之前执行(也由onLoadScene+的异步性质提出onLoadComplete)。

由于 API 无法做出此保证,因此您必须做好处理此案的准备。这可以像创建一个boolean sceneReady = false;标志一样简单(volatile如果需要,我也不知道这个 API 的详细信息),将其设置为true加载完成时,并在标志为false. 其他选项可能更适合您。

另外,顺便说一句,您应该验证 API 文档中的线程保证,并仔细检查您是否以适当的方式处理数据 - 您的问题的性质会引发一个危险信号,即可能存在其他潜在问题。

于 2013-11-05T21:43:18.690 回答
0

在 onCreate() 中尽可能多地初始化是处理这些问题的最佳方法。

于 2013-11-05T21:42:53.197 回答