Monkey Fighter Monkey Fighter
Games Help Help Search Search Shop Shop
Watch

Lesson 6: Timing

3D Game Programming - Java Programming Language

OpenGL Game Programming For the Web!

Home Page

3D Asteroids Home

Files

Lesson6.zip

Lessons

1. Models
2. Actors
3. Keyboard
4. Fonts
5. Collisions
6. Timing
7. Particles

Play Now!

3D Asteroids Normal
3D Asteroids Tiny
3D Asteroids 800x600
3D Asteroids 1024x768

Find Books

- Java Game Coding
- Game Programming
- Java Programming
- OpenGL



Before you read this lesson, must warn you that I am not a Java Game Programming guru. The timing method I implemented is my own creation. As such, you may find a better method if you are ambitious enough to search. My method relies on threads and running threads can resume execution at the whim of the thread scheduler in the Java Virtual Machine. In other words, the are no guarantees when a thread will start executing when the start() method is called. Despite all this, this method seems easy to implement, and reliable (at least on a Windows box).


Methods of Timing

Before explaining my code, I thought that it would be interesting to briefly explain several timing techniques.


Delay Loops Timing

There are many ways to implement timing in a video game. The simplest, crudest, and least professional is the delay loop. Using a for loop burdens the CPU with useless processing in order to slow down the overall execution of the game. Users may, or may not, be able to tweak the amount of delay at runtime to adjust for their system. I used this technique for my Word 97 game/hack, WordTris .


Hardware Synchronization Timing

A better way to implement video game timing is to synchronize the code with a guaranteed periodic system event. For example, the vertical blank (when video monitor is waiting to redraw the display) period of the Amiga is 60hz NTSC (because the video monitor is physically redrawn every 1/60th second - 50hz, 1/50th second PAL). Anyhow, if we can write code that is guaranteed to execute in 1/60th second or less, then all we need to do is wait for the vertical blank, swap video buffers, and proceed with the game code. The advantage to this method is visually flawless game play and seamless animation. The disadvantage is the limited game complexity due to code execution time constraints. Albeit, I used this technique in Biker Babe from Barbados and Route 666 .


Interrupt Timing

The get around code execution time constraints, all the game code, except for video buffer drawing code, can be executed during a periodic system interrupt such as the video interrupt. In this method, the game would always be trying to redraw the next frame of the video buffer but every 1/60th second (or whatever the interrupt period may be), everything but the video buffer is updated. This technique allows for greater game complexity but suffers from possible low frame redraw rates and choppy animation. However, it is the preferred method.


Thread Based Timing

Unfortunately, none of these methods are suitable for developing on-line games with the Java Programming Language. That is because nothing about the hardware running the game is guaranteed. The best guarantee is with the programming language its self. So, after playing aroung with Java for a while, I discovered a few things. First, never use the system timer for game timing. It varies too much between platforms and its resolution may be too crude to use. Threads and the sleep() method, however, seems to be fairly reliable even though thread execution details are not guaranteed in Java. So, I used them to develop a timing method for my game. So, let's look at the code to see how its done.


class RunAsteroids extends Thread
{ public void run()
  {   doKeyboard();
      gEngine.updateActors();
      collisionBulletRock();
      if(aRocks.size()==0) addRocks(8);
}

As mentioned previously, we want all the non-display drawing code in one thread, and all the display drawing code in another. The method that we were always using to draw the OpenGl display, sDisplay(), was a thread all along. In fact, it is syncronized, which means that a repeated call made while it is still drawing a display is ignored. So, let's put the rest of the running game code in its own class. Just cut the indicated lines from the while loop in the run() method. Then, paste them into the run method of this class.


  public void run()
  { RunAsteroids runAsteroids = new RunAsteroids();   // *** New Line ***

    runAsteroids.setPriority(10);                     // *** New Line **
								

Now, add these two lines to the run() method. The first line creates a new instance of the thread we just made. The second sets its priority to the highest possible state. That means that the JVM will favor this thread. Ideally, we would give this routine all the clock cycles because it must complete before it gets called again. If it doesn't, the JVM will wait for it the old thread to complete before running a new thread. Thus, the game will slow down.


    while(!stop)
    { runAsteroids.run();                             // *** New Line ***
      gEngine.sDisplay();
      sleep(10);
} }

Here is the updated while loop in the run() method. Notice the lines that were cut and pasted to the runAsteroids thread. Those lines were replaced with a call to that the runAsteroids thread. So, here's how the timing scheme works. The non-display drawing thread is called but we don't wait for it to run. Instead, we start the display drawing thread. And again, instead of waiting for it to run, we sleep for 10 milliseconds. The process of starting the two threads should take very, very little time on virtually any modern computer. So, the total time it takes for one iterration of this loop is 10 milliseconds + the very little time it takes to start two threads. That should be unnoticably similar on any computer.


Asteroids

Your applet should now displays four rocks moving across the display. The player's space craft is visible, centered in the display. Pressing shift will fire bullets from the space craft. The left and right arrows will rotate the craft. The up and down arrows will provide movement and stopping and SCORE: 000000 is displayed at the top of the screen. Rocks are removed when they encounter collisions with the bullets. Rocks are renewed when they are all removed. 100 points are added to the score every time a rock is removed. And, the game should never run too fast.


Copyright © 2005, Robert Walsh, All Rights reserved.