22
Lecture20 Lecture20 Java Game Programming III Java Game Programming III – Rate Control, Simple – Rate Control, Simple Animation and Display Animation and Display Mode Mode

Lecture20 Java Game Programming III – Rate Control, Simple Animation and Display Mode

  • View
    218

  • Download
    2

Embed Size (px)

Citation preview

Page 1: Lecture20 Java Game Programming III – Rate Control, Simple Animation and Display Mode

Lecture20Lecture20

Java Game Programming III – Java Game Programming III – Rate Control, Simple Rate Control, Simple

Animation and Display ModeAnimation and Display Mode

Page 2: Lecture20 Java Game Programming III – Rate Control, Simple Animation and Display Mode

Timing IssuesTiming Issues In Java 1.4.2 the simplest way to get hold In Java 1.4.2 the simplest way to get hold

of the time is to use of the time is to use System.currentTimeMillis(). System.currentTimeMillis(). • The resolution of this timer is sometimes not The resolution of this timer is sometimes not

good enough to get a consistent frame rate.good enough to get a consistent frame rate.• Timer resolution, or Timer resolution, or granularitygranularity, is the amount , is the amount

of time that must separate two timer calls so of time that must separate two timer calls so that different values are returned. For instance, that different values are returned. For instance, what is the value of diff in the code fragment what is the value of diff in the code fragment below?below?

long t1 = System.currentTimeMillis();long t1 = System.currentTimeMillis();

long t2 = System.currentTimeMillis();long t2 = System.currentTimeMillis();

long diff = t2 – t1; // in mslong diff = t2 – t1; // in ms

Page 3: Lecture20 Java Game Programming III – Rate Control, Simple Animation and Display Mode

Timing IssuesTiming Issues In Windows 95/98, the resolution is 55ms, which In Windows 95/98, the resolution is 55ms, which

means that repeated calls to currentTimeMillis() means that repeated calls to currentTimeMillis() will only return different values roughly every will only return different values roughly every 55ms.55ms.• In the animation loop, the overall effect of poor resolution In the animation loop, the overall effect of poor resolution

is to cause the animation to run slower than intended, The is to cause the animation to run slower than intended, The elapsed value between iterations will be set to 0 if the elapsed value between iterations will be set to 0 if the game update and rendering time is less than 55ms.game update and rendering time is less than 55ms.

• This causes each iteration to sleep longer than necessary.This causes each iteration to sleep longer than necessary.• To try to combat this, the minimum iteration period in To try to combat this, the minimum iteration period in

Game loop should be greater than 55ms, indicating an Game loop should be greater than 55ms, indicating an upper limit of about 18 FPS.upper limit of about 18 FPS.

On Windows 2000, NT, and XP, currentTimeMillis() On Windows 2000, NT, and XP, currentTimeMillis() has a resolution of 10-15ms, making it possible to has a resolution of 10-15ms, making it possible to obtain 67-100 FPS.obtain 67-100 FPS.

The Mac OS X and Linux have timer resolutions of The Mac OS X and Linux have timer resolutions of 1ms, which is excellent.1ms, which is excellent.

Page 4: Lecture20 Java Game Programming III – Rate Control, Simple Animation and Display Mode

Timing IssuesTiming Issues Java 1.5 has a better timerJava 1.5 has a better timer

• System.nanoTime() System.nanoTime() Third party timer libraries are also Third party timer libraries are also

available.available. Most of these timing problems are to do Most of these timing problems are to do

with Java on windows platforms.with Java on windows platforms. One of the things directly dependent upon One of the things directly dependent upon

accurate timing is any form of animation. accurate timing is any form of animation. An upper bound for a good FPS value is An upper bound for a good FPS value is

the monitor refresh rate. This is typically the monitor refresh rate. This is typically 70-90Hz (i.e. 70-90 FPS).70-90Hz (i.e. 70-90 FPS).

Page 5: Lecture20 Java Game Programming III – Rate Control, Simple Animation and Display Mode

Rate ControlRate Control

One way to deal with the One way to deal with the inconsistency of timing on Windows inconsistency of timing on Windows is to average the change in time is to average the change in time between frames. between frames.

1.1. Each game loop record the render time Each game loop record the render time between frames. between frames.

2.2. Average the last 5 frame times Average the last 5 frame times

3.3. Use the average to move and update Use the average to move and update game elements game elements

Page 6: Lecture20 Java Game Programming III – Rate Control, Simple Animation and Display Mode

