Java-Gaming.org    
Featured games (81)
games approved by the League of Dukes
Games in Showcase (495)
Games in Android Showcase (114)
games submitted by our members
Games in WIP (563)
games currently in development
News: Read the Java Gaming Resources, or peek at the official Java tutorials
 
    Home     Help   Search   Login   Register   
Pages: [1]
  ignore  |  Print  
  Game Loop variations  (Read 2240 times)
0 Members and 1 Guest are viewing this topic.
Offline Juriy

Junior Member





« Posted 2007-07-04 07:13:50 »

I have a simple question. It's about basic game loop. When I've written my apps, I used a loop like this:

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
while (true)
{
   int delta = (int) (System.currentTimeMillis() - lastLoopTime);
   logic(delta);
   lastLoopTime = System.currentTimeMillis();
   
   draw((Graphics2D) strategy.getDrawGraphics());
   
   strategy.show();
        // Calculate sleep time
       try { Thread.sleep (sleepTime);}catch(Exception e) {}
}


recently i started looking at others' people sources and I've found loops like this:
(source taken from http://www.cokeandcode.com/games/4k/city4k/R.java)

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
while (true)
{
   int delta = (int) (System.currentTimeMillis() - lastLoopTime);
   for (int i=0;i<delta/10;i++) {
      logic(10);
   }
   logic(delta % 10);
   
   lastLoopTime = System.currentTimeMillis();
   
   draw((Graphics2D) strategy.getDrawGraphics());
   
   strategy.show();
}


Could you please explain me the reason, why is it better to break logic into 10 millisecond calls plus one delta % 10 call?
Second point is: code below never sleeps. I thought it is good idea to call Thread.sleep from a game loop to give some time to other threads. Actually this code is from 4k contest so this might be the reason.

In other pieces of code I've seen Thread.yield() instead of Thread.sleep(). Which approach is preferable?

http://voituk.kiev.ua - java tutorials, tips and tricks (Russian)
Offline keldon85

Senior Member


Medals: 1



« Reply #1 - Posted 2007-07-04 07:37:13 »

I personally use the following:
1  
2  
3  
4  
5  
while (playing) {
   updateGameState();
   renderScene();
   waitForSynchronization();
}


It works by having a high priority thread that does nothing but awake a synchronization thread 60 times a second. waitForSynchronization will enter the synchronization thread and call wait(), it's a really good way to handle the game loop.

In fact it works so well that I have modelled my game engine like the gameboy advance hardware (with the same registers etc), so if you unroll what happens this is what you get:
 - updateGameState called
 - renderScene called (prepares tiles for the graphics engine)
 - waitForSynchronization called
 - synchronization threads awakened
 - graphics engine renders screen
 - <<< loop

The synchronization allows you to make a simple call similar to what would typically be used in a game (waitVBL()).

Offline Juriy

Junior Member





« Reply #2 - Posted 2007-07-04 07:49:59 »

Hmm, interesting. I have some questions about your approach.

You actually call updateGameState(deltaMills) not just updateGameState()?
"renderScene" is the same action as "graphics engine renders screen" or not?
waitForSynchronization(); - just waits for other thread to call "notify" on some object?

Can you explain why your solution is better than the game threads from initial post?

PS Sorry for so much questions, but your approach is rather interesting and I'm just curious about details.

http://voituk.kiev.ua - java tutorials, tips and tricks (Russian)
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline keldon85

Senior Member


Medals: 1



« Reply #3 - Posted 2007-07-04 08:25:28 »

No need to send the frame time, you update the game state irrespective of the time and assume that you are running at a constant frame rate. You can [of course] track when you've taken too long and adjust the physics to take account of that time, but you probably would rather change the framerate completely for the game based on an a benchmark of the hardware (if your game is more CPU intensive).

renderScene is not the same as the graphics engine rendering the screen, it is when you are [say] setting the tiles for the tetris block, when the graphics engine renders the screen it is plotting the pixels of each of the tiles with its layer effects, rotation and zoom.

Yes, waitForSynchronization() does just wait for another thread to call notify on an object. I find it better as it allows me to use the same approach you would use when developing for a console. It gives you a simple implementation with full synchronization for consistent frame rates with much more readable code. Plus any beginner can understand it!

Offline Juriy

Junior Member





« Reply #4 - Posted 2007-07-04 14:33:21 »

Thanks for the reply. I'll try to implement your technique.
Still I'm wondering about the questions in the initial post:

why is it better to break logic into several relatively small calls?
should I sleep or yield in my game loop?

http://voituk.kiev.ua - java tutorials, tips and tricks (Russian)
Offline keldon85

Senior Member


Medals: 1



« Reply #5 - Posted 2007-07-04 17:21:51 »

In the method I gave you need not yield or sleep, just wait. Here are two examples that are probably the same!

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
39  
40  
41  
42  
43  
44  
45  
46  
// method 1
package javaThreadSynchronization;

public class WaitVBLSynchronization implements Runnable {
   public boolean running = true;
   public Object waitingObject=null;
   public static void main ( String argv [] ) throws InterruptedException {
      WaitVBLSynchronization sync = new WaitVBLSynchronization();
      for ( int i = 0; i < 6; i ++ ) {
         sync.waitVBL();
         System.out.println(i);
      }
      sync.running = false;
   }
   public WaitVBLSynchronization (){
      Thread t = new Thread(this);
      t.start();
     
      // this high priority is valid because of how little the thread does
     t.setPriority(Thread.MAX_PRIORITY);
   }
   
   public void waitVBL () throws InterruptedException{
      waitingObject =  new Object();
      synchronized ( waitingObject ) {
         
         waitingObject.wait();
         waitingObject = null;
      }
   }
   
   public void run() {
      while ( running ){
         try {
            Thread.sleep(1000);
         } catch (InterruptedException e) { }
         
         if ( waitingObject != null ) {
            synchronized (waitingObject){
               waitingObject.notify();
            }
         }
      }
   }
   
}


1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
39  
40  
41  
42  
43  
44  
45  
46  
47  
48  
49  
50  
51  
52  
53  
54  
55  
56  
57  
58  
59  
60  
61  
62  
63  
// method 2
package javaThreadSynchronization;

/**
 * Will test synchronization involving one thread synchronizing
 * itself wake another thread once every 60th of a second
 * @author Keldon
 *
 */

public class VBLScreenSynchronizationTest {
   public static void main ( String argv [] ) throws InterruptedException {
      Runnable runnable = new Runnable(){
         public void run() {
            int counter = 0;
            int seconds = 0;
            while (true){
               if ( counter == 0){
                  counter = 60;
                  System.out.println((seconds++) + " seconds has passed");
               }
               counter--;
               try {
                  synchronized (this){
                     wait();                    
                  }
               } catch (InterruptedException e) {
                  System.err.println("wait failed");
                  System.exit(0);
               }
            }
         }
      };
      Thread currentThread = new Thread(runnable);
      currentThread.start();
      VBLSynchronization sync = new VBLSynchronization(runnable);
      sync.begin();
   }
   
   private static class VBLSynchronization implements Runnable {
      Object object;
      public VBLSynchronization (Object o ){
         this.object = o;
      }
     
      public void begin (){
         new Thread(this).start();
      }
     
      public void run() {
         while (true){
            try {
               Thread.sleep(1000/60);
               synchronized (object){
                  object.notify();                  
               }
            } catch (InterruptedException e) {
               System.err.println("Thread sleeping failed");
               System.exit(0);
            }
         }
      }
   }
}

Offline broumbroum

Junior Member





« Reply #6 - Posted 2007-07-04 18:38:09 »

By the way, it may be easier to synchronize on current Object instead of creating a single object monitor. See:
1  
2  
3  
public synchronized void waitForURL() {
        try{ wait(); } catch(InterruptedException e) { e.printStackTrace(); }
}
Cheesy

::::... :..... :::::: ;;;:::™ b23:production 2006 GNU/GPL @ http://b23prodtm.webhop.info
on sf.net: /projects/sf3jswing
Java (1.6u10 plz) Web Start pool
dev' VODcast[/ur
Offline keldon85

Senior Member


Medals: 1



« Reply #7 - Posted 2007-07-04 22:15:48 »

By the way, it may be easier to synchronize on current Object instead of creating a single object monitor. See:
1  
2  
3  
public synchronized void waitForURL() {
        try{ wait(); } catch(InterruptedException e) { e.printStackTrace(); }
}
Cheesy

lol; oh yeah! Maybe there was some profound reasoning behind the decision; it might be because I was at one time maintaining the HBL interrupts with threads until I felt it would be too much of an overhead waiting and notifying a single thread for every horizontal line in each frame.

Looking at it it makes sense to synchronize the entire object, thanks for pointing that out.

Offline broumbroum

Junior Member





« Reply #8 - Posted 2007-07-04 22:49:37 »

that sounds good... good luck!

::::... :..... :::::: ;;;:::™ b23:production 2006 GNU/GPL @ http://b23prodtm.webhop.info
on sf.net: /projects/sf3jswing
Java (1.6u10 plz) Web Start pool
dev' VODcast[/ur
Offline jojoh

JGO Knight


Medals: 5
Projects: 7


games4j.com


« Reply #9 - Posted 2007-07-05 16:40:01 »

There are two basic approaches in controlling the gameloop speed
1. Use a fixed framerate (for example 60 fps)
2. Go "flat out" or with fixed small sleep and calculate all movement based on the deltaTicks between frameloops (fast machines could for example run at 100fps and slow at 40)

1 is what Keldon described. (Using synchronization or more commonly calculate sleep so that each game loop takes the same time)
Pro:
The game always plays the same
Easy to program

Con:
Faster computers will not be utilized fully
Game will not be playable at all/behave differently on computers that not quite can produce the fixed framerate.


2. AAA games will typically use this and many hobby games as well
Pro:
Utilized the power of the machines very well.

Con:
Game might behave slightly different on computers with different performance
A bit more complex to code


What you saw in the 4K code was a clever way to try to get the game to always play the same at the same time as the computer is utilized to the max.
Con:
A slight performance hit (if the logic part takes a relevant time compared to the draw task), since logic is executed several times per loop instead of one.
The game loop is still tick based so the logic is still a bit more complex than fixed framerate.
Behavior will not be 100% identical on different computers, just more similar.

I hope it is possible to understand my brief explanation and that I haven't said anything completely wrong Tongue

Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline keldon85

Senior Member


Medals: 1



« Reply #10 - Posted 2007-07-05 17:10:02 »

I beg to differ; every game on the GBA, SNES and NES would have used one like what I gave.  In fact this is why 60hz NTSC games play faster than their 50hz (UK) PAL systems. On the PC it would be a different story where you have the varying frame rates, etc. Another pro/con is to do with consistency of calculations; for example if your replay code works by tracking the user input each frame then you will have to recalculate with the frame difference.

And for some games you don't want varying frame rates, take Tetris for example; it's a simple game so there is no benefit from a faster computer. AAA titles tend to have a minimum frame-rate, and just play games slower! You can only really utilize CPU power with more detailed graphics and effects, any utilization affecting gameplay will essentially mean that your PC determines what game you are playing Smiley

When you are animating with bitmaps and not tweened vectors and polygons then assuming a fixed frame rate is easier for collision since you are not able to utilize frame independent collisions. Now don't get me wrong, I'm not suggesting not to use variable frame rates (because I use them too), but know reasons why - but more importantly how.

Having said that my method requires only one minor change, which is to pass the time taken for the frame!

Offline 2playgames

Junior Member





« Reply #11 - Posted 2007-07-05 22:10:40 »

In my game engine, the FPS is default limited to the screen refresh rate. The user of the engine can then decide to either remove all limits (which will just let the game loop call a Thread.yield() without sleeping) or set a fixed limit. All game objects speeds etc. are set in pixels/second, as opposed to pixels/step

Pages: [1]
  ignore  |  Print  
 
 
You cannot reply to this message, because it is very, very old.

 

Add your game by posting it in the WIP section,
or publish it in Showcase.

The first screenshot will be displayed as a thumbnail.

Dwinin (23 views)
2014-09-12 09:08:26

Norakomi (56 views)
2014-09-10 13:57:51

TehJavaDev (69 views)
2014-09-10 06:39:09

Tekkerue (34 views)
2014-09-09 02:24:56

mitcheeb (56 views)
2014-09-08 06:06:29

BurntPizza (40 views)
2014-09-07 01:13:42

Longarmx (25 views)
2014-09-07 01:12:14

Longarmx (32 views)
2014-09-07 01:11:22

Longarmx (31 views)
2014-09-07 01:10:19

mitcheeb (39 views)
2014-09-04 23:08:59
List of Learning Resources
by Longor1996
2014-08-16 10:40:00

List of Learning Resources
by SilverTiger
2014-08-05 19:33:27

Resources for WIP games
by CogWheelz
2014-08-01 16:20:17

Resources for WIP games
by CogWheelz
2014-08-01 16:19:50

List of Learning Resources
by SilverTiger
2014-07-31 16:29:50

List of Learning Resources
by SilverTiger
2014-07-31 16:26:06

List of Learning Resources
by SilverTiger
2014-07-31 11:54:12

HotSpot Options
by dleskov
2014-07-08 01:59:08
java-gaming.org is not responsible for the content posted by its members, including references to external websites, and other references that may or may not have a relation with our primarily gaming and game production oriented community. inquiries and complaints can be sent via email to the info‑account of the company managing the website of java‑gaming.org
Powered by MySQL Powered by PHP Powered by SMF 1.1.18 | SMF © 2013, Simple Machines | Managed by Enhanced Four Valid XHTML 1.0! Valid CSS!