3

我开始学习用 Java 创建游戏,我使用的方法之一包括 BufferedImage。这是我得到的错误:

"Exception in thread "main" java.lang.NullPointerException
     at tm.Game.init(Game.java:48)
     at tm.Game.<init>(Game.java:54)"

从这段代码:

package tm;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.image.BufferedImage;

import javax.swing.JPanel;

@SuppressWarnings("serial")
public class Game extends JPanel implements Runnable {
    private Settings Settings;

    private Thread t;
    private BufferedImage offscreenImage;
    private Graphics offscr;

    public void run() {
        while(true) {
            repaint();

            try {
                Thread.sleep(1000/30);
            } catch (InterruptedException e) { }
        }
    }

    public void paint(Graphics g) {
        offscr.setColor(Color.blue);
        offscr.fillRect(0, 0, Settings.GAME_WIDTH, Settings.GAME_HEIGHT);

        offscr.setColor(Color.white);
        offscr.drawString("Lolz", 10, 10);

        g.drawImage(offscreenImage, 0, 0, this);
    }

    public void update(Graphics g) {
        paint(g);
    }

    public void init() {
        t = new Thread(this);
        t.start();

        offscreenImage = (BufferedImage) createImage(Settings.GAME_WIDTH, Settings.GAME_HEIGHT);
        offscr = offscreenImage.getGraphics();
    }

    public Game() {
        Settings = new Settings();

        init();
    }

}

设置类:

package tm;

public class Settings {

    public final int GAME_WIDTH = 500;
    public final int GAME_HEIGHT = 500;

}

屏幕类:

package tm;

import javax.swing.JFrame;

public class Screen extends JFrame {
    private static final long serialVersionUID = 1L;
    private JFrame mainScreen;
    private Game mainGame;
    private Settings Settings;

    public Screen() {
        mainGame = new Game();
        Settings = new Settings();

        mainScreen = new JFrame();
        mainScreen.add(mainGame);
        mainScreen.setSize(Settings.GAME_WIDTH, Settings.GAME_HEIGHT);
        mainScreen.setTitle("Lolz");
        mainScreen.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        mainScreen.setResizable(false);
        mainScreen.setVisible(true);
    }

    public static void main(String[] args) {
        new Screen();
    }

}
4

3 回答 3

3

不是getGraphics()返回 null 而是返回前一个函数createImage()。从组件文档中createImage()

返回可用于双缓冲的离屏可绘制图像。如果组件不可显示,则返回值可能为 null。如果 GraphicsEnvironment.isHeadless() 返回 true,这将始终发生。

然后,当调用getGraphics()为 null 的 offscreenImage 时,您会得到一个 NullPointerException。

于 2012-08-17T17:19:12.497 回答
1

抛出 NullPointer 异常的原因是你在错误的地方初始化了 offScreenImage 和 offScr。

offscreenImage = (BufferedImage) createImage(Settings.GAME`WIDTH, Settings.GAME_HEIGHT);
offscr = offscreenImage.getGraphics();

这段代码应该在函数paint中。要获得结果,应该像这样定义 Game 类。另一个提示最好将变量 inn Settings 类声明为 public static final 以便可以以静态方式访问它们。对您的 Game 类进行少量更改,如下所示。我认为这应该对你有所帮助。

package tm;

import javax.swing.JPanel;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.image.BufferedImage;

import tm.Screen.Settings;

public class Game extends JPanel implements Runnable {
    // private Setting Settings;

    private Thread t;
    private BufferedImage offscreenImage;
    private Graphics offscr;

    public void run() {
        while (true) {
            repaint();

            try {
                Thread.sleep(1000 / 30);
            } catch (InterruptedException e) {
            }
        }
    }

    public void paint(Graphics g) {

        if (offscreenImage == null) {

            offscreenImage = (BufferedImage) createImage(Settings.GAME_WIDTH,
                    Settings.GAME_HEIGHT);
        }
        offscr = offscreenImage.getGraphics();
        offscr.setColor(Color.black);
        offscr.fillRect(0, 0, Settings.GAME_WIDTH, Settings.GAME_HEIGHT);
        offscr.setColor(Color.white);
        offscr.drawString("Lolz", 10, 10);

        g.drawImage(offscreenImage, 0, 0, this);
    }

    public void update(Graphics g) {
        paint(g);
    }


    public void init() {
        t = new Thread(this);
        t.start();
    }

    public Game() {
        init();
    }
}
于 2012-08-18T05:14:01.133 回答
0

由于 createImage 仅在组件“可显示”后才起作用,例如它附加到可见的 JFrame,因此您当前的代码将无法工作。

有几种方法可以处理它。

  • 将 JFrame 作为参数添加到 ctor 并在调用 create 组件之前将 Game 添加到 JFrame - 只要 JFrame.add 不调用被部分初始化的 Game 实例覆盖的任何方法,这应该可以工作。

    Game(JFrame jf){
        jf.add(this);
        ...
    }
    
    JFrame mainFrame = new JFrame();
    mainFrame.setVisible(true);
    Game game = new Game(mainFrame);
    
  • 创建一个额外的 init 方法,在将 Game 添加到 JFrame 后调用该方法。这很难看,因为在调用此方法之前,Game 对象并没有真正完全初始化。

    Game game = new Game();
    JFrame mainFrame = new JFrame();
    mainFrame.add(game);
    mainFrame.setVisible(true);
    game.init();
    
  • 找出组件何时可显示的一种方法是侦听 HierarchyEvent。您可以修改答案中显示的侦听器以调用 createImage 而不是打印“显示”。(该答案提供的课程也需要extends HierarchyListener工作)

于 2012-08-17T21:27:52.597 回答