Category Archives: Development

Galactic Blast Released on App World!

I’m very excited to say Galactic Blast is now officially available for purchase from App World!!

Pick it up now and save the galaxy, right from your Blackberry!

And for all the aspiring developers out there, don’t forget to check out the tutorial to make games just like this one.

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…

Unfortunate News for a Realtime Blackberry Mixer

Overview

Sometimes I’m not sure if it’s a good thing or a bad one, but I have the kind of personality that when I get involved trying to solve a problem, I can’t stop until it’s solved. This works out well as eventually the issue at hand is fixed, but it also has the side effect that I forsake pretty much everything else until I can resolve things. When I can’t find a solution, or there isn’t a good one, it drives me nuts.

And unfortunately, I’m in that irritated mindset now. If you read my post on Mixing Two or More Sounds Together on the Blackberry, you saw the video I posted of a software sound mixer I had written. While the mixer did indeed work, the problem was I had only tested one scenario – where the user has chosen to start mixing all the sounds together at the same time. This use case is no problem.

The Ongoing Problem

The use case that’s an issue (and honestly the whole point of a realtime mixer), is where you start playing one sound, and then mix another one in at an arbitrary time later. The reason why this is an issue is fairly easily explained (and unfortunately not apparent to me until I had written most of the code).

As you know if you’re a Blackberry developer, all user code is written in Java – the BB runs a JVM where all the software runs – that’s how the phone is designed. This creates a layer of abstraction, where the user doesn’t have direct access to the hardware, and where the code runs relatively slow (compared to native instructions). Because of this, RIM provided mappings from the javax package’s Player class to the Blackberry sound hardware.

The Problem of Buffers and Fetching

Player does a number of things – but the core of it retrieves data from a sound stream (a wav file in our case), massages it as necessary, and then loads the sound hardware buffers with the data. The big problem is at the stage when Player retrieves data. It does so in chunks of data – specifically (from my experiments and as other people on the web have reported) in 58000 byte chunks. That means that is takes in a few seconds of sound at a time so the hardware buffers don’t underrun during playback. You can do some tricks with blocking the stream and force it not to load in this full 58000 – and you will immediately hear the effects – choppy audio. The 58000 byte buffer is not to be annoying – it’s necessary for smooth and clean audio.

And this is why we can’t do realtime mixing. We don’t have direct access to the hardware buffers, we only have access to the buffer streams we can feed to Player. And if Player demands a few seconds of audio at each read, we cannot insert a sound into the few seconds that we feed to it after the fact.

An Example of the Problem

I have two sounds. Drums.wav which is a 20 second wav, and flute.wav which is a 5 second wave. I would like to play drums over and over again, and then immediately mix the flute in when the user presses the ‘F’ button.

Player immediately reads in, let’s say 5 seconds of drum.wav. Then at second 3, the user presses the ‘F’ button. Our program can immediately queue in flute.wav into the input stream, but it won’t be played until second 5, since the Player already read in 5 seconds. Even if we do some creative thread blocking, we can never guarantee a real time mix at all times.

The Code (Could Still Be Useful in Certain Applications)

Below I have included all my work on this project. It consists of a “MixerStream”, which is meant to be a replacement to InputStream. You feed an instantiated MixerStream object to Player, and then call the MixerStream “addStream” method to mix other audio files, in real time, into the Player. It does work – but there will be large delays between when the sound is added, to when it is heard, due to the problem described above.

Note – this code is currently hardcoded to only work with one format of PCM stream right now (I put two hardcoded headers of a 44.1khz, 16bit, stereo, and a 44.1khz, 8bit, mono) – in addition to doing a very low tech way of mixing streams together. The method “getMixedByte” is all setup for future functionality (Allowing any format of PCM, doing better mixing, preventing clipping, etc) – but I’m not up to doing any more work with this right now. It only works as a semi-real time mixer, which I don’t think is too useful – the only place where it might be nice is if you’re developing a Blackberry audio-editing application, or something to that effect – where realtime isn’t necessary. If you are doing this – feel free to use the code below – I’ll provide any help I can.

So for now – this project is abandoned. Frustrating, but necessary for now. Hopefully with the new QNX based OS coming out, there will be more support for directly accessing the hardware buffers.

