0

当我使用 ACM 库编译和运行我的 Java 程序时,我不断收到此错误

Exception in thread "Thread-3" java.lang.NullPointerException
    at SpaceTravel.getBlackHoleDistance(SpaceTravel.java:148)
    at SpaceTravel.gameOverBlackHole(SpaceTravel.java:132)
    at BlackHole.oneTimeStep(BlackHole.java:84)
    at BlackHole.run(BlackHole.java:45)
    at java.lang.Thread.run(Unknown Source)

这是游戏类:

import acm.graphics.*;
import acm.program.*;
import acm.util.*;
import java.awt.*;

public class SpaceTravel extends GraphicsProgram {
  // specify the size of the window
  public static int APPLICATION_WIDTH = 1280;
  public static int APPLICATION_HEIGHT = 600;

  // class constants
  private static final double
    PLANET_SIZE = 80,
    BLACK_HOLE_SIZE = 100,
    STAR_SIZE = 2;

  // instance variables
  private GOval ice, fire, iron;
  private GPoint lastPoint;
  private boolean isDragging = false;
  private GLabel gameOverText, goal, win;
  private BlackHole blackhole1, blackhole2;
  private RandomGenerator rand = new RandomGenerator();

  // init method, draw the graphics objects
  public void init() {

    setBackground(Color.BLACK);

    // call the randomly colored stars method
    drawStars();

    // call 1 instance of BlackHole class
    blackhole1 = new BlackHole(BLACK_HOLE_SIZE, 5, 2, this);
    add(blackhole1, APPLICATION_WIDTH-400, APPLICATION_HEIGHT/2 );
    new Thread(blackhole1).start();

    // call 1 instance of BlackHole class, but name it differently
    blackhole2 = new BlackHole(BLACK_HOLE_SIZE, 3, -4, this);
    add(blackhole2, APPLICATION_WIDTH-200, APPLICATION_HEIGHT/2 );
    new Thread(blackhole2).start();

    // draw fire planet
    fire = drawCircleCentered(100, 400, PLANET_SIZE);
    add(fire);
    fire.setFilled(true);
    fire.setColor(Color.RED);

    // draw ice planet
    ice = drawCircleCentered(100, 100, PLANET_SIZE);
    add(ice);
    ice.setFilled(true);
    ice.setColor(Color.BLUE);

    // draw iron planet
    iron = drawCircleCentered(100, 250, PLANET_SIZE);
    add(iron);
    iron.setFilled(true);
    Color grey = new Color(34, 34, 34);
    iron.setColor(grey);

    // game over text
    gameOverText = new GLabel ("GAME OVER", APPLICATION_WIDTH/2 - 250, APPLICATION_HEIGHT/2);
    gameOverText.setColor(Color.RED);
    gameOverText.setFont(new Font("DEFAULT_FONT", Font.BOLD, 90));

    // goal text
    goal = new GLabel ("GOAL", APPLICATION_WIDTH-150, APPLICATION_HEIGHT/2);
    goal.setColor(Color.RED);
    goal.setFont(new Font("DEFAULT_FONT", Font.BOLD, 20));
    add(goal);

    // win text
    win = new GLabel ("WINRAR IS YOU!", APPLICATION_WIDTH/2 - 350, APPLICATION_HEIGHT/2);
    win.setColor(Color.RED);
    win.setFont(new Font("DEFAULT_FONT", Font.BOLD, 90));
  }

  // checker method if the ice and fire plantes touch, call the game over method below.
  private void checkFireIce(GOval fire, GOval ice) {
    if(getDistance(fire, ice) < PLANET_SIZE ) {
      gameOver(fire);
    }
  }

  // checker method for when fire planet gets to the goal text, call the game winning method below
  private void checkPlanetsGoal() {
    if(fire.getBounds().intersects(goal.getBounds())) {
      winGame();
    }
  }

  // start dragging if the ball is pressed
  public void mousePressed(GPoint point) {
    if (ice.contains(point)) {
      isDragging = true;
      lastPoint = point;
    }
  }

  // move the ball when it is dragged, and call checking methods for game winning or game over conditions
  public void mouseDragged(GPoint point) {
    checkFireIce(fire, ice);
    checkPlanetsGoal();
    if (isDragging) {
      ice.move(point.getX()-lastPoint.getX(),
               point.getY()-lastPoint.getY());
      lastPoint = point;
      // bump the planets
      bump(ice, iron);
      bump(iron, fire);
    }
  }

  // checking method for if any of the planets have touched an instance of black hole
  public void gameOverBlackHole(BlackHole blackhole) {
    double a = getBlackHoleDistance(fire, blackhole);
    double b = getBlackHoleDistance(ice, blackhole);
    double c = getBlackHoleDistance(iron, blackhole);
    if(a < BLACK_HOLE_SIZE/2 + PLANET_SIZE/2) {
      gameOver(fire);
    }
    if(b < BLACK_HOLE_SIZE/2 + PLANET_SIZE/2) {
      gameOver(ice);
    }
    if(c < BLACK_HOLE_SIZE/2 + PLANET_SIZE/2) {
      gameOver(iron);
    }
  }

  // get distance between a black hole instance and a planet
  private double getBlackHoleDistance(GOval planet, BlackHole blackhole) {
    return GMath.distance(planet.getX()+PLANET_SIZE/2, planet.getY()+PLANET_SIZE/2,

                          blackhole.getX(), blackhole.getY());
  }

