2

免责声明:我在 2 天前第一次开始为 Android(手机)编程,所以我没有那么有经验。我对 C++ 相当熟悉,但我只接触过几次 Java。

问题:当我在模拟器中运行游戏时,该应用程序按预期运行。但是,当我按下 Home 按钮时,我的 LogCat 中通常会出现一些红线,并且在模拟器中会显示“不幸的是,[app name] 已停止”的消息。弹出。如果这没有发生,当我尝试再次打开应用程序时它会发生。

一些可能有助于找到问题的信息:我从本教程开始: http : //www.edu4java.com/androidgame.html 当我尝试使用 onDraw 函数时,我必须添加“@SuppressLint(” WrongCall")" abow 使用“onDraw”的函数。教程没有说什么,所以我有点困惑。

日志猫:

06-09 01:51:43.161: E/AndroidRuntime(23830): FATAL EXCEPTION: Thread-1173
06-09 01:51:43.161: E/AndroidRuntime(23830): java.lang.NullPointerException
06-09 01:51:43.161: E/AndroidRuntime(23830):    at com.example.braincollect.Background.onDraw(Background.java:24)
06-09 01:51:43.161: E/AndroidRuntime(23830):    at com.example.braincollect.GameView.onDraw(GameView.java:132)
06-09 01:51:43.161: E/AndroidRuntime(23830):    at com.example.braincollect.GameLoopThread.run(GameLoopThread.java:37)

Background.java:24 的代码:

canvas.drawBitmap(bmp, 0, 0, null);

GameView.java:117 的代码

introBackground.onDraw(canvas);

GameLoopThread.java:37 的代码:

view.getHolder().unlockCanvasAndPost(c);

我的项目中有 7 个 java 类:MainActivity(activity)、GameView(view)、GameLoopThread(处理游戏循环)、Background(image)、Brain(image)、Zombie(image)、Timer(只是一些数字处理)

MainActivity.java:

package com.example.braincollect;

import android.media.AudioManager;
import android.os.Bundle;
import android.app.Activity;
import android.content.Context;
import android.content.res.Configuration;
import android.view.KeyEvent;
import android.view.Window;

public class MainActivity extends Activity {
    private AudioManager am;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(new GameView(this));

        am = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
    }

    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
    }

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        switch (keyCode) {
            case KeyEvent.KEYCODE_BACK:
                return true;

            case KeyEvent.KEYCODE_MENU:
                return true;

            case KeyEvent.KEYCODE_VOLUME_UP:
                am.adjustStreamVolume(AudioManager.STREAM_MUSIC,
                        AudioManager.ADJUST_RAISE, AudioManager.FLAG_SHOW_UI);
                return true;

            case KeyEvent.KEYCODE_VOLUME_DOWN:
                am.adjustStreamVolume(AudioManager.STREAM_MUSIC,
                        AudioManager.ADJUST_LOWER, AudioManager.FLAG_SHOW_UI);
                return true;

            default:
                return false;
        }
    }
}

游戏视图.java:

package com.example.braincollect;

import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.media.MediaPlayer;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

public class GameView extends SurfaceView {

    private Bitmap bmp;
    private Bitmap bmp2;
    private Bitmap bmp3;
    private Bitmap bmp4;
    private SurfaceHolder holder;
    private GameLoopThread gameLoopThread;

    private Timer timer;

    public Background introBackground;
    public Background background;
    private Zombie zombie;
    private Brain brain;

    private int score = 0;  

    MediaPlayer mTheme;
    MediaPlayer mGameover;
    MediaPlayer mBrain;
    MediaPlayer mCollect;

    Context myContext;

    int pauseTimer;
    boolean intro = true;

    public GameView(Context context) {
        super(context);     

        myContext = context;
        gameLoopThread = new GameLoopThread(this);

        holder = getHolder();

        holder.addCallback(new SurfaceHolder.Callback() {

            @Override
            public void surfaceDestroyed(SurfaceHolder holder) {
               gameLoopThread.setRunning(false);

                mTheme.stop();

                while (gameLoopThread != null) {
                    try {
                        gameLoopThread.join();
                        gameLoopThread = null;
                    } catch (InterruptedException e) {

                    }
                }
            }

            @Override
            public void surfaceCreated(SurfaceHolder holder) {
                gameLoopThread.setRunning(true);
                gameLoopThread.start();
            }

            @Override
            public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {

            }
        });

        timer = new Timer(context);

        bmp = BitmapFactory.decodeResource(getResources(), R.drawable.zombie);
        zombie = new Zombie(this, bmp);

        bmp2 = BitmapFactory.decodeResource(getResources(), R.drawable.brain);
        brain = new Brain(this, bmp2);

        bmp3 = BitmapFactory.decodeResource(getResources(), R.drawable.background);
        background = new Background(this, bmp3);

        bmp4 = BitmapFactory.decodeResource(getResources(), R.drawable.intro);
        introBackground = new Background(this, bmp4);

        // Music
        mTheme = MediaPlayer.create(context, R.raw.theme);
        mTheme.setLooping(true);
        mTheme.setVolume(0.99f, 0.99f);

        mBrain = MediaPlayer.create(context, R.raw.brain);
        mBrain.setVolume(0.9f, 0.9f);

        mCollect = MediaPlayer.create(context, R.raw.getbrain);
        mCollect.setVolume(0.2f, 0.2f);

        mGameover = MediaPlayer.create(context, R.raw.gameover);
        mGameover.setVolume(0.2f, 0.2f);

        pauseTimer = 0;
    }

