Archive for the 'Games' Category

Screenshots of Our Upcoming Blackberry Game!

Well – I’m very excited. If you’ve been following the Twitter feed at all, you know that I’ve been working at a breakneck pace trying to get Galactic Blast completed. You might recognize the title from the demo game featured in our tutorial on creating a Blackberry game. The commercial release of Galactic Blast is built off a very similar framework to what’s featured in the demo, only with a LOT of extra stuff added – pre-rendered 3d graphics, bonus rounds, weapon upgrades, etc.

So without further ado, screenshots!

The Gamma-3 base - the final boss.

The demolition controller destroys the derelict ships in decommissioned shipyard A-3. In this case, however, he's trying to destroy you! Third boss in the game.

The Sutoran Nebula is home to the Phoraxian Shadow Fleet. They hide within the clouds of the nebula to make detection more difficult.

Every 5 waves your SR-13 kicks it into hyperdrive, and you enter the bonus round. Pass through as many rings as possible for maximum points!

Main menu. Start/Resume game, Instructions, View High Scores, Change settings (Sound/Music/Vibration, etc), and Quit.

Title Screen

I just submitted the application to RIM for approval on App World, so hopefully it checks out and it will be available for download soon! More to come…

Blackberry – Mixing 2 or More Sounds Together (Concept Video)

An Audio Issue

One thing that I (and many others judging by forum posts) have run into is the fact that the Blackberry isn’t very good at mixing more than one sound together. You’ll be listening to music, or playing a game with music, and suddenly you’ll get a text message, and it will simply terminate the current sound and play the new one. If you’ve got a friendly application, it will restart/resume the original audio, but it’s a jarring audio experience.

What I’m about to post won’t fix that. However – developers also run into the issue when they want to mix sounds together in their applications and games. Play 2 or more sound effects simultaneously and/or while music is playing. I’ve seen official RIM developers comment that certain devices can achieve two simultaneous sounds by instantiating the Player class twice – but from what I gather, this is on GSM only phones – and still limited to two. On CDMA devices, you’re completely out of luck.

The Cheap and Quick Workaround

In my 6 part tutorial on writing a Blackberry game, in the audio article, I mentioned how the Alert.startAudio method can be used for simple sound effects (tone/duration pairs) that will play simultaneously while your midi or mp3 music plays in the background. For many applications, this is enough if you don’t need sophisticated sound effects.

The Start of a Mixer

I’m guessing that the limitation is imposed by the audio chipset/DAC inside of CDMA devices, and perhaps RIM realizes the CPU time involved in a software based audio mixer would slow the phone down too much. However, I think the software option should be there, and developers can use it if they’d like – they might not need a large amount of CPU, or might be dealing with low quality sound files – there are a few scenarios where a software mixer would just be a nice options.

Tonight I sat down and wrote a quick and dirty proof of concept application showing a PCM audio mixer in action. I loaded in 3 audio 44.1khz 8bit mono files and mixed them together in real time. I didn’t normalize the audio at all, so its a little soft, but the code works, and could be expanded on quite a bit to make a full featured mixer. Maybe I’ll run into problems down the road that RIM already has, but it’ll be interesting nonetheless.

Here is the video of the test:

Blackberry Programming: Increasing Video Speed Through Prerendering

A Problem of Efficiency

As I finishing up the full version of Galactic Blast (screenshots on this soon, its a fully fleshed out game inspired by the demo, to be released on App World) – I ran into an issue in a strange area. The animation was smooth throughout the game, except oddly enough, on the instructions screen.

The instructions screen in Galactic Blast includes some text describing the storyline, some text describing the keyboard controls, bitmaps showing each of the enemies and power ups with description text, and some credits at the end. Since there’s much more than can fit on a single screen, the user can scroll up and down – nothing fancy, just your basic instructions screen. However, the scrolling was anything but smooth. As I debugged more, I found out that redrawing all the bitmaps and text at each scroll was simply taking too long – all the function and helper calls involved in rendering everything was just too much for the processor.

The Solution

As I thought more about it, I realized that it would be much better to simply render one item instead of 20-30 items each time. And since instructions are static in nature (they don’t change or animate), it was a prime candidate for prerendering all the text and bitmaps to a single, big bitmap. However, I wanted the program to prerender the items automatically at runtime – I didn’t want to have to create the bitmap manually (which would be a huge pain anytime I needed to edit something – like adding a new line of text in). The code below achieves this by creating a bitmap in memory and rendering all the desired text/images to it at the start of the program, and then simply displays (and scrolls) this bitmap on the instructions screen.

The Code

I’ve removed the specific text, bitmaps, and positioning from the code to make things a little clearer:


// _instructionsBM is the large bitmap we will be rendering all our text
// and images to.  This is the bitmap we will actually
// display on the instructions screen, thereby increasing efficiency
// since we're only redrawing one bitmap each time the
// player scrolls instead of a bunch of bitmaps.
private static Bitmap _instructionsBM;

   public static void prerenderInstructions() {
      Graphics tempGraphics;
      String objectiveString;
      Bitmap tempBitmap;
      Object castArray[][];     

      // Populate a string with the objective of the game
      objectiveString = "Text describing the objective of the game  ";

      // Populate an array with the enemy bitmaps, their names,
      // and how many points they are
      castArray = new Object[2][];
      castArray[0] = new Object[] { enemyBitmap1, "Enemy 1", "50 Points" };
      castArray[1] = new Object[] { enemyBitmap2, "Enemy 2", "75 Points" };

        // Initialize the bitmap, and then give it an alpha channel for
        // transparency, allowing the background to show through
        // behind the text and bitmaps
       _instructionsBM = new Bitmap(Bitmap.ROWWISE_16BIT_COLOR, WIDTH, HEIGHT);
       _instructionsBM.createAlpha(Bitmap.ALPHA_BITDEPTH_8BPP); 

        // Start with a blank, completely transparent image
      _instructionsBM.setARGB(new int[_instructionsBM.getWidth()*_instructionsBM.getHeight()], 0,
                                             _instructionsBM.getWidth(), 0, 0,
                                             _instructionsBM.getWidth(), _instructionsBM.getHeight());

      // The Graphics object acts a surface that drawing operations
      // can be performed on.  By calling the Graphics constructor
      // with the bitmap as an argument, all drawing operations
      // will be performed upon the bitmap itself.
      tempGraphics = new Graphics(_instructionsBM);

      // All operations to follow will be fully opaque (so pixels not
      //acted upon will stay transparent, while any text/images drawn
      // will be solid.
      tempGraphics.setGlobalAlpha(255);

      // Draw the text onto the bitmap
      tempGraphics.setColor(Color.YELLOW);
      tempGraphics.drawText(objectiveString, 5, 5);    

      // Draw enemy bitmaps onto the bitmap
      for (int lcv = 0 ; lcv < castArray.length ; lcv++) {
         tempBitmap = (Bitmap) castArray[lcv][0];
         tempGraphics.drawBitmap(Utils.getDimension(5, 50+lcv*50,
                                                tempBitmap.getWidth(), tempBitmap.getHeight(), tempBitmap, 0, 0);
         tempGraphics.drawText((String) castArray[lcv][1], 100, 50+lcv*50);
         tempGraphics.drawText((String) castArray[lcv][1], 200, 50+lcv*50);
      }
   }

« Previous PageNext Page »