package com.synthdreams;

import java.io.IOException;
import java.io.InputStream;
import java.util.Vector;

import net.rim.device.api.ui.component.Dialog;


// The MixerStream class allows us to add multiple PCM wave streams to mix together in real time
public class MixerStream extends InputStream{
   private Vector _streamVector; // All wave streams currently managed by the mixer
   int[] _headerArray;
   int _headerPos;
   int _totalRead;
   
   
   // WaveStream class is an InputWrapper stream that stores wav audio information
   private class WaveStream extends InputStream {
      private InputStream _fileStream; // The input stream containing the wav data
      private int _sampleRate; // Samplerate of the wave
      private int _bitRate; // Bitrate of the wave
      private int _channels; // Channels in the wave 
    
      public int getSampleRate() { return _sampleRate; }
      public int getBitRate() { return _bitRate; }
      public int getChannels() { return _channels; }
      
      public WaveStream(InputStream passStream) throws IOException {
         byte[] byteArray;
         String tempChunkName;
         int tempChunkSize;
         
         // Assign the file stream, then read in header info
         _fileStream = passStream;

         // 4 - ChunkID (RIFF)
         _fileStream.read(byteArray = new byte[4]);
         if (new String(byteArray).equals("RIFF") == false) {
            throw new IOException("Not a valid wave file (ChunkID).");
         }
         
         // 4 - ChunkSize
         _fileStream.read(byteArray = new byte[4]);

         // 4 - Format (WAVE)
         _fileStream.read(byteArray = new byte[4]);
         if (new String(byteArray).equals("WAVE") == false) {
            throw new IOException("Not a valid wave file (Format).");
         }
         
         // 4 - SubchunkID (fmt)
         _fileStream.read(byteArray = new byte[3]);
         if (new String(byteArray).equals("fmt") == false) {
            throw new IOException("Not a valid wave file (SubchunkID).");
         }
         _fileStream.read(byteArray = new byte[1]);
         
         // 4 - Subchunk1Size
         _fileStream.read(byteArray = new byte[4]);        
         tempChunkSize = ((byteArray[3] & 0xff) << 24) | ((byteArray[2] & 0xff) << 16) | ((byteArray[1] & 0xff) << 8) | (byteArray[0] & 0xff);
             
         // 2 - AudioFormat(1)
         _fileStream.read(byteArray = new byte[2]);
         if (byteArray[0] != 1) {
            throw new IOException("PCM Compression not supported.");
         }

         // 2 - NumChannels
         _fileStream.read(byteArray = new byte[2]);
         _channels = ((byteArray[1] & 0xff) << 8) | (byteArray[0] & 0xff); 
 
         // 4 - Sample Rate
         _fileStream.read(byteArray = new byte[4]);
         _sampleRate = ((byteArray[3] & 0xff) << 24) | ((byteArray[2] & 0xff) << 16) | ((byteArray[1] & 0xff) << 8) | (byteArray[0] & 0xff);
         
         // 6 - Byte Rate, Block Align
         _fileStream.read(byteArray = new byte[6]);

         // 2 - Bitrate
         _fileStream.read(byteArray = new byte[2]);
         _bitRate = ((byteArray[1] & 0xff) << 8) | (byteArray[0] & 0xff); 
         
         // variable - Read in rest of chunk 1
         _fileStream.read(byteArray = new byte[tempChunkSize-16]);
         
         // Burn through unneeded chunks until we get to data
         tempChunkName = "";
         tempChunkSize = 0;
         while (tempChunkName.equals("data") == false) {
            // Read in name and size of chunk
            _fileStream.read(byteArray = new byte[4]);
            tempChunkName = new String(byteArray);
            _fileStream.read(byteArray = new byte[4]);
            tempChunkSize = ((byteArray[3] & 0xff) << 24) | ((byteArray[2] & 0xff) << 16) | ((byteArray[1] & 0xff) << 8) | (byteArray[0] & 0xff);

            // Burn through non-data chunks
            if (tempChunkName.equals("data") == false) {
               _fileStream.read(byteArray = new byte[tempChunkSize]); 
            }
         }
         // End of header
      }
      
      public int read() throws IOException {
         return _fileStream.read();
      }           
   }