    @SuppressLint({ "WrongCall", "DrawAllocation" })
    @Override
    protected void onDraw(Canvas canvas) {
        if(intro == true) {
            introBackground.onDraw(canvas);

            Paint paint;
            paint = new Paint();
            paint.setARGB(200,  255,  0,  0);
            paint.setTextSize(30);

            if(pauseTimer >= 20) {
                canvas.drawText("Click to play!", 100,  getHeight() - 200, paint);
            }

            pauseTimer += 1;
        }

        else if(gameLoopThread.pause == false) {
            background.onDraw(canvas);

            brain.onDraw(canvas);
            zombie.onDraw(canvas);

            timer.onDraw(canvas);

            if(zombie.isWalking) {
                timer.update();
            }

            Paint paint;
            paint = new Paint();
            paint.setARGB(200,  255,  0,  0);
            paint.setTextSize(25);

            canvas.drawText(Integer.toString(score), 10,  30, paint);

            if(zombie.isCollition(brain.x,  brain.y, brain.width, brain.height)) {
                brain.changePos();

                if(zombie.isWalking) {
                    score += 1;
                    mBrain.start();
                }

                timer.reset();
            }

            if(timer.width <= 0) {
                mGameover.start();
                pauseTimer = 0;
                gameLoopThread.pause = true;
                mTheme.setVolume(0.3f, 0.3f);
            }
        } else {
            background.onDraw(canvas);

            Paint paint;
            paint = new Paint();
            paint.setARGB(200,  255,  0,  0);
            paint.setTextSize(30);

            canvas.drawText("Your Score: " + Integer.toString(score), 100,  (getHeight() / 2) - 40, paint);

            if(pauseTimer >= 20) {
                canvas.drawText("Click to play again!", 100,  getHeight() / 2, paint);
            }

            pauseTimer += 1;
        }
    }

    public boolean onTouchEvent(MotionEvent event) {
        if(event.getAction() == MotionEvent.ACTION_DOWN) {
            zombie.changeDir();
            if(intro == true && pauseTimer >= 20) {
                intro = false;
                mTheme.start();
                mCollect.start();

                pauseTimer = 0;

                gameLoopThread.pause = false;

                mTheme.setVolume(0.99f, 0.99f);
                mTheme.start();

                timer.width = timer.widthMax;
                score = 0;

                zombie.x = zombie.xStart;
                zombie.y = zombie.yStart;
                zombie.isWalking = false;
                zombie.xSpeed = 1;
                zombie.ySpeed = 0;
                zombie.currentFrame = 0;

                brain.changePos();
            }

            if(gameLoopThread.pause == true && pauseTimer >= 20) {
                pauseTimer = 0;

                gameLoopThread.pause = false;

                mTheme.setVolume(0.99f, 0.99f);
                mTheme.start();

                mCollect.start();

                timer.width = timer.widthMax;
                score = 0;

                zombie.x = zombie.xStart;
                zombie.y = zombie.yStart;
                zombie.isWalking = false;
                zombie.xSpeed = 1;
                zombie.ySpeed = 0;
                zombie.currentFrame = 0;

                brain.changePos();
            }
        }

        return super.onTouchEvent(event);
    }
}

(“bmp”名称只是临时的,所有声音都不会是 MediaPlayer 对象)

GameLoopThread.java:

package com.example.appname;

import android.annotation.SuppressLint;
import android.graphics.Canvas;

public class GameLoopThread extends Thread {
      static final long FPS = 10;
       private GameView view;
       public boolean running = false;
       public boolean pause = false;

       public GameLoopThread(GameView view) {
             this.view = view;
       }

       public void setRunning(boolean run) {
             running = run;
       }

       @SuppressLint("WrongCall") @Override
       public void run() {
           long ticksPS = 1000 / FPS;
           long startTime;
           long sleepTime;

             while (running) {
                    Canvas c = null;
                    startTime = System.currentTimeMillis();

                    try {
                           c = view.getHolder().lockCanvas();
                           synchronized (view.getHolder()) {
                               view.onDraw(c);
                           }
                    } finally {
                           if (c != null) {
                                  view.getHolder().unlockCanvasAndPost(c);
                           }
                    }

                    sleepTime = ticksPS-(System.currentTimeMillis() - startTime);
                    try {
                           if (sleepTime > 0)
                                  sleep(sleepTime);
                           else
                                  sleep(10);
                    } catch (Exception e) {}
             }
       }
}

如果您需要查看更多代码,请告诉我。我不知道错在哪里。

4

2 回答 2

1

我很确定视图将相等的 null 传递给 GameLoopThread 构造函数,因此当您调用时,此行将引发 NPE setRunning(true)

c = view.getHolder().lockCanvas();

您应该通过调用发布其他代码片段GameLoopThread(view),以便更好地了解问题。

祝你好运

于 2013-06-09T02:31:28.517 回答
0

这很简单,在Grass.java文件的第 24 行,你有一个NullPointerException, 所以使用断点和Debug模式(而不是Run)可以轻松检查该行的值并查看哪些变量可能为空,或者在该行之前放置一个空检查器,或者捕捉异常:

1.

if(canvas != null) {

...

}

2.

try {

...

} catch (NullPointerException e) {

....
}
于 2013-06-09T02:28:41.550 回答