190 likes | 299 Views
BlackBerry Game Development Challenges. Jeff Bacon, Sr. Smartphone Product Manager Simon Dale, Smartphone Services Team Lead J15. Agenda. Buffering Strategies Parallax Scrolling Case Study: Worms A Space Oddity Optimizing with the JDE Navigation API Deficiencies. Magmic Experience.
E N D
BlackBerry Game Development Challenges Jeff Bacon, Sr. Smartphone Product Manager Simon Dale, Smartphone Services Team Lead J15
Agenda • Buffering Strategies • Parallax Scrolling • Case Study: Worms A Space Oddity • Optimizing with the JDE • Navigation • API Deficiencies
Magmic Experience 5+ years of BlackBerry game development Feature Phones (J2ME/MIDP) BlackBerry Original & Licensed IP Over 45 Games Feature Phones (BREW) Windows Mobile Licensed IP: 60+ Titles J2ME/MIDP BlackBerry BREW Windows Mobile
Buffering StrategiesWhat do we mean by buffering? 11 x Graphics.drawBitmap 110 x Graphics.drawBitmap Tiles Raging Rivers, Magmic Games
Buffering StrategiesMotivations • Why do we need to buffer the screen? • Customers think big screen == big performance • Meet customer expectations • Optimization is FUN!
Buffering StrategiesFull Screen Image Bitmap buffer = new Bitmap(screenWidth, screenHeight); private booleanbufferDirty = true; private void repaintBuffer() { synchronized (buffer) { // … draw all the static content onto the buffer … bufferDirty = false; } } public void setBufferDirty() { synchronized (buffer) { bufferDirty = true; } }
Buffering StrategiesFull Screen Image // OPTION 1: Paint Method public void paint(Graphics g) { if (buffer_is_dirty) { repaintBuffer(); } g.drawBitmap(0, 0, screenWidth, screenHeight, buffer, 0, 0); // … draw all dynamic content … } • Good: guarantee clean paints • Bad: frame rate choppy • Bad: long synchronization in paint // OPTION 2: Game Run Loop if (buffer_is_dirty) { repaintBuffer(); } • Good: control when frame rate suffers • Bad: can have dirty paints
Buffering StrategiesFull Screen Image: Working and Live buffers private void repaintBuffer() { synchronized (workingBuffer) { // … draw all the static content onto the workingBuffer … synchronized (liveBuffer) { Graphics g = liveBuffer.getGraphics(); g.drawBitmap(... workingBuffer ...); } bufferDirty = false; } } public void paint(Graphics g) { synchronized (liveBuffer) { g.drawBitmap(... liveBuffer ...); } // … draw all dynamic content … } • Reduces maximum paint time • Low variance in FPS • Risk of stale paints
Buffering StrategiesLarger-Than-Full Screen Image Content Area Viewport • Same basic code as Full Screen • Keep track of viewport co-ordinates • Offset rendering in drawBitmap with viewport Call of Duty 3, HandsOn Mobile
Buffering StrategiesSegmented Buffer intnumBuffers = (screenWidth/ bufferWidth) + 1; Bitmap buffers[] = new Bitmap[numBuffers]; private boolean[] bufferIsDirty = new boolean[numBuffers]; private intleftBuffer = 0; private intleftOffset = 0; public synchronized void setBufferDirty(intbufferId) { synchronized (buffers) { bufferIsDirty[bufferId] = true; } } private void repaintBuffer(intbufferId) { synchronized (buffers) { // … draw all the static content onto the buffer … bufferIsDirty[bufferId] = false; } }
Buffering StrategiesSegmented Buffer public void paint(Graphics g) { synchronized (buffers) { for (inti = 0; i < numBuffers; i++) { if (bufferIsDirty[i]) { repaintBuffer(i); } } } intcurrentBuffer = leftBuffer; for (inti = 0; i < numBuffers; i++) { g.drawBitmap(… buffers[currentBuffer % numBuffers] …); ++currentBuffer; } // … draw all dynamic content … } • Remember to respect the leftOffset • Remember to start at leftBuffer index
Buffering StrategiesSegmented Buffer, Example Screen Area Indiana Jones and the Kingdom of the Crystal Skull, THQ Wireless • More buffers == smoother scrolling • Less buffers == faster painting when not scrolling • Horizontal Scroller: • buffer height == screen height • width can be varied • (ex. above) • Vertical Scroller: • buffer width == screen width • height can be varied
Parallax Scrolling What is parallax scrolling? New Super Mario Bros., Nintendo, Nintendo DS
Parallax ScrollingOptimization: Reduce Number of Paints • Avoid tiled backgrounds • Use fewer, larger images • Buffer the background layer(s) • Only paint visible areas Eagle Eye, Magmic Games
Case Study: Worms A Space OddityProblem: Very Slow Frame Rate • Why? • Large level maps (1024x512) • Repainting on every tick • Repainting using Graphics.drawRGB() • Updating all map data for all changes • Can we Buffer? • Can’t draw to a large Bitmap • Difficult to maintain transparency in a buffer • How do we efficiently deform the world? • Stationary camera: 3-5 fps • Moving camera (viewport): 1-2 fps • Explosion: 0 fps
Case Study: Worms A Space OddityStage 1: Basic Optimizations & Full Screen Buffer • Use lookup-tables for trig functions • Faster calculations, less accurate • Localize painting to the current viewport • Remove some detail • Decreases production quality • Performance often outweighs detail • Full Screen buffer • Stationary camera improved dramatically • Stationary camera: 17 fps • Moving camera (viewport): 8-12 fps • Explosion: 0-3 fps
Case Study: Worms A Space OddityStage 2: More Optimizations & Segmented Buffer 1024px • Create a world buffer: 1024x512px • Manipulate ARGB data for transparency • Painting buffer done on load • Allows parallax scrolling • Optimize explosions & bounds checking • Localize small changes 512px • Stationary camera: 12 fps • Moving camera: 12 fps • Explosion: 8-10 fps Worms A Space Oddity, THQ Wireless
Case Study: Worms A Space OddityStage 3: Double Buffering • Improve stationary camera frame rate • Paint 1 live buffer vs. 1-4 working buffers • Possible panning improvement • Painting off-screen faster than direct to screen • Stationary camera: 14-16 fps • Moving camera: 12-14 fps • Explosion: 8-10 fps Worms A Space Oddity, THQ Wireless