   public MixerStream()  {
      _headerPos = 0;
      _totalRead = 0;
      
      // A constructed wav header for a 44100hz, 16bit, stereo wav of maximum length
      /*_headerArray = new byte[] {'R','I','F','F', (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, 
                                 'W','A','V','E', 'f','m','t', 0x20, 0x10, 0x00, 0x00, 0x00, 
                                 0x01, 0x00, 0x02, 0x00, 0x44, (byte)0xAC, 0x00, 0x00,
                                 0x10, (byte)0xB1, 0x02, 0x00, 0x04, 0x00, 0x10, 0x00,
                                 'd','a','t','a', (byte)0xDB, (byte)0xFF, (byte)0xFF, (byte)0xFF};*/
      
      // A constructed wav header for a 4410hz, 8bit, mono wav of maximum length
      _headerArray = new int[] {'R','I','F','F', 0xFF, 0xFF, 0xFF, 0xFF, 
            'W','A','V','E', 'f','m','t', 0x20, 0x10, 0x00, 0x00, 0x00, 
            0x01, 0x00, 0x01, 0x00, 0x44, 0xAC, 0x00, 0x00,
            0x44, 0xAC, 0x00, 0x00, 0x01, 0x00, 0x08, 0x00, 
            'd','a','t','a', 0xDB, 0xFF, 0xFF, 0xFF};
      
      _streamVector = new Vector();
   }
      
      
   // MixerStream will first present a wav header (as documented above), then will mix data
   // from all added streams.  If there aren't any streams, it will block.
   public int read() throws IOException {
      // Increase the total count of bytes read
      _totalRead++;
            
      // First present header       
      if (_headerPos < _headerArray.length) {
         return _headerArray[_headerPos++];    
      }
      else {
         // Mix any streams together
         if (_streamVector.size() > 0) {
            return getMixedByte();
         }
         else {
            // If no streams are available, normally block.  
            // Return 0 during the prefetch process (58000 bytes) so prefetch 
            // doesn't block forever
            try {
               if (_totalRead < 58001) return 0;
               
               synchronized(_streamVector) {
                  _streamVector.wait();
               }
               
               return getMixedByte();
            }
            catch (Exception e) {
               return 0;
            }
         }
      }
   }
   
   // This method will mix all the available streams together, keep track of current
   // playback byte position to accommodate different PCM formats, and normalize the
   // sound mixing.
   private int getMixedByte() throws IOException {
      int tempRead;
      int tempValue;
      
      tempValue = 0;
      
      // Loop through each stream
      for (int lcv = 0 ; lcv < _streamVector.size() ; lcv++) {
         tempRead = ((WaveStream)_streamVector.elementAt(lcv)).read();
         
         // If we're at the end of the stream, remove it.  Otherwise, add it
         if (tempRead == -1) {
            _streamVector.removeElementAt(lcv--);
         }
         else {
            tempValue += tempRead;
         }
      }
      
      // Normalize
      if (_streamVector.size() > 0) {
         tempValue /= _streamVector.size();
         return tempValue;
      }
      else {
         return 0;   
      }
   }
   
   // Queue an audio stream to be mixed by MixerStream
   public int addStream(InputStream passStream) throws IOException {
      WaveStream tempStream;
      
      tempStream = new WaveStream(passStream);
      
      // Make sure this WaveStream is compatible with MixerStream
      // Check for sample rates
      if (tempStream.getSampleRate() != 11025 && tempStream.getSampleRate() != 22050 && tempStream.getSampleRate() != 44100) {
         throw new IOException("Sample rate not supported.  (11025, 22050, 44100)");
      }
      
      // Check for bitrates
      if (tempStream.getBitRate() != 8 && tempStream.getBitRate() != 16) {
         throw new IOException("Bit rate not supported.  (8, 16)");
      }
      
      // Check for channels
      if (tempStream.getChannels() != 1 && tempStream.getChannels() != 1) {
         throw new IOException("Number of channels not supported.  (1, 2)");
      }
      
      // Wave Stream checks out, let's add it to the list of streams to mix
      _streamVector.addElement(tempStream);
      
      try {
         // Notify the read method that there's data now if it's currently blocked
         synchronized(_streamVector) {
            _streamVector.notify();
         }
      }
      catch (Exception e) {
         Dialog.inform("Error notifying _streamVector");
      }
      return 0;
   }
}

