我正在編寫一個Java RPG遊戲的過程中,並且遇到了一個障礙。我的代碼目前有精靈動畫,隨機地圖生成perlin噪聲和碰撞檢測。該地圖是平鋪的基地,所以我目前正試圖將perlin噪音轉換爲瓷磚。 perlin函數生成一個數組,並將該數組中的每個數字輸入到一個tile png中。這是問題出現的地方:RUNTIME ERROR:Java.Lang.NullPointerException。 問題是我的編譯器(netbeans)不會告訴我發生錯誤的地方,而是隻給我這個錯誤代碼。通過排除過程,我設法找到錯誤,該錯誤發生在第364行。如果此網站不支持行,則位於loadTile()方法的「if(perlinIsland [x] [y] < = 0.05)blockImg [x] [y] = TILE [0];「。我相信所有變量都被正確初始化,但我無法找到解決方案。請原諒長碼,但爲了提供信息,我包含了所有內容。預先感謝您的幫助!java.lang.NullPointerException找不到源
package java4k;
import java.awt.*;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Rectangle2D;
import java.awt.image.*;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.Random;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import java.math.*;
import java.util.*;
/**
*
* @author Christophe
*/
public class Main extends JFrame implements Runnable{
public Image dbImage;
public Graphics dbGraphics;
//Image + Array size
final static int listWidth = 500, listHeight = 500;
//Move Variables
int playerX = 320, playerY = 240, xDirection, yDirection;
//Sprites
BufferedImage spriteSheet;
//Lists for sprite sheet: 1 = STILL; 2 = MOVING_1; 3 = MOVING_2
BufferedImage[] ARCHER_NORTH = new BufferedImage[4];
BufferedImage[] ARCHER_SOUTH = new BufferedImage[4];
BufferedImage[] ARCHER_EAST = new BufferedImage[4];
BufferedImage[] ARCHER_WEST = new BufferedImage[4];
Image[] TILE = new Image[8];
//Animation Variables
int currentFrame = 0, framePeriod = 150;
long frameTicker = 0l;
Boolean still = true;
Boolean MOVING_NORTH = false, MOVING_SOUTH = false, MOVING_EAST = false, MOVING_WEST = false;
BufferedImage player = ARCHER_SOUTH[0];
//World Tile Variables
//20 X 15 = 300 tiles
Rectangle[][] blocks = new Rectangle[listWidth][listHeight];
Image[][] blockImg = new Image[listWidth][listHeight];
Image[][] blockImgTrans = new Image[listWidth][listHeight];
Boolean[][] isSolid = new Boolean[listWidth][listHeight];
int tileX = 0, tileY = 0;
Random r = new Random();
Rectangle playerRect = new Rectangle(playerX + 4,playerY+20,32,20);
//Map Navigation
static final byte PAN_UP = 0, PAN_DOWN = 1, PAN_LEFT = 2, PAN_RIGHT = 3;
//Perlin noise variables:
Color test = new Color(0, 0, 0);
static float[][] perlinNoise = new float[listWidth][listHeight];
static float[][] gradiantNoise = new float[listWidth][listHeight];
static float[][] perlinIsland = new float[listWidth][listHeight];
static float[][] biome = new float[listWidth][listHeight];
//Saved as png
static BufferedImage perlinImage;
public Main(){
this.setTitle("JAVA4K");
this.setSize(640,505);
this.setResizable(false);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setVisible(true);
addKeyListener(new AL());
TILE[0] = new ImageIcon("C:/Users/Christophe/Documents/NetBeansProjects/Java4k/src/java4k/TILE_GRASS_1.png").getImage();
TILE[1] = new ImageIcon("C:/Users/Christophe/Documents/NetBeansProjects/Java4k/src/java4k/TILE_GRASS_2.png").getImage();
TILE[2] = new ImageIcon("C:/Users/Christophe/Documents/NetBeansProjects/Java4k/src/java4k/TILE_GRASS_3.png").getImage();
TILE[3] = new ImageIcon("C:/Users/Christophe/Documents/NetBeansProjects/Java4k/src/java4k/TILE_WATER_1.png").getImage();
TILE[4] = new ImageIcon("C:/Users/Christophe/Documents/NetBeansProjects/Java4k/src/java4k/TILE_TREE_1_BOT.png").getImage();
TILE[5] = new ImageIcon("C:/Users/Christophe/Documents/NetBeansProjects/Java4k/src/java4k/TILE_TREE_1_TOP.png").getImage();
TILE[6] = new ImageIcon("C:/Users/Christophe/Documents/NetBeansProjects/Java4k/src/java4k/TILE_TREE_2_BOT.png").getImage();
TILE[7] = new ImageIcon("C:/Users/Christophe/Documents/NetBeansProjects/Java4k/src/java4k/TILE_TREE_2_TOP.png").getImage();
loadTiles();
init();
}
//Step 1: Generates array of random number 0 < n < 1
public static float[][] GenerateWhiteNoise(int width, int height){
Random r = new Random();
Random random = new Random(r.nextInt(1000000000)); //Seed to 0 for testing
float[][] noise = new float[width][height];
for (int i = 0; i < width; i++)
{
for (int j = 0; j < height; j++)
{
noise[i][j] = (float)random.nextDouble() % 1;
}
}
return noise;
}
//Step 2: Smooths out random numbers
public static float[][] GenerateSmoothNoise(float[][] baseNoise, int octave){
int width = baseNoise.length;
int height = baseNoise.length;
float[][] smoothNoise = new float[width][height];
int samplePeriod = 1 << octave; // calculates 2^k
float sampleFrequency = 1.0f/samplePeriod;
for (int i = 0; i < width; i++)
{
//calculate the horizontal sampling indices
int sample_i0 = (i/samplePeriod) * samplePeriod;
int sample_i1 = (sample_i0 + samplePeriod) % width; //wrap around
float horizontal_blend = (i - sample_i0) * sampleFrequency;
for (int j = 0; j < height; j++)
{
//calculate the vertical sampling indices
int sample_j0 = (j/samplePeriod) * samplePeriod;
int sample_j1 = (sample_j0 + samplePeriod) % height; //wrap around
float vertical_blend = (j - sample_j0) * sampleFrequency;
//blend the top two corners
float top = Interpolate(baseNoise[sample_i0][sample_j0],
baseNoise[sample_i1][sample_j0], horizontal_blend);
//blend the bottom two corners
float bottom = Interpolate(baseNoise[sample_i0][sample_j1],
baseNoise[sample_i1][sample_j1], horizontal_blend);
//final blend
smoothNoise[i][j] = Interpolate(top, bottom, vertical_blend);
}
}
return smoothNoise;
}
//Used in GeneratePerlinNoise() to derivate functions
public static float Interpolate(float x0, float x1, float alpha)
{
float ft = alpha * 3.1415927f;
float f = (float) (1 - Math.cos(ft)) * .5f;
return x0*(1-f) + x1*f;
}
//Step 3: Combines arrays together to generate final perlin noise
public static float[][] GeneratePerlinNoise(float[][] baseNoise, int octaveCount)
{
int width = baseNoise.length;
int height = baseNoise[0].length;
float[][][] smoothNoise = new float[octaveCount][][]; //an array of 2D arrays containing
float persistance = 0.5f;
//generate smooth noise
for (int i = 0; i < octaveCount; i++)
{
smoothNoise[i] = GenerateSmoothNoise(baseNoise, i);
}
float[][] perlinNoise = new float[width][height];
float amplitude = 1.0f;
float totalAmplitude = 0.0f;
//blend noise together
for (int octave = octaveCount - 1; octave >= 0; octave--)
{
amplitude *= persistance;
totalAmplitude += amplitude;
for (int i = 0; i < width; i++)
{
for (int j = 0; j < height; j++)
{
perlinNoise[i][j] += smoothNoise[octave][i][j] * amplitude;
}
}
}
//normalisation
for (int i = 0; i < width; i++)
{
for (int j = 0; j < height; j++)
{
perlinNoise[i][j] /= totalAmplitude;
}
}
return perlinNoise;
}
//Step 4: Generate circular gradiant: center = 0, outside = 1
public static float[][] GenerateCircularGradiant(float[][] base, int size, int centerX, int centerY){
base = new float[size][size];
for (int x = 0; x < base.length; x++) {
for (int y = 0; y < base.length; y++) {
//Simple squaring, you can use whatever math libraries are available to you to make this more readable
//The cool thing about squaring is that it will always give you a positive distance! (-10 * -10 = 100)
float distanceX = (centerX - x) * (centerX - x);
float distanceY = (centerY - y) * (centerY - y);
float distanceToCenter = (float) Math.sqrt(distanceX + distanceY);
//Make sure this value ends up as a float and not an integer
//If you're not outputting this to an image, get the correct 1.0 white on the furthest edges by dividing by half the map size, in this case 64. You will get higher than 1.0 values, so clamp them!
float mapSize = base.length/2;
//mapSize = 500;
distanceToCenter = distanceToCenter/mapSize;
base[x][y] = distanceToCenter - 0.2f;
}
}
return base;
}
//step 5: Combine perlin noise with circular gradiant to create island
public static float[][] GenerateIsland(float[][] baseCircle, float[][] baseNoise){
float[][] baseIsland = new float[baseNoise.length][baseNoise.length];
for(int x = 0; x < baseNoise.length; x++){
for(int y = 0; y < baseNoise.length; y++){
baseIsland[x][y] = baseNoise[x][y] - baseCircle[x][y];
}
}
return baseIsland;
}
//Method for optional paramater = float[][] biome
public static void GreyWriteImage(float[][] data, String filename){
float[][] temp = null;
GreyWriteImage(data, temp, filename);
}
//Converts array data to png image
public static void GreyWriteImage(float[][] data, float[][] biome, String fileName){
//this takes and array of doubles between 0 and 1 and generates a grey scale image from them
BufferedImage image = new BufferedImage(data.length,data[0].length, BufferedImage.TYPE_INT_RGB);
for (int y = 0; y < data[0].length; y++)
{
for (int x = 0; x < data.length; x++)
{
if (data[x][y]>1){
data[x][y]=1;
}
if (data[x][y]<0){
data[x][y]=0;
}
Color col;
//Deep Water 0 - 0.05
if(data[x][y] <= 0.05) col = new Color(0, 0, 255);
//Shallow Water 0.05 - 0.08
else if(data[x][y] <= 0.08) col = new Color(100, 100, 255);
//Beach 0.08 - 0.2
else if(data[x][y]<=0.15) col = new Color(255, 255, 0);
//Forest 0.2 - 0.6 + 0 0 0.7
else if(data[x][y]<=0.6 && biome != null && (biome[x][y] < 0.6 || biome[x][y] > 0.9)){
//Forest
if(biome[x][y] < 0.6) col = new Color(0, 150, 0);
//Desert
else col = new Color(200, 200, 0);
}
//Plains 0.2 - 0.6
else if(data[x][y] <= 0.6) col = new Color(0, 255, 0);
//Rocky Mountains 0.6 - 0.8
else if(data[x][y] <= 0.65) col = new Color(100, 100, 100);
//Snowy Mountains 0.6 - 1
else col = new Color(255, 255, 255);
image.setRGB(x, y, col.getRGB());
}
}
try {
// retrieve image
File outputfile = new File(fileName);
outputfile.createNewFile();
ImageIO.write(image, "png", outputfile);
} catch (IOException e) {
System.out.println("GREY WRITE IMAGE ERROR 303: " + e);
}
}
//First called to store image tiles in blockImg[][] and tile rectangles in blocks[][]
private void loadTiles(){
//Primary Perlin Noise Generation
perlinNoise = GenerateWhiteNoise(listWidth, listHeight);
GreyWriteImage(perlinNoise, "perlinNoise.png");
perlinNoise = GenerateSmoothNoise(perlinNoise, 7);
GreyWriteImage(perlinNoise, "smoothNoise.png");
perlinNoise = GeneratePerlinNoise(perlinNoise, 5);
GreyWriteImage(perlinNoise, "finalPerlin.png");
gradiantNoise = GenerateCircularGradiant(gradiantNoise, listWidth, listWidth/2 - 1, listHeight/2 - 1);
GreyWriteImage(gradiantNoise, "gradiantNoise.png");
perlinIsland = GenerateIsland(gradiantNoise, perlinNoise);
GreyWriteImage(perlinIsland, "perlinIsland.png");
//Biome Perlin Noise Generation
biome = GenerateWhiteNoise(listWidth, listHeight);
biome = GenerateSmoothNoise(biome, 6);
biome = GeneratePerlinNoise(biome, 5);
GreyWriteImage(perlinIsland, biome, "biome.png");
for(int y = 0; y < listHeight; y++){
for(int x = 0; x < listWidth; x++){
//Sets boundaries: 0 < perlinIsland[x][y] < 1
if (perlinIsland[x][y]>1) perlinIsland[x][y]=1;
if (perlinIsland[x][y]<0) perlinIsland[x][y]=0;
//Deep Water 0 - 0.05
if(perlinIsland[x][y] <= 0.05)blockImg[x][y] = TILE[0];
//Shallow Water 0.05 - 0.08
else if(perlinIsland[x][y] <= 0.08) blockImg[x][y] = TILE[3];
//Beach 0.08 - 0.2
else if(perlinIsland[x][y]<=0.15) blockImg[x][y] = TILE[4];
//Forest 0.2 - 0.6 + 0 0 0.7
else if(perlinIsland[x][y]<=0.6 && biome != null && (biome[x][y] < 0.6 || biome[x][y] > 0.9)){
//Forest
if(biome[x][y] < 0.6) blockImg[x][y] = TILE[5];
//Desert
else blockImg[x][y] = TILE[3];
}
//Plains 0.2 - 0.6
else if(perlinIsland[x][y] <= 0.6) blockImg[x][y] = TILE[2];
//Rocky Mountains 0.6 - 0.8
else if(perlinIsland[x][y] <= 0.65) blockImg[x][y] = TILE[3];
//Snowy Mountains 0.6 - 1
else blockImg[x][y] = TILE[1];
blocks[x][y] = new Rectangle(x*32, y*32, 32, 32);
}
}
}
//collision detection
public boolean collide(Rectangle in)
{
if(blocks[0][0] != null){
for (int y = (int)((playerRect.y - blocks[0][0].y)/32)-1; y <= (int)((playerRect.y+playerRect.height - blocks[0][0].y)/32)+1; y++){
for (int x = (int)((playerRect.x - blocks[0][0].x)/32)-1; x <= (int)((playerRect.x+playerRect.width - blocks[0][0].x)/32) + 1; x++){
if (x >= 0 && y >= 0 && x < 32 && y < 32){
if (blockImg[x][y] != null)
{
if (in.intersects(blocks[x][y]) && isSolid[x][y] == true){
{
return true;
}
}
}
}
}
}
}
return false;
}
//Key Listener
public class AL extends KeyAdapter{
public void keyPressed(KeyEvent e){
int keyInput = e.getKeyCode();
still = false;
if(keyInput == e.VK_LEFT){
navigateMap(PAN_RIGHT);
MOVING_WEST = true;
}if(keyInput == e.VK_RIGHT){
navigateMap(PAN_LEFT);
MOVING_EAST = true;
}if(keyInput == e.VK_UP){
navigateMap(PAN_DOWN);
MOVING_NORTH = true;
}if(keyInput == e.VK_DOWN){
navigateMap(PAN_UP);
MOVING_SOUTH = true;
}
}
public void keyReleased(KeyEvent e){
int keyInput = e.getKeyCode();
setYDirection(0);
setXDirection(0);
if(keyInput == e.VK_LEFT){
MOVING_WEST = false;
player = ARCHER_WEST[0];
}if(keyInput == e.VK_RIGHT){
MOVING_EAST = false;
player = ARCHER_EAST[0];
}if(keyInput == e.VK_UP){
MOVING_NORTH = false;
player = ARCHER_NORTH[0];
}if(keyInput == e.VK_DOWN){
MOVING_SOUTH = false;
player = ARCHER_SOUTH[0];
}
if(MOVING_SOUTH == MOVING_NORTH == MOVING_EAST == MOVING_WEST == false){
still = true;
}
}
}
public void moveMap(){
for(int a = 0; a < 30; a++){
for(int b = 0; b < 30; b++){
if(blocks[a][b] != null){
blocks[a][b].x += xDirection;
blocks[a][b].y += yDirection;
}
}
}
if(collide(playerRect) && blocks[0][0]!= null){
for(int a = 0; a < 30; a++){
for(int b = 0; b < 30; b++){
blocks[a][b].x -= xDirection;
blocks[a][b].y -= yDirection;
}
}
}
}
public void navigateMap(byte pan){
switch(pan){
default:
System.out.println("Unrecognized pan!");
break;
case PAN_UP:
setYDirection(-1);
break;
case PAN_DOWN:
setYDirection(+1);
break;
case PAN_LEFT:
setXDirection(-1);
break;
case PAN_RIGHT:
setXDirection(+1);
break;
}
}
//Animation Update
public void update(long gameTime) {
if (gameTime > frameTicker + framePeriod) {
frameTicker = gameTime;
currentFrame++;
if (currentFrame >= 4) {
currentFrame = 0;
}
}
if(MOVING_NORTH) player = ARCHER_NORTH[currentFrame];
if(MOVING_SOUTH) player = ARCHER_SOUTH[currentFrame];
if(MOVING_EAST) player = ARCHER_EAST[currentFrame];
if(MOVING_WEST) player = ARCHER_WEST[currentFrame];
}
public void setXDirection(int xdir){
xDirection = xdir;
}
public void setYDirection(int ydir){
yDirection = ydir;
}
//Method to get sprites
public BufferedImage grabSprite(int x, int y, int width, int height){
BufferedImage sprite = spriteSheet.getSubimage(x, y, width, height);
return sprite;
}
private void init(){
spriteSheet = null;
try {
spriteSheet = loadImage("ARCHER_SPRITESHEET.png");
} catch (IOException ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
}
for(int i = 0; i <= 3; i++){
ARCHER_NORTH[i] = grabSprite(i*16, 16, 16,16);
ARCHER_SOUTH[i] = grabSprite(i*16, 0, 16, 16);
ARCHER_EAST[i] = grabSprite(i*16, 32, 16, 16);
ARCHER_WEST[i] = grabSprite(i*16, 48, 16, 16);
}
}
public BufferedImage loadImage(String pathRelativeToThis) throws IOException{
URL url = this.getClass().getResource(pathRelativeToThis);
BufferedImage img = ImageIO.read(url);
return img;
}
public void paint(Graphics g){
dbImage = createImage(getWidth(), getHeight());
dbGraphics = dbImage.getGraphics();
paintComponent(dbGraphics);
g.drawImage(dbImage, 0, 25, this);
}
public void paintComponent(Graphics g){
requestFocus();
/**
//Draws tiles and rectangular boundaries for debugging
for(int a = 200; a < 230; a++){
for(int b = 200; b < 230; b++){
if(blockImg[a][b] != null && blocks[a][b] != null){
g.drawImage(blockImg[a][b], Math.round(blocks[a][b].x), Math.round(blocks[a][b].y), 32, 32, null);
}
}
}
//Draw player and rectangular boundary for collision detection
g.drawImage(player, playerX, playerY, 40, 40, null);
repaint();
//Draws transparent tiles
for(int a = 0; a < 20; a++){
for(int b = 0; b < 15; b++){
if(blockImgTrans[a][b] != null && blocks[a][b] != null){
g.drawImage(blockImgTrans[a][b], blocks[a][b].x, blocks[a][b].y, 32, 32, null);
}
}
}
**/
}
public void run(){
try{
while(true){
moveMap();
if(!still) update(System.currentTimeMillis());
Thread.sleep(13);
}
}catch(Exception e){
System.out.println("RUNTIME ERROR: " + e);
}
}
public static void main(String[] args) {
Main main = new Main();
//Threads
Thread thread1 = new Thread(main);
thread1.start();
}
}
stacktrace應該是不錯的開始:) – rocketboy
方式太多的代碼,包括註釋掉的代碼。你應該逐步診斷,減少代碼的數量,直到它是可管理的。那時你可能已經自己發現了這個問題。 –
你無法找到有限的catch代碼異常:catch(Exception e){System.out.println(「RUNTIME ERROR:」+ e);}'。至少打印堆棧跟蹤。至少在你的catch塊中有'e.printStackTrace()'。 –