0

I'm working on a splashscreen of a game and there is a problem while trying to repaint it. I have 3 classes, 1 Main, 1 Game Manager and 1 for the splashscreen & loading, but when I try to repaint the screen to set show the current amount of loaded textures, it doesn't do anything. I have tried in more ways to call the repaint function, but it doesn't work and I don't understand why. Here is my Main class:

package basics;
import java.awt.Toolkit;
import javax.imageio.ImageIO;
import javax.swing.JFrame;

public class Main extends JFrame {

private static final long serialVersionUID = -2321072791006153371L;

public static void main(String[] args) {
    System.out.println("Booting...");
    try {
        new Main();
    } catch (Exception e) {
        e.printStackTrace();
    }
}   

public Main() throws Exception {
    this.setIconImage(ImageIO.read(Main.class.getResourceAsStream("/res/character.png")));
    this.setSize((int)Toolkit.getDefaultToolkit().getScreenSize().getWidth(), (int)Toolkit.getDefaultToolkit().getScreenSize().getHeight());
    System.out.println("manager");
    GameManager manager = new GameManager(this);
    this.add(manager);
    this.setUndecorated(true);
    this.setVisible(true);
    this.setTitle("Gem Hunt");
    this.setDefaultCloseOperation(EXIT_ON_CLOSE);
    this.setResizable(false);
    manager.startLoading();
}

}

Then here is the Game Manager's code:

package basics;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.image.BufferedImage;

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

import states.Credits;
import states.InGame;
import states.MainMenu;
import states.Splashscreen;


public class GameManager extends JPanel implements KeyListener, ActionListener {

private static final long serialVersionUID = -2781472756180639288L;
long lastLoopTime = System.currentTimeMillis();

public enum GameState {
    SPLASH_SCREEN, MAIN_MENU, LEVEL_SELECTOR, IN_GAME, CREDITS;
}

private JFrame frame;
private Timer timer;
private static GameState state;

private Splashscreen splashscreen;
private InGame game;
private MainMenu mainMenu;

private Credits credits;

/*
 * scale = iwidth/iheight
 * scale = i2width/x
 * i2width/x = scale
 * scale*x = i2width
 * x = i2width/scale
 * 
 */

public GameManager(JFrame frame) throws Exception {
    System.out.println("Loading splashscreen");
    this.frame = frame;
    frame.requestFocus();
    this.splashscreen = new Splashscreen(frame, this);
    state = GameState.SPLASH_SCREEN;
    timer = new Timer(30, this);
}

public void startLoading() {
    timer.start();
}

/**
 * @throws Exception
 */

public void startGame(BufferedImage[][][] textures) throws Exception {
    /* 
     * textures[0] - MainMenu
     * textures[1] - Game
     * textures[2] - LevelSelector
     * 
     * textures[0][0] - Backgrounds
     * textures[0][1-textures.length()-1] - Buttons
     * 
     * textures[1][0] - Background
     * textures[1][1] - Player
     * textures[1][2] - Objects
     * textures[1][3] - Gems
     * textures[1][4] - BackgroundObjects
     * textures[1][5] - Letters
     */
    this.mainMenu = new MainMenu(textures[0], frame);
    this.game = new InGame(frame, textures[1]);
    this.credits = new Credits(frame);

    state = GameState.IN_GAME;//TODO: Set it to MAIN_MENU when Main Menu is ready
    frame.addKeyListener(this);
    frame.addMouseListener(mainMenu);
    timer.start();
}

@Override
public void paint(Graphics g) {
    System.out.println("paint");
    switch(state) {
        case IN_GAME:
            game.draw(g);
            break;
        case MAIN_MENU:
            mainMenu.draw(g);
            break;
        case SPLASH_SCREEN:
            splashscreen.paint(g);
            break;
        case CREDITS:
            credits.paint(g);
            break;
        case LEVEL_SELECTOR:
            break;
        default:
            break;
    }
     long delta = System.currentTimeMillis() - lastLoopTime;
     lastLoopTime = System.currentTimeMillis();
     g.setColor(Color.yellow);
     g.drawString("FPS: " + delta, 0, 20);
     g.dispose();
}

@Override
public void actionPerformed(ActionEvent a) {
    timer.start();
    switch (state) {
    case IN_GAME:
        game.runAction();
        break;
    case MAIN_MENU:
        mainMenu.update();
        break;
    case CREDITS:
        credits.update();
        break;
    case LEVEL_SELECTOR:
        break;
    case SPLASH_SCREEN:
        splashscreen.update();
        break;
    default:
        break;
    }
    repaint();
}


@Override
public void keyPressed(KeyEvent e) {
    if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {
        System.exit(-1);
    } else {
        if (!game.isRunning()) {
            game.startGame();
        }
        switch (state) {
        case IN_GAME:
            game.keyPressed(e);
            break;

        default:
            break;
        }
    }
}

@Override
public void keyReleased(KeyEvent e) {
    switch (state) {
    case IN_GAME:
        game.keyReleased(e);
        break;

    default:
        break;
    }
}

@Override
public void keyTyped(KeyEvent e) {}

public static void setState(GameState inGame) {
    state = GameState.IN_GAME;
}

public void updateDisplay(Graphics g) {
    timer.start();
    repaint();
}

}

