Graphics2D / BufferStrategy / Swing mess

Hey, guys. Having a really hairy quandary here that perhaps you could help me with.

I’m working on a 2D adventure game engine, and doing the following:

  1. Rendering to an offscreen image, then getting the Graphics2D of a JPanel inside of / same size as my JFrame, rendering the image to the panel.
  2. That render performs a scale operation as well, so that my entire scene fits in the window regardless of the window size.
  3. Trying to render a Swing component or two over top of this panel. They should stay in the same position onscreen, even when the underlying panel scrolls to reveal more of the game scene.
  4. Manually repainting the object using a timer.

Here’s the issues I have:

  1. Rendering Swing over the JPanel causes the Swing to flicker badly.
    I tried using a JLayeredPane to help, it didn’t. -Dsun.java2d.noddraw and the other posted tweaks didn’t help either. The only solution I was able to find is to render the swing into the same graphics as my game objects (thus, onto the backbuffer) and then drawing it all at once. Now it doesn’t flicker as much, but the Swing rendering doesn’t look quite right and the game doesn’t acknowledge that I’ve clicked on the Swing object.

  2. Rendering performance is awful and seems to be fill-bound, as it gets significantly worse as the window gets bigger.

I recently tried switching the solution to a BufferedStrategy. I gained a ton of framerate by so doing, but the Swing was still an issue. Additionally, if I render to the JFrame’s Graphics2D object, in windowed (decorated) mode, the game seems to count the titlebar as part of the window and cost me 30 px of my scene’s image. Finally, without an Image object in hand, I can’t use the drawImage function that permits me to scale a rectangle of an image into another rectangle, which I have been using to get the window the appropriate size.

I also looked at using a RepaintManager but didn’t see much luck there either.

Here’s the solution I need; maybe one of you can point me in the right direction.

  1. My scene is often bigger than the window, so I need to be able to scroll. Right now I am using a Rectangle as a “viewport”, copying out of the back buffer image (which is the size of the entire screen) only what is needed.

  2. I need to be able to render Swing components on top of the still-refreshing Graphics2D work, either on a JPanel or in the JFrame itself without losing the pixels on the top of the window to the titlebar.

  3. I need to be able to scale the final render so that it fits in the window regardless of the window’s size (or full screen). Optimally, the Swing components would scale also, but this is not crucial. They do, however, need to stay in place while the background (the game’s graphics) scroll.

  4. I need rendering performance to not totally suck.

Can anyone help me with this conundrum?

OK. New strategy. I found that I can build a BufferStrategy from a Canvas, so I replaced the internal JPanel with a Canvas. Now I am using the BufferedStrategy with a backbuffer, on the Canvas. Doing this sped me up significantly and eliminated the offset for the titlebar, while still letting me use my backbuffer to retain my scaling and scrolling functionality.

All that’s left now is getting Swing to render right. I can get it to draw by calling my Swing components’ paint() and passing in the buffer strategy’s getDrawGraphics(), but the component doesn’t register clicks. I think it’s because I am forcibly drawing them there, as opposed to them natively being there. I tried putting the Swing and the Canvas in the JFrame’s getLayeredPane() with the Swing higher than the Canvas. Doing this still doesn’t render the swing (it may be overdrawn by my Canvas somehow) unless I call the swing’s paint(), at which point it still doesn’t see clicks.

Are you disabling autopaint of the component?

regarding your problem with the clicks not recognized:
i had the same problem quite some time ago. the solution was to either disable the canvas getting the focus or registering keyinputlisteners for the canvas and the jframe.
something like that:

public class ChopperGame extends JFrame implements MouseInputListener {

// ...

public ChopperGame() {
    // create a frame to contain our game
    super(WINDOW_TITLE, CONFIG);
    
    setDefaultCloseOperation(EXIT_ON_CLOSE); 
    
    setFocusTraversalKeysEnabled(false); // disable focus change when tab is pressed
        
    // Tell AWT not to bother repainting our canvas since we're
    // going to do that our self in accelerated mode
    setIgnoreRepaint(true);

    // setup canvas
    canvas = new Canvas(GRAPHICS_CONFIG);
    canvas.setSize(WIDTH, HEIGHT);
    getContentPane().add(canvas, BorderLayout.CENTER);
    
    canvas.setFocusTraversalKeysEnabled(false); // disable focus change when tab is pressed
    canvas.setIgnoreRepaint(true);
    
    // make the window visible 
    pack();
    setResizable(false);
    setLocationRelativeTo(null); // center on screen
    setVisible(true);
    
    // create the buffering strategy which will allow AWT
    // to manage our accelerated graphics
    canvas.createBufferStrategy(2);
    strategy = canvas.getBufferStrategy();

    // add a key input system to our jframe
    addKeyListener(new KeyInputHandler());
    canvas.addMouseListener(this);
    canvas.addMouseMotionListener(this);
    
    // canvas must not get the focus or we have to register a keyListener for it as well
    canvas.setFocusable(false);

    // request the focus so key events come to us
    requestFocus();
}

hth.

Not that I know of.

hello.
i am re-starting this thread because i am having a similar problem with swing and a buffer strategy.
i am in the middle of creating a new game engine for an existing application which uses a lot of swing components throughout.
my goal is to make the app double buffered and fullscreen.
for the past week i’ve been trying to make it happen, and with the help of previous posts and some online tutorials regarding this subject, i think i am almost there.

the last thing (i hope) that i’ve stumbled on is swing ui components not responding to mouse input.
i have created a very simple test case which shows the problem. everything displays fine, but the JSlider does not respond to the mouse. there is an input listener class which handles keyboard and mouse input. it works correctly for the keyboard (ie pressing escape exits the game) but does not receive the JSlider data. I was not sure what the “autopaint” suggestion was referring to.

if someone would be willing to take a look at this and offer some suggestions, i would be most appreciative.

thanks for your time
-rob.

the code TestCase.java is linked here:
http://www.robtherich.org/TestCase.java