For my fellow noobs: this code shows how to implement a basic game loop. It puts the display into full screen exclusive mode or, if that’s not available, a window of a fixed size, then loops until the “game” is over, then exits. It should compile and run as-is (it does for me on my Windows boxen).
It uses double buffering, so animation is smooth and flicker-free.
For those who know oh so much more than I do (most of you I imagine): is this code correct? Am I missing anything?
This is what I came up with after many hours of looking at many different examples. I was trying to boil them all down to the barest essentials. I didn’t really understand Jeff’s code until I got mine working, then his made sense to me. I figured other newbies like myself might like something simpler with more comments…
import java.awt.*;
import java.awt.image.BufferStrategy;
public class Test
{
// Our main method simply invokes an instance of our application. We pass it a boolean
// argument that is TRUE if we want full screen exclusive mode, or false if we want a
// window.
public static void main( String[] args )
{
Test test = new Test( true );
System.exit( 0 );
}
// This is an array of the desired full screen graphics modes, in the order we most
// prefer them. If we request full screen mode, and this system supports it, then the
// first entry here that matches a supported mode will be used.
private static DisplayMode[] PreferredModes = new DisplayMode[]
{
new DisplayMode( 800, 600, 32, 0 ),
new DisplayMode( 800, 600, 16, 0 ),
new DisplayMode( 800, 600, 8, 0 )
};
// This method finds the best matching full screen mode from the array above that is
// supported on this system.
private DisplayMode bestmode( GraphicsDevice gd )
{
// Get the list of supported modes on this system
DisplayMode[] modes = gd.getDisplayModes();
// For every mode we'd prefer to use...
for( int j = 0; j < PreferredModes.length; j++ )
{
// ...we check it against each mode the system supports...
for( int i = 0; i < modes.length; i++ )
{
// ...and if we find a matching entry we return it.
if( modes[i].getWidth() == PreferredModes[j].getWidth()
&& modes[i].getHeight() == PreferredModes[j].getHeight()
&& modes[i].getBitDepth() == PreferredModes[j].getBitDepth() )
return PreferredModes[j];
}
}
// ...we couldn't find a matching mode, return null.
return null;
}
// "Globals"
Frame mainFrame;
BufferStrategy bufferStrategy;
int ScreenWidth;
int ScreenHeight;
boolean Running = true;
// Our appliclation
public Test( boolean fs )
{
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
GraphicsDevice gd = ge.getDefaultScreenDevice();
GraphicsConfiguration gc = gd.getDefaultConfiguration();
DisplayMode dm = bestmode( gd );
// If we can't have one of our preferred display modes, or the system does not support
// full screen exclusive mode, then we'll stick with a window.
if( dm == null || gd.isFullScreenSupported() == false )
fs = false;
// Create our main frame and set attributes common to both FS and windowed modes.
mainFrame = new Frame( gc );
mainFrame.setLayout( null );
mainFrame.setIgnoreRepaint( true );
// If full screen is wanted (and possible), set it up.
if( fs )
{
mainFrame.setUndecorated( true ); // No window decorations
gd.setFullScreenWindow( mainFrame ); // Create a full screen window
gd.setDisplayMode( dm ); // Change to our preferred mode
ScreenWidth = dm.getWidth(); // Get the screen dimensions
ScreenHeight = dm.getHeight();
}
// Otherwise we use a window with a fixed size
else
{
ScreenWidth = 800; // Default window size
ScreenHeight = 600;
mainFrame.setSize( new Dimension( ScreenWidth, ScreenHeight ) );
mainFrame.show(); // Show it
}
// Set up our buffer strategy (with double buffering)
mainFrame.createBufferStrategy( 2 );
bufferStrategy = mainFrame.getBufferStrategy();
// Main game loop
while( Running )
{
// This is where you would call a method that updates your game state (ie: moves
// objects, checks for collisions, etc.
// updategame();
// Call our render function to draw everything.
render();
// Sleep
try
{
Thread.sleep( 30 ); // This should be replaced with proper frame rate limiting code
} catch( InterruptedException e ) {}
}
}
// A variable used with render()
int i = 0;
// This method is called once every frame to display the current state of our game.
private void render()
{
// If we've lost our video memory, don't bother drawing anything
if( !bufferStrategy.contentsLost() )
{
Graphics g = bufferStrategy.getDrawGraphics();
// Clear the drawing buffer to white
g.setColor( Color.white );
g.fillRect( 0, 0, ScreenWidth, ScreenHeight );
// Say hello
g.setColor( Color.black );
g.drawString( "Hello World!", i, i );
// We'll stop after 400 frames.
i++;
if( i > 400 )
Running = false;
bufferStrategy.show();
g.dispose();
}
}
}