Upload
sullivan-hunt
View
223
Download
0
Tags:
Embed Size (px)
Citation preview
4.1. GRAPHICS IIAnimated image sequences, fonts and image transforms
ANIMATIONSAnimated image sequences; playback speed and image source
Image SequencesAn image sequence is simply a series of images, displayed one after the other. If the playback is fast a series of progressive images will appear as continuous, unbroken animation.
Typically, how many frame/s are needed to give the appearance of unbroken animation?
A – 50 frame/s
B – 30 frame/s
C – 20 frame/s
D – 10 frame/s
E – 5 frame/s
Image Sequences● TV provides either 25 or 30 frame/s (PAL = 30)
● Consider the set of 6 images:
○ At 2 frame/s it is not smooth
○ At 10 frame/s it is reasonably smooth
● A typical animated cartoon run at 12 frame/s
Sequence SourceImages to be played back as a sequence may reside within a number of different file structures, including:
● A series of files (1 image per file)
● A continuous image strip (1 file)
● An image sheet (1 file)
Aside: For best performance, all images should be stored in an image sheet, with all animations using that sheet rendered together.
IMAGE SEQUENCE PLAYBACKAnimating a sequence of images
Image sequence playbackPlayback of an image sequence can be integrated into the update/draw loop as follows:
• During the update phase determine when the next image in the sequence should be selected to provide the target number of frames/second
• During the draw phase, render the current selected image
Aside: The following example is based on the
ImageAssetSequence within the Java code repository
Image sequence playback (example implementation)
Assuming the images are stored as an array (or an array of rectangles into a single image sheet) the following parameters can be used to offer different playback options:
• playCount- number of times to play the animation (-1 = loop forever, 0 = pause)
• homeFrame – frame to display when not animating
• currentFrame – current frame to display
• animationPeriodms – number of ms which a single playback should take
• animationStartTime – start time of the animation (if playback has commenced)
private int playCount;private int homeFrame;private int currentFrame;private long animationPeriodms; private long animationStartTime;
private BufferedImage[] images;
The update() method determines the current frame that should be displayed in the animation. In turn the draw() method simply draws the current frame.
public void update() {determineCurrentFrame();
} public void draw(Graphics2D graphics2D,
int drawX, int drawY) {graphics2D.drawImage(
images[currentFrame], drawX, drawY, null);}
A check is made to see if the animation has completed, in which case the playCount is reset to zero.
Based on the current time, target animation period and playCount value the current frame is calculated and returned.
private int determineCurrentFrame() {
long currentTime = GetCurrentTime();if (animinationStartTime == -1)
animinationStartTime = currentTime;
if (playCount > 0) {if (currentTime - animinationStartTime
> (long) playCount * animationPeriodms) {playCount = 0;
}}
if (playCount == 0) {currentFrame = homeFrame;
} else {long timeIntoAniminationPeriod = (currentTime –
animinationStartTime) % animationPeriodms;currentFrame = (int) (
(timeIntoAniminationPeriod * (long)images.length )/ animationPeriodms );
}return currentFrame;
}
Aside: This is a slightly different version of the
ImageAssetSequence implementation – the later ensures that the
end frame of the animation is always drawn at least once.
The start time will be reset to -1 anytime the play count is changed.
IN-GAME FONTSDisplaying textual information within games
The expense of drawing a font…Early fonts were bitmap based. Most modern fonts (e.g. TrueType) are outline based, providing a set of line and curve equations describing the shape of each ‘glyph’ (character). When drawing a font, the outline is rendered and then filled by an ink colour.
Generating text by doing this 50-60 times per second is needlessly expensive. How can we improve performance?
Render text once into a bitmap and use bitmap until text changes
Revert to using a bitmap font
In-game fonts (using Java)• Load an image
asset sequence holding the bitmap font characters.
• Create a base TextElement, holding the image sequence and a corresponding text-to-image mapping.
• Use the base TextElement to create text strings that can be drawn.
TextElement guiText = new TextElement(this, (ImageAssetSequence)
assetManager.retrieveAsset( "GUIFont" ), 0, "ABCDEFGHIJKLMNOPQRSTUVWXYZ“ + "abcdefghijklmnopqrstuvwxyz" + "1234567890`!\"$%^&*()-+={}[];:'@#~,.<>/\\? ", "");
TextElement someText =guiText.getMatchingElement(“Hello!");
someText.draw(graphics2D, x, y);
In-game fonts (using XNA)
• Specify and add a SpriteFont content asset (the SpriteFont converts any installed TrueType font into an XNB sprite sheet)
• Load in the SpriteFont within the game.
• Use the SpriteBatch. DrawString() method to render text.
<Asset Type="Graphics:FontDescription"><FontName>Courier New</FontName><Size>10</Size><Spacing>0</Spacing><UseKerning>true</UseKerning><Style>Regular</Style>
SpriteFont spriteFont;SpriteBatch spriteBatch;
spriteFont = content.Load<SpriteFont>("SpriteFont");
spriteBatch.Begin();spriteBatch.DrawString(
spriteFont, “Hello! ", position, Color.White);spriteBatch.End();
Aside: For more information on importing fonts, see:
http://blogs.msdn.com/shawnhar/archive/2007/04/26/bitma
p-fonts-in-xna.aspx
Exercise: Using digit arrays• Assume you have a series of images representing the digits 0 to 9 stored in an array
• Develop an approach that will take a positive integer score and graphically illustrate it using the image sequence.
Start
10 mins9 mins8 mins7 mins6 mins5 mins4 mins3 mins2 mins 1 min 30 secFinished
ImageAsset[] digitImage = new ImageAsset[10];
Exercise: Using digit arrays• By using the modulus
(%) operator the last digit in the score can be extracted and printed.
• Using integer division, the last digit can then be removed and the process iterated until no more digits remain.
void drawScore( int targetScore ) {int scoreFragment = targetScore;do {
int digit = scoreFragment % 10;digitImages[digit].Draw( ... )
scoreFragment = scoreFragment / 10;} while(scoreFragment > 9 );
}
Aside: When drawing the images, it will be necessary to
ensure the draw location of each image is determined. Additionally, the score will
need to be drawn right-to-left.
IMAGE MANIPULATIONBasic forms of image transform
Basic forms of image transform
A number of affine image transforms can be usefully employed within games, including:
Resizing Rotating FlippingFadding
• Depth of view effects
• Object rotation
• Appear / disappear effects
• Left / right / up / down sprite reuse
To do:
Consider
game
applicability
Image Transforms (Resizing)
drawResizedImage( Graphics2D graphics2D, BufferedImage image, int drawX, int drawY, double scaleX, double scaleY )
{int newWidth = (int) (image.getWidth() * scaleX );int newHeight = (int) (image.getHeight() * scaleY );
// Optional… if desiredint newDrawX = drawX + image.getWidth()/2 - newWidth/2;int newDrawY = drawY + image.getHeight()/2 - newHeight/2;
graphics2D.drawImage( image, newDrawX, newDrawY, newWidth, newHeight, null );
}
newWidth
newH
eigh
t
drawX, drawY
newDrawX, newDrawY
SpriteBatch.Draw( Texture2D texture, Rectangle destinationRectangle, Color color )
For Java use:
For XNA use:The source texture will be scaled to fit the destination rectangle.
Image Transforms (Rotation)
drawRotatedImage( Graphics2D graphics2D, BufferedImage image, int drawX, int drawY, double rotationDeg )
{AffineTransform origAT = graphics2D.getTransform(); AffineTransform rotation = new AffineTransform(); rotation.rotate( Math.toRadians(rotationDeg),
drawX + image.getWidth()/2, drawY + image.getHeight()/2 );
graphics2D.setTransform( rotation ); graphics2D.drawImage( image, drawX, drawY, null ); graphics2D.setTransform(origAT);
}
drawX, drawY
For Java use:
SpriteBatch.Draw( Texture2D texture, Rectangle destinationRectangle, Nullable<Rectangle> sourceRectangle, Color color, float rotation, Vector2 origin, SpriteEffects effects, float layerDepth )
The source texture will be rotated around the specified origin
For XNA use:
drawX, drawY
drawX, drawY
For Java use:
drawFadedImage( Graphics2D graphics2D, BufferedImage image, int drawX, int drawY, float alpha )
{Composite origComposite = graphics2D.getComposite();
graphics2D.setComposite( AlphaComposite.getInstance(
AlphaComposite.SRC_OVER, alpha) ); graphics2d.drawImage( image, drawX, drawY, null);
graphics2D.setComposite( origComposite );} Specify a
colour with an alpha component < 256, e.g. for 50% fading new Color( ???, ???, ???, 128 );
Image Transforms (Fading)
SpriteBatch.Draw( Texture2D texture, Rectangle destinationRectangle, Color color )
For XNA use:
drawX, drawY
drawX, drawY
Image Transforms (Flipping)For Java use:
drawHorizFlip(Graphics2D graphics2D, BufferedImage image, int drawX, int drawY )
{int width = image.getWidth(); int height = image.getHeight();
graphics2d.drawImage( image, drawX, drawY+height, drawX+width, drawY,0, 0, width, height, null);
}
drawImage( Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2, ImageObserver obs)
SpriteBatch.Draw( Texture2D texture, Rectangle destinationRectangle, Nullable<Rectangle> sourceRectangle, Color color, float rotation, Vector2 origin, SpriteEffects effects, float layerDepth )
SpriteEffects includes FlipVertically and FlipHorizontally
For XNA use:
Summary
To do:Continue to explore image
repository and select
graphics
Think about the types of
image animation/transform
and font usage in your
game.
Write code snippets to load /
display and animate /
transform images
Today we explored:
The basics behind image sequence playback
How in-game fonts can be efficiently rendered
Some useful image transforms