And finally the SplashScreen class, where I tried to repaint the window after each texture that I have loaded, because it wasn't repainting by itself, only after it has loaded everything:

package states;

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.font.FontRenderContext;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.io.BufferedInputStream;

import javax.imageio.ImageIO;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
import javax.sound.sampled.FloatControl;
import javax.swing.JFrame;

import basics.GameManager;

public class Splashscreen {

    private static final int ALL_TO_LOAD = 25;

    private JFrame frame;
    private GameManager manager;

    private int loaded;
    private boolean loading;

    public Splashscreen(JFrame frame, GameManager manager) throws Exception {
        this.frame = frame;
        this.manager = manager;
        this.loaded = 0;
        this.loading = false;
    }

    private Graphics g;

    public void paint(Graphics g) {
        this.g= g;
        g.setColor(Color.black);
        g.fillRect(0, 0, frame.getWidth(), frame.getHeight());
        g.setColor(Color.green);
        centerString(g, new Rectangle(0,0,frame.getWidth(),frame.getHeight()), loaded + " / " + ALL_TO_LOAD, new Font("Times New Roman", Font.BOLD, 20));
    }

    public void update() {
        if (!loading) {
            try {
                doLoading();
            } catch (Exception e) {
                e.printStackTrace();
                System.exit(-1);
            }
        }
    }



