2013-09-16 5 views
0

Я создаю игру. Он не выдаст ошибку в Eclipse, но когда я запускаю его в режиме отладки он бросает NullPointerException на линии:Получение NullPointerException при создании игры

System.out.println("Stone x: " + blocks.get(BlockRectangle.getByID(rectID)).getX() + " y: " + blocks.get(BlockRectangle.getByID(rectID)).getY()); 

Game.java:

package lt.projecturanium; 

import java.awt.BorderLayout; 
import java.awt.Canvas; 
import java.awt.Color; 
import java.awt.Dimension; 
import java.awt.Graphics; 
import java.awt.Graphics2D; 
import java.awt.image.BufferStrategy; 
import java.util.HashMap; 

import javax.swing.JFrame; 

import lt.projecturanium.blocks.Block; 
import lt.projecturanium.blocks.BlockRectangle; 
import lt.projecturanium.entity.Player; 
@SuppressWarnings("unused") 

public class Game extends Canvas implements Runnable{ 

    private static final long serialVersionUID = 1L; 

    private static JFrame _frame; 
    public static Game _instance; 

    private static final String TITLE = "Project Uranium"; 
    private static final int WIDTH = 650; 
    private static final int HEIGHT = WIDTH * 3/4; 

    private static final int UPDATE_RATE = 50; 
    private static final int RENDER_RATE = 100; 

    public static HashMap<Block, Coordinates> blocks = new HashMap<Block, Coordinates>(); 

    public int rectx = 0; 
    public int recty = 0; 
    public int rectID = 0; 

    public boolean hitted = false; 

    public float interpolation; 

    public static final Dimension SIZE = new Dimension(WIDTH, HEIGHT); 

    private Thread _thread; 

    private boolean _running; 

    private int _totalTicks = 0; 
    private int _tps = 0; 
    private int _fps = 0; 

    public Game() 
    { 
     _instance = this; 
     setPreferredSize(SIZE); 
     setMinimumSize(SIZE); 
     setMaximumSize(SIZE); 

     _frame = new JFrame(TITLE); 

     _frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); 
     _frame.setLayout(new BorderLayout()); 
     _frame.add(_instance, BorderLayout.CENTER); 
     _frame.pack(); 

     _frame.setResizable(false); 
     _frame.setLocationRelativeTo(null); 
     _frame.setVisible(true); 
     createBufferStrategy(2); 
     blocks.put(new Block(new BlockRectangle(200)), new Coordinates(30, 50)); 
    } 
    public synchronized void start() 
    { 
     _running = true; 
     _thread = new Thread(this, TITLE+"_main"); 
     _thread.start(); 
    } 
    public synchronized void stop() 
    { 
     _running = false; 
     if (_thread != null) 
     { 
      try { 
       _thread.join(); 
      } catch (InterruptedException e) { 
       e.printStackTrace(); 
      } 
     } 
    } 
    public void paint(Graphics g) { 
     super.paint(g); // fixes the immediate problem. 
     Graphics2D g2 = (Graphics2D) g; 
     g2.drawString("FPS: " + _fps + "\n TPS: " + _tps, 10, 10); 
     if (hitted) 
     { 
      recty = 0; 
      rectx += 21; 
      rectID++; 
      blocks.put(new Block(new BlockRectangle(rectID)), new Coordinates(rectx, recty)); 
      hitted = false; 
     } 
     recty++; 
     g2.drawImage(Player.getTexture(), 60, 60, null); 
     g2.drawRect(rectx, recty, 20, 20); 
     g2.setColor(new Color(101, 67, 33)); 
     g2.fillRect(0, 430, getWidth(), getHeight()); 
     g2.setColor(new Color(0, 100, 0)); 
     g2.fillRect(0, 420, getWidth(), 10); 
     g2.setColor(Color.BLACK); 
     if (recty == (419 - 20)) 
     { 
      hitted = true; 
     } 
    } 
    public void run() { 
     double lastUpdateTime = System.nanoTime(); 
     double lastRenderTime = lastUpdateTime; 
     final int ns = 1000000000; 
     final double nsPerUpdate = (double) ns/UPDATE_RATE; 
     final double nsPerRender = (double) ns/RENDER_RATE; 
     final int maxUpdatesBeforeRender = 5; 

     int lastSecond = (int) (lastUpdateTime/ns); 
     int tickCount = 0; 
     int renderCount = 0; 
     while (_running) { 

      long currTime = System.nanoTime(); 
      int tps = 0; 

      while ((currTime - lastUpdateTime) > nsPerUpdate && tps < maxUpdatesBeforeRender) { 
      update(); 
      tickCount++; 
      _totalTicks++; 
      tps++; 
      lastUpdateTime += nsPerUpdate; 
      interpolation = Math.min(1.0F, (float) ((currTime - lastUpdateTime)/nsPerUpdate)); 
      render(interpolation, getGraphics()); 
      } 

      if (currTime - lastUpdateTime > nsPerUpdate) { 
      lastUpdateTime = currTime - nsPerUpdate; 
      } 
      if (currTime - lastRenderTime == maxUpdatesBeforeRender + 1) 
      { 
       render(interpolation, getGraphics()); 
      } 
      renderCount++; 
      lastRenderTime = currTime; 

      int currSecond = (int) (lastUpdateTime/ns); 
      if (currSecond > lastSecond) { 
      _tps = tickCount; 
      _fps = renderCount; 
      tickCount = 0; 
      renderCount = 0; 
      lastSecond = currSecond; 
      _frame.setTitle(TITLE + " | TPS: " + _tps + " | FPS: "+ _fps); 

      } 

      while (currTime - lastRenderTime < nsPerRender && currTime - lastUpdateTime < nsPerUpdate) { 
      Thread.yield(); 
      try { 
       Thread.sleep(1); 
      } catch (InterruptedException e) { 
       e.printStackTrace(); 
      } 
      currTime = System.nanoTime(); 
      } 
     } 
     } 
    public void update() 
    { 
     _frame.pack(); 
    } 
    public void render(float interp, Graphics g) 
    { 
     BufferStrategy myStrategy = getBufferStrategy(); 
     Graphics gra = myStrategy.getDrawGraphics(); 
     paint(gra); 
     g.dispose(); 
     myStrategy.show(); 
     //System.out.println("Grass x: " + blocks.get("grass").getX() + " y: " + blocks.get("grass").getY()); 
     System.out.println("Stone x: " + blocks.get(BlockRectangle.getByID(rectID)).getX() + " y: " + blocks.get(BlockRectangle.getByID(rectID)).getY()); 
    } 
} 

