簡體   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

當我從 Home Activity 中打開帶有 Intent 的 Game Activity 時,應用程序會在游戲 Activity 啟動時立即崩潰。 游戲活動基本上是一個用畫布繪制蛇的蛇游戲。 請幫助是否有特定原因或我的代碼有問題? 我將在下面刪除我的游戲活動代碼和清單

這是游戲活動代碼

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;
        
 }

} 

這是我的清單

<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>

我的 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)

堆棧跟蹤顯示 NPE 發生的方法和行:

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

發生這種情況是因為您的SurfaceHolder變量為null ,直到您在surfaceCreated中設置它:

    private SurfaceHolder surfaceHolder;

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

        init();
    }

這就是問題所在,而不是設置創建的SurfaceHolder ,而是在其自身上設置類變量。 創建的SurfaceHolder稱為holder而不是surfaceHolder

您可以通過重命名方法參數來修復它:

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

或正確分配方法參數。

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM