@Override
    public void run() {
        final long EXPECTED_ELAPSED_TIME = 1000L / 30L;

        Graphics g = null;
        Graphics2D g2 = null;

        BufferedImage screen = GameUtils.createCompatibleImage(width, height);

        long frameTime = 0;
        long elapsedTime = 0;
        long currentTime = 0;
        long lastTime = System.currentTimeMillis();

        while (running) {
            currentTime = System.currentTimeMillis();
            elapsedTime = currentTime - lastTime;

            if (elapsedTime <= 0) {
                continue;
            }

            while (elapsedTime > 0 && !paused) {
                frameTime = elapsedTime;

                if (frameTime > EXPECTED_ELAPSED_TIME) {
                    frameTime = EXPECTED_ELAPSED_TIME;
                }

                update(frameTime);

                elapsedTime -= frameTime;
            }

            try {
                g2 = screen.createGraphics();

                g2.setColor(background);
                g2.fillRect(0, 0, width, height);

                draw(g2);

                g = buffer.getDrawGraphics();
                g.drawImage(screen, 0, 0, null);

                if (!buffer.contentsLost()) {
                    buffer.show();
                }

                toolkit.sync();
            }
            
            catch (Exception e) {
                
            }
            
            finally {
                if (g != null) {
                    g.dispose();
                }
                if (g2 != null) {
                    g2.dispose();
                }
            }

            lastTime = currentTime;
        }
    }