1

I am making a game in Java. Basically, I have two different "planes" of updating that I need to take care of the. The base layer is the actual game painting itself. It is simply a JPanel that covers the entire JFrame, and is drawn to using its Graphics object.

I use a fixed timestep to take care of these first graphical updates. I have overwritten the paintComponent() method to do absolutely nothing, as I have written a custom render(float interpolation) method that takes care of that, as to prevent unwanted updates.

However, this panel can take no input beyond primitive mouse clicks and keyboard input. I need the ability to create various menus, text boxes, etc, that are also on the screen. Like various abilities, or even the "Menu" button that usually appears in the upper left corner of most games.

To take care of that input, such as creating buttons, I have a second JPanel that has setOpaque(false) applied to it. Then I create various Swing components that I might need, such as a JButton.

To contain the two JPanels, I use a JLayeredPane, and set their layers appropriately, as seen below. This way the input layer should always be on top of the actual game layer.

The code below shows how I create and add the Swing components to each other. addLoginDialog() is a method that adds a Swing component for the login. It has been tested and works properly, and isn't the problem.

private void initComponents()
{
    //This code is inside of the JFrame
    wholePane = new JLayeredPane();
    add(wholePane);
    guiPanel = new GUIPanel();
    guiPanel.setOpaque(false);
    gamePanel = new RPGPanel();
    gamePanel.setOpaque(false);
    wholePane.add(gamePanel, JLayeredPane.DEFAULT_LAYER);
    wholePane.add(guiPanel, JLayeredPane.POPUP_LAYER);
    guiPanel.addLoginDialog();
}

So when I run the code, I get horrible flickering. This is the code that is run from my fixed timestep ~60 times per second.

public void handleRepaint()
{
    //I don't use repaint() for the game drawing so I can be sure that fps is controlled.
    Graphics g = gamePanel.getGraphics();
    gamePanel.render(g);
    g.dispose();
    wholePane.repaint();
}

The problem is, I think, that the two different systems of updating the screen are clashing. The standard paintComponent() system is great for more static screens, but when I need to update consistently and keep track of the fps, I can't have updates going off randomly.

However, for the input layer, I only want to update as Swing normally does. When the mouse moves over a button, when I component is moved or is resized, etc.

Also, note the way the screen flickers: The Background image goes blank and then comes back again repeatedly. The input panel is always there, but is actually painted behind the game drawing, which shouldn't happen, because it is put in the default layer. The reason I know it isn't completely disappearing is because the game painting is partially transparent, so I can see underneath it, and the buttons I added are still there.

My main question is, how can I stop the flickering? Why is the game drawing being drawn on top of the input components when the game drawing is being done on the Panel that is in a lower layer in the JLayeredPane? And I supposed most importantly, what is causing the flickering? Thank you for any help.

