• Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Ron McLeod
  • Tim Cooke
  • Liutauras Vilda
  • Jeanne Boyarsky
Sheriffs:
  • Paul Clapham
  • Rob Spoor
  • Junilu Lacar
Saloon Keepers:
  • Stephan van Hulst
  • Tim Holloway
  • Piet Souris
  • Carey Brown
Bartenders:

Getting paint to run independantly of main loop

 
Ranch Hand
Posts: 279
2
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I'm in the middle of writing a game and I'm fairly pleased with it's progress. However, at the moment, I call paint directly from the main game loop. So the FPS is linked directly to the main loop. I'd like to have the paint method running independently so the FPS will be independent of the main loop but I'm not sure how to do this.

I tried to show the bits of code that illustrate my question. Can anyone suggest how to get paint running independently?  Preferably in a way that a fool like me can understand



 
Marshal
Posts: 77168
370
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Afraid if that is supposed to be a Swing® display, I can see all sorts of problems.
Don't make Graphics objects fields. If you want to repaint the display,
  • 1: Override the paintComponent(Graphics) method in whichever Components you are displaying.
  • 2: Call repaint().
  • If you do need a Graphics object, it is usually better as a local variable. Remember the JVM will usually provide a Graphics object to paintComponent() as required.
    Don't try to repaint anything on a different thread; Swing® isn't thread‑safe. You can get all sorts of problems like that.
    Make all your fields private.
    Find out about Swing® Timers, which might be a better way to get your 28 frames per second. Don't fall for the blandishments of Thread.sleep(); that is an effective way of making your display unresponsive.
     
    Saloon Keeper
    Posts: 26537
    187
    Android Eclipse IDE Tomcat Server Redhat Java Linux
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    Painting is already supposed to be being done on a separate thread. If you're painting on the main thread, you're not doing it right.

    In AWT and Swing, you don't brute-force render graphics, you create what amounts to a graphics program that defines the artefacts that will be painted. You then indicate that you want them rendered with a simple (re)paint method call from your main code, at which point the Swing/AWT rendering thread will be scheduled to execute the "graphics program" you defined. Rendering is actually a complex process, since it can be invoked not only when you explicitly force it, but also as a response to events such as moving a covering window out of the way or resizing the windowpane. It's also done intelligently. Normally, the renderer accumulates "damage", which is a set of areas which need re-rendering and when repainting is done, the actual rendering is clipped to only the parts which were "damaged".

    Damage can be due to explict changes in your "graphics program" and/or in response to other events such as window movement. The use of clipping areas makes the whole display process much faster since only the damaged parts have to be repainted instead of every last little detail.
     
    Mich Robinson
    Ranch Hand
    Posts: 279
    2
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    I'm not actually sure what a Swing display is It's in full-screen exclusive mode if that helps and the resolution has been changed to 800 x 600. I will admit that it doesn't work for wide screen laptops as it just creates the game in a window. The display is created just using lots of drawImage calls. Not sure if it helps but the title screen looks a bit like this.

    Is there a simple way of getting the paint method to run independently of the main method using the structure I have?
     
    Tim Holloway
    Saloon Keeper
    Posts: 26537
    187
    Android Eclipse IDE Tomcat Server Redhat Java Linux
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    Swing is for GUIs. What you are doing is generally done at a lower level using framebuffers. Basically you render a frame into the buffer, wait until the next frame interval, then switch buffers. You typically would have at least two framebuffers, one to render into while the other is being displayed. For smooth animation, your per-frame render time has to be less than the frame rate. Otherwise you get partially-rendered displays.

    You need to find a good book on Java gaming, since it's a fairly specialized subject.
     
    Mich Robinson
    Ranch Hand
    Posts: 279
    2
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    I believe that's what I'm doing. I write to the offscreen framebuffer "og" and, when the work's done, I write it to the main framebuffer "g". That's done in the current paint routine. The game is fairly smooth at 28 FPS (at 800x600) but obviously the paint is being done in the main loop. This means that if there's any delay in the drawing then this delay is reflected in the movement. It doesn't happen often, maybe once every 10 mins on a slowish PC, but it's annoying. This is the main reason for trying to get the paint done outside the loop.

    I was hoping for a simple hint/explanation on how I could tweak my code but maybe that's not possible with how it is.
     
    Saloon Keeper
    Posts: 9831
    80
    Eclipse IDE Firefox Browser MySQL Database VI Editor Java Windows
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    Have you been able to narrow down what is happening every ~10 minutes that causes this? Are there other tasks that could be run in a background thread?
     
    Tim Holloway
    Saloon Keeper
    Posts: 26537
    187
    Android Eclipse IDE Tomcat Server Redhat Java Linux
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    In older times, I'd suspect that the garbage collector was kicking in. Nowadays I wouldn't expect it, although if you're creating and discarding very large objects (like hi-res framebuffers) it's still possible.

    Anyway you shouldn't be copying framebuffers, you should be keeping 2 (or more) of them and swapping the graphics between them. Copying raw pixels is an incredible amount of overhead and even when the graphics card itself is doing bit-blits in RAM it's far slower than simply switching buffer pointers.
     
    Tim Holloway
    Saloon Keeper
    Posts: 26537
    187
    Android Eclipse IDE Tomcat Server Redhat Java Linux
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    Here's some good general background on using framebuffers for performance:

    https://en.wikipedia.org/wiki/Multiple_buffering

    And specifically for Java:

    https://docs.oracle.com/javase/tutorial/extra/fullscreen/doublebuf.html

    I did a little memory refreshing and it seems that the standard way for Java to do double buffering has been rather low-performance. One thing that might be a better solution than using the standard graphics classes would be to use one of the OpenGL libraries like JOGL or LWJGL. I think Minecraft does this.
     
    Mich Robinson
    Ranch Hand
    Posts: 279
    2
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    I don't think I have access to a profiler so I spent a bit of time looking for likely suspects in my code and then playing the game for approximately 30 mins each time and manually getting some stats. If calls take less than 1ms then they show as 0ms.

    I looked into assigning the offscreen buffer to the onscreen buffer. I'll admit it's not very efficient but it just showed up as running in 0ms each time.

    A few things could be moved to a background thread (collisions between bullets and things and things and other things, the movement of explosions and smoke etc) but these again seemed to run fairly quickly. I'm not sure it would be worth the effort to create a separate thread. There'd also be the inevitable issues from having 2 threads playing with the same data. There is a fancy sun animation that could also run independently but, again, it ran fairly quickly.

    The major culprit seemed to be a drawExplosions call which mostly ran very quickly (average of 0ms) but there were 5 calls when it took longer than 20ms and one call that took 41ms. It would be totally OK if the paint was happening in the background but, because it's running in the main loop, there's a slight pause in play. The explosions are either flames, solid bits that fly through the air when aliens are shot or particle effects. It's the particle bit which seems to take the time as one explosion might have 20 small rectangles of colour being drawn with the colour slowly fading to transparent. I think I can get round this by seeing what type of explosions affect the draw times and then monitor the time to age out these explosions more quickly when timings are getting affected.

    I assume there's no easy way of altering my existing structure so the paint simply happens in the background? (I'm reading through the article that was linked to).

     
    Tim Holloway
    Saloon Keeper
    Posts: 26537
    187
    Android Eclipse IDE Tomcat Server Redhat Java Linux
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    If you're doing true page flipping, then ALL painting is supposed to be done in the background, actually. Then you flip the background page to the foreground.

    The Java default, alas seems to be to draw in background and then brute-force copy to the active display buffer instead on flipping display buffers. And that's a lot more overhead.
     
    Don't get me started about those stupid light bulbs.
    reply
      Bookmark Topic Watch Topic
    • New Topic