Fun Ways to Sharpen Your CS Skills

If you’re anything like me, once you learned how to code, you would take any chance you could get to write little programs for fun. I remember once I finally “got” BASIC on my Commodore 64 growing up, I would spend hours writing the cheeziest (looking back) programs. A favorite of mine was writing countless “Question and Answer” programs, where the computer would ask “How are you?” and depending on your answer, the program would issue a different (and probably inappropriate given my age at the time) response.

Time Marches On

As time went on though, and I got better at programming, learned the fundamentals, studied Computer Science – things started to change. I still loved to program, but my goals became larger and more complex. Pet projects would take days to complete, then weeks, then months. Once I started doing it professionally, that added a whole new level, where the projects were for money, and project management, sustainability, fiscal viability, etc, all became factors. I had to specialize and focus on specific areas to remain competitive. And the technology changed – whereas once I was communicating directly with the processor and memory I/O, now I was communicating 17 levels up to a a COM object or framework API. It was just a different ballgame – which isn’t necessarily a bad thing, but sometimes working at such a high level for different purposes can make you lose site of the underlying CS. Sometimes it’s important to keep your CS skills as fresh and sharp as your software engineering ones.

Some Fun Ways to Up Your CS Game

Luckily, there are some sites out there that are awesome for keeping those little grey CS cells active in your head.

Project Euler
This is by far my favorite one. Euler offers a large number of problems (currently 300) that require a computer program to solve. They are generally geared toward mathematics of different levels and areas (generally the higher the problem, the more difficult it is), and you can solve them using any method or programming language you wish. The website keeps track of how many you’ve solved and how you’re faring with the rest of the members, but really you’re competing with yourself to write the best program you can. As you get into later problems, even your efficiency matters, as your first solution might take 3 days to complete, whereas the better one takes .25 seconds. They have discussion forums for each problem as well (once you’ve solved it), where people show their solutions and help each other out. Some example problems on the site:

1. Add all the natural numbers below one thousand that are multiples of 3 or 5.
7. Find the 10001st prime.
15. Starting in the top left corner in a 20 by 20 grid, how many routes are there to the bottom right corner?
109. How many distinct ways can a player checkout in the game of darts with a score of less than 100?
157. Solving the diophantine equation 1/a+1/b= p/10n

As you can see, there are a large range of problems targeting different areas and algorithms. I’ve solved 34 to date – sometimes I’ll spend a lunch hour working on a problem, they’re great fun and you can do them at your own pace – and learn new techniques in the process.

Hack This Site!
No, that wasn’t an invitation! Hack This Site . Org is an interesting site that offers a number of security, reverse engineering, and application development missions. While I’m actually against the practice of unauthorized computer access (especially being a IT Manager by day) – penetration testing is a great thing for a network administrator to know, and reverse engineering is a fantastic thing for a programmer to know. In the high-level development world we now live in, getting back to the processor and memory level is definitely a plus – and studying the binary structure of an executable certainly achieves that. Not only does it strengthen your machine language skills, but it also gives you great insight into how compilers work, how operating systems link DLLs, management memory, and achieve IPC.

Many More

Project Euler and Hack This Site are the two I focus on (and between the two of them, there are enough problems to keep me busy for years), but if they aren’t your cup of tea, here are a list of other programming problem related sites:

Bright Shadows
Electrica
Programming Challenges
Python Challenge
TopCoder

Have fun, and get your CS in shape!

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);  
      }
   }

Blackberry Programming: Alter Bitmap Color on the Fly

While working on my current Blackberry game, I ran into a situation where I needed to change the color of of a bitmap. Specifically, I wanted to signify an object was “hit” by temporarily tinting it red – i.e. I wanted to keep the original bitmap color pattern, but wanted to increase the red portion of all the pixels so it had a red shade to it.

Example
Fighter - Before
Before
Fighter - After
After

ARGB Methods

