Why isn't my paintComponent() method getting called?

Here are my classes that do the rendering:

Game.java

package poke;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.GridLayout;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;

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

import poke.GamePanel;

import poke.graphics.GraphicsHandler;
import poke.player.Player;
import poke.player.PlayerHandler;
import poke.world.WorldHandler;

public class Game extends JFrame implements MouseListener, MouseMotionListener, KeyListener {

    private GamePanel gamePanel = new GamePanel();
    public static Toolkit toolkit = Toolkit.getDefaultToolkit();
    public static final int gameWidth = 1280;
    public static final int gameHeight = 720;

    public static String version = "Indev v0.1";
    private boolean running = false;

       private int fps = 60;
       private int frameCount = 0;

    // GAME INITIALIZATION

    public Game() {
        super("PokéRealms Client " + version);
        JFrame f = new JFrame();
        setVisible(true);
        running = true;
        setSize(new Dimension(gameWidth, gameHeight));
        setResizable(false);
        setBackground(Color.BLACK);

        Image icon = toolkit.getImage("./data/graphics/misc/icon.png");
        setIconImage(icon);

        addMouseListener(this);
        addMouseMotionListener(this);
        addKeyListener(this);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        runGameLoop();
    }

    // RUN THREAD

    public void runGameLoop() {
        Thread loop = new Thread() {
            public void run() {
                gameLoop();
            }
        };
        loop.start();
    }

    // GAME LOOP

    private void gameLoop() {

        final double GAME_HERTZ = 30.0;
        final double TIME_BETWEEN_UPDATES = 1000000000 / GAME_HERTZ;
        final int MAX_UPDATES_BEFORE_RENDER = 5;
        double lastUpdateTime = System.nanoTime();
        double lastRenderTime = System.nanoTime();
        final double TARGET_FPS = 60;
        final double TARGET_TIME_BETWEEN_RENDERS = 1000000000 / TARGET_FPS;

        int lastSecondTime = (int) (lastUpdateTime / 1000000000);

        while (running) {

            double now = System.nanoTime();
            int updateCount = 0;

            while( now - lastUpdateTime > TIME_BETWEEN_UPDATES && updateCount < MAX_UPDATES_BEFORE_RENDER ) {
                updateGame();
                lastUpdateTime += TIME_BETWEEN_UPDATES;
                updateCount++;
            }

            if (lastUpdateTime - now > TIME_BETWEEN_UPDATES) {
                lastUpdateTime = now - TIME_BETWEEN_UPDATES;
            }

            float interpolation = Math.min(1.0f, (float) ((now - lastUpdateTime) / TIME_BETWEEN_UPDATES) );
            drawGame(interpolation);
            lastRenderTime = now;

            int thisSecond = (int) (lastUpdateTime / 1000000000);
            if(thisSecond > lastSecondTime) {
                System.out.println("NEW SECOND " + thisSecond + " " + frameCount);
                fps = frameCount;
                frameCount = 0;
                lastSecondTime = thisSecond;
            }

            while(now - lastRenderTime < TARGET_TIME_BETWEEN_RENDERS && now - lastUpdateTime < TIME_BETWEEN_UPDATES) {
                Thread.yield();
                try {
                    Thread.sleep(1);
                } catch(Exception e) {
                    System.err.println(e);
                }

                now = System.nanoTime();
            }
        }
    }

    // UPDATES AND DRAWS

    private void updateGame() {
        gamePanel.update();
    }

    private void drawGame(float interpolation) {
        gamePanel.setInterpolation(interpolation);
        gamePanel.repaint();
    }

    // MAIN METHOD

    public static void main(String[] args) {
        Game game = new Game();
        System.out.println("Game initialized.");
    }
}

GamePanel.java

package poke;

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

import javax.swing.JPanel;

import poke.graphics.GraphicsHandler;
import poke.player.PlayerHandler;
import poke.util.ClockTime;
import poke.world.WorldHandler;

public class GamePanel extends JPanel {

    private static final long serialVersionUID = 1L;
    Image image;
    Graphics graphics;
    float interpolation;
    private int fps = 60;
    private int frameCount = 0;
    public boolean time = false;
    public int lastSecond = 0;

    public GamePanel() {
        PlayerHandler.addPlayer(0);
        WorldHandler.loadTiles();
        WorldHandler.loadObjects();
    }

    public void setInterpolation(float interp) {
        interpolation = interp;
    }

    public void update() {
        PlayerHandler.processWalking();
    }

    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        if(lastSecond != ClockTime.getSecond()) {
            lastSecond = ClockTime.getSecond();
            time = !time;
        }

        GraphicsHandler.drawWorld(g, time);
        PlayerHandler.process(g);

        image = createImage(getWidth(), getHeight());
        graphics = image.getGraphics();
        g.drawImage(image, 0, 0, this);

        g.setColor(Color.yellow);
        g.drawString("FPS: " + fps, 5, 10);

        frameCount++;
    }
}

My game had been working fine but I needed to add a time tick function because the game logic would tick at the same rate as the graphics, and I eventually intend to add multiplayer support, so I obviously need a fixed time tick rate for the logic. I've tried to implement a loop here, but I can't figure out why my paintComponent() method isn't getting called. Any help is appreciated.

Answers


Swing paint methods need to be invoked by the event handler thread. See http://java.sun.com/products/jfc/tsc/articles/threads/threads1.html#single_thread_rule


Need Your Help

Process to big for one request, when splitted in multiple request too the same page i get redirect loop

php cakephp loops redirect

I have a foreach in cakephp that processes products from a distributor, but the thing is the lists have up to 200products each product can have 3 big pictures with 2 resizes.

Android buttons not displaying on top of SurfaceView

android android-layout button surfaceview

So in an Activity I have a SurfaceView which I use as a drawing canvas, and 2 layouts to provide UI function. There is a LinearLayout holding buttons and a RelativeLayout which I use later on (it i...