简体   繁体   English

当我打开游戏活动时,我的应用程序不断崩溃。 我试图创建一个从主要活动打开的游戏活动

[英]My app keeps crashing when I Open the Game Activity. I tried to create a game activity to be opened from the main activity

When I open my Game Activity with Intent from my Home Activity, the app keeps crashing immediately the game activity launches.当我从 Home Activity 中打开带有 Intent 的 Game Activity 时,应用程序会在游戏 Activity 启动时立即崩溃。 The game activity is basically a snake game with canvas to draw out the snake.游戏活动基本上是一个用画布绘制蛇的蛇游戏。 Please help is there a specific reason for this or is something wrong with my code?请帮助是否有特定原因或我的代码有问题? I am going to drop my game activity code and manifest below我将在下面删除我的游戏活动代码和清单

here is the game activity code这是游戏活动代码

import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.AppCompatImageButton;

import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.os.Bundle;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.widget.TextView;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.Timer;
import java.util.TimerTask;

public class GameActivity extends AppCompatActivity implements SurfaceHolder.Callback {

    // list snake points / snake length
    private List<SnakePoints> snakePointsList = new ArrayList<>();
    private SurfaceView surfaceView;
    private TextView scoreTV;

    // surface holder draws the snake on the surface's canvas
    private SurfaceHolder surfaceHolder;

    // snake moving position. Values can be right, left, top, bottom.
    // by default, snake mover to right.
    private String movingPosition = "right";

    // score
    private int score = 0;

    // snake size / point size
    private  static  final int pointSize = 28;

    // default tail size
    private static final int defaultTailPoints = 3;

    // snake color
    private static final int snakeColor = Color.YELLOW;

    // snake speed
    private static final int snakeMovingSpeed = 800;

    // random point coordinates on the surfaceView
    private int positionX, positionY;

    // timer to move snake / change snake position after a specific time
    private Timer timer;
    
    // canvas to draw snake and show on surfaceView
    private Canvas canvas = null;
    