  // bump helper method, calculates how much to move a tangent planet by when it is being bumped by another
  private void bump(GOval planet1, GOval planet2) {
    double offset = PLANET_SIZE+1.5 - getDistance(planet1, planet2);
    if (offset > 0) {
      planet2.move(offset*(planet2.getX()-planet1.getX())/PLANET_SIZE,
                   offset*(planet2.getY()-planet1.getY())/PLANET_SIZE);
    }
  }

  // a helper method, compute the distance between the centers of the balls
  private double getDistance(GOval planet1, GOval planet2) {
    return GMath.distance(planet1.getX()+PLANET_SIZE/2, planet1.getY()+PLANET_SIZE/2,

                          planet2.getX()+PLANET_SIZE/2, planet2.getY()+PLANET_SIZE/2);
  }

  // a helper method, draw a circle centered at the given location
  private GOval drawCircleCentered(double centerX, double centerY, double size) {
    return new GOval(centerX-size/2, centerY-size/2, size, size);
  }

  // a helper method, draw randomly colored stars 
  private void drawStars() {
    for (int i = 0; i < 1000; i++) {
      GOval star = drawCircleCentered(rand.nextDouble(0, APPLICATION_WIDTH), rand.nextDouble(0, APPLICATION_HEIGHT), STAR_SIZE);
      add(star);
      star.setFilled(true);
      star.setColor(rand.nextColor());
    }    
  }

  // helper method to switch dragging off when mouse is released from window
  public void mouseReleased(GPoint point) {
    isDragging = false;
  }

  // helper method to switch dragging off, remove the planet that touched the goal, and display game over text
  public void gameOver(GOval planet) {
    isDragging = false;
    remove(planet);
    add(gameOverText);
  }

  // helper method to switch dragging off, remove planets, and display win text
  private void winGame() {
    isDragging = false;
    add(win);
    remove(fire);
    remove(ice);
    remove(iron);
    remove(goal);
  }
}

这是创建可以结束游戏的黑洞的类。

// import libraries
import acm.program.*;
import acm.graphics.*;
import acm.util.*;
import java.awt.*;
import java.util.*;

public class BlackHole extends GCompound implements Runnable {

  // instance variables
  private double size, xSpeed, ySpeed;
  private SpaceTravel game;
  private boolean stopHammerTime = false;

  // constructor for BlackHole
  public BlackHole(double size, double xSpeed, double ySpeed, SpaceTravel game) {

    // save the parameters size, xSpeed, ySpeed, centerX, centerY, and game
    this.size = size;
    this.xSpeed = xSpeed;
    this.ySpeed = ySpeed;
    this.game = game;

    // call method drawBlackhole
    drawBlackhole(0, 0, size, 3, 40);
  }

  // run method, move the black hole until it hits a planet || stopHammerTime = true
  public void run() {
    while(!stopHammerTime) {
      oneTimeStep();
    }
  }

  // helper method, creates a black hole
  private void drawBlackhole(double centerX, double centerY, double size, double gap, int layers) {

    for (int i = 0; i < layers; i++) {

      // this gradient color will lighten each time the for loop completes
      Color gradient = new Color(0 + 5*i, 0 + 5*i, 0 + 5*i);

      GOval ring = drawCircleCentered(centerX, centerY, size-gap*2*i);
      add(ring);
      ring.setFilled(true);
      ring.setColor(gradient);
    }
  }

  // a helper method, draw a circle centered at the given location
  private GOval drawCircleCentered(double centerX, double centerY, double size) {
    return new GOval(centerX-size/2, centerY-size/2, size, size);
  }

  // a helper method, move the blackHole in oneTimeStep
  private void oneTimeStep() {
    double x = getX();
    double y = getY();

    // if the black hole hits the left or the right wall, reverse the x-speed
    if (x < size/2 || x+size/2 > game.getWidth()) xSpeed = -xSpeed;

    // if the black hole hits the top or the bottom wall, reverse the y-speed
    if (y < size/2 || y+size/2 > game.getHeight()) ySpeed = -ySpeed;

    // move the black hole by a small interval, incorporating changes from if statements
    move(xSpeed, ySpeed);

    // check if a planet has touched a blackhole
    game.gameOverBlackHole(this);

    // delay
    pause(20);
  }  
}

我很确定我对类的调用是正确的,但由于某种原因,被调用的 blackhole2 只是崩溃了。

4

3 回答 3

4
Exception in thread "Thread-3" java.lang.NullPointerException

这是NullPointerException在执行线程时发生的"Thread-3"

SpaceTravel.java文件中的第 148 行。

似乎在Thread-3执行时,第 148 行正在尝试对null引用进行一些操作,这导致NullPointerException.

于 2012-10-04T18:43:11.857 回答
1

显然崩溃的代码如下所示:

return GMath.distance(planet.getX()+PLANET_SIZE/2, planet.getY()+PLANET_SIZE/2,
                      blackhole.getX(), blackhole.getY());

很可能planetorblackhole参数是null. 使用调试器或println()找出哪一个。这段代码从三个地方调用:

double a = getBlackHoleDistance(fire, blackhole);
double b = getBlackHoleDistance(ice, blackhole);
double c = getBlackHoleDistance(iron, blackhole);

你的行号有点偏离,但我敢说这是第一行,所以要么fireor blackholeis null

于 2012-10-04T18:45:37.043 回答
0

快速分析:

gameOverBlackHole方法被称为表单BlackHole类,这会导致问题,因为删除发生在该方法内部。如果在一个线程执行时发生删除,那么将有 NPE

如果您在多个线程之间共享对象状态,这可能是一个可能出错的示例

于 2012-10-04T19:00:59.883 回答