AnimationAnimation

Animation adds the dimension of Animation adds the dimension of time to computer graphics.time to computer graphics.

To animate something, the animator To animate something, the animator has to be able to control, either has to be able to control, either directly or indirectly, how the thing is directly or indirectly, how the thing is to move through time and space as to move through time and space as well as how it might change its own well as how it might change its own shape or appearance over time.shape or appearance over time.

Page 7: Lecture20 Java Game Programming III – Rate Control, Simple Animation and Display Mode

Animating the AliensAnimating the Aliens Instead of the entity maintaining just a single Instead of the entity maintaining just a single

sprite we'll add a few sprites and flip between sprite we'll add a few sprites and flip between them over time, i.e. Animation. them over time, i.e. Animation.

We need We need additional variables to our AlienEntity: additional variables to our AlienEntity:

/** The animation frames */ /** The animation frames */ private Sprite[] frames = new Sprite[4]; private Sprite[] frames = new Sprite[4]; /** The time since the last frame change took place */ /** The time since the last frame change took place */ private long lastFrameChange; private long lastFrameChange; /** The frame duration in milliseconds, i.e. how long any given /** The frame duration in milliseconds, i.e. how long any given

frame of animation lasts */ frame of animation lasts */ private long frameDuration = 250; private long frameDuration = 250; /** The current frame of animation being displayed */ /** The current frame of animation being displayed */ private int frameNumber; private int frameNumber;

Page 8: Lecture20 Java Game Programming III – Rate Control, Simple Animation and Display Mode

AlienEntity Class – ConstructorAlienEntity Class – Constructorpublic AlienEntity(Game game,int x,int y) { public AlienEntity(Game game,int x,int y) {

super("sprites/alien.gif",x,y); super("sprites/alien.gif",x,y); // setup the animatin frames // setup the animatin frames frames[0] = sprite; frames[0] = sprite; frames[1] = frames[1] = SpriteStore.get().getSprite("sprites/alien2.gif"); SpriteStore.get().getSprite("sprites/alien2.gif"); frames[2] = sprite; frames[2] = sprite; frames[3] = frames[3] = SpriteStore.get().getSprite("sprites/alien3.gif"); SpriteStore.get().getSprite("sprites/alien3.gif"); this.game = game; this.game = game; dx = -moveSpeed; dx = -moveSpeed;

} }

Page 9: Lecture20 Java Game Programming III – Rate Control, Simple Animation and Display Mode

AlienEntity Class – move() methodAlienEntity Class – move() methodpublic void move(long delta) { public void move(long delta) {

// since the move tells us how much time has passed // since the move tells us how much time has passed // by we can use it to drive the animation// by we can use it to drive the animationlastFrameChange += delta; lastFrameChange += delta; // if we need to change the frame, update the frame number // if we need to change the frame, update the frame number // and flip over the sprite in use // and flip over the sprite in use if (lastFrameChange > frameDuration) { if (lastFrameChange > frameDuration) {

// reset our frame change time counter // reset our frame change time counter lastFrameChange = 0; lastFrameChange = 0; // update the frame // update the frame frameNumber++; frameNumber++; if (frameNumber >= frames.length) { if (frameNumber >= frames.length) {

frameNumber = 0; frameNumber = 0; } } sprite = frames[frameNumber]; sprite = frames[frameNumber];

} } ... ...

} }

Page 10: Lecture20 Java Game Programming III – Rate Control, Simple Animation and Display Mode

Full-Screen Exclusive Mode (FSEM)

Full-screen exclusive mode (FSEM) suspends most of Java's windowing environment, bypassing the Swing and AWT graphics layers to offer almost direct access to the screen.

It allows graphics card features, such as page flipping, to be exploited, and permits the screen’s resolution and bit depth to be adjusted.

The graphics hardware acceleration used by FSEM has a disadvantage: • it utilizes video memory (VRAM) which may be 'grabbed back’

by the OS when, for example, it needs to draw another window, display a screensaver, or change the screen's resolution. The application's image buffer, which is stored in the VRAM, will then have to be reconstructed from scratch.

• A related issue is that VRAM is not an infinite resource, and trying to place too many images there may cause the OS to start swapping them in and out of memory, causing a slowdown in the rendering.

Page 11: Lecture20 Java Game Programming III – Rate Control, Simple Animation and Display Mode

Setting up JFrame to Full-Screen Exclusive Mode (FSEM)