Off the bat, I couldn’t find any method of directly altering the bitmap color using built in routines. There are a few routines for altering the alpha channel of bitmaps, but nothing for the color channels. After sifting through all the members of the Bitmap class, I came across the getARGB method (see link for details). This method will populate an int array with argb data, e.g. an int (4 bytes) per pixel signifying the alpha, red, green, and blue values (each value stored per byte). And sure enough, there is a setARGB method as well, for taking such an int array and applying it to a bitmap object.

The Strategy

With these methods at our disposal, it now becomes a matter of populating an array with ARGB data, then altering each int in the manner desired to achieve a specific effect. In this case, increasing the value of the RED byte (2nd byte) to increase the red tint of each pixel. However, the sky is the limit, as you could alter transparency for each pixel (alpha byte) and create a disintegration effect, average and equalize each of the color bytes to create greyscale, invert the colors, dim/brighten, etc. However, for now, lets stick to adding a red tint.

The Code

 public static Bitmap generateHitBitmap(Bitmap passBitmap) {
      Bitmap retBitmap;  // Altered, tinted bitmap being returned
      int[] argbData; // Array holding the ARGB data
      int redData;  // The red value of a pixel

      // Create a new, empty bitmap with the same dimensions
      retBitmap = new Bitmap(passBitmap.getType(), passBitmap.getWidth(), passBitmap.getHeight());

      // Prepare the ARGB array
      argbData = new int[passBitmap.getWidth() * passBitmap.getHeight()];
      
      // Grab the ARGB data
      passBitmap.getARGB(argbData, 0, passBitmap.getWidth(), 0, 0, passBitmap.getWidth(), passBitmap.getHeight());

      // Loop through each pixel in the array
      for (int lcv = 0 ; lcv < argbData.length ; lcv++) {
         // Get the red data by masking out the 2nd byte
         redData = (argbData[lcv] & 0x00FF0000) >> 16;

         // Increase the red value by 80 (maximum of 255)
         redData += 80; 
         if (redData > 255) redData = 255;

         // Shift it back to the right place, and set it back into array
         redData = redData << 16;
         argbData[lcv] = (argbData[lcv] & 0xFF00FFFF) + redData;
      }

      //  Set the return Bitmap to use this altered ARGB array 
      retBitmap.setARGB(argbData, 0, passBitmap.getWidth(), 0, 0, passBitmap.getWidth(), passBitmap.getHeight());

      return retBitmap;
   }

Note: There is some bitwise math going on here, and a few ways to accomplish this. I like to isolate out the value first and work with it separately, but you may feel more comfortable working directly with the array – either works.

Please feel free to share any cool effects you’ve achieved altering the ARGB data, or even constructing completely new ARGB data on the fly – I would love to see programmatically generated bitmaps!

A Quick Kudos to Blender

As I mentioned in a previous post, I’m currently developing another Blackberry game, one I hope that turns out fun enough that people will want to play. As with most games, it requires graphics – which has actually always been somewhat of a road block for me. I don’t have many acquaintances that are able / have time / are interested in doing the artwork for a game, especially one that isn’t going to make much, if any, money. I myself love art, but I’m not very good at it. That leaves the options of buying stock art for obscene amounts of money (due to rights to use it commercially – I try to always play by the book), or finding royalty free art – which is usually difficult and I can never find exactly what I’m looking for.

3D packages are a good middle ground for me. Granted – it takes a boatload of talent and experience to get professional looking results, but you can get respectable art with a little practice. Most 3D packages are fairly expensive, which can again be a roadblock – but this is where Blender comes in. Blender is an open source 3D rendering application available for pretty much all platforms. I’ve heard the learning curve is a little steeper with Blender than with other packages like 3DS (I’ve only used 3DS once so I don’t quite remember), but after you use it for a week or so, you get into the rhythm and it’s not bad at all – and then from there you start learning cool tricks for lighting and textures, and things look better and better.

Below are a few objects that may appear in the game in one form or another. They’re not great by any means, especially compared to what Blender pros have put out (Check out the cream of the crop from the Blender site), but it’s not bad for a day or twos work, and after getting shrunk down for a mobile platform, is acceptable.

SR-13

Enemy Drone

Tetron Mine

And, Blender is just fun to play around with – especially when you start getting into animations. So if you get a chance, definitely check it out, for fun – or for your next project.

Blender Website

Using Excel to Create Your Game’s Binary Data Files