user3144349
  • 419
  • 1
  • 4
  • 12
  • For better help sooner, post an [SSCCE](http://sscce.org/). – Andrew Thompson Dec 30 '13 at 05:36
  • `wholePane.setSize(getSize());` A layout manager is more likely to honor the referred size, than the size, but we should not be setting either. See [Should I avoid the use of set(Preferred|Maximum|Minimum)Size methods in Java Swing?](http://stackoverflow.com/q/7229226/418556) (Yes.) – Andrew Thompson Dec 30 '13 at 05:38
  • @AndrewThompson The sizing isn't a problem, so I'm not too concerned about that right now. – user3144349 Dec 30 '13 at 05:42
  • @AndrewThompson Actually I have gone through multiple tutorials, and all of them have told me to, when only concerning the drawing code, to use a render method and to make sure not to use paintComponent to avoid unwanted paint calls. – user3144349 Dec 30 '13 at 05:43
  • *"Actually I have gone through multiple tutorials,"* Apparently the wrong ones. Learn how to paint properly using the standard mechanisms before you go optimizing code for 200 FPS performance. It seems like 'premature optimization'. *"The sizing isn't a problem, so I'm not too concerned about that right now."* You should be. Not only is it stuff that will need to be fixed later, but ***every*** time you show source that has it, you will get tips like that. It seems you are wasting our time when you reply WTE 'ignore that..' because no, we won't ignore it. – Andrew Thompson Dec 30 '13 at 05:47
  • *"Well I'm not an expert, but I completely disagree."* Then apparently I can be of no further help. Besides that, you have spent time justifying your bad technique that would be better spent preparing an SSCCE. Good luck with it all. I have better things to do. – Andrew Thompson Dec 30 '13 at 05:50
  • I do know how to paint properly. I am not a fool. I am using a null layout, and the getSize() method returns the size properly of the parent JFrame. It does exactly what it is intended to do. – user3144349 Dec 30 '13 at 05:53
  • @AndrewThompson I don't mean any disrespect. You seem to be an expert in Swing and creating standard application GUIs, but that's not what I am trying to do. It isn't often that I am dead sure about something, but I do know that the way I am updating is not bad practice. It may be implemented improperly, I have no idea, but using the `paintComponent()` method when doing game painting is never a good idea, due to render/interpolation consistency. – user3144349 Dec 30 '13 at 05:57
  • Swing uses a passive rendering approach. If you want to use a direct painting process, then you need to use a Canvas and implement your own BufferStrategy. This will mean you won't be use Swing components, but you gain the control of the frame rate – MadProgrammer Dec 30 '13 at 06:17
  • *"Why is the game drawing being drawn on top of the input components when the game drawing is being done on the Panel that is in a lower layer in the JLayeredPane? "* mostly because you've circumvented how Swing works, – MadProgrammer Dec 30 '13 at 06:21
  • @MadProgrammer I would rather stick with Swing if possible. I was using http://docs.oracle.com/javase/tutorial/extra/fullscreen/rendering.html tutorial, which shows the use of Swing. However, if absolutely necessary, I will switch to Canvas. Although I think simply disabling the passive rendering of the components will do the trick, but I'm not sure. I would assume the passive/active rending clash is what is causing this problem. – user3144349 Dec 30 '13 at 06:26
  • 1
    @user3144349 You just "disable" the rendering engine, that's not how Swing is designed. It was made to work this way. You might as well try a cook a roast in the freezer...sorry, but that's the truth of the matter. I would imagine any tutorial that is telling you to avoid `paintComponent` should also be telling you to use a `BufferStrategy` instead. This is the only way to gain control over the paint process. The problem here is, Swing components are designed to use the passive rendering engine...catch 22... – MadProgrammer Dec 30 '13 at 06:35

1 Answers1

2

Why is the game drawing being drawn on top of the input components when the game drawing is being done on the Panel that is in a lower layer in the JLayeredPane?

Mostly because you've circumvented how Swing works.

Let's start with the fact that the Graphics context is a shared resource (typically there is a single Graphics context per native peer), that is, every component gets the same context, this means, when you use your own painting routine, you are basically painting over every thing else.

The RepaintManager is responsible for making decisions about what and when something should be painted. So what you now have is two artist fighting over the same canvas, wanting to paint on it simultaneously, which is just making a mess.

Add into the fray that Swing's painting process is not thread safe and you end up with a complete mess.

If you absolutely must have control, then you need to remove Swing's painting engine from the equation.

Start by taking a look at Passive vs. Active Rendering

ps- There is also hard ware acceleration benefits to using a BufferStrategy

MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
  • That's the tutorial I had looked at earlier. +1 for the "two artists" description, I don't know why, but that really helped clarify what is going on for me. Thank you. So if I am going to convert entirely to active rendering, can I still use JButtons, JTextAreas, etc? If so, how would I go about doing that? – user3144349 Dec 30 '13 at 06:38
  • Yes and no. There is a not of wiring that goes into the components that make them useful. Because there are issues with mixing heavy and light weight components and because you are basically now acting as the Repaint Manager, you will become responsible for ensuring that they painted using the `BufferStrategy`. I've not personally tried, but I've not seen a lot of success in getting this kind of thing to work, doesn't mean it can't be done – MadProgrammer Dec 30 '13 at 06:41
  • Thank you very much. Does that mean that the Graphics object that I am using is attached to every component? I guess I don't quite understand what you meant by "native peer". Also, in response to your second comment, would it be best to just draw directly onto the JFrame using a BufferStrategy? And then draw the components onto the JFrame with the BufferStrategy? I'm not sure how that would work, maybe I'm misunderstanding what you're saying. – user3144349 Dec 30 '13 at 06:42
  • [This](http://www.java-gaming.org/index.php/topic,9825.) might help shed some light – MadProgrammer Dec 30 '13 at 06:42
  • A native peer is the heavyweight, OS specific component onto which all Swing components are painted. This is typically represented by the window. All Swing components share the same `Graphics` context and the `RepaintManager` does some trickery getting them to paint in the proper order as it needs to... – MadProgrammer Dec 30 '13 at 06:44
  • [This](http://stackoverflow.com/questions/9554731/java-swing-double-buffering) may also help, I've only glanced at it... – MadProgrammer Dec 30 '13 at 06:45
  • [This](http://jamesgames.org/resources/double_buffer/double_buffering_and_active_rendering.html) might also help - going back to read this one.. – MadProgrammer Dec 30 '13 at 06:47