简体   繁体   中英

When to use Thread.sleep over SwingTimer in 2D animation

The context in this case is creating a game loop that integrates with the model and updates the view once per frame. Listeners interface with the controller, controller updates the model, repaint() handles the view update from model (on an overridden paintComponent() on a JPanel ).

Appropriate answers include "never", haha.

This is a question I would think there is a preferable answer to, so it shouldn't be in violation of the rules.

I'm asking this because the main game loop is a Runnable instance which I'm locking to 60FPS (roughly, at the moment. Few milliseconds of difference as the current render loop is very inexpensive and 1000 / 60 loses a millisecond or two each cycle). Not locking the frame rate via Thread.sleep() causes something like 2.3 billion frames per second (apparently), which understandably thrashes my CPU. Not a problem per say, more of an example why frame-locking is desirable.

However in every single answer I come across, every single comment, the majority of them say "why are you even touching Thread.sleep() you don't want the EDT to sleep". Which is understandable if you have flaws in your loop that cause non-responsiveness, but this isn't the case in the applications I've put together yet. I've read all of the associated Event Dispatch Thread documentation, how to use Swing Timers, etc. I've even used Timers myself, and SwingWorkers too (in one case to delegate icon loading to the background to prevent blockers on GUI instantiation).

Is there even a preferred method here? I haven't come across many / any standalone game solutions in Java that don't rely on libgdx.

Use Swing Timer when:

You don't want to throttle or control the time between updates. Swing Timer only guarantees "at least" duration (it will trigger AFTER a given delay) and the length of time in which the event is processed may effect the amount of time before the next update.

So, if you have a delay of 16ms (rough 60fps), your callback takes 20ms to process, the time between the first and second callback may actually be 36ms

You would also use a Swing Timer when you want to use the existing (passive) rendering system supplied by Swing

Swing Timer is relatively simple and easy to use, it triggers callbacks within the Event Dispatching Thread, making it easy to modify the state of the game and schedule an updates to the UI, this reduces possible thread race conditions (between the painting and the updating)

Use Thread#sleep when:

You want more control over the timing, producing variable delays. In order to do this, you will need to manage your own Thread

This approach is more suitable to more complex animations and when you are using a BufferStrategy to control the output.

The reason for this is, with a Thread approach, you run the risk of race conditions between your thread changing the state and the paint cycle painting it. Instead, you will need to take control of the paint process yourself, so you know that when you paint something, the state does not change while you do it.

Using this approach provides more flexibility and control to make decisions about when things get done (and how), but increases the complexity and your responsibility for doing things

Thread.sleep is almost certainly used in the implementation of javax.swing.Timer and java.util.Timer, but these days the only real use case of Thread.sleep is for creating a timeout on something, typically an I/O connection. I used this once at work way back for delaying updating the GUI after requesting the users messages until a certain amount of time past from the last message sent from the server. I also used it here

In your case, you should be using the swing timer for your game loop

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM