An Almost Full-Screen (AFS) Worm


Figure 4-1 shows the WormChase application running inside a JFrame that almost covers the entire screen. The JFrame's titlebar, including its close box and iconification/de-iconfication buttons are visible, and a border is around the window. The OS desktop controls are visible (in this case, Windows's task bar at the bottom of the screen).

Figure 4-1. An AFS WormChase


These JFrame and OS components allow the player to control the game (e.g., pause it by iconification) and to switch to other applications in the usual way, without the need for GUI controls inside the game. Also, little code has to be modified to change a windowed game into an AFS version, aside from resizing the canvas.

Though the window can be iconified and switched to the background, it can't be moved. To be more precise, it can be selected and dragged, but as soon as the mouse button is released, the window snaps back to its original position.

This is a fun effect, as if the window is attached by a rubber band to the top lefthand corner of the screen.


Figure 4-2 gives the class diagrams for the AFS version of WormChase, including the public methods.

Figure 4-2. Class diagrams for the AFS version of WormChase


The AFS approach and the windowed application are similar as shown by the class diagrams in Figure 4-2 being identical to those for the windowed WormChase application at the start of Chapter 3. The differences are located in the private methods and the constructor, where the size of the JFrame is calculated and listener code is put in place to keep the window from moving.

WormPanel is almost the same as before, except that WormChase passes it a calculated width and height (in earlier version these were constants in the class). The Worm and Obstacles classes are unaltered from Chapter 3.

The code for the AFS WormChase can be found in the directory Worm/WormAFS/ .


The AFS WormChase Class

Figure 4-3 gives a class diagram for WormChase showing all its variables and methods.

The constructor has to work hard to obtain correct dimensions for the JPanel. The problem is that the sizes of three distinct kinds of elements must be calculated:

  • The JFrame's insets (e.g., the titlebar and borders)

  • The desktop's insets (e.g., the taskbar)

  • The other Swing components in the window (e.g., two text fields)

Figure 4-3. WormChase in detail


The insets of a container are the unused areas around its edges (at the top, bottom, left, and right). Typical insets are the container's border lines and its titlebar. The widths and heights of these elements must be subtracted from the screen's dimensions to get WormPanel's width and height. Figure 4-4 shows the insets and GUI elements for WormChase.

The subtraction of the desktop and JFrame inset dimensions from the screen size is standard, but the calculation involving the on-screen positions of the GUI elements depends on the game design. For WormChase, only the heights of the text fields affect WormPanel's size.

A subtle problem is that the dimensions of the JFrame insets and GUI elements will be unavailable until the game window has been constructed. In that case, how can the panel's dimensions be calculated if the application has to be created first?

The answer is that the application must be constructed in stages. First, the JFrame and other pieces needed for the size calculations are put together. This fixes their sizes, so the drawing panel's area can be determined. The sized JPanel is then added to the window to complete it, and the window is made visible. The WormChase constructor utilizes these stages:

     public WormChase(long period)     { super("The Worm Chase");       makeGUI( );

Figure 4-4. Dimensions in the AFS WormChase


       pack( );    // first pack (the GUI doesn't include the JPanel yet)       setResizable(false);  //so sizes are for nonresizable GUI elems       calcSizes( );       setResizable(true);    // so panel can be added       Container c = getContentPane( );       wp = new WormPanel(this, period, pWidth, pHeight);       c.add(wp, "Center");       pack( );      // second pack, after JPanel added       addWindowListener( this );       addComponentListener( new ComponentAdapter( ) {         public void componentMoved(ComponentEvent e)         {  setLocation(0,0);  }       });       setResizable(false);       setVisible(true);     }  // end of WormChase( ) constructor

makeGUI( ) builds the GUI without a drawing area, and the call to pack( ) makes the JFrame displayable and calculates the component's sizes. Resizing is turned off since some platforms render insets differently (i.e., with different sizes) when their enclosing window can't be resized.

calcSizes( ) initializes two globals, pWidth and pHeight, which are later passed to the WormPanel constructor as the panel's width and height:

     private void calcSizes( )     {       GraphicsConfiguration gc = getGraphicsConfiguration( );       Rectangle screenRect = gc.getBounds( );  // screen dimensions       Toolkit tk = Toolkit.getDefaultToolkit( );       Insets desktopInsets = tk.getScreenInsets(gc);       Insets frameInsets = getInsets( );     // only works after pack( )       Dimension tfDim = jtfBox.getPreferredSize( );  // textfield size       pWidth = screenRect.width                  - (desktopInsets.left + desktopInsets.right)                  - (frameInsets.left + frameInsets.right);       pHeight = screenRect.height                   - (desktopInsets.top + desktopInsets.bottom)                   - (frameInsets.top + frameInsets.bottom)                   - tfDim.height;     }

If the JFrame's insets (stored in frameInsets) are requested before a call to pack( ), then they will have zero size.


An Insets object has four public variablestop, bottom, left, and rightthat hold the thickness of its container's edges. Only the dimensions for the box's text field (jtfBox) is retrieved since its height will be the same as the time-used text field. Back in WormChase( ), resizing is switched back on so the correctly sized JPanel can be added to the JFrame. Finally, resizing is switched off permanently, and the application is made visible with a call to show( ).

Stopping Window Movement

Unfortunately, there is no simple way of preventing an application's window from being dragged around the screen. The best you can do is move it back to its starting position as soon as the user releases the mouse.

The WormChase constructor sets up a component listener with a componentMoved( ) handler. This method is called whenever a move is completed:

     addComponentListener( new ComponentAdapter( ) {       public void componentMoved(ComponentEvent e)       {  setLocation(0,0);  }     });

setLocation( ) positions the JFrame so its top-left corner is at the top left of the screen.

Timings for AFS

Timing results for the AFS WormChase are given in Table 4-1.

Table 4-1. Average FPS/UPS rates for the AFS WormChase

Requested FPS

20

50

80

100

Windows 98

20/20

49/50

75/83

86/100

Windows 2000

20/20

20/50

20/83

20/100

Windows XP (1)

20/20

50/50

82/83

87/100

Windows XP (2)

20/20

50/50

75/83

75/100


WormChase on the slow Windows 2000 machine is the worst performer again, as seen in Chapter 3, though its slowness is barely noticeable due to the update rate remaining high.

The Windows 98 and XP boxes produce good frame rates when 80 FPS is requested, which is close to or inside my desired range (80 to 85 FPS). The numbers start to flatten as the FPS request goes higher, indicating that the frames can't be rendered any faster.

The timing tests for Windows XP were run on two machines to highlight the variation in WormChase's performance at higher requested FPSs.




Killer Game Programming in Java
Killer Game Programming in Java
ISBN: 0596007302
EAN: 2147483647
Year: 2006
Pages: 340

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net