Search code examples
javaswingjframejpanelpaintcomponent

JPanel not rendering when added to other JPanel


This is my Game Class:

package Game;

import java.awt.Color;
import java.awt.Graphics;

import javax.swing.JFrame;
import javax.swing.JPanel;

public class Game extends JPanel implements Runnable {
    Thread thread;
    private boolean running = true;
    private double FPS = 1.0/60.0;
    private Level level;

    public Game(){
        level = new LevelOne();
        level.setBackground(Color.BLACK);
        add(level);
    }

    public synchronized void start() {
        thread = new Thread(this, "Game");
        thread.start();
    }

    public synchronized void stop() {
        running = false;
        try {
            thread.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void run() {
        double firstTime = 0;
        double lastTime = System.nanoTime() / 1000000000.0;
        double passedTime = 0;
        double updateTime = 0;
        double timer = System.nanoTime() / 1000000000.0;
        int rendered = 0;
        int updates = 0;


        while (running) { 
            firstTime = System.nanoTime() / 1000000000.0;
            passedTime = firstTime - lastTime;
            lastTime = firstTime;

            updateTime += passedTime;

            while(updateTime > FPS){
                updates++;
                update();
                updateTime -= FPS;
            }

            render();
            rendered++;
            if((System.nanoTime() / 1000000000) - timer > 1){
                timer += 1;
                System.out.println("FPS:"+rendered+" Updates:"+updates);
                updates = 0;
                rendered = 0;
            }
        }
    }

    private void update() {

    }

    private void render() {
        this.repaint();
    }

    public void paintComponent(Graphics g){
        super.paintComponent(g);
        level.repaint();
    }

    public static void main(String[] args) {
        JFrame frame = new JFrame();
        frame.setLocationRelativeTo(null);
        frame.setSize(300, 300);
        frame.setVisible(true);
        frame.setTitle("Game");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        Game game = new Game();
        frame.add(game);
        game.start();
    }

}

My LevelOne class: package Game;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class LevelOne extends Level {
    private BufferedImage spriteSheet;
    private BufferedImage[] player = new BufferedImage[4]; //0 = down, 1 = right, 2 = up, 3 = left
    private int dir = 0;
    private String UP = "W";
    private String DOWN = "S";
    private String LEFT = "A";
    private String RIGHT = "D";
    private int speedX = 0;
    private int speedY = 0;

    public LevelOne(){
        try {
            spriteSheet = ImageIO.read(new File("images/sprites.png"));
        } catch (IOException e) {
            e.printStackTrace();
        }

        for (int i = 0; i < 4; i++) {
            player[i] = spriteSheet.getSubimage((i * 18), 0, 18, 28);
        }

        this.addKeyListener(new KeyListener() {
            @Override
            public void keyPressed(KeyEvent e) {
                String key = e.getKeyText(e.getKeyCode());
                if (key.equals(UP)) {
                    dir = 2;
                    speedY = -5;
                } else if (key.equals(LEFT)) {
                    dir = 3;
                    speedX = -5;
                } else if (key.equals(RIGHT)) {
                    dir = 1;
                    speedX = 5;
                } else if (key.equals(DOWN)) {
                    dir = 0;
                    speedY = 5;
                }
            }
            @Override
            public void keyReleased(KeyEvent e) {
                String key = e.getKeyText(e.getKeyCode());
                if (key.equals(UP)) {
                    speedY = 0;
                } else if (key.equals(LEFT)) {
                    speedX = 0;
                } else if (key.equals(RIGHT)) {
                    speedX = 0;
                } else if (key.equals(DOWN)) {
                    speedY = 0;
                }
            }
            @Override
            public void keyTyped(KeyEvent e) {

            }
        });
    }

    public void paintComponent(Graphics g){
        super.paintComponent(g);
        g.drawImage(player[dir], 0, 0, 18, 28, null);
    }
}

LevelOne extends Level, which is currently empty(And extends JPanel), I'm not sure if I need to add anything to Level. I just dont get what I need to do to make the player image show up...

And sorry if my code is sloppy, I'm trying to get into higher level Java, and im not sure if I am just approaching it wrong.

Thanks.


Solution

  • Six things...

    1. Don't call level.repaint from within the paintComponent method of Game, this could cause an infinite loop of repaint requests which is going to screw with your frame rate. Consider calling it within your render method
    2. paintComponent should never public, there's no reason for anybody to ever call it directly.
    3. Use key bindings over KeyListener, they will solve focus related issues. How to Use Key Bindings
    4. Move frame.setVisible AFTER frame.add(game);, in fact, it really should the last thing you do
    5. Make sure your images are loading properly
    6. Set the layout manager for Game to BorderLayout