Search code examples
javaanimationnullpointerexceptionbufferstrategy

Problem with NullPointerException in Animation method


I'm not very good at programming, it's my very first programme which uses Swing and AWT libraries. I have a problem while buffering my gameview. Here's the code of my Gra (game) class. This class uses some attributes like xPredkoscMax (xMaxVelocity) or some coordinates (to build the moon and other stuff on canvas) from the PropertiesGry class which is parsing attributes from configuration file.

'''

public class Gra extends Canvas {

private BufferStrategy bufferStrategy = null;
int score = 1000;
boolean hasCrushed;
boolean hasWon;
boolean isPaused = false;
int vy;
int vx;
int x;
int y;
boolean plus300Taken = false;
boolean minus300Taken = false;
public boolean minusShipTaken = false;
public static Timer timerForBonuses;
int time = 10;

Gra(int level) throws IOException {
    PropertiesGry.wczytajPlansze(level);
    x = PropertiesGry.xStartoweStatku[0];
    //bonusesTime();
}


private void shipLocation() {
    y = y + vy;
    if (vy < abs(PropertiesGry.yPredkoscMax)) vy++;
    if (vx > abs(PropertiesGry.yPredkoscMax)) vx = PropertiesGry.yPredkoscMax;
    if (vx < -PropertiesGry.yPredkoscMax) vx = -PropertiesGry.yPredkoscMax;
    x = x + vx;
    if (x > PropertiesGry.SZEROKOSC * 0.97)
        x = (int) (PropertiesGry.SZEROKOSC * 0.97);
    if (y < 0)
        y = 0;
    if (x < 0)
        x = 0;
    if (vx > 1) vx--;
    if (vx < -1) vx++;
}

@Override
public void addNotify() {
    super.addNotify();
    createBufferStrategy(3);
    bufferStrategy = getBufferStrategy();
}


@Override
public void paint(Graphics graphics) {
    super.paint(graphics);

    Shape moon = new Polygon(PropertiesGry.xWierzcholkiPlanety, PropertiesGry.yWierzcholkiPlanety, PropertiesGry.xWierzcholkiPlanety.length);
    Shape landing = new Polygon(PropertiesGry.xLadowiska, PropertiesGry.yLadowiska, PropertiesGry.xLadowiska.length);
    Graphics2D graphics2D = (Graphics2D) graphics;
    setBackground(new Color(47, 46, 64));
    graphics.clearRect(0, 0, getWidth(), getHeight());

    AffineTransform scaleTransform = graphics2D.getTransform();
    AffineTransform scaleMatrix = new AffineTransform();
    float xScale = (1f + (getSize().width - PropertiesGry.SZEROKOSC) / (float) PropertiesGry.SZEROKOSC);
    float yScale = (1f + (getSize().height - PropertiesGry.WYSOKOSC) / (float) PropertiesGry.WYSOKOSC);
    scaleMatrix.scale(xScale, yScale);
    graphics2D.setTransform(scaleMatrix);

    Rectangle2D ship = new Rectangle2D.Float(x, y, 25, 25);
    graphics2D.setColor(Color.white);
    graphics2D.fill(ship);

    graphics2D.setColor(Color.green);
    graphics2D.fill(landing);

    graphics2D.setColor(Color.gray);
    graphics2D.fill(moon);

    if (!plus300Taken) {
        Shape bonus = new Polygon(PropertiesGry.xBonusu, PropertiesGry.yBonusu, PropertiesGry.xBonusu.length);
        graphics2D.setColor(Color.yellow);
        graphics2D.fill(bonus);
        plus300(ship, bonus);
    }

    graphics2D.setTransform(scaleTransform);
    isColliding(moon, landing, ship);
}


private void isColliding(Shape moon, Shape landing, Rectangle2D player) {
    if ((moon.intersects(player)) || (landing.intersects(player)) && Math.abs(vy) > PropertiesGry.yPredkoscLadowania) {
        hasCrushed = true;
        hasWon = false;
    }
    if (landing.intersects(player) && Math.abs(vy) <= PropertiesGry.yPredkoscLadowania && Math.abs(vx) <= Math.abs(PropertiesGry.xPredkoscLadowania)) {
        hasWon = true;
        hasCrushed = false;
    }
}


private void minus300(Rectangle2D player, Shape minus) {
    if (minus.intersects(player)) {
        score -= 300;
        minus300Taken = true;
    }
}


private void plus300(Rectangle2D player, Shape bonus) {
    if (bonus.intersects(player)) {
        score += 300;
        //plus300Taken = true;
    }
}

private void deletebonuses() {
    plus300Taken = true;

}


public void isPaused() {
    this.isPaused = true;
}


public void isResumed() {
    this.isPaused = false;
}


public class AnimationTimerTask extends TimerTask {
    int i = 0;

    public void run() {
        if (!isPaused) {
            if (i == 2) {
                shipLocation();
                i = 0;
            }
            i++;
        }
        do {
            do {
                Graphics graphics = bufferStrategy.getDrawGraphics();
                paint(graphics);
                graphics.dispose();
                if (!isPaused) score--;

                //System.out.println(score);
            } while (bufferStrategy.contentsRestored());
                bufferStrategy.show();
            } while (bufferStrategy.contentsLost());
        }
    }
}

'''

Here is my class where I'm creating an Gra object, a Timer (licznikAnimacji) etc.

'''

public abstract class Logika {
Timer licznikAnimacji;

public void oknoGry(int numerPlanszy) throws IOException {
JFrame ramka = new JFrame("Gra");
ramka.setSize(PropertiesGry.SZEROKOSC,PropertiesGry.WYSOKOSC);
ramka.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
ramka.setLocationRelativeTo(null);
ramka.setLayout(new BorderLayout());

JPanel panel = new JPanel();
panel.setLayout(new GridLayout(5,1));

panel.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createEmptyBorder(0,0,0,0),BorderFactory.createMatteBorder(5,5,5,5,new Color(94, 179, 228))));    
JButton bPauza = new JButton("PAUZA");

panel.add(bPauza);

JLabel lStatki = new JLabel("", SwingConstants.CENTER);
panel.add(lStatki);

JLabel lPaliwo = new JLabel("", SwingConstants.CENTER);
panel.add(lPaliwo);

JLabel lPredkoscX = new JLabel("", SwingConstants.CENTER);
panel.add(lPredkoscX);

JLabel lPredkoscY = new JLabel("", SwingConstants.CENTER);
panel.add(lPredkoscY);

ramka.add(panel,BorderLayout.EAST);

licznikAnimacji = new Timer();
Gra gra = new Gra(numerPlanszy);

licznikAnimacji.scheduleAtFixedRate(gra.new AnimationTimerTask(), 100, 25);
//this.setFocusable(false);
ramka.add(gra);

Klawiatura klawiatura = new Klawiatura(gra);
ramka.addKeyListener(klawiatura);

ramka.requestFocus();
//ramka.setVisible(true);

//setBackground(Color.BLACK);

new Thread(() -> {
    while (!gra.hasCrushed && !gra.hasWon) {
        try {
            Thread.sleep(10);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }


        lPredkoscX.setText("PRĘDKOŚĆ X: " + gra.vx);
        if (Math.abs(gra.vx) > PropertiesGry.xPredkoscLadowania)
            lPredkoscX.setForeground(Color.RED);
            lPredkoscY.setText("PRĘDKOŚĆ Y: " + gra.vy);
        if (Math.abs(gra.vy) > PropertiesGry.yPredkoscLadowania)
            lPredkoscY.setForeground(Color.RED);
    }
    try {
        resetujLicznikAnimacji();
        if (gra.czyWyladowano) {

        }
        if (gra.czyRozbitoSie && gra.liczbaStatkow > 1) {

        }
        if (gra.czyRozbitoSie && gra.liczbaStatkow <= 1) {

        }
    } catch (Exception e) {
        e.printStackTrace();
    }
    }).start();
}

public void resetujLicznikAnimacji() {
    licznikAnimacji.cancel();
    licznikAnimacji.purge();
}

}

'''

The problem is that when I'm running this programme this Exception appears:

Exception in thread "Timer-0" java.lang.NullPointerException
at Gra$AnimationTimerTask.run(Gra.java:601)
at java.base/java.util.TimerThread.mainLoop(Timer.java:556)
at java.base/java.util.TimerThread.run(Timer.java:506)

The 601'st line is

 Graphics graphics = bufferStrategy.getDrawGraphics();

What I have to do? It looks like the addNotify method has not been called. I don't know why. Where I should pass the value of variable bufferstrategy to avoid this exception and display the animation of my ship?

Thank you for your help. Sorry if there was some similar question, but I'm a beginner in programming and I don't know what I need to do in my case.


Solution

  • As methods createBufferStrategy and getBufferStrategy are defined in Canvas you can add a method to you Gra class and call it from wherever you want (Gra constructor or the task):

    private BufferStrategy getInitializedBufferStrategy() {
        BufferStrategy strategy = getBufferStrategy();
        if (null == strategy) {
            createBufferStrategy(3);
            strategy = getBufferStrategy();
        }
        return strategy;
    }
    

    then in the Task code replace call to the instance:

    Graphics graphics = getInitializedBufferStrategy().getDrawGraphics();