    private void doLoading() throws Exception {
        BufferedImage[][][] textures = new BufferedImage[3][6][5];
        /* 
         * textures[0] - MainMenu
         * textures[1] - Game
         * textures[2] - LevelSelector
         * 
         * textures[0][0] - Backgrounds
         * textures[0][1] -textures.length()-1] - Buttons
         * 
         * textures[1][0] - Background
         * textures[1][1] - Player
         * textures[1][2] - Objects
         * textures[1][3] - Gems
         * textures[1][4] - BackgroundObjects
         * textures[1][5] - Letters
         */
        System.out.println("Loading some cool music");
        AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(new BufferedInputStream(GameManager.class.getResourceAsStream("/res/Dead Or Alive - You Spin Me Round (Like a Record).wav")));
        loaded++; manager.updateDisplay(g);
        Clip clip = AudioSystem.getClip();
        clip.open(audioInputStream);
        FloatControl volume = (FloatControl) clip.getControl(FloatControl.Type.MASTER_GAIN);
        volume.setValue(-20);
        clip.start();
        clip.loop(Clip.LOOP_CONTINUOUSLY);
        System.out.println("Loading the textures");

        textures[1][0][0] = ImageIO.read(GameManager.class.getResourceAsStream("/res/backgroundAboveFloor.jpg")); loaded++; manager.updateDisplay(g);
        textures[1][0][1] = ImageIO.read(GameManager.class.getResourceAsStream("/res/SkyBackground.jpg")); loaded++; manager.updateDisplay(g);

        textures[1][1][0] = ImageIO.read(GameManager.class.getResourceAsStream("/res/character.png")); loaded++; manager.updateDisplay(g);

        textures[1][2][0] = ImageIO.read(GameManager.class.getResourceAsStream("/res/backgroundFloor.jpg")); loaded++; manager.updateDisplay(g);
        textures[1][2][1] = ImageIO.read(GameManager.class.getResourceAsStream("/res/floor original.png")); loaded++; manager.updateDisplay(g);

        textures[1][3][0] = ImageIO.read(GameManager.class.getResourceAsStream("/res/coin.png")); loaded++; manager.updateDisplay(g);

        textures[1][4][0] = ImageIO.read(GameManager.class.getResourceAsStream("/res/cloud1.png")); loaded++; manager.updateDisplay(g);
        textures[1][4][1] = ImageIO.read(GameManager.class.getResourceAsStream("/res/cloud2.png")); loaded++; manager.updateDisplay(g);
        textures[1][4][2] = ImageIO.read(GameManager.class.getResourceAsStream("/res/cloud3.png")); loaded++; manager.updateDisplay(g);
        textures[1][4][3] = ImageIO.read(GameManager.class.getResourceAsStream("/res/cloud4.png")); loaded++; manager.updateDisplay(g);
        textures[1][4][4] = ImageIO.read(GameManager.class.getResourceAsStream("/res/cloud5.png")); loaded++; manager.updateDisplay(g);

        textures[1][5][0] = ImageIO.read(GameManager.class.getResourceAsStream("/res/S.png")); loaded++; manager.updateDisplay(g);
        textures[1][5][1] = ImageIO.read(GameManager.class.getResourceAsStream("/res/c.png")); loaded++; manager.updateDisplay(g); 
        textures[1][5][2] = ImageIO.read(GameManager.class.getResourceAsStream("/res/o.png")); loaded++; manager.updateDisplay(g);
        textures[1][5][3] = ImageIO.read(GameManager.class.getResourceAsStream("/res/r.png")); loaded++; manager.updateDisplay(g);
        textures[1][5][4] = ImageIO.read(GameManager.class.getResourceAsStream("/res/e.png")); loaded++; manager.updateDisplay(g);

        System.out.println("Setting rescaling the textures");

        double scale = (double)textures[1][2][1].getWidth()/textures[1][2][1].getHeight();
        int height = (int) (((frame.getWidth()/4)*2)/6/scale);

        Image img = textures[1][2][1].getScaledInstance(((frame.getWidth()/4)*2)/6, height, Image.SCALE_AREA_AVERAGING);
        BufferedImage bimage = new BufferedImage(img.getWidth(null), img.getHeight(null), BufferedImage.TYPE_INT_ARGB);
        Graphics2D bGr = bimage.createGraphics();
        bGr.drawImage(img, 0, 0, null);
        bGr.dispose();

        textures[1][2][1] = bimage; loaded++; manager.updateDisplay(g);

        scale = textures[1][1][0].getWidth()/(double)textures[1][1][0].getHeight();
        height = (int)(textures[1][2][1].getWidth()/scale);

        img = textures[1][1][0].getScaledInstance(textures[1][2][1].getWidth(), height, Image.SCALE_AREA_AVERAGING);
        bimage = new BufferedImage(img.getWidth(null), img.getHeight(null), BufferedImage.TYPE_INT_ARGB);
        bGr = bimage.createGraphics();
        bGr.drawImage(img, 0, 0, null);
        bGr.dispose();

        textures[1][1][0] = bimage; loaded++; manager.updateDisplay(g);

        scale = (double)textures[1][4][0].getWidth()/textures[1][4][0].getHeight();
        height = (int) (((frame.getWidth()/4)*2)/3/scale);

        img = textures[1][4][0].getScaledInstance(((frame.getWidth()/4)*2)/3, height, Image.SCALE_AREA_AVERAGING);
        bimage = new BufferedImage(img.getWidth(null), img.getHeight(null), BufferedImage.TYPE_INT_ARGB);
        bGr = bimage.createGraphics();
        bGr.drawImage(img, 0, 0, null);
        bGr.dispose();

        textures[1][4][0] = bimage; loaded++; manager.updateDisplay(g);

        scale = (double)textures[1][4][1].getWidth()/textures[1][4][1].getHeight();
        height = (int) (((frame.getWidth()/4)*2)/3/scale);

        img = textures[1][4][1].getScaledInstance(((frame.getWidth()/4)*2)/3, height, Image.SCALE_AREA_AVERAGING);
        bimage = new BufferedImage(img.getWidth(null), img.getHeight(null), BufferedImage.TYPE_INT_ARGB);
        bGr = bimage.createGraphics();
        bGr.drawImage(img, 0, 0, null);
        bGr.dispose();

        textures[1][4][1] = bimage; loaded++; manager.updateDisplay(g);

        scale = (double)textures[1][4][2].getWidth()/textures[1][4][2].getHeight();
        height = (int) (((frame.getWidth()/4)*2)/3/scale);

        img = textures[1][4][2].getScaledInstance(((frame.getWidth()/4)*2)/3, height, Image.SCALE_AREA_AVERAGING);
        bimage = new BufferedImage(img.getWidth(null), img.getHeight(null), BufferedImage.TYPE_INT_ARGB);
        bGr = bimage.createGraphics();
        bGr.drawImage(img, 0, 0, null);
        bGr.dispose();

        textures[1][4][2] = bimage; loaded++; manager.updateDisplay(g);

        scale = (double)textures[1][4][3].getWidth()/textures[1][4][3].getHeight();
        height = (int) (((frame.getWidth()/4)*2)/3/scale);

        img = textures[1][4][3].getScaledInstance(((frame.getWidth()/4)*2)/3, height, Image.SCALE_AREA_AVERAGING);
        bimage = new BufferedImage(img.getWidth(null), img.getHeight(null), BufferedImage.TYPE_INT_ARGB);
        bGr = bimage.createGraphics();
        bGr.drawImage(img, 0, 0, null);
        bGr.dispose();

        textures[1][4][3] = bimage; loaded++; manager.updateDisplay(g);

        scale = (double)textures[1][4][4].getWidth()/textures[1][4][4].getHeight();
        height = (int) (((frame.getWidth()/4)*2)/3/scale);

        img = textures[1][4][4].getScaledInstance(((frame.getWidth()/4)*2)/3, height, Image.SCALE_AREA_AVERAGING);
        bimage = new BufferedImage(img.getWidth(null), img.getHeight(null), BufferedImage.TYPE_INT_ARGB);
        bGr = bimage.createGraphics();
        bGr.drawImage(img, 0, 0, null);
        bGr.dispose();

        textures[1][4][4] = bimage; loaded++; manager.updateDisplay(g);
        manager.startGame(textures);
    }

