The Game
As an example game, you'll use a very simple space game. The idea of the game is to shoot enemy ships. Without sounds, the game consists of three classes and three resource files. The resource files contain images for the background and for the ships. The classes are the main MIDlet class (SpaceGameMIDlet), a class extended from Canvas (SpaceGameCanvas) and a special class for enemy ships (Enemy).
When the game is started, a thread is started in the SpaceGameCanvas class that contains the game loop. The game loop is very simple; it updates the objects on the screen, scrolls the view (makes the landscape move), and checks to see whether any shots are fired. The game screen is shown in Figure 1.
Figure 1 Space game screen.
Choices for the Game
What kinds of sounds do you to add to this game? Because it is a very simple game that has only the game screen, you don't need startup music or music for the menus. You do need a nice theme for the game play and some sounds for firing and explosions.
Now that you know the type of sounds to use, you have to decide the format (or the type of the media). Because tone sequences are something that should work in all devices, you'll use them. For the firing and explosions, you can use some individual tones.
Adding Sounds to the Game
You can add another class in the game project, SpaceGameSounds, and then centralize all sounds in this class. The class has simple methods for turning the background music on and off and for firing and explosion sounds.
The single sounds are easy, but how should we keep the music going on in the background? There's a nice little interface just for this kind of purpose in the Media API called PlayerListener. This interface has one method:
public void playerUpdate(Player player, String event, Object eventData)
The implementing class can now be registered to a player as a listener, and the player will notify the listener whenever there's a change in its state. The possible events are CLOSED, DEVICE_AVAILABLE, DEVICE_UNAVAILABLE, DURATION_UPDATED, END_OF_MEDIA, ERROR, STARTED, STOPPED, and VOLUME_CHANGED. This time, you'll use only the END_OF_MEDIA event. If the music is set to on, you'll just play the music again whenever it stops.
The most interesting parts of the code below include the construction of the melody, playing the simple tones (they might not sound like firearms, but...), and the updatePlayer() method where the music is played again.
package com.kontio; import javax.microedition.midlet.*; import javax.microedition.lcdui.*; import javax.microedition.media.*; import javax.microedition.media.control.*; public class SpaceGameSounds implements PlayerListener{ private Player player; boolean toggle = false; byte tempo = 30; byte d = 8; // duration Player p = null; byte C4 = ToneControl.C4;; byte D4 = (byte)(C4 + 2); byte E4 = (byte)(C4 + 4); byte F4 = (byte)(C4 + 5); byte G4 = (byte)(C4 + 7); byte rest = ToneControl.SILENCE; byte[] mySequence = { ToneControl.VERSION, 1, ToneControl.TEMPO, tempo, ToneControl.BLOCK_START, 0, // starting A part C4,d, F4,d, F4,d, C4,d, F4,d, F4,d, C4,d, F4,d, ToneControl.BLOCK_END, 0, // ending A part ToneControl.BLOCK_START, 1, // starting B part C4,d, E4,d, E4,d, C4,d, E4,d, E4,d, C4,d, E4,d, ToneControl.BLOCK_END, 1, // ending B part ToneControl.BLOCK_START, 2, // starting C part F4,d, rest,d, F4,d, rest,d, F4,d, rest,d, F4,d, rest,d, ToneControl.BLOCK_END, 2, // ending C part ToneControl.PLAY_BLOCK, 0, // playing A part ToneControl.PLAY_BLOCK, 1, // playing B part ToneControl.PLAY_BLOCK, 0, // playing A part ToneControl.PLAY_BLOCK, 2, // playing C part }; public SpaceGameSounds(){ try{ p = Manager.createPlayer(Manager.TONE_DEVICE_LOCATOR); p.realize(); p.addPlayerListener(this); ToneControl c = (ToneControl)p.getControl("ToneControl"); c.setSequence(mySequence); } catch (Exception e) { System.out.println("Exception in constructor..."); } } public void soundsOn(){ toggle = true; playTones(); } public void soundsOff(){ toggle = false; } public void fire(){ try{ Manager.playTone(G4, 2, 50); } catch (Exception e) { System.out.println("Exception in fire()..."); } } public void explosion(){ try{ Manager.playTone(C4+11, 4, 80); } catch (Exception e) { System.out.println("Exception in explosion()..."); } } public void playTones() { try{ p.start(); } catch (Exception e) { System.out.println("Exception in playTones()..."); } } public void playerUpdate(Player pl, String str, Object o){ if (str.equals("endOfMedia") && toggle){ playTones(); } }
}