0

我的代码中不断出现错误,但我无法在任何地方找到它,它是在我添加 Spritesheet 和我的 Screen 类时开始的,这是堆栈:

Thread [Thread-2] (Suspended (exception NullPointerException))  
Screen.render(int[], int, int) line: 51 
Game.render() line: 128 
Game.run() line: 101    
Thread.run() line: not available    

`

第 51 行是这一行:

int colour = tileIndex * 4 + sheet.pixels[sheetPixel++];

这是 Screen 类:

package ca.vanzeben.game.gfx;

public class Screen {

    public static final int MAP_WIDTH = 64;
    public static final int MAP_WIDTH_MASK = MAP_WIDTH - 1 ;

    public int[] tiles = new int[MAP_WIDTH*MAP_WIDTH];
    public int[] colours = new int[MAP_WIDTH*MAP_WIDTH*4];

    public int xOffset = 0;
    public int yOffset = 0;

    public int width;
    public int height;

    public SpriteSheet sheet;

    public Screen(int width, int height, SpriteSheet sheet) {
        this.width = width;
        this.height = height;
        this.sheet = sheet;

        for (int i = 0; i<MAP_WIDTH*MAP_WIDTH; i++) {
            colours [i*4+0] = 0xff00ff;
            colours [i*4+1] = 0x00ffff;
            colours [i*4+2] = 0xffff00;
            colours [i*4+3] = 0xffffff;
        }
    }

    public void render(int[] pixels, int offset, int row) {
        for (int yTile = yOffset >>3;yTile <= (yOffset+height)>>3;yTile++) {
            int yMin = yTile * 8 - yOffset;
            int yMax = yMin + 8;
            if (yMin < 0) yMin = 0;
            if (yMax > height) yMax = height;

            for (int xTile = xOffset >>3;xTile <= (xOffset+width)>>3;xTile++) {
                int xMin = xTile * 8 - xOffset;
                int xMax = xMin + 8;
                if (xMin < 0) xMin = 0;
                if (xMax > width) xMax = width;

                int tileIndex = (xTile & (MAP_WIDTH_MASK))+ (yTile &(MAP_WIDTH_MASK))*MAP_WIDTH;

                for (int y = yMin; y <yMax; y++) {
                    int sheetPixel = ((y + yOffset)& 7)* sheet.width + ((xMin + xOffset) & 7);
                    int tilePixel = offset + xMin + y*row;
                    for (int x = xMin; x<xMax; x++) {
                        int colour = tileIndex * 4 + sheet.pixels[sheetPixel++];
                        pixels [tilePixel++] = colours [colour];
                    }
                }
            }
        }
    }
}

这是游戏类:

package ca.vanzeben.game;

import java.awt.BorderLayout;
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.image.BufferStrategy;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferInt;

import javax.swing.JFrame;


public class Game extends Canvas implements Runnable {


    private static final long serialVersionUID = 1L;

    public static final int WIDTH = 160;
    public static final int HEIGHT = WIDTH /12*9;
    public static final int SCALE =3;
    public static final String NAME = "Wake Me Up";

    private JFrame frame;

    public boolean running = false;
    public int tickCount = 0;

    private BufferedImage image = new BufferedImage     (WIDTH,HEIGHT,BufferedImage.TYPE_INT_RGB);
    private int[] pixels =((DataBufferInt)image.getRaster().getDataBuffer()).getData();

    private Screen screen;

    public Game() {
        setMinimumSize(new Dimension (WIDTH*SCALE,HEIGHT*SCALE));
        setMaximumSize(new Dimension (WIDTH*SCALE,HEIGHT*SCALE));
        setPreferredSize(new Dimension (WIDTH*SCALE,HEIGHT*SCALE));

        frame = new JFrame(NAME);

        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setLayout(new BorderLayout());

        frame.add(this,BorderLayout.CENTER);
        frame.pack();

        frame.setResizable(false);
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    public void init() {
        screen = new Screen (WIDTH,HEIGHT, new SpriteSheet("/sprite_sheet.xcf"));
    }


    public synchronized void start() {
        running = true;
        new Thread(this).start();

    }

    public synchronized void stop() {

    }

    public void run() {
        long lastTime = System.nanoTime();
        double nsPerTick = 1000000000D/60D;

        int frames = 0;
        int ticks = 0;

        long lastTimer = System.currentTimeMillis();
        double delta = 0;

        init();

        while (running) {
            long now = System.nanoTime();
            delta += (now-lastTime) / nsPerTick;
            lastTime = now;
            boolean shouldRender = true;

            while (delta >=1) {
                ticks++;
                tick();
                delta -= 1;
                shouldRender = true;
            }
            try {
                Thread.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            if (shouldRender) {
                frames++;
                render();
            }

            if (System.currentTimeMillis()-lastTimer>=1000) {
                lastTimer += 1000;
                System.out.println(ticks+ "," +frames);
                frames = 0;
                ticks = 0;
            }
        }
    }

    public void tick() {
        tickCount++;    

        for (int i=0; i < pixels.length;i++) {
            pixels[i] = i+tickCount;
        }
    }

    public void render() {
        BufferStrategy bs = getBufferStrategy();
        if (bs == null) {
            createBufferStrategy(3);
            return;
        }

        screen.render(pixels, 0, WIDTH);

        Graphics g = bs.getDrawGraphics();

        g.setColor(Color.BLACK);
        g.fillRect(0, 0, getWidth(), getHeight());

        g.drawImage(image, 0, 0, getWidth(), getHeight(), null);

        g.dispose();
        bs.show();
    }

    public static void main(String[]args) {
        new Game().start();
    }

}

这是 SpriteSheet 类:

package ca.vanzeben.game.gfx;

import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.imageio.ImageIO;

public class SpriteSheet {

    public String path;
    public int width;
    public int height;

    public int [] pixels;

    public SpriteSheet(String path) {
        BufferedImage image = null;
        try {

            image = ImageIO.read(SpriteSheet.class.getResourceAsStream(path));
        } catch (IOException e) {
            e.printStackTrace();
        }
        if (image == null) {
            return;
        }

        this.path = path;
        this.width = image.getWidth();
        this.height = image.getHeight();

        pixels = image.getRGB(0, 0, width, height, null, 0, width);

        for(int i = 0; i< pixels.length;i++) {
            pixels[i] = (pixels[i] & 0xff)/64;
        }

        for(int i = 0; i<8;i++) {
            System.out.println(pixels[i]);
        }
    }  
}

通常我不寻求帮助,但我可以在任何地方找到错误。谢谢!

4

2 回答 2

2

最可能的解释是sheet.pixelsnull如果sheet它本身是null,您会在前面的行中获得 NPE)。

于 2013-09-08T17:24:33.033 回答
0

我能找到的关于 sheet.pixels 在指示行为 null 的唯一解释是ImageIO.read(...)SpriteSheet 构造函数中的 IOException 遇到了一个 IOException,因此将 image 保留为 null。

public SpriteSheet(String path) {
    BufferedImage image = null;
    try {
        image = ImageIO.read(SpriteSheet.class.getResourceAsStream(path)); //<-- has an IOException problem
    } catch (IOException e) {
        e.printStackTrace();
    }
    if (image == null) { //<--image remains null
        return; //<--- rest of constructor is skipped
    }
    this.path = path;
    this.width = image.getWidth();
    this.height = image.getHeight();

    pixels = image.getRGB(0, 0, width, height, null, 0, width);
    .... rest of constructor

这里如果image = ImageIO.read(SpriteSheet.class.getResourceAsStream(path));遇到 IOException 并且 image 保持为空,那么下一个 if 语句只是终止 SpriteSheet 构造函数,未能初始化包括像素在内的许多变量;让它为空。

如果遇到问题,让构造函数返回一个可怕的未正确初始化的对象是一个非常糟糕的主意,除非您有特定的理由这样做;如果需要或者(如果您不想正确处理它;也许是因为您相信它永远不会出现)传播错误,至少抛出一个运行时异常,所以如果所有其他方法都失败了,您至少知道出了什么问题。像这样留下一个未完全初始化的对象比异常糟糕得多,因为它仍然会导致问题(并且可能稍后会出现异常),但异常与您发现的问题的实际原因相去甚远;或者更糟糕的是,它可能不会在以后导致异常,而只会给出更难诊断的“疯狂”结果。

于 2013-09-08T19:03:48.697 回答