I don’t think I’ve mentioned it here yet, but I’m currently in the middle of developing a new Blackberry game that I hope to have on App World when I’m complete (as I get closer to completion I’ll put some screen shots up). I’ve always wanted to put an application or game up on one of the mobile stores, not so much to make any significant amount of money (which I won’t), but just to get the program into more people’s hands easily. We’ll see how it goes – but until then, onto the point of this article.

One of the things I ran into on this game (and others) is the need to generate binary files – specifically in this case, level data that dictates where and when objects are in the game, their effects, behaviors, etc. While there is always the option to create a text file to hold this data, this can be problematic in many ways. First, the data you need to store may actually be binary data that doesn’t lend itself to text conversion – also, more handling to read the file (encoding, line feeds, parsing), larger files (which is a concern on devices with little storage like older Blackberrys), and no obfuscation to the end user (which kind of takes the fun out of the game if they can open up this file easily and read where everything is). Binary files are definitely the way to go. And while sometimes it makes sense to make a level editor that will generate the binary files, in some instances you may not have the time or resources to accomplish this. It would be nice to have a tool to generate these files so you don’t have to go hexediting for hours to make a 1K file.

Excel at Creating These Files!

I find Microsoft Excel to be an extremely useful tool in so many situations, especially those where I need to bang out results quickly. Past the normal math, accounting, and analysis capabilities, Excel is awesome for generating files that depend on working with lots of imported data, such as script files and, in our case, binary data files.

In my example, each object had 7 values associated with it. And with some of these values being 2 bytes in size, this came out to 12 or so bytes I would have to enter hex code in with an editor, per object. If I wanted 500 objects, thats 6K of writing hex values. No thanks. It would be much easier to write these values into Excel cells (even auto-generating many of them using Fill-Down with an equation). Then, using VBA (Visual Basic for Applications) that’s built into Excel, dump the contents of the cells out into the binary format I want them in. So let’s see how to do that.

Settings Up Your Sheet

This is the simple part. For this example, I have created a fictional game called “Just Desserts” in which each level consists of a screen filled with desserts and vegetables, and you must eat the various cakes, pies, and puddings but avoid carrots and celery. Our data file that describes each level has 4 values per entry.

Value 1: What level this food is on
Value 2: The ID of this food (E.g. 1=cake, 2=pie, 3=pudding, 4=celery, 5=carrot)
Value 3: X coordinate on screen of this food
Value 4: Y coordinate on the screen of this food

Here’s what an example spreadsheet would look like:

Excel Data

So each row is an object, and each column is one of the values. In our example above, we see on level one we should create a cake at coords (25,70), a pie at (50,20) and another at (10,10), and a celery at (400, 400). On level 2, we should create a cake at coords (250, 30), a pudding at (20,160), and a celery at (70,90). You can manually enter your data in, or use the power of excel and generate the data using a formula – it’s up to you. Once your data is in your spreadsheet, then comes time to turn it into a binary file that can be used by your game.

Macro Time

The power of Excel is increased 10-fold by the ability to include programs in your spreadsheets. Excel uses Visual Basic to accomplish this. By creating a new macro, you can attach a Visual Basic function to it that gets called whenever your macro is. In Excel 2007, Macros are under the View tab. After you create a new one, you are presented with a code editor where you can write your VB function.

Below is the example VB function that would work with the above data and pump it out into a file. Please note – one thing you may run into depending on what language you’re working with, and what architecture, is a little/big endian conflict. VBA pumps out little-endian, but since I was creating a BB game in Java, it expects big endian. I included how to do this inline below, though you could make a function out of it as well.