    //point color / single point color of a snake
    private Paint pointColor = null;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_game);

        // getting surfaceView and score TextView from xml file
        surfaceView = findViewById(R.id.surfaceView);
        scoreTV = findViewById(R.id.scoreTV);

        // getting image buttons from xml file
        final AppCompatImageButton topBtn = findViewById(R.id.topBtn);
        final AppCompatImageButton leftBtn = findViewById(R.id.leftBtn);
        final AppCompatImageButton rightBtn = findViewById(R.id.rightBtn);
        final AppCompatImageButton bottomBtn = findViewById(R.id.bottomBtn);

        // call back to surfaceView
        surfaceView.getHolder().addCallback(this);

        topBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (!movingPosition.equals("bottom")){
                    movingPosition = "top";
                }
            }
        });

        leftBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (!movingPosition.equals("right")){
                    movingPosition = "left";
                }
            }
        });

        rightBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (!movingPosition.equals("left")){
                    movingPosition = "right";
                }
            }
        });

        bottomBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (!movingPosition.equals("top")){
                    movingPosition = "bottom";
                }
            }
        });

    }

    @Override
    public void surfaceCreated(@NonNull SurfaceHolder holder) {

        // when the surface is created, get surfaceHolder and assign it to surfaceHolder
        this.surfaceHolder = surfaceHolder;

        // initialize data for snake / surfaceView
        init();
    }

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

    }

    @Override
    public void surfaceDestroyed(@NonNull SurfaceHolder holder) {

    }

 private void init(){

        // clear the snake points / length
     snakePointsList.clear();

     // set default score
     scoreTV.setText("0");

     // make score 0
     score = 0;

     // default moving position is right
     movingPosition = "right";

     // default snake starting position on the screen
     int startPositionX = (pointSize) * defaultTailPoints;

     // making snake's default length / points
     for (int i = 0; i < defaultTailPoints; i++){

         // adding points to snake tail
         SnakePoints snakePoints = new SnakePoints(startPositionX, pointSize);
         snakePointsList.add(snakePoints);

         // increasing the value for the next snake tail
         startPositionX = startPositionX - (pointSize * 2);

     }

     // add random point on the screen to be eaten by snake
     addPoint();

     // start moving the snake / start game
     moveSnake();

 }

 private void  addPoint(){

        // getting surfaceView width and height to add point on the surface to be eaten by the snake
        int surfaceWidth = surfaceView.getWidth() - (pointSize * 2);
        int surfaceHeight = surfaceView.getHeight() - (pointSize * 2);

        int randomXPosition = new Random().nextInt(surfaceWidth / pointSize);
        int randomYPosition = new Random().nextInt(surfaceHeight / pointSize);

        //check if randomXPosition is even orr odd value coz we need only even number
        if ((randomXPosition % 2) != 0){
            randomXPosition = randomXPosition + 1;
        }
        if ((randomYPosition % 2) != 0){
            randomYPosition = randomYPosition + 1;
        }

        positionX = (pointSize * randomXPosition) + pointSize;
        positionY = (pointSize * randomYPosition) + pointSize;

 }

 private void moveSnake(){

        timer = new Timer();
        timer.scheduleAtFixedRate(new TimerTask() {
            @Override
            public void run() {

                // getting head position
                int headPositionX = snakePointsList.get(0).getPositionX();
                int headPositionY = snakePointsList.get(0).getPositionY();

                // to check if the snake has eaten a point
                if (headPositionX == positionX && positionY == headPositionY){

                    //grow snake after eating
                    growSnake();

                    // add another random point on the screen
                    addPoint();

                }

                // check which side the snake is moving
                switch (movingPosition){
                    case "right":

                        //move snakes head to right
                        snakePointsList.get(0).setPositionX(headPositionX + (pointSize * 2));
                        snakePointsList.get(0).setPositionY(headPositionY);
                        break;

                    case "left":

                        //move snakes head to left
                        snakePointsList.get(0).setPositionX(headPositionX - (pointSize * 2));
                        snakePointsList.get(0).setPositionY(headPositionY);
                        break;

                    case "top":

                        //move snakes head to top
                        snakePointsList.get(0).setPositionX(headPositionX);
                        snakePointsList.get(0).setPositionY(headPositionY - (pointSize * 2));
                        break;

                    case "bottom":

                        //move snakes head to bottom
                        snakePointsList.get(0).setPositionX(headPositionX);
                        snakePointsList.get(0).setPositionY(headPositionY + (pointSize * 2));
                        break;
                }

                //check if game is over. Weather snake touch edges or snake itself
                if (checkGameOver(headPositionX, headPositionY)){

                    //stop timer / stop moving snake
                    timer.purge();
                    timer.cancel();

                    //game over dialogue
                    AlertDialog.Builder builder = new AlertDialog.Builder(GameActivity.this);
                    builder.setMessage("Your Score = " +score);
                    builder.setTitle("Game Over");
                    builder.setCancelable(false);
                    builder.setPositiveButton("Go back", new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialogInterface, int i) {

                            // return
                            Intent intent = new Intent(GameActivity.this, HomeActivity.class);
                            startActivity(intent);
                        }
                    });

                    //timer runs in background so show dialogue in main thread
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            builder.show();
                        }
                    });

                }
                
                else {
                    
                    //lock canvas on surfaceHolder to draw on it
                    canvas = surfaceHolder.lockCanvas();
                    
                    //clear canvas with white color
                    canvas.drawColor(Color.WHITE, PorterDuff.Mode.CLEAR);
                    
                    // change snake's head position. Other snake points will follow snake's head
                    canvas.drawCircle(snakePointsList.get(0).getPositionX(), snakePointsList.get(0).getPositionY(), pointSize, createPointColor());

                    // draw random point circles on the surface to be eaten by the snake
                    canvas.drawCircle(positionX, positionY, pointSize, createPointColor());

                    // all other points following snake's head position 0 is head of snake
                    for (int i = 1; i < snakePointsList.size(); i++){

                        int getTempPositionX = snakePointsList.get(i).getPositionX();
                        int getTempPositionY = snakePointsList.get(i).getPositionY();

                        // move points across the head
                        snakePointsList.get(i).setPositionX(headPositionX);
                        snakePointsList.get(i).setPositionY(headPositionY);
                        canvas.drawCircle(snakePointsList.get(i).getPositionX(), snakePointsList.get(i).getPositionY(), pointSize, createPointColor());

                        //change head position
                        headPositionX = getTempPositionX;
                        headPositionY = getTempPositionY;

                    }

                    //unlock canvas to draw on surfaceView
                    surfaceHolder.unlockCanvasAndPost(canvas);

                }
                
            }
        }, 1000- snakeMovingSpeed, 1000- snakeMovingSpeed);

 }

 private void growSnake(){

        // create new snake points
        SnakePoints snakePoints = new SnakePoints(0,0);

        //add points to the snake's tail
        snakePointsList.add(snakePoints);

        //increase score
     score++;

     //setting score to textView
     runOnUiThread(new Runnable() {
         @Override
         public void run() {
             scoreTV.setText(String.valueOf(score));
         }
     });

 }

 private boolean checkGameOver(int headPositionX, int headPositionY){
        boolean gameOver = false;

        //check if snake's head touches edges
        if (snakePointsList.get(0).getPositionX() < 0 ||
            snakePointsList.get(0).getPositionY() < 0 ||
            snakePointsList.get(0).getPositionX() >= surfaceView.getWidth() ||
            snakePointsList.get(0).getPositionY() >= surfaceView.getHeight()){

            gameOver = true;

        }
        else {

            //check if snake's head touches itself
            for (int i = 1; i < snakePointsList.size(); i++){

                if (headPositionX == snakePointsList.get(i).getPositionX() &&
                    headPositionY == snakePointsList.get(i).getPositionY()){
                    gameOver = true;
                    break;
                }

            }

        }

        return gameOver;
 }
 
 private Paint createPointColor(){
        
        if (pointColor == null){
            
            pointColor = new Paint();
            pointColor.setColor(snakeColor);
            pointColor.setStyle(Paint.Style.FILL);
            pointColor.setAntiAlias(true);
                        
        }

     return pointColor;
        
 }

} 