BlockRectangle.java:

package lt.projecturanium.blocks; 

import java.awt.Image; 
import java.io.IOException; 
import java.util.HashMap; 

import javax.imageio.ImageIO; 

import lt.projecturanium.Game; 

public class BlockRectangle extends Block{ 
    private int id; 
    private static HashMap<Integer, BlockRectangle> rects = new HashMap<Integer, BlockRectangle>(); 
    public BlockRectangle(int id) 
    { 
     super(); 
     this.id = id; 
     rects.put(id, this); 
    } 
    public int getID() 
    { 
     return this.id; 
    } 
    public static BlockRectangle getByID(int id) 
    { 
     return rects.get(id); 
    } 
    public static Image getTexture() 
    { 
     try{   
      return ImageIO.read(Game._instance.getClass().getClassLoader().getResource("../res/player.png")); 
     } 
     catch(IOException e) 
     { 
      e.printStackTrace(); 
     } 
     return null; 
    } 
} 

Block.java:

пакет lt.projecturanium.blocks;

public class Block { 
    private Block block; 
    public Block (Block block){ 
     this.block = block; 
    } 
    public Block getBlock() { 
     return block; 
    } 
    public Block getBlockById(int id) 
    { 
     return block; 
    } 
    public Block() 
    { 

    } 
} 

Ошибка:

Thread [Project Uranium_main] (Suspended (exception NullPointerException)) 
    Game.render(float, Graphics) line: 186 
    Game.run() line: 139  
    Thread.run() line: not available  
+4

Можете вы добавить ошибки в вопрос? – fvrghl

+11

'Я думаю, вы знаете, что я создаю игру. '- Не знал до сих пор, но буду помнить об этом. – devnull

+4

Что вы подразумеваете под словом «это не ошибка в Eclipse»? Вы имеете в виду, что Eclipse не сообщает об ошибке компиляции? Вы отлаживаете его в Eclipse, правильно? –

ответ

1

Начать отладку, глядя на отдельные значения, которые могут быть нулевым. Вы можете использовать этот блок в качестве примера:

BlockRectangle blockRectangle = BlockRectangle.getByID(rectID); 
System.out.println("BlockRectangle: " + blockRectangle); 
Coordinates coordinates= blocks.get(blockRectangle); 
System.out.println("Coordinates: " + coordinates); 
System.out.println("X: " + coordinates.getX()); 
System.out.println("Y: " + coordinates.getY()); 

После того, как вы определили, что имеет нулевое значение, вы можете начать обратно отслеживание через ваш код, чтобы определить, почему не существует установленное значение, где вы ожидаете один быть.

+0

Я определил, что это координаты. –

+0

Это хороший первый шаг - теперь вы знаете, что когда вы вызываете blocks.get (blockRectangle), вы возвращаете нулевое значение. Поскольку вы используете HashMap, есть две возможные причины для получения нулевого значения: либо ключ (blockRectangle) не существует, либо ключ существует, но ему присваивается нулевое значение. Вы можете определить это, выполнив итерацию через Карту и распечатку того, что она содержит. Вы также захотите посмотреть, где вы назначаете значения в свои блоки HashMap, чтобы удостовериться, что 1) фактически вызывал код в какой-то момент, 2) не вставляя нулевые значения, если вам не следует. – GamerJosh