Sub GenDatFile()

   Dim TempByte as Byte ' Holds 1 byte
   Dim TempInt as Integer ' Holds 2 bytes

   ' Specify the path and filename of the binary file.  You could turn this into an input to specify it at runtime as well.  
   Open "C:\temp\objects.dat" For Binary Access Write As #1 ' Open it for binary writing with the handle #1

   CurrentRow = 1

   ' Keep reading the spreadsheet until we come to a blank row, then we're done
   Do While Not IsEmpty(Worksheets(1).Cells(CurrentRow, 1))
      'Level of object
      TempByte = Worksheets(1).Cells(CurrentRow, 1) ' Get the value from the first cell in the current row
      Put 1, , TempByte ' Write that byte to the data file (handle #1)

      'ID of object
      TempByte = Worksheets(1).Cells(CurrentRow, 2) ' Get the value from the second cell in the current row
      Put 1, , TempByte ' Write that byte to the data file (handle #1)

      'X Coordinate of object - this is a 2 byte value since it can be greater than 255, we need to swap endian
      TempInt = Worksheets(1).Cells(CurrentRow, 3) ' Get the value from the third cell in the current row
      TempByte = TempInt \ 256 ' Integer divide by 256, aka shift right 8 bits and put that into TempByte
      Put 1, , TempByte ' Write that byte to the data file (handle #1)
      TempByte = TempInt AND 255 ' Mask the data to grab the first byte and put that into TempByte
      Put 1, , TempByte ' Write that byte to the data file (handle #1)

      'Y Coordinate of object - this is a 2 byte value since it can be greater than 255, we need to swap endian
      TempInt = Worksheets(1).Cells(CurrentRow, 4) ' Get the value from the fourth cell in the current row
      TempByte = TempInt \ 256 ' Integer divide by 256, aka shift right 8 bits and put that into TempByte
      Put 1, , TempByte ' Write that byte to the data file (handle #1)
      TempByte = TempInt AND 255 ' Mask the data to grab the first byte and put that into TempByte
      Put 1, , TempByte ' Write that byte to the data file (handle #1)

      CurrentRow = CurrentRow + 1 ' Move to the next row in the spreadsheet
   Loop

   Close 1 ' Close the file (handle #1)

End Sub

And we’re done! A very simple program, with only a tiny bit of magic to flip the bytes when we need to make little endian into big endian. But a simple program which saves us hours of tedious hex encoding, plus the power of Excel gives us data storage and manipulation that we didn’t have to take time to manually program ourselves.

Next time you’re faced with a problem that deals with working with a lot of data, keep Excel (or it’s open source brethren) in mind – it can definitely save you a lot of time and headaches.

From Pong to Platformers – An Introduction to Game Physics – Part 4

Acceleration for Better Goomba Stomping

So now we understand positioning an object on a screen, moving the object around using the principles of velocity, and how to handle collisions with walls and other simple objects. While we can do quite a lot with these simple fundamentals, there is one more that is key to modeling realistic movement. We can understand a little how it works by watching how Mario jumps in the Super Mario Bros series.

Physics - Mario
Mario jumps in an arc movement

For those who haven’t played Super Mario Bros, Mario jumps in an arc. When he begins to jump, the sprite on the screen moves up very quickly, then slows at the top of the arc, then slowly starts moving back down, until he’s going the same speed as when he started the jump when hitting the ground. The reason for this movement is due to acceleration. Specifically, the game is modeling the affects of gravity, gravity being a force that causes acceleration in the downward direction.

Just as velocity is the rate of change of an object’s position (e.g. meters per second), acceleration is the rate of change of an object’s velocity (e.g. meters per second per second). Gravity is a force that causes constant acceleration in the downward direction. Because of this, though Mario starts with a velocity that causes him to move in an upward direction, acceleration downward causes this velocity to slowly decrease, then reverse, getting faster in the opposite direction.

Programatically, we can handle this the same way we do velocity. In addition to updating position with velocity, we’ll want to update velocity with acceleration – so we’ll need two more variables, AccX and AccY. During our redraw, we’ll want to update both velocity and position: (VelX = VelX + AccX) (VelY = VelY + AccY) (X = X + VelX) (Y = Y + VelY). Acceleration can be used to model many realistic scenarios besides jumping in platform adventures, such engines firing in a spaceship simulator, or shells being fired from a cannon in a tank war game.

Onto More Advanced Topics

We’ve covered position, velocity, acceleration, and basic collisions – with these basic techniques, a wide range of realistic motions can be accomplished when making your next game. There are, however, hundreds of more topics, including friction, complex collisions, fluid dynamics, light oriented (shading, diffraction, reflection), etc. However, before getting too crazy, try some of these techniques in simple games to get familiar with Newtonian Mechanics. After that, more advanced topics will be easier to handle. Have fun with you physics!