How to Double-Buffer JLayeredPane - java

I am currently making a path-laying Tile game in Java where I am using a JLayeredPane with multiple layers. The game runs fine, but everytime the repaint method is called, the entire pane flickers.
Right now I have the game running on a timer where every tick automatically moves the character one tile at a time along the path in which I have laid out. Naturally, I would need to update the screen in order to reflect the changes to the user, but the problem is that the repaint method forces a redraw on all layers of the LayeredPane. Every tick would cause a flicker on the map area of the screen. While it is bearable, I would just like to get rid of it so it looks nicer.
I have researched on the use of double buffering and have even set the option to double buffer the pane to true as well (e.g. pane.setDoubleBuffered(true)), but have had no luck with various implementations. Is there a way to just draw the entire pane with all layers for every tick in an outside buffer, then copy it in one go over to the main screen?
Thank you

Related

Libgdx: the render method

I don't think I understand how the render method works.
From what I read online / saw on youtube tutorials, I gathered that the render method is a looping function that you can use to keep your game updated and read users' inputs. When you want to draw something in the screen you do so in this method, and before drawing anything you clear the screen.
But if I want to draw something stationary, wouldn't it be better to draw it outside the render method (so the computer doesn't have to clear the screen and redraw everything many times)?
What am I missing?
You can't draw outside the render method, because it's the method called on the OpenGL thread. You can't draw to OpenGL from other threads.
If your entire screen is frequently static for more than a few ms, which might be the case in something like a card game, you can disable the continuous refreshing of the screen using Gdx.graphics.setContinuousRendering(false). This will save energy because the GPU and CPU won't have to work as hard. See here for instructions on using it.
As for why this typically isn't done:
Think of a "frame buffer" as a bitmap image in memory that can be drawn to and then shown on screen. Most mobile rendering is done with double-buffering. This means while one buffer is being drawn to (the back buffer), the front buffer that was drawn to on the previous frame is being rendered directly to the screen. They swap back and forth each frame for faster rendering.
The way graphics work is that each item that's drawn modifies the color of pixels in the frame buffer where the item is drawn. Items may be masked or be translucent, and these will alter the color of pixels behind them. The original color of those pixels are lost once something is drawn in front and modifies them
So, even if some item on your screen is static, if there are other items on the screen that move or change color, and they overlap the static item (either in front of or behind), you still have to redraw the whole screen every time anything changes.
If one area of the screen is static and never overlapped by dynamic objects, and the dynamic objects are contained entirely within a rectangle, you could potentially set a viewport that limits drawing to the dynamic area and avoid clearing the whole screen. However, GPUs are designed specifically to be efficient at clearing the whole screen. Because of double-buffering, if you don't clear the whole screen, it's actually likely to harm performance because if you don't clear it, the contents of the screen have to be copied between the front and back buffers before you can start drawing the next frame.
Another strategy is if you have a static object that is very complicated and taxing for the GPU to draw because it has lots of layers or a complicated shader, you could draw it to an off-screen frame buffer object (FrameBuffer class in libGDX) one time, and then render that FrameBuffer's texture to the screen on each frame like a sprite.

How to put paint component pieces on top of a background in Java?

We have a group project where we must create a turn based, 2 player, grid game for class, i.e. Chutes and Ladders. The whole project is done except for the fact that when we bring the background image up, the players pieces get painted behind the background, and are therefore not visible. Is there a way to get the pieces to show up on top of the background image? We are using imageIO for the image, GridLayout for the Grid, and then using PaintComponent to place the pieces on the grid. When we do not have the background image, the pieces show up on the Grid flawlessly.
using PaintComponent to place the pieces on the grid
Make sure to call the super's paintComponent(...) method first thing in your paintComponent override.
Make sure that your paintComponent method has no program logic inside of it.
Sometimes it's better to place your pieces in ImageIcons and the Icons in JLabels, and then place your JLabels on a Grid of JPanels. For example.
For more help, post code and give more details. To be honest, I'm a little surprised that you haven't even posted your paintComponent method code.

Flickering when updating overlapping JPanels inside a JLayeredPane using timestep

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.
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

Lagging graphics in Java swing

I have a program that bounces an arbitrary number of balls around a predefined window. It relies on a Swing Timer to update the balls according to a delay set by the user. My problem is this: the balls lag much more than they should under modest circumstances. The weird thing is that the balls move smoothly if there is another action being performed (e.g. mouse click or mouse moving around the screen). Does anyone know what would cause this?
The weird thing is that the balls move smoothly if there is another action being performed (e.g. mouse click or mouse moving around the screen).
Based on that statement, I would guess that your problem is not properly calling repaint() on JPanel or other java.awt.Component subclass which is displaying the balls. You need to call Component.repaint() whenever your code changes the position of the balls.
Not sure if this might help: have you considered double buffering? (that is doing all expensive paint operations in an 'off-image' and copying that image into the visible area when done).

Jpanel / Jframe / buffering graphics etc game structure direction

I'd like some advice regarding structure of a game I'm working on. Specifically where to place painting methods.
Currently there is a applet wrapper class for a Jpanel which runs the game loop.
The game itself is meant to simulate a very large area. objects will have x&y values which themselves will part of a larger x&y grid.
i.e. object1 position is 150000x30000 in grid block 1,5.
objects will need to be able to move into neighbouring grids, however I'd rather not run each grid block until needed as 99% of them will be empty.
Currently the UI is a Jpanel with a few buttons + listeners, a large drawing pane is needed to display the objects.
my question is:
what class should this internal drawing pane be based on? I'd like to have control to zoom and pan around the grid. it only needs to draw what is visible, but object movements will continue in the game loop.
what painting strategy would be applicable for simple (icons really when zoomed out) moving around vast areas, I'm guessing relying on the EDT to repaint isn't going to be good enough?
I'm not really after specific code, I want to learn myself how to do this, I just need pointing in the right direction, as most things I read don't seam to quite cover what I'm after, or don't make use of JRE6+ features.
Many Thanks
Rather than paint each grid cell in your drawing pane, why don't you have each object repaint itself onto the grid?

Categories