0

Me and my friend are working on a game where we want to have layered images in the background, and buttons to navigate through them on top of those images. One image could stay the same, while the other is constantly changing. To do this, I thought the render and tick philosophy would be great.

For those of you that have seen those cheesy visual novel games from japan, that is basically what we are working on.

Update: So I used many of your suggestions below. My new problem is my JButton will disappear underneath the picture before I scroll over it. When I add the super.paintComponent(g) as suggested, everything disappears immediately as it appears.

The code of my main method looks like this currently:

package Urban.Blade.Package;

import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.io.*;
import Urban.Blade.Package.gfx.*;
import javax.swing.*;

public class MainGame extends JPanel{
    private static final long serialVersionUID = 1L;
    public static final int WIDTH = 300, HEIGHT = 300, SCALE = 2, PICSCALE = 0;
    public BufferedImage background1;
    public BufferedImage testCharacter1;
    static JButton b1 = new JButton();
    static JButton b2 = new JButton();
    static JPanel j1 = new JPanel();
    static JPanel j2 = new JPanel();
    static JFrame frame = new JFrame("Urban Blade");
    static MainGame mGame = new MainGame();
    static JLayeredPane lJ = new JLayeredPane();
    static JLayeredPane lJ2 = new JLayeredPane();


    public static void main(String[] args){ 
        lJ.setPreferredSize(new Dimension(WIDTH * SCALE, HEIGHT * SCALE));
        lJ.setMaximumSize(new Dimension(WIDTH * SCALE, HEIGHT * SCALE));
        lJ.setMinimumSize(new Dimension(WIDTH * SCALE, HEIGHT * SCALE));
        lJ.setBounds(0, 0, WIDTH * SCALE, HEIGHT * SCALE);

        mGame.setPreferredSize(new Dimension(WIDTH * SCALE, HEIGHT * SCALE));
        mGame.setMaximumSize(new Dimension(WIDTH * SCALE, HEIGHT * SCALE));
        mGame.setMinimumSize(new Dimension(WIDTH * SCALE, HEIGHT * SCALE));
        mGame.setBounds(0, 0, WIDTH * SCALE, HEIGHT * SCALE);

        frame.setSize(WIDTH * SCALE, HEIGHT * SCALE);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setResizable(false);
        lJ.setLayout(null);

        frame.add(mGame);
        frame.add(lJ);

        j2.setLayout(new GridLayout());
        j2.setSize(WIDTH * SCALE, HEIGHT * SCALE);
        j2.setLocation(0, 0);

        j1.setLayout(new GridLayout());
        j1.setSize(100, 25);
        j1.setLocation(225*SCALE, 250*SCALE);
        j1.add(b1);
        b1.addMouseListener(new MouseAdapter() {
                public void mouseClicked(MouseEvent me) {
                System.out.println("CLICKED");
            }
        });


        frame.setVisible(true);

        lJ.add(j2);
        lJ.add(j1);
        lJ.setComponentZOrder(j2, 1);
        lJ.setComponentZOrder(j1, 0);
        mGame.init();
        mGame.paintComponent();
    }

    public void init(){
        ImageLoader loader = new ImageLoader();
        background1 = loader.load(new File("res/testBackground.png"));
        testCharacter1 = loader.load(new File("res/testForeground.png"));


    }

    public void paintComponent(){
        Graphics g = j2.getGraphics();

        g.drawImage(background1, 0, 0, WIDTH * SCALE, HEIGHT * SCALE, null);
        g.drawImage(testCharacter1, 0, 0, WIDTH * SCALE, HEIGHT * SCALE, null);

        super.paintComponent(g);

        g.dispose();
    }
}
Cœur
  • 37,241
  • 25
  • 195
  • 267
Shawn
  • 3
  • 2
  • You could start with a JLayeredPane, each image could be rendered via a custom JPanel or JLabel. You could then add the button to this. The JLayeredPane will allow you to specify the z-order of the components, but you will become responsible for positioning and sizing the components yourself...it does mean you can't use BufferStrategy. Swing components don't work with BufferStrategy and AWT components can't be z-ordered – MadProgrammer Aug 20 '14 at 20:35

1 Answers1

0

Your problem is you are trying to mix normal GUI drawing with custom drawing in a BufferStrategy. If you are using a BufferStrategy, then update/paint operations don't work. One option is to use normal paint/paintComponent overrides with a null layout manager so you can position the button wherever you want and draw your images behind them.

If you want to continue to use BufferStrategy you can try to manually call paint passing in your Graphics object. Not sure if this will work since I have never tried it.

If you use the first option you have to make sure that the JPanel has a transparent background instead of opaque. You also have to call super.paint() after you draw your images so the JDK drawing will occur after your custom drawing and the buttons will appear on top.

markbernard
  • 1,412
  • 9
  • 18
  • Thank you for the help, I am now able to move the button to where I want it to be, and the picture shows up. However, I have two different problems. The first problem is the button always disappears behind the picture. The second is when I add the super.paintComponent(g) to my paintComponent method after I draw my images, everything vanishes as soon as it appears. – Shawn Aug 20 '14 at 23:22
  • That is because JPanel is opaque by default. As soon as it draws it overdraws everything that is there already. Try calling setOpaque(false) in your constructor. – markbernard Aug 21 '14 at 01:04
  • Now I am able to call super.paint(g) without everything disappearing. I still run into the problem of the button getting painted over when I call paint component though. I assumed z Order was supposed to fix that, but it didn't. – Shawn Aug 21 '14 at 01:16
  • I managed to fix it by merging the two images into a single icon, making it into a jLabel, and then assigning it to the back layer! Thank you for all of your help, I wouldn't have been able to solve this much without you. – Shawn Aug 21 '14 at 01:27
  • @Shawn *"Now I am able to call super.paint(g) without everything disappearing"* scares me, a lot. Painting is destructive, each time a component paints, it is expected to completely repaint itself from scratch, that's the point. See [Painting in AWT and Swing](http://www.oracle.com/technetwork/java/painting-140037.html) for more details. Consider providing a [runnable example](https://stackoverflow.com/help/mcve) which demonstrates your problem. This will result in less confusion and better responses – MadProgrammer Aug 21 '14 at 02:11
  • @MadProgrammer Since JPanel is a container it has no visible element except the background. You can make the background transparent and when you call paint on a JPanel it will only paint the components it contains. – markbernard Aug 21 '14 at 09:54
  • @markbernard Except Swing only knows if a component is transparent when it's opaque state is set to false. Failing to paint the background, or set the background to a transparent color will cause all sorts of nasty paint artifacts because Swing won't update the component(s) below it... – MadProgrammer Aug 21 '14 at 09:57
  • @MadProgrammer Correct. That is why I told him to call setOpaque(false). Also when you are game programming you have to break the "rules" a lot of the time to get things to work. – markbernard Aug 21 '14 at 09:59
  • @markbernard You, never, want to break the paint rules, they will come back to bite you...In Swing, you don't control the paint process, so you have to play nice and within the rules to make it work ;) – MadProgrammer Aug 21 '14 at 10:22
  • @MadProgrammer I guess will have to agree to disagree. When you call setOpaque(false) you can do custom drawing them allow normal painting to proceed. This allows you to have custom backgrounds on a JPanel instead of the standard background fill. Perfectly within the rules. Too bad we can't discuss this over a beer. :) – markbernard Aug 21 '14 at 11:01
  • @markbernard No, I agree, I didn't see setOpaque mentioned, so that scared me ;) – MadProgrammer Aug 21 '14 at 11:14