Game Programming Algorithms and Techniques Chapter 2 2D Graphics
Chapter 2 Objectives 2D Rendering Foundations Learn the basics how monitors work Cover color buffers, vertical sync, and screen tearing Sprites Learn about both basic and animated sprites Learn how sprite sheets can save space Scrolling Single-axis and infinite scrolling Using the parallax effect to give an illusion of depth Implementing four-direction scrolling Tile Maps Learn how to use basic tile maps Using isometric tile maps
CRT Monitor Basics CRTs contain an array of picture elements known as pixels: For color displays, each pixel contains a red, green, and blue sub-pixel. Resolution determines the total number of pixels: 300x200 means each row or scan line has 300 pixels and there's a total of 200 rows. CRTs use an electron gun to activate the various pixels.
CRT Monitor Basics, Cont'd Electron gun draws one scan line at a time. When it gets to bottom-right corner, it takes some time to get the aim back to top left (vertical blank interval or VBLANK). Basic CRT drawing
Screen tearing caused by updating video data while the CRT is drawing Color Buffer A buffer is memory that stores the color data for all the pixels on the screen. With only a single color buffer, writing to it outside of VBLANK will result in screen tearing. Screen tearing caused by updating video data while the CRT is drawing
Double Buffering Use two color buffers: While buffer A is written to, display buffer B. Then next frame, write to B and display A. As long as the swap occurs during VBLANK, there is no screen tearing: This corresponds to the VSYNC setting in many games. Triple buffering is when there are three color buffers.
Sprites 2D visual objects used to represent: Characters Other dynamic objects For simple games, backgrounds The corresponding image format can vary depending on the platform (PNG, TGA, and PVR are all potential options).
Basic Sprite Object class Sprite ImageFile image int drawOrder int x, y function Draw() // Draw the image at the correct (x,y) ... end
Painter’s algorithm applied to a 2D space scene Sprites are drawn from back to front. Painter’s algorithm applied to a 2D space scene
Animating Sprites Like flipbook animations. Animation FPS can vary (24 is a common rate). Animated run cycle
AnimatedSprite Implementation AnimFrameData struct stores: Starting frame of animation Total number of frames of animation AnimData struct stores: Array of images used for all the frames Array of AnimFrameData
AnimatedSprite Members class AnimatedSprite inherits Sprite // All of the animation data (includes ImageFiles and FrameData) AnimData animData // The particular animation that is active int animNum // The frame number of the active animation that's being displayed int frameNum // Amount of time the current frame has been displayed float frameTime // The FPS the animation is running at (24FPS by default). float animFPS = 24.0f function Initialize(AnimData myData, int startingAnimNum) function UpdateAnim(float deltaTime) function ChangeAnim(int num) end
Updating the Animation If animation FPS is higher than game FPS, we may need to skip frames in the animation, so: frameNum += frameTime * animFPS If frameNum > the number of frames: Use modulus to figure out new frame number. Similarly, use fmod to determine what amount to reset frameTime.
Sprite Sheets Rather than separate image files per sprite, pack them all into a single image file. Can greatly reduce empty space, thus reducing size. Individual sprites (a), and those sprites packed in a sprite sheet (b)
Single-Axis Scrolling Game scrolls in a single direction, like Jetpack Joyride. Single-direction scrolling in Jetpack Joyride. The dotted line demonstrates a boundary.
Single-Axis Scrolling, Cont'd Easiest with screen-sized background sprites. Create a list of background sprites with their x-positions set as appropriate. While scrolling, change the camera position based on the player's position: camera.x = clamp(player.x, screenWidth / 2, hCount * screenWidth – screenWidth / 2)
Single-Axis Scrolling, Cont'd Once the appropriate background image is determined, offset the position based on the camera: draw s at (s.x – camera.x + screenWidth/2, 0) Then draw the subsequent image, in case it, too, is visible.
Infinite Scrolling When the game continues to scroll until the player loses. There can't be an infinite number of background segments, so segments must be repeated. Increasing the unique images increases variety, as does randomizing sequences of images.
Space scene broken into three layers to facilitate parallax scrolling Separate the background into layers, and then scroll them at different speeds. This gives the illusion of depth. Space scene broken into three layers to facilitate parallax scrolling
Scene broken up into four segments to support four-way scrolling When the game world scrolls horizontally and vertically. Code is similar to single-axis, just in two directions. Scene broken up into four segments to support four-way scrolling
Tile Maps Partition world into squares (or other polygon). Size of a tile is game-specific. Each square references a particular image in the tile set. Scene from the classic platformer Jazz Jackrabbit 2, which uses tile maps for its levels
Basic Level Format Represent each tile onscreen with a number specifying the index into the tile set: 0,0,1,0,0 0,1,1,1,0 1,1,2,1,1
Sample isometric scene Isometric Tile Map Can create a greater sense of depth. Used in games like Diablo II. Tiles are usually parallelograms or hexagons. Sample isometric scene © denis_pc/fotolia