    public void centerString(Graphics g, Rectangle r, String s, Font font) {
        FontRenderContext frc = new FontRenderContext(null, true, true);

        Rectangle2D r2D = font.getStringBounds(s, frc);
        int rWidth = (int) Math.round(r2D.getWidth());
        int rHeight = (int) Math.round(r2D.getHeight());
        int rX = (int) Math.round(r2D.getX());
        int rY = (int) Math.round(r2D.getY());

        int a = (r.width / 2) - (rWidth / 2) - rX;
        int b = (r.height/ 2) - (rHeight / 2) - rY;
        g.setFont(font);
        g.drawString(s, r.x + a, r.y + b);
    }
}

I have tried to do the repaint stuff without the timer.start method in the updateWindow method, I have also tried to call repaint directly from the Splashscreen class.

Andrew Thompson
  • 168,117
  • 40
  • 217
  • 433
  • 1
    Yours is an [XY Problem](http://xyproblem.info) type question. You're able to call `repaint()` just fine, and so your title is incorrect. The problem is that it is having no effect, likely because you're probably loading textures on the Swing event thread, blocking the thread, preventing the GUI from doing any rendering whatsoever. That's the *real* problem here, not your "inability to call repaint". The solution is to use a background thread to do any long-running code, such as via a SwingWorker. – Hovercraft Full Of Eels Jan 05 '19 at 21:30
  • Yes, creating a Graphics field, g, and then doing `this.g= g;` is not wise. You certainly are not treating the Swing event thread correctly and need to read [Concurrency in Swing](https://docs.oracle.com/javase/tutorial/uiswing/concurrency/) to better understand the workings of the Swing event thread. – Hovercraft Full Of Eels Jan 05 '19 at 21:32
  • Honestly, I think you’re just blocking the event dispatching thread, which will prevent the system from been able to update the ui. Personally, I’m not sure that “loading” should be done in the game manager (or I’d use a better delegate model) – MadProgrammer Jan 05 '19 at 21:33
  • You've got a really insane amount of code here that basically duplicates what `ImageIcon` already does. You don't need all this just to display a splash screen. – markspace Jan 05 '19 at 21:34
  • You are right, but can you help me how could I add a background thread to do the long running code? – dominikremes Jan 05 '19 at 21:35
  • What you should do is properly use the EDT, and just load it on the main thread. Don't block the EDT. – markspace Jan 05 '19 at 21:36
  • Again, please have a look at the tutorial link that I've given you about [Concurrency in Swing](https://docs.oracle.com/javase/tutorial/uiswing/concurrency/) – Hovercraft Full Of Eels Jan 05 '19 at 21:37
  • Thank you all guys, you have really helped me a lot – dominikremes Jan 05 '19 at 21:45

0 Answers0