The Player
class is used for playing samples.
On Series 40 devices, a maximum of eight players are allowed at the
same time, and only some of the players can play simultaneously because
of memory restrictions. Due to these limitations, the MIDlet must
monitor the number of players created and how many of them are playing.
While the Drumkit MIDlet demonstrates how to manage audio in a low-latency application, in the Explonoid MIDlet the latency is a minor issue. Of course, it is convenient that a sample plays fairly fast, but the MIDlet does not require the audio handling to be implemented in exactly the same way to reach sufficient results. Basically, if the sample must play as fast as possible, the MIDlet must create a player and prefetch the sample in advance. However, as the Explonoid MIDlet has more than eight samples to be played, you cannot reserve one player per sample or predict which sample is played next. Consequently, the simple solution is to create a new player every time the MIDlet needs to play a sample. If there are too many players already playing, the one that has been playing the longest is stopped and deallocated.
To implement audio:
Define the maximum
number of players, and use the playSample
method
to play the sample.
Note that the addPlayerListener
method call is used to register a listener for the END_OF_MEDIA
events to enable effective looping.
public Player playSample(String filename) { Player player = null; if (audioEnabled) { InputStream stream = AudioManager.class.getResourceAsStream(filename); try { limitPlaybacks(); player = Manager.createPlayer(stream, "audio/mp3"); playing.addElement(player); player.realize(); player.prefetch(); player.addPlayerListener(this); player.start(); } catch (Exception e) { } } return player; }
Use the limitPlaybacks
method to track the number of concurrent
players, and to stop the longest playing player when the maximum number
of players is reached.
/** * Shuts down the player, that has been playing the longest */ private synchronized static void limitPlaybacks() { try { while (playing.size() > MAX_PLAYERS) { Player player = (Player) playing.firstElement(); playing.removeElementAt(0); stop(player); } } catch (Exception e) { } }
To loop a sample,
you can use the player.setLoopCount(-1)
method. However,
it does not always result in an indefinite loop. Listening to the END_OF_MEDIA
event and then starting the player again manually
seems to be a more reliable way to implement looping.
public Player loopSample(String filename) { Player p = playSample(filename); looping.addElement(p); return p; } // ... public void playerUpdate(Player player, String event, Object eventData) { if (event.equals(PlayerListener.END_OF_MEDIA)) { if (looping.contains(player)) { try { player.setMediaTime(0); player.start(); } catch (Exception e) { } } else { stopPlayer(player); } } }
To make the Explonoid MIDlet look better than just an Arkanoid clone, it contains some additional effects, such as vibrations and the following:
Spark bursts
Every time the ball hits a brick,
the brick explodes with a spark burst. The spark burst consists of Spark
sprites that hold a fade-out animation. When shooting
sparks, each spark gets a random velocity and direction and the animation
is started from a random place.
Shaking
Shaking is a simple Timer
-based effect, which shakes the game
area with a given magnitude and subsides as the time goes on.
Shock waves
Shock waves occur when the ball slips past the plate. They are basically just ellipses that grow every time they are painted and disappear after their maximum size has been reached.
Electrical arcs
Electrical arcs occur in the menu view when the user touches the screen. The arcs are randomly generated from the pointer coordinates outward.
Figure: Explonoid effects
When handling effects, you must consider memory as well. The garbage collector cannot always keep up if the MIDlet generates new objects too fast. To prevent problems, for example, with spark bursts, limit the maximum number of sparks and reuse the same spark instances over and over again.