GraphicsEnvironment ge =GraphicsEnvironment.getLocalGraphicsEnvironment();

GraphicsDevice gd = ge.getDefaultScreenDevice();setUndecorated(true); // no menu bar, borders, etc.setIgnoreRepaint(true);// turn off paint events since doing active renderingsetResizable(false);

if (!gd.isFullScreenSupported()) {System.exit(0);

}gd.setFullScreenWindow(this); // switch on FSEM

Page 12: Lecture20 Java Game Programming III – Rate Control, Simple Animation and Display Mode

BufferStrategyBufferStrategytry {

EventQueue.invokeAndWait( new Runnable() {public void run() {

createBufferStrategy(2); }

});} catch (Exception e) {

System.out.println("Error while creating buffer strategy");System.exit(0);

}try { // sleep to give time for buffer strategy to be done

Thread.sleep(500); // 0.5 sec} catch (InterruptedException ex){}bufferStrategy = getBufferStrategy(); // store for later

Page 13: Lecture20 Java Game Programming III – Rate Control, Simple Animation and Display Mode

BufferStrategyBufferStrategy invokeAndWait() is employed to avoid a

possible deadlock between the createBufferStrategy() call and the event dispatcher thread (this issue should be fixed in J2SE 1.5)

createBufferStrategy() is an asynchronous operation, so the sleep() call delays execution a little time so that the getBufferStrategy() call will get the correct details.

Other asynchronous methods include setDisplayMode(), show(), and setFullScreenWindow().

Page 14: Lecture20 Java Game Programming III – Rate Control, Simple Animation and Display Mode

Rendering onto Frame BuffersRendering onto Frame Buffers

Graphics g = bufferStrategy.getDrawGraphics();

// Write rendering commands with g// …g.dispose();

Page 15: Lecture20 Java Game Programming III – Rate Control, Simple Animation and Display Mode

Page Flipping

if (!bufferStrategy.contentsLost())bufferStrategy.show();

elseSystem.out.println("Contents Lost");

Page 16: Lecture20 Java Game Programming III – Rate Control, Simple Animation and Display Mode

Page Flipping The amount of copying required to display even a The amount of copying required to display even a

single frame is substantial. single frame is substantial. • For example, a display of 1024 by 768 pixels, with 32 bit For example, a display of 1024 by 768 pixels, with 32 bit

depth, will need a 3MB sized copy.depth, will need a 3MB sized copy. Page flipping avoids these overheads by using a Page flipping avoids these overheads by using a

video pointer (if one is available).video pointer (if one is available).• The video pointer tells the graphics card where to look in The video pointer tells the graphics card where to look in

VRAM for the image to be displayed during the next VRAM for the image to be displayed during the next refresh. refresh.

• Page flipping involves two buffers, which are used Page flipping involves two buffers, which are used alternatively as the primary surface for the screen. While alternatively as the primary surface for the screen. While the video pointer is pointing at one buffer, the other is the video pointer is pointing at one buffer, the other is updated. updated.

• When the next refresh cycle comes around, the pointer When the next refresh cycle comes around, the pointer is changed to refer to the second buffer, and the first is is changed to refer to the second buffer, and the first is updated.updated.

With more than two frame buffers, With more than two frame buffers, a a flip chain flip chain is is created. The video pointer cycles through the created. The video pointer cycles through the buffers while rendering is carried out to the other buffers while rendering is carried out to the other buffers in the chain.buffers in the chain.

Page 17: Lecture20 Java Game Programming III – Rate Control, Simple Animation and Display Mode

Setting the display modeSetting the display mode A smaller screen resolution and bit depth reduces A smaller screen resolution and bit depth reduces

the amount of data transferred when the back the amount of data transferred when the back buffer is copied to the screen.buffer is copied to the screen.• For example, a display of 1024 by 768 pixels, with 32 bit For example, a display of 1024 by 768 pixels, with 32 bit

depth, will need a 3MB sized copy.depth, will need a 3MB sized copy.• However, this advantage is irrelevant if the rendering is However, this advantage is irrelevant if the rendering is

carried out by page flipping with video pointer carried out by page flipping with video pointer manipulation.manipulation.

A game can run more quickly if its images share A game can run more quickly if its images share the same bit depth as the screen. This is easier to the same bit depth as the screen. This is easier to do if we fix the bit depth inside the application.do if we fix the bit depth inside the application.

A known screen size may make drawing A known screen size may make drawing operations simpler, especially for images which operations simpler, especially for images which would normally have to be scaled to fit different would normally have to be scaled to fit different display sizes.display sizes.

Page 18: Lecture20 Java Game Programming III – Rate Control, Simple Animation and Display Mode

Setting the display modeSetting the display modeGraphicsEnvironment ge =

GraphicsEnvironment.getLocalGraphicsEnvironment();GraphicsDevice gd = ge.getDefaultScreenDevice();if (gd.isDisplayChangeSupported()) {

DisplayMode dm = new DisplayMode(width, height, bitDepth,DisplayMode.REFRESH_RATE_UNKNOWN); // any refresh rate

try {gd.setDisplayMode(dm);

} catch (IllegalArgumentException e) { System.out.println("Error setting Display mode");

}try { // sleep to give time for the display to be changed

Thread.sleep(1000); // 1 sec} catch(InterruptedException ex){}

}

Page 19: Lecture20 Java Game Programming III – Rate Control, Simple Animation and Display Mode

Checking whether a display mode Checking whether a display mode is availableis available

private boolean isDisplayModeAvailable( GraphicsDevice gd, int width, int height, int bitDepth)

DisplayMode[] modes = gd.getDisplayModes();for(int i = 0; i < modes.length; i++) {

if ( width == modes[i].getWidth() && height == modes[i].getHeight() &&

bitDepth == modes[i].getBitDepth() )return true;

}return false;

}

Page 20: Lecture20 Java Game Programming III – Rate Control, Simple Animation and Display Mode

Accessing the video memory for imagesAccessing the video memory for images Use the Use the VolatileImage class. E.g.VolatileImage class. E.g.

// image creation // image creation VolatileImage vImg = createVolatileImage(w, h); VolatileImage vImg = createVolatileImage(w, h); // rendering to the image // rendering to the image void renderOffscreen() { void renderOffscreen() {

do { do { if (vImg.validate(getGraphicsConfiguration()) == if (vImg.validate(getGraphicsConfiguration()) == VolatileImage.IMAGE_INCOMPATIBLE) { VolatileImage.IMAGE_INCOMPATIBLE) {

// old vImg doesn't work with new GraphicsConfig; re-create it // old vImg doesn't work with new GraphicsConfig; re-create it vImg = createVolatileImage(w, h); vImg = createVolatileImage(w, h);

} } Graphics2D g = vImg.createGraphics(); Graphics2D g = vImg.createGraphics(); // // // miscellaneous rendering commands... // miscellaneous rendering commands... // // g.dispose(); g.dispose(); } while (vImg.contentsLost()); } while (vImg.contentsLost());

} } Note: Note: createVolatileImage() is a method of Component class or otherwise you may createVolatileImage() is a method of Component class or otherwise you may

want to use createCompatibleVolatileImage() method of a want to use createCompatibleVolatileImage() method of a GraphicsConfiguration object.GraphicsConfiguration object.

Page 21: Lecture20 Java Game Programming III – Rate Control, Simple Animation and Display Mode

VolatileImage – Restoring the VolatileImage – Restoring the contentscontents

// copying from the image (here, ghs is a Graphics // copying from the image (here, ghs is a Graphics // object for a frame buffer possibly in the video memory) // object for a frame buffer possibly in the video memory)

do { do { int returnCode = vImg.validate(getGraphicsConfiguration()); int returnCode = vImg.validate(getGraphicsConfiguration()); if (returnCode == VolatileImage.IMAGE_RESTORED) { if (returnCode == VolatileImage.IMAGE_RESTORED) {

// Contents need to be restored // Contents need to be restored renderOffscreen(); // restore contents renderOffscreen(); // restore contents

} else if (returnCode == VolatileImage.} else if (returnCode == VolatileImage.IMAGE_INCOMPATIBLEIMAGE_INCOMPATIBLE) { ) { // old vImg doesn't work with new GraphicsConfig; re-create it// old vImg doesn't work with new GraphicsConfig; re-create it vImg = createVolatileImage(w, h); vImg = createVolatileImage(w, h); renderOffscreen(); renderOffscreen();

} } ghs.drawImage(vImg, 0, 0, this); ghs.drawImage(vImg, 0, 0, this);

} while (vImg.contentsLost()); } while (vImg.contentsLost());

Page 22: Lecture20 Java Game Programming III – Rate Control, Simple Animation and Display Mode

ReferencesReferences

Space invaders tutorial available at Space invaders tutorial available at http://www.codebeach.com/http://www.codebeach.com/