0

Исключение с нулевым указателем, где ваш код пытается что-то сделать со значением, но значение равно null. Значение равно null, потому что либо оно не создается Object o = new Object, либо вы извлекаете из источника данных, где нужная запись не существует, она возвращает нуль. См. http://docs.oracle.com/javase/7/docs/api/java/lang/NullPointerException.html

В вашем случае вы получаете NPE в строке System.out.println("Stone x: " + blocks.get(BlockRectangle.getByID(rectID)).getX() + " y: " + blocks.get(BlockRectangle.getByID(rectID)).getY());, потому что Карта возвращает нулевой объект BlockRectangle.

Что касается вашего комментария к ответу @ GamerJosh, ваша ошибка находится в координатах, что я собираюсь угадать, потому что вы возвращаете нулевой BlockRectangle из getById(). Подумайте об этом так: вы никогда не увеличиваете/не изменяете поле rectId, но добавляете первый объект к идентификатору 200. Помимо этого, вы добавляете новые блоки с идентификатором 0 в свой метод paint(). Но что произойдет, если вы перейдете к этому протоколу регистрации до того, как эти другие блоки будут на вашей карте? Что бы ваша карта вернулась для Id 0, если единственная запись там имеет идентификатор 200?

Это, как говорится, я не думаю, что сохранение карты всех BlockRectangles является самым большим программным проектом. Вместо этого подумайте о наличии переменной в вашем основном классе, которая отслеживает все это.

PS. Вы очень хороший английский, и вам интересно узнать, что вы начинаете программировать в молодом возрасте! Кроме того, поскольку вы делаете игру, я хотел бы указать на сайт Game Development Stack Exchange, где вы можете задать конкретные вопросы игры, такие как дизайн игр или вопросы программирования, которые могут возникнуть у разработчиков игр.

+0

Okey, я проверю это :) Спасибо за ответ :) –

+0

Это не работает. Вы проверили мой код blockRectangle? –

+0

вы можете ответить? –

0

Ваш код генерирует исключение NullPointerException независимо от того, где вы его запускаете. Просто исключение этого исключения в методе потока run может быть выполнено только двумя способами: либо путем ловли его явно try {...} catch(NullPointerException e) {...}, либо с определением uncaughtExceptionHandler() Thread.

Метод run Я не обязательно ваш run, но тот, который определен для вызова рисования.

В зависимости от того, какие ожидания RuntimeExceptions вы ожидаете, вы либо определяете такой обработчик исключений, либо устраняете причину исключения. В вашем случае один из методов get не находит элемент и возвращает null.

1

Что странное программирование ...

Однако проблема, кажется, сидит здесь:

1) В классе Game у вас есть статическое поле типа HashMap<Block, Coordinates> называется блоков. Вы вводите экземпляры класса Block для ключей на эту карту. Соответствующая линия:

blocks.put(new Block(new BlockRectangle(rectID)), new Coordinates(rectx, recty)); 

2) В то время как также создание instace типа BlockRectangle в одной и той же линии, конструктор помещает объект в строительстве в качестве ключа в статическом поле типа HashMap<Integer, BlockRectangle> под названием прямоугольникам. Соответствующая строка:

rects.put(id, this); 

3) Затем вы пытаетесь получить блок, вызвав

blocks.get(BlockRectangle.getByID(rectID)) 

Внутреннего выражение BlockRectangle.getByID(rectID) возвратит BlockRectangle экземпляра, которое ищется на карте прямоугольников. С этим экземпляром теперь выполняется поиск на карте блоков, но в этом случае хранятся только Block s, а не BlockRectangle s (см. Пункт 1).

Без equalshashCode) метода в Block и BlockRectangle, вы не получаете дальше. Но реализация этих методов в любом из этих классов делает его еще хуже, так как нецелесообразно сравнивать блоки с блочными прямоугольниками.

Вы должны сделать полную редизайн своего программного обеспечения.

+0

Хорошо, я сменил HashMap в BlockRectangle на HashMap , но ничего не изменилось. –

+0

Не могли бы вы рассказать мне, как мне исправить ошибку проще? –

+0

Изменение карты в BlockRectangle на HashMap ничего не меняет, поскольку вы все еще сохраняете экземпляры BlockRectangle как значения внутри этой карты. Возможно, вы могли бы изменить другую карту на HashMap , а затем вам не следует создавать «новый блок (...)», который обертывает BlockRectangle, но просто использует только что созданный BlockRectangle в качестве ключа. Я не знаю, если это работает. Может быть, вы знаете кого-то, кто мог бы работать с вами в серьезной редизайне. – Seelenvirtuose

Смежные вопросы