here is my manifest这是我的清单

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.practechs.kubetnew28_05">

    <uses-permission android:name="android.permission.INTERNET" />

    <application
        android:allowBackup="true"
        android:exported="false"
        android:icon="@mipmap/logo"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/logo"
        android:supportsRtl="true"
        android:theme="@style/Theme.KubetNew25_05">
        <activity
            android:name=".GameActivity"
            android:exported="false"
            android:theme="@style/Theme.AppCompat.Light.NoActionBar.FullScreen"/>
        <activity
            android:name=".WebsiteActivity"
            android:exported="false" />
        <activity
            android:name=".HomeActivity"
            android:exported="false" />
        <activity
            android:name=".MainActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

The error displayed in my logcat我的 logcat 中显示的错误

2022-06-08 14:21:13.881 19048-19242/com.practechs.kubetnew28_05 E/AndroidRuntime: FATAL EXCEPTION: Timer-0
    Process: com.practechs.kubetnew28_05, PID: 19048
    java.lang.NullPointerException: Attempt to invoke interface method 'android.graphics.Canvas android.view.SurfaceHolder.lockCanvas()' on a null object reference
        at com.practechs.kubetnew28_05.GameActivity$5.run(GameActivity.java:290)
        at java.util.TimerThread.mainLoop(Timer.java:562)
        at java.util.TimerThread.run(Timer.java:512)

The stack trace shows you the method and line in which the NPE occurs:堆栈跟踪显示 NPE 发生的方法和行:

...SurfaceHolder.lockCanvas()...
...(GameActivity.java:290)

This happens because your SurfaceHolder variable is null until you set it in surfaceCreated :发生这种情况是因为您的SurfaceHolder变量为null ,直到您在surfaceCreated中设置它:

    private SurfaceHolder surfaceHolder;

    @Override
    public void surfaceCreated(@NonNull SurfaceHolder holder) {
        this.surfaceHolder = surfaceHolder;

        init();
    }

And here lies the problem, instead of setting the created SurfaceHolder you set the class variable on itself.这就是问题所在,而不是设置创建的SurfaceHolder ,而是在其自身上设置类变量。 The created SurfaceHolder is called holder not surfaceHolder .创建的SurfaceHolder称为holder而不是surfaceHolder

You can fix it by renaming the method parameter:您可以通过重命名方法参数来修复它:

    @Override
    public void surfaceCreated(@NonNull SurfaceHolder surfaceHolder) {
      this.surfaceHolder = surfaceHolder;
    
      init();
    }

or assign the method parameter correctly.或正确分配方法参数。

    @Override
    public void surfaceCreated(@NonNull SurfaceHolder holder) {
      this.surfaceHolder = holder;
    
      init();
    }

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 当我打算从 Fragment 到新 Activity (Android) 时,我的应用程序不断崩溃 - My app keeps crashing when I intent from a Fragment to a new Activity (Android) 当我尝试打开它时,微调器活动崩溃 - Spinner activity crashing when I try to open it 我试图在模拟器中运行该应用程序,但未显示第一个活动。 它只是打开并显示白屏 - I tried to run the app in the emulator but its not showing the first activity. it just opens and shows a white screen 尝试进行其他活动时,我的应用程序崩溃了 - My app is crashing when I try to go to another activity 从导航抽屉打开新活动时,我的Android应用不断崩溃 - My Android App Keeps Crashing When Opening A New Activity From My Navigation Drawer 当我打开它时,我的应用程序一直崩溃 - My app keeps crashing when i open it 如何直接打开非主要活动的Android应用程序,然后再转到主要活动? - How do I open an Android app straight to an activity that is not the main activity and later move to the main activity? 当我将内容解析器添加到主要活动时,我的应用程序崩溃 - When I add in content resolver to main activity,my app crashes 单击按钮切换到另一个活动时,我的应用程序被强制关闭。 我把我的代码放在这里 - My app is force closing when clicking on button to switch to another activity. here i am putting my code 应用程序崩溃,无法从主要活动转到另一个活动 - Unable to go from main activity to another activity, app is crashing
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM