2

I believe my code will describe what I wrote, But the problem is, is that When I run it, I get that infamous "Exception in thread "Animator" java.lang.IllegalArgumentException: Width (0) and height (0) cannot be <= 0" Error. I have searched for answers but have yet to find why this is happening.

package com.shparki.TowerDefense;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Toolkit;

import javax.swing.JPanel;

public class GamePanel extends JPanel implements Runnable{

//==================== PROGRAM VARIABLES ====================//
    private static final int WIDTH = 300;
    private static final int HEIGHT = WIDTH / 16 * 9;
    private static final int SCALE = 4;

    private static final int TARGET_FPS = 45;
    private static final int PERIOD = 1000 / TARGET_FPS;

    private boolean debug = true;
    private volatile boolean running = false;
    private volatile boolean gameOver = false;
    private volatile boolean paused = false;

    private Thread animator;
    private TowerDefense frame;

    private double currentFPS;


//==================== PROGRAM METHODS ====================//
    public GamePanel(TowerDefense td){
        frame = td;

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

        setVisible(true);
    }
    public void addNotify(){
        super.addNotify();
        startGame();
    }
    public void startGame(){
        if (!running && animator == null){
            animator = new Thread(this, "Animator");
            animator.start();
        }
    }
    public void stopGame(){
        running = false;
    }
    public void run(){
        running = true;
        Long beforeTime, timeDiff, sleepTime;

        while(running){
            beforeTime = System.currentTimeMillis();

            update();
            render();
            paintScreen();

            timeDiff = System.currentTimeMillis() - beforeTime;
            sleepTime = PERIOD - timeDiff;
            if (sleepTime <= 0){
                sleepTime = 5L;
            }

            currentFPS = (1000 / ( timeDiff + sleepTime ));

            try{
                Thread.sleep(sleepTime);
            } catch (InterruptedException ex) { ex.printStackTrace(); }
        }
        System.exit(0);
    }

//==================== DRAWING METHODS ====================//
    private Graphics dbg;
    private Image dbImage;

    public void paintComponenet(Graphics g){
        super.paintComponent(g);
        if (dbImage != null){
            g.drawImage(dbImage, 0, 0, null);
        }
    }
    public void paintScreen(){
        Graphics g;
        try{
            g = this.getGraphics();
            if (g != null & dbImage != null){
                g.drawImage(dbImage, 0, 0, null);
            }
            Toolkit.getDefaultToolkit().sync();
            g.dispose();
        } catch (Exception ex) { System.out.println("Graphics context error: " + ex); }
    }
    public void doubleBuffer(){
        if (dbImage == null){
            dbImage = createImage(getWidth(), getHeight());
            if (dbImage == null){
                System.out.println("dbImage is null");
                return;
            } else {
                dbg = dbImage.getGraphics();
            }
        }
    }

//==================== UPDATE METHODS ====================//
    public void update(){

    }


//==================== RENDER METHODS ====================//
    public void render(){
        doubleBuffer();

        Graphics2D g2d = (Graphics2D) dbg;

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

}

And this is my frame class:

package com.shparki.TowerDefense;

import java.awt.BorderLayout;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;

import javax.swing.JFrame;

public class TowerDefense extends JFrame implements WindowListener{

    public TowerDefense(String name){
        super(name);
        setResizable(false);

        setLayout(new BorderLayout());
        add(new GamePanel(this), BorderLayout.CENTER);
        pack();

        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setLocationRelativeTo(null);
        setVisible(true);

    }


    public void windowActivated(WindowEvent arg0) {  }
    public void windowClosed(WindowEvent arg0) {  }
    public void windowClosing(WindowEvent arg0) {  }
    public void windowDeactivated(WindowEvent arg0) {  }
    public void windowDeiconified(WindowEvent arg0) {  }
    public void windowIconified(WindowEvent arg0) {  }
    public void windowOpened(WindowEvent arg0) {  }

    public static void main(String[] args){
        new TowerDefense("Tower Defense Game");
    }

}
BenMorel
  • 34,448
  • 50
  • 182
  • 322
matt murray
  • 233
  • 2
  • 12
  • Just as a comment, Swing components are already double buffered and using `this.getGraphics` is highly unrecommended as it can produce undesirable effects and paint problems... – MadProgrammer Jun 24 '13 at 23:56
  • Just as another Comment: You should try and [avoid tweaking the sizing hints](http://stackoverflow.com/questions/7229226/should-i-avoid-the-use-of-setpreferredmaximumminimumsize-methods-in-java-swi) i.e. setXXsize – Java Devil Jun 24 '13 at 23:59
  • Thanks for the input! As you can tell I am just learning Graphics Programming, and most of what I know so far comes for "Killer Java Game Programming". – matt murray Jun 25 '13 at 00:00

1 Answers1

2

The JFrame has not been packed then the height and widths are requested here in GamePanel

dbImage = createImage(getWidth(), getHeight());

resulting in 0x0 dimension for the JPanel.

The reason is that Swing invokes addNotify (where startGame resides) almost immediately once the parent component has been set for the component.

You could invoke startGame explicitly after pack has been called.

add(gamePanel, BorderLayout.CENTER);
pack();
gamePanel.startGame();
Reimeus
  • 158,255
  • 15
  • 216
  • 276
  • Thanks! I edited my code so that I use a method getPWidth() & getPHeight() rather than the default so that it works. – matt murray Jun 25 '13 at 04:36