From cf6e8050cae05cf4bd7f8bd7ca385d4294cfce10 Mon Sep 17 00:00:00 2001 From: forteri76 Date: Thu, 29 May 2014 17:17:57 +0000 Subject: [PATCH] Code cleanup and bugfixes per crash/ARN reports. --- AndroidManifest.xml | 4 +- src/com/efortin/frozenbubble/ModPlayer.java | 40 +- .../frozenbubble/NetworkGameManager.java | 30 +- .../andmodplug/MODResourcePlayer.java | 39 +- .../andmodplug/PlayerThread.java | 798 ++++++++++-------- .../gsanson/frozenbubble/CollisionHelper.java | 296 +++---- src/org/gsanson/frozenbubble/Freile.java | 302 +++---- src/org/gsanson/frozenbubble/MalusBar.java | 17 +- src/org/gsanson/frozenbubble/Opponent.java | 36 +- src/org/jfedor/frozenbubble/BubbleSprite.java | 34 +- src/org/jfedor/frozenbubble/FrozenBubble.java | 28 +- src/org/jfedor/frozenbubble/FrozenGame.java | 71 +- src/org/jfedor/frozenbubble/GameView.java | 180 ++-- .../frozenbubble/InterstitialActivity.java | 9 +- src/org/jfedor/frozenbubble/LevelManager.java | 48 +- 15 files changed, 941 insertions(+), 991 deletions(-) diff --git a/AndroidManifest.xml b/AndroidManifest.xml index c184bba..a7d22b9 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -1,8 +1,8 @@ + android:versionCode="32" + android:versionName="2.8"> // get player instance (in topmost activity, etc.) *
mrp = MODResourcePlayer(); *
// load MOD/XM data into player - *
mrp.LoadMODResource(R.raw.coolsong); + *
mrp.loadModuleResource(R.raw.coolsong); *
mrp.start(); // start thread (playing song)
*
Then when changing songs (new game level or transition to * another sub-activity, etc.): - *
mrp.PausePlay(); - *
mrp.LoadMODResource(R.raw.newcoolsong); - *
mrp.UnPausePlay(); + *
mrp.pausePlay(); + *
mrp.loadModuleResource(R.raw.newcoolsong); + *
mrp.unPausePlay(); *
// repeat...
* @version 1.0 * @author P.A. Casey (crow) Peculiar-Games.com + * @author Eric Fortin * */ public class MODResourcePlayer extends PlayerThread { @@ -95,8 +96,7 @@ public class MODResourcePlayer extends PlayerThread { * extensions. *

The context argument is the application context * which allows MODResourcePlayer to load resources directly. - * @param context - Application context that is creating this - * instance. + * @param context - Application context creating this instance. */ public MODResourcePlayer(Context context) { // Get super class (PlayerThread) with default rate. @@ -112,27 +112,27 @@ public MODResourcePlayer(Context context) { *
Developers using Eclipse as an IDE should note that it allows * the .xm file extension but may be fussy about other tracker format * extensions. - *

The modresource argument is the resource id for the + *

The modResource argument is the resource id for the * MOD/XM song file, e.g. R.raw.coolsong - * @param modresource - Android resource id for a MOD/XM/etc. (tracker + * @param modResource - Android resource ID for a MOD/XM/etc. (tracker * format) song file. * @param gc - if true, perform garbage collection prior * to loading the file. */ - public boolean LoadMODResource(int modresource, boolean gc) { + public boolean loadModuleResource(int modResource, boolean gc) { byte[] modData = null; int currfilesize = 0; InputStream mModfileInStream; /* - * Unload any mod file we have currently loaded. + * Unload any MOD file we have currently loaded. */ - UnLoadMod(); + unLoadMod(); /* * Get an input stream for the MOD file resource. */ - mModfileInStream = mContext.getResources().openRawResource(modresource); + mModfileInStream = mContext.getResources().openRawResource(modResource); try { currfilesize = mModfileInStream.available(); } catch (IOException e) { @@ -172,19 +172,18 @@ public boolean LoadMODResource(int modresource, boolean gc) { /* * Load the song into the player. */ - LoadMODData(modData); + loadModuleData(modData); return true; } /** * Stop playing the song, close down the player and * join() the player thread. - *

Typically called in the application's (Activity's) - * onPause() method. + *

Typically called in the application's main activity + * onDestroy() method. */ - public void StopAndClose() { - PausePlay(); - StopThread(); + public void stopAndClose() { + stopThread(); /* * Now close and join() the MOD player thread. */ @@ -199,7 +198,7 @@ public void StopAndClose() { */ } } - CloseLIBMODPLUG(); - InvalidatePlayer(); + closeLibModPlug(); + invalidatePlayer(); } } diff --git a/src/com/peculiargames/andmodplug/PlayerThread.java b/src/com/peculiargames/andmodplug/PlayerThread.java index 95549cd..7418970 100644 --- a/src/com/peculiargames/andmodplug/PlayerThread.java +++ b/src/com/peculiargames/andmodplug/PlayerThread.java @@ -105,21 +105,22 @@ *

Typical call order: *
// get player instance (in topmost activity, etc.) *
pt = PlayerThread(); - *
pt.LoadMODData(); // load MOD/XM data into player
+ *
pt.loadModuleData(); // load MOD/XM data into player
*
or:
* // get player & load data in one call - *
pt = PlayerThread(moddatabuffer);
+ *
pt = PlayerThread(modDataBuffer); *
then:
* pt.start(); // start thread (playing song)
* To play a different song: *
// changing songs... - *
pt.PausePlay(); - *
pt.UnLoadMod(); - *
pt.LoadMODData(newmodfiledata); - *
pt.UnPausePlay(); + *
pt.pausePlay(); + *
pt.unLoadMod(); + *
pt.loadModuleData(newModFileData); + *
pt.unPausePlay(); *
// repeat...
* @version 1.0 * @author P.A. Casey (crow) Peculiar-Games.com + * @author Eric Fortin * */ public class PlayerThread extends Thread { @@ -177,20 +178,24 @@ public class PlayerThread extends Thread { * PlayerThread object in whichever Activity shuts it down. */ public boolean mPlayerValid = false; - private boolean mWaitFlag = false; - private boolean mFlushedData = false; - private boolean mPlaying = true; - private boolean mRunning = true; + + /* + * Private audio playback control flags. + */ + private boolean mFlushed = false; + private boolean mPaused = false; + private boolean mPausedWas = false; + private boolean mRunning = true; /* * Android will report the minimum buffer size needed to keep playing * audio at our requested rate smoothly. */ private int mMinbuffer; - private int mModsize; // holds the size in bytes of the mod file + private int mModsize; // holds the size in bytes of the MOD file private final static int BUFFERSIZE = 20000; // the sample buffer size - private AudioTrack mMytrack; - private boolean mLoad_ok; + private AudioTrack mMyTrack; + private boolean mLoadOk; /* * Variables for storing info about the MOD file currently loaded. @@ -203,14 +208,14 @@ public class PlayerThread extends Thread { private boolean songFinishedWas; /* - * Track if player has started (after loading a new mod). + * Track if player has started (after loading a new MOD). */ - private boolean sPlayerStarted; + private boolean playerStarted; /* * Start the player in a paused state? */ - private boolean mStart_paused; + private boolean startPaused; /* * Audio sampling rate definitions. @@ -219,35 +224,25 @@ public class PlayerThread extends Thread { private final int[] try_rates = {44100, 32000, 22000, 16000, 8000}; /* - * Ownership code -- for when several activities try to share a - * single mod player instance... - * - * This probably needs to be synchronized... + * Static initializer block. This block is executed if a static + * PlayerThread field is accessed, even without prior instantiation + * of a PlayerThread object. */ - private Object mOwner; - - public boolean TakeOwnership(Object newowner) { - if (mOwner == null || mOwner == newowner) { - mOwner = newowner; - return true; - } - else { - return false; - } - } - - public boolean GiveUpOwnership(Object currowner) { - if (mOwner == null || mOwner == currowner) { - mOwner = null; - return true; - } - else { - return false; + static { + try { + System.loadLibrary("modplug-"+VERS); + //System.loadLibrary("modplug"); + } catch (UnsatisfiedLinkError ule) { + Log.e(LOGPREFIX, "WARNING: Could not load libmodplug-"+VERS+".so"); + Log.e(LOGPREFIX, "------ older or differently named libmodplug???"); } - } - public Object GetOwner() { - return mOwner; + /* + * Get lock objects for synchronizing access to playerValid flag and + * GetSoundData() call. + */ + sPVlock = new Object(); + sRDlock = new Object(); } //******************************************************************** @@ -287,60 +282,59 @@ public void setPlayerListener(PlayerListener pl) { * for now we'll do it this way. * * You could use this in the top parent activity (like a game menu) - * to create a PlayerThread and load the mod data in one call. + * to create a PlayerThread and load the MOD data in one call. */ /** * Allocates a MOD/XM/etc. song PlayerThread *

The modData argument is a byte[] array with the MOD file - * preloaded into it. The desiredrate argument is a specifier that + * preloaded into it. The desiredRate argument is a specifier that * attempts to set the rate audio data will play at - will be * overridden if the OS doesn't allow that rate. * @param modData - A byte[] array containing the MOD file data. - * @param desiredrate - Rate of playback (e.g. 44100Hz, or 0 for + * @param desiredRate - Rate of playback (e.g. 44100Hz, or 0 for * default rate) for system audio data playback. */ - public PlayerThread(byte[] modData, int desiredrate) { + public PlayerThread(byte[] modData, int desiredRate) { /* * Just call the regular constructor and then load in the supplied * MOD file data. */ - this(desiredrate); + this(desiredRate); /* * Load the module file (data) into libmodplug and initialize module * information variables. */ - LoadModuleInfo(modData); + loadModuleInfo(modData); } /** * Allocates a MOD/XM/etc. song PlayerThread. This method just gets - * an audio track. The mod file will be loaded later with a call to + * an audio track. The MOD file will be loaded later with a call to * LoadMODData(). - *

The desiredrate argument is a specifier that attempts to set the + *

The desiredRate argument is a specifier that attempts to set the * rate audio data will play at - will be overridden if the OS doesn't * allow that rate. *

General call order when using this constructor is: - *
pthr = new PlayerThread(0); - *
pthr.LoadMODData(modData); - *
pthr.start();
- * @param desiredrate - Rate of playback (e.g. 44100Hz, or 0 for + *
pt = new PlayerThread(0); + *
pt.loadModuleData(modData); + *
pt.start();
+ * @param desiredRate - Rate of playback (e.g. 44100Hz, or 0 for * default rate) for system audio data playback. */ - public PlayerThread(int desiredrate) { + public PlayerThread(int desiredRate) { /* * No Activity owns this player yet. */ - mMytrack = null; - mOwner = null; - mStart_paused = false; - sPlayerStarted = false; + mMyTrack = null; + startPaused = false; + playerStarted = false; /* * Try to get the audio track. */ - if (!GetAndroidAudioTrack(desiredrate)) { + if (!getAndroidAudioTrack(desiredRate)) { return; } @@ -351,7 +345,7 @@ public PlayerThread(int desiredrate) { * Determine when a song has played to completion. This method also * detects when a looping track has started over from the beginning. */ - private void CheckSongCompleted() { + private void checkSongCompleted() { int posNow = getCurrentPos(); if ((posNow >= posWas) && (posNow < getMaxPos())) { @@ -365,12 +359,29 @@ private void CheckSongCompleted() { posWas = posNow; } + /** + * Close the native internal tracker library (libmodplug) and + * deallocate any resources. + */ + public void closeLibModPlug() { + ModPlug_JUnload(); + ModPlug_CloseDown(); + /* + * Release the audio track resources. + */ + if (mMyTrack != null) + { + mMyTrack.release(); + mMyTrack = null; + } + } + /** * Try to get an Android stereo audio track used by the various * constructors. */ - private boolean GetAndroidAudioTrack(int desiredrate) { - int rateindex = 0; + private boolean getAndroidAudioTrack(int desiredRate) { + int rateIndex = 0; /* * Get a stereo audio track from Android. @@ -383,50 +394,56 @@ private boolean GetAndroidAudioTrack(int desiredrate) { * Init the track and player for the desired rate, or if none * specified, highest possible. */ - if (desiredrate == 0) { + if (desiredRate == 0) { boolean success = false; - while (!success && (rateindex < NUM_RATES)) { + while (!success && (rateIndex < NUM_RATES)) { try { - mMinbuffer = AudioTrack.getMinBufferSize(try_rates[rateindex], + mMinbuffer = AudioTrack.getMinBufferSize(try_rates[rateIndex], AudioFormat.CHANNEL_CONFIGURATION_STEREO, AudioFormat.ENCODING_PCM_16BIT); - mMytrack = new AudioTrack(AudioManager.STREAM_MUSIC, - try_rates[rateindex], + mMyTrack = new AudioTrack(AudioManager.STREAM_MUSIC, + try_rates[rateIndex], AudioFormat.CHANNEL_CONFIGURATION_STEREO, AudioFormat.ENCODING_PCM_16BIT, mMinbuffer, AudioTrack.MODE_STREAM); /* * Init the Modplug player for this sample rate. */ - ModPlug_Init(try_rates[rateindex]); + ModPlug_Init(try_rates[rateIndex]); success = true; } catch (IllegalArgumentException e) { - rateindex++; + rateIndex++; } } } else { - mMinbuffer = AudioTrack.getMinBufferSize(desiredrate, + mMinbuffer = AudioTrack.getMinBufferSize(desiredRate, AudioFormat.CHANNEL_CONFIGURATION_STEREO, AudioFormat.ENCODING_PCM_16BIT); - mMytrack = new AudioTrack(AudioManager.STREAM_MUSIC, desiredrate, + mMyTrack = new AudioTrack(AudioManager.STREAM_MUSIC, desiredRate, AudioFormat.CHANNEL_CONFIGURATION_STEREO, AudioFormat.ENCODING_PCM_16BIT, mMinbuffer, AudioTrack.MODE_STREAM); /* * Init the Modplug player for this sample rate. */ - ModPlug_Init(desiredrate); + ModPlug_Init(desiredRate); } - if (desiredrate == 0) { - mRate = try_rates[rateindex]; + if (desiredRate == 0) { + if (rateIndex < NUM_RATES) { + mRate = try_rates[rateIndex]; + } + else { + mMyTrack = null; + mRate = 0; + } } else { - mRate = desiredrate; + mRate = desiredRate; } - if (mMytrack == null) { + if (mMyTrack == null) { mPlayerValid = false; /* * Couldn't get an audio track so return false to caller. @@ -434,20 +451,19 @@ private boolean GetAndroidAudioTrack(int desiredrate) { return false; } else { - switch(mMytrack.getState()) { + /* + * An audio track was successfully created, so check if the + * appropriate resources were acquired for audio streaming. If + * not, then attempt to re-create the audio track one more time. + */ + switch(mMyTrack.getState()) { case AudioTrack.STATE_INITIALIZED: break; default: - mMytrack = new AudioTrack(AudioManager.STREAM_MUSIC, mRate, + mMyTrack = new AudioTrack(AudioManager.STREAM_MUSIC, mRate, AudioFormat.CHANNEL_CONFIGURATION_STEREO, AudioFormat.ENCODING_PCM_16BIT, mMinbuffer*2, AudioTrack.MODE_STREAM); - switch(mMytrack.getState()) { - case AudioTrack.STATE_INITIALIZED: - break; - default: - break; - } break; } } @@ -458,8 +474,9 @@ private boolean GetAndroidAudioTrack(int desiredrate) { } /** - * Loads MOD/XM,etc. song data for playback. Call PausePlay() if a - * song is currently playing prior to invoking this method. + * Loads MOD/XM,etc. song data for playback. Call + * pausePlay() if a song is currently playing prior to + * invoking this method. *

The modData argument is a byte[] array with the MOD containing * the song file data. *

Example of loading the data:
@@ -472,14 +489,14 @@ private boolean GetAndroidAudioTrack(int desiredrate) { *
}
* @param modData - A byte[] array containing the MOD file data. */ - public void LoadMODData(byte[] modData) { - UnLoadMod(); + public void loadModuleData(byte[] modData) { + unLoadMod(); /* * Load the module file (data) into libmodplug and initialize module * information variables. */ - LoadModuleInfo(modData); + loadModuleInfo(modData); /* * Re-init this flag so that an event will be passed to the @@ -487,7 +504,7 @@ public void LoadMODData(byte[] modData) { * I assume music will actually start playing... */ synchronized(this) { - sPlayerStarted = false; + playerStarted = false; } } @@ -496,10 +513,10 @@ public void LoadMODData(byte[] modData) { *

If the module loads successfully, initialize module info (name * and number of tracks, track playback location, etc.). */ - private void LoadModuleInfo(byte[] modData) { - mLoad_ok = ModPlug_JLoad(modData, modData.length); + private void loadModuleInfo(byte[] modData) { + mLoadOk = ModPlug_JLoad(modData, modData.length); - if (mLoad_ok) { + if (mLoadOk) { mModname = ModPlug_JGetName(); mNumChannels = ModPlug_JNumChannels(); posWas = 0; @@ -508,6 +525,95 @@ private void LoadModuleInfo(byte[] modData) { } } + /* + * MOD file info retrieval methods. + */ + + /** + * Get the name of the song. + * @return the name of the song (from the MOD/XM file header) + */ + public String getModName() { + return mModname; + } + + /** + * Get the file size of the MOD/XM song. + * @return the size of the song file + */ + public int getModSize() { + return mModsize; + } + + /** + * Get the number of channels used in the song (MOD/XM songs + * typically use from 4 to 32 channels in a pattern, mixed together + * for awesomeness). + * @return the number of channels the song uses + */ + public int getNumChannels() { + return mNumChannels; + } + + public int getRate() { + return mRate; + } + + /** + * Mark this PlayerThread as invalid (typically when + * we're closing down the main Activity). + */ + public void invalidatePlayer() { + synchronized(sPVlock) { + mPlayerValid = false; + } + } + + /** + * Pauses playback of the current song. + * @param immediate - if true, pause() then + * flush() the audio stream to immediately stop audio + * playback, otherwise simply stop() the audio stream + * which continues playing until the last buffer written has been + * played to completion. + * @return true if the song was successfully paused. + */ + public boolean pausePlay(boolean immediate) { + boolean paused = false; + + /* + * Set the control flags to stop playback and suspend the thread. + */ + mPaused = true; + mPausedWas = true; + + if (mMyTrack != null) + { + /* + * This check is usually not needed before stopping the audio + * track, but we seem to get an uninitialized audio track here + * occasionally, which throws an IllegalStateException. + */ + if (mMyTrack.getState() == AudioTrack.STATE_INITIALIZED) try { + if (immediate) { + mMyTrack.pause(); + mMyTrack.flush(); + mFlushed = true; + } + else { + mMyTrack.stop(); + } + paused = true; + } catch (IllegalStateException ise) { + /* + * Nothing to do here, so just try to continue gracefully. + */ + } + } + + return paused; + } + /** * This PlayerValid stuff is for multi-activity use, or also * Android's Pause/Resume. @@ -517,7 +623,7 @@ private void LoadModuleInfo(byte[] modData) { * onCreate()??). *

Check if the player thread is still valid. */ - public boolean PlayerValid() { + public boolean playerValid() { /* * Return whether this player is valid. */ @@ -526,28 +632,18 @@ public boolean PlayerValid() { } } - /** - * Mark this playerthread as invalid (typically when we're closing - * down the main Activity). - */ - public void InvalidatePlayer() { - synchronized(sPVlock) { - mPlayerValid = false; - } - } - /** * The thread's run() call, where the modules are played. *

Start playing the MOD/XM song (hopefully it's been previously - * loaded using LoadMODData() or - * LoadMODResource() ;) + * loaded using loadModuleData() or + * loadModuleResource() ;) */ public void run() { - boolean pattern_change = false; + boolean patternChange = false; /* - * Set up our audio sample buffer(libmodplug processes the mod file + * Set up our audio sample buffer(libmodplug processes the MOD file * and fills this with sample data). - * + * * For proper error checking, this should check that BUFFERSIZE is * greater than the minbuffer size the audio system reports in the * contructors... @@ -561,37 +657,83 @@ public void run() { mBuffer = null; } - if (mStart_paused) { - mPlaying = false; + if (startPaused) { + mPaused = true; + mPausedWas = true; } else { - mPlaying = true; + mPaused = false; + mPausedWas = false; } - /* - * Main play loop. - */ - if ((mMytrack != null) && (mBuffer != null)) { - mMytrack.play(); + if ((mMyTrack != null) && (mBuffer != null)) { + boolean startedPlaying = false; + while (mRunning && !startedPlaying) { + try { + mMyTrack.play(); + startedPlaying = true; + } catch (IllegalStateException ise) { + /* + * The audio track isn't initialized yet. Wait a short + * duration, then try again. + */ + startedPlaying = false; + synchronized(this) { + try { + sleep(20); + } catch (InterruptedException ie) { + /* + * This is expected behavior. + */ + } + } + } + } } else { mRunning = false; } + /* + * Main play loop. + */ while (mRunning) { - while (mPlaying) { + while (!mPaused) { + /* + * To prevent unwanted playback of prior audio track buffer + * data, only unpause the audio track after sufficient time has + * elapsed to permit the audio stream to flush the previous + * audio stream buffer if the audio track was flushed. Thus + * playback is resumed here where the audio track control timing + * is managed correctly. + */ + if (mRunning && !mPaused && mPausedWas) { + mPausedWas = false; + if (mFlushed) { + try { + sleep(200); + } catch (InterruptedException ie) { + /* + * This is expected behavior. + */ + } + } + mFlushed = false; + unPause(); + } + /* * Pre-load another packet. */ synchronized(sRDlock) { - if (mRunning && mPlaying && mLoad_ok) { + if (mRunning && !mPaused && mLoadOk) { ModPlug_JGetSoundData(mBuffer, BUFFERSIZE); if (ModPlug_CheckPatternChange()) { - pattern_change = true; + patternChange = true; } - CheckSongCompleted(); + checkSongCompleted(); } } @@ -599,21 +741,23 @@ public void run() { * Pass a packet of sound sample data to the audio track * (blocks until audio track can accept the new data). */ - mMytrack.write(mBuffer, 0, BUFFERSIZE); + if (mRunning && !mPaused) { + mMyTrack.write(mBuffer, 0, BUFFERSIZE); + } /* * Send player events. */ synchronized(this) { - if (!sPlayerStarted) { - sPlayerStarted = true; + if (!playerStarted) { + playerStarted = true; if (mPlayerListener != null) { mPlayerListener.onPlayerEvent(eventEnum.PLAYER_STARTED); } } - if (pattern_change) { - pattern_change = false; + if (patternChange) { + patternChange = false; if (mPlayerListener != null) { mPlayerListener.onPlayerEvent(eventEnum.PATTERN_CHANGE); } @@ -632,55 +776,28 @@ public void run() { * Wait until notify() is called. */ synchronized(this) { - if (mWaitFlag) { + if (mRunning && mPaused) { try { wait(); - - if (mFlushedData) { - sleep(20); - } - } catch (Exception e) { - e.getCause().printStackTrace(); + } catch (InterruptedException ie) { + /* + * This is expected behavior. + */ } } } - /* - * Clear flushed flag. - */ - mFlushedData = false; } + /* * Release the audio track resources. */ - if (mMytrack != null) + if (mMyTrack != null) { - mMytrack.release(); - mMytrack = null; + mMyTrack.release(); + mMyTrack = null; } } - /* - * MOD file info retrieval methods. - */ - - /** - * Get the name of the song. - * @return the name of the song (from the MOD/XM file header) - */ - public String getModName() { - return mModname; - } - - /** - * Get the number of channels used in the song (MOD/XM songs - * typically use from 4 to 32 channels in a pattern, mixed together - * for awesomeness). - * @return the number of channels the song uses - */ - public int getNumChannels() { - return mNumChannels; - } - /** * Set the file size of the MOD/XM song. */ @@ -688,67 +805,6 @@ public void setModSize(int modsize) { mModsize = modsize; } - /** - * Get the file size of the MOD/XM song. - * @return the size of the song file - */ - public int getModSize() { - return mModsize; - } - - public int getRate() { - return mRate; - } - - /** - * Pauses playback of the current song. - */ - public void PausePlay() { - mPlaying = false; - if (mMytrack != null) - { - /* - * This check is usually not needed before stop()ing the audio - * track, but seem to get an uninitialized audio track here - * occasionally, generating an IllegalStateException. - */ - if (mMytrack.getState() == AudioTrack.STATE_INITIALIZED) { - mMytrack.stop(); - } - mWaitFlag = true; - - synchronized(this) { - this.notify(); - } - } - } - - /** - * Resumes playback of the current song. - */ - public void UnPausePlay() { - if (mMytrack != null) - { - mMytrack.play(); - mPlaying = true; - mWaitFlag = false; - - synchronized(this) { - this.notify(); - } - } - } - - /** - * Flush the audio data still left in mMytrack. - */ - public void Flush() { - if (!mPlaying) { - mMytrack.flush(); - mFlushedData = true; - } - } - /** * Sets playback volume for the MOD/XM player. * @param vol - An integer from 0 (sound off) to 255 (full volume). @@ -757,7 +813,7 @@ public void setVolume(int vol) { vol = vol>>5; if (vol>7) vol = 7; if (vol<0) vol = 0; - mMytrack.setStereoVolume(sVolume_floats[vol], sVolume_floats[vol]); + mMyTrack.setStereoVolume(sVolume_floats[vol], sVolume_floats[vol]); } /** @@ -768,7 +824,7 @@ public void setVolume(int vol) { public void setVolume(float vol) { if (vol>1.0f) vol = 1.0f; if (vol<0) vol = 0; - mMytrack.setStereoVolume(vol, vol); + mMyTrack.setStereoVolume(vol, vol); } /** @@ -783,103 +839,93 @@ public void startPaused(boolean flag) { * Set before calling the thread's start() method. This will cause * it to start in paused mode. */ - mStart_paused = flag; + startPaused = flag; } /** - * This completely stops the thread, which will also stop the current - * song if it is playing. + * This stops the current song if it is playing, and stops the thread. *

Typically the player should then be join()ed to * completely remove the thread from the application's Android - * process, and also call CloseLIBMODPLUG() to close + * process, and also call closeLibModPlug() to close * the native player library and de-allocate all resources it used. */ - public void StopThread() { + public void stopThread() { /* * Stops the music player thread (see run() above). */ - mPlaying = false; mRunning = false; + pausePlay(true); + /* - * This check is usually not needed before stop()ing the audio - * track, but seem to get an uninitialized audio track here - * occasionally, generating an IllegalStateException. + * Interrupt the thread if it is sleeping or waiting. */ - if (mMytrack != null) try { - if (mMytrack.getState() == AudioTrack.STATE_INITIALIZED) { - mMytrack.stop(); - } - } catch (NullPointerException npe) { - npe.printStackTrace(); - } - catch (IllegalStateException ise) { - ise.printStackTrace(); - } - - mPlayerValid = false; - mWaitFlag = false; - synchronized(this) { - this.notify(); + this.interrupt(); } } /** - * Close the native internal tracker library (libmodplug) and - * deallocate any resources. + * Unload the current MOD from libmodplug, but make sure to wait + * until any GetSoundData() call in the player thread has + * finished.

Unload MOD/XM data previously loaded into the native + * player library. */ - public void CloseLIBMODPLUG() { - ModPlug_JUnload(); - ModPlug_CloseDown(); + public void unLoadMod() { /* - * Release the audio track resources. + * Since this can/will be called from the UI thread, need to synch + * and not have a call into libmodplug unloading the file, while a + * call to GetModData() is also executing in the player thread (see + * run() above). */ - if (mMytrack != null) - { - mMytrack.release(); - mMytrack = null; + synchronized(sRDlock) { + mLoadOk = false; + ModPlug_JUnload(); } } /** - * EXPERIMENTAL method for modifying the song's tempo (+ or -) by - * mt. - * @param mt - Modifier for the song's "native" tempo (positive values - * to increase tempo, negative values to decrease tempo). - */ - public void modifyTempo(int mt) { - ModPlug_ChangeTempo(mt); - } - /** - * EXPERIMENTAL method for setting the song's tempo to - * tempo. - * @param tempo - The tempo for the song (overrides song's "native" - * tempo). - */ - public void setTempo(int tempo) { - ModPlug_SetTempo(tempo); - } - /** - * EXPERIMENTAL: Get the default tempo from the song's header. - * @return the tempo. + * Resumes playback of the current song. + * @return true if the song was successfully unpaused. */ - public int getSongDefaultTempo() { - return ModPlug_GetNativeTempo(); + private boolean unPause() { + boolean unPaused = false; + if (mMyTrack != null) + { + try { + mMyTrack.play(); + unPaused = true; + } catch (IllegalStateException ise) { + /* + * This is a spurious exception, with the only drawback being + * that audio will remain stopped. Nothing to do here but + * continue gracefully and wait for the next attempt. + */ + } + } + return unPaused; } + /** - * EXPERIMENTAL: Get the current "position" in song - * @return the position. + * Resumes playback of the current song. */ - public int getCurrentPos() { - return ModPlug_GetCurrentPos(); + public void unPausePlay() { + mPaused = false; + + synchronized(this) { + this.notify(); + } } + /** - * EXPERIMENTAL: Get the maximum "position" in song - * @return the maximum position. + * EXPERIMENTAL: Change patterns in a song (playing in PATTERN LOOP + * mode). Waits for the currently playing pattern to finish. + * @param newpattern - The new song pattern to start playing + * (repeating) in PATTERN LOOP mode. */ - public int getMaxPos() { - return ModPlug_GetMaxPos(); + public void changePattern(int newpattern) { + ModPlug_ChangePattern(newpattern); } + /** * EXPERIMENTAL: Get the current order * @return the order. @@ -887,6 +933,7 @@ public int getMaxPos() { public int getCurrentOrder() { return ModPlug_GetCurrentOrder(); } + /** * EXPERIMENTAL: Get the current pattern * @return the pattern. @@ -894,23 +941,15 @@ public int getCurrentOrder() { public int getCurrentPattern() { return ModPlug_GetCurrentPattern(); } + /** - * EXPERIMENTAL: set the current pattern (pattern is changed but - * plays from current row in pattern). - * @param pattern - The new pattern to start playing immediately. - */ - public void setCurrentPattern(int pattern) { - ModPlug_SetCurrentPattern(pattern); - } - /** - * EXPERIMENTAL: set the next pattern to play after current pattern - * finishes. - * @param pattern - The new pattern to start playing after the current - * pattern finishes playing. + * EXPERIMENTAL: Get the current "position" in song + * @return the position. */ - public void setNextPattern(int pattern) { - ModPlug_SetNextPattern(pattern); + public int getCurrentPos() { + return ModPlug_GetCurrentPos(); } + /** * EXPERIMENTAL: Get the current row in the pattern * @return the row. @@ -918,44 +957,60 @@ public void setNextPattern(int pattern) { public int getCurrentRow() { return ModPlug_GetCurrentRow(); } + /** - * EXPERIMENTAL: Set log printing flag - * @param flag - true to start printing debug information - * to log output, false to stop. + * EXPERIMENTAL: Get the maximum "position" in song + * @return the maximum position. */ - public void setLogOutput(boolean flag) { - ModPlug_LogOutput(flag); + public int getMaxPos() { + return ModPlug_GetMaxPos(); } + /** - * EXPERIMENTAL method to change patterns in a song (playing in - * PATTERN LOOP mode). Waits for the currently playing pattern to - * finish. - * @param newpattern - The new song pattern to start playing - * (repeating) in PATTERN LOOP mode. + * EXPERIMENTAL: Get the default tempo from the song's header. + * @return the tempo. */ - public void changePattern(int newpattern) { - ModPlug_ChangePattern(newpattern); + public int getSongDefaultTempo() { + return ModPlug_GetNativeTempo(); } + + /** + * EXPERIMENTAL: Modify the song's tempo (+ or -) by mt. + * @param mt - Modifier for the song's "native" tempo (positive values + * to increase tempo, negative values to decrease tempo). + */ + public void modifyTempo(int mt) { + ModPlug_ChangeTempo(mt); + } + /** - * EXPERIMENTAL method to change song to PATTERN LOOP mode, repeating - * pattern + * EXPERIMENTAL: Change song to PATTERN LOOP mode, repeating + * pattern. * @param pattern - The song pattern to start playing(repeating) in * PATTERN LOOP mode. */ public void repeatPattern(int pattern) { ModPlug_RepeatPattern(pattern); } + /** - * EXPERIMENTAL method to loop song in a group of patterns. - * @param from - Start of pattern range to play in loop. - * @param to - End of pattern range to play in loop. - * @param when - A constant flag (PATTERN_CHANGE_IMMEDIATE, - * PATTERN_CHANGE_AFTER_CURRENT, PATTERN_CHANGE_AFTER_GROUP) to signal - * when the new pattern range should take effect. + * EXPERIMENTAL: set the current pattern (pattern is changed but + * plays from current row in pattern). + * @param pattern - The new pattern to start playing immediately. */ - public void setPatternLoopRange(int from, int to, int when) { - ModPlug_SetPatternLoopRange(from, to, when); + public void setCurrentPattern(int pattern) { + ModPlug_SetCurrentPattern(pattern); } + + /** + * EXPERIMENTAL: Set log printing flag. + * @param flag - true to start printing debug information + * to log output, false to stop. + */ + public void setLogOutput(boolean flag) { + ModPlug_LogOutput(flag); + } + /** * EXPERIMENTAL method to loop song the specified number of times. * @param number - The number of times to loop (-1 = forever). @@ -963,6 +1018,17 @@ public void setPatternLoopRange(int from, int to, int when) { public void setLoopCount(int loopcount) { ModPlug_SetLoopCount(loopcount); } + + /** + * EXPERIMENTAL: set the next pattern to play after current pattern + * finishes. + * @param pattern - The new pattern to start playing after the current + * pattern finishes playing. + */ + public void setNextPattern(int pattern) { + ModPlug_SetNextPattern(pattern); + } + /** * EXPERIMENTAL method to set song to PATTERN LOOP mode, repeating * any pattern playing or subsequently set via @@ -973,79 +1039,65 @@ public void setLoopCount(int loopcount) { public void setPatternLoopMode(boolean flag) { ModPlug_SetPatternLoopMode(flag); } + /** - * Unload the current mod from libmodplug, but make sure to wait - * until any GetSoundData() call in the player thread has finished. - *

Unload MOD/XM data previously loaded into the native player - * library. + * EXPERIMENTAL method to loop song in a group of patterns. + * @param from - Start of pattern range to play in loop. + * @param to - End of pattern range to play in loop. + * @param when - A constant flag (PATTERN_CHANGE_IMMEDIATE, + * PATTERN_CHANGE_AFTER_CURRENT, PATTERN_CHANGE_AFTER_GROUP) to signal + * when the new pattern range should take effect. */ - public void UnLoadMod() { - /* - * Since this can/will be called from the UI thread, need to synch - * and not have a call into libmodplug unloading the file, while a - * call to GetModData() is also executing in the player thread (see - * run() above). - */ - synchronized(sRDlock) { - mLoad_ok = false; - ModPlug_JUnload(); - } + public void setPatternLoopRange(int from, int to, int when) { + ModPlug_SetPatternLoopRange(from, to, when); + } + + /** + * EXPERIMENTAL: Set the song's tempo to tempo. + * @param tempo - The tempo for the song (overrides song's "native" + * tempo). + */ + public void setTempo(int tempo) { + ModPlug_SetTempo(tempo); } /* * Native methods in our JNI libmodplug stub code. */ + public native boolean ModPlug_CloseDown(); public native boolean ModPlug_Init(int rate); + public native String ModPlug_JGetName(); + public native int ModPlug_JGetSoundData(short[] sndbuffer, int datasize); public native boolean ModPlug_JLoad(byte[] buffer, int size); - public native String ModPlug_JGetName(); - public native int ModPlug_JNumChannels(); - public native int ModPlug_JGetSoundData(short[] sndbuffer, int datasize); + public native int ModPlug_JNumChannels(); public native boolean ModPlug_JUnload(); - public native boolean ModPlug_CloseDown(); /* * HACKS ;-). */ - public native int ModPlug_GetNativeTempo(); - public native void ModPlug_ChangeTempo(int tempotweak); - public native void ModPlug_SetTempo(int tempo); + public native void ModPlug_ChangeTempo(int tempotweak); public native void ModPlug_ChangePattern(int newpattern); public native void ModPlug_RepeatPattern(int pattern); - public native boolean ModPlug_CheckPatternChange(); - public native void ModPlug_SetPatternLoopMode(boolean flag); public native void ModPlug_SetCurrentPattern(int pattern); + public native void ModPlug_SetLoopCount(int loopcount); public native void ModPlug_SetNextPattern(int pattern); + public native void ModPlug_SetPatternLoopMode(boolean flag); public native void ModPlug_SetPatternLoopRange(int from, int to, int when); - public native void ModPlug_SetLoopCount(int loopcount); + public native void ModPlug_SetTempo(int tempo); /* * More info. */ - public native int ModPlug_GetCurrentPos(); - public native int ModPlug_GetMaxPos(); - public native int ModPlug_GetCurrentOrder(); - public native int ModPlug_GetCurrentPattern(); - public native int ModPlug_GetCurrentRow(); + public native boolean ModPlug_CheckPatternChange(); + public native int ModPlug_GetCurrentOrder(); + public native int ModPlug_GetCurrentPattern(); + public native int ModPlug_GetCurrentPos(); + public native int ModPlug_GetCurrentRow(); + public native int ModPlug_GetMaxPos(); + public native int ModPlug_GetNativeTempo(); /* * Log output. */ public native void ModPlug_LogOutput(boolean flag); - - static { - try { - System.loadLibrary("modplug-"+VERS); - //System.loadLibrary("modplug"); - } catch (UnsatisfiedLinkError ule) { - Log.e(LOGPREFIX, "WARNING: Could not load libmodplug-"+VERS+".so"); - Log.e(LOGPREFIX, "------ older or differently named libmodplug???"); - } - - /* - * Get lock objects for synchronizing access to playervalid flag and - * GetSoundData() call. - */ - sPVlock = new Object(); - sRDlock = new Object(); - } } diff --git a/src/org/gsanson/frozenbubble/CollisionHelper.java b/src/org/gsanson/frozenbubble/CollisionHelper.java index f806d06..6bf91dc 100644 --- a/src/org/gsanson/frozenbubble/CollisionHelper.java +++ b/src/org/gsanson/frozenbubble/CollisionHelper.java @@ -53,36 +53,42 @@ package org.gsanson.frozenbubble; import org.jfedor.frozenbubble.BubbleSprite; +import org.jfedor.frozenbubble.LevelManager; public class CollisionHelper { private static final int STATE_INTERMEDIATE_CHECK = -2; - private static final int STATE_CHECK_NEXT = -1; + private static final int STATE_CHECK_NEXT = -1; - public static final int STATE_UNDEFINED = 0; - public static final int STATE_POTENTIAL_REMOVE = 1; - public static final int STATE_REMOVE = 2; - public static final int STATE_ATTACHED = 3; + public static final int STATE_UNDEFINED = 0; + public static final int STATE_POTENTIAL_REMOVE = 1; + public static final int STATE_REMOVE = 2; + public static final int STATE_ATTACHED = 3; public static final int STATE_POTENTIAL_DETACHED = 4; - public static final int STATE_DETACHED = 5; + public static final int STATE_DETACHED = 5; - private CollisionHelper() {} + private CollisionHelper() { + } /** - * Checks whether a moving ball collides with fixed balls - * @param x X-coord of the moving ball, relative to the game area - * @param y Y-coord of the moving ball, relative to the game area (right under the compressor) - * @param grid The grid of fixed balls - * @return the position in the grid of the moving ball or null if no collision occurs + * Checks whether a moving ball collides with fixed balls. + * @param x X-coord of the moving ball, relative to the game area. + * @param y Y-coord of the moving ball, relative to the game area + * (right under the compressor). + * @param grid The grid of fixed bubbles. + * @param toCheck The array of bubbles to check. + * @param minCoords The collision distance coordinates. + * @return true if a collision was detected. */ - public static int[] collide(int x, int y, BubbleSprite[][] grid) { - + public static boolean collide(int x, int y, BubbleSprite[][] grid, + int[][] toCheck, int[] minCoords) { + boolean collision = false; int minDist = (int)BubbleSprite.minDistance; - int[] minCoords = null; - int[][] toCheck = toCheck(x, y); + minCoords[0] = 0; + minCoords[1] = 0; + toCheck(x, y, toCheck); // Check for collision - boolean collision = false; int i = 0; while (!collision && i < 4) { collision = collision(x, y, toCheck[i][0], toCheck[i][1], grid); @@ -91,30 +97,32 @@ public static int[] collide(int x, int y, BubbleSprite[][] grid) { // Check for position if (collision) { - minCoords = new int[2]; - for (i = 0; i < 4; i++) { minDist = distance(x, y, toCheck[i][0], toCheck[i][1], minDist, minCoords); } } - return minCoords; + return collision; } /** - * Calculates the distance between real position and a specific point in the grid - * @param x real X-coord - * @param y real Y-coord - * @param targetX X target point (grid) - * @param targetY Y target point (grid) - * @param minDist current minimum distance - * @param outCoords the coordinates associated with the minimum distance found - * @return The real distance or the current minDist if the point is out of the grid or empty + * Calculates the distance between real position and a specific point + * in the grid. + * @param x real X-coord. + * @param y real Y-coord. + * @param targetX X target point (grid). + * @param targetY Y target point (grid). + * @param minDist current minimum distance. + * @param outCoords the coordinates associated with the minimum distance found. + * @return The real distance or the current minDist if the point is + * out of the grid or empty. */ - private static int distance(int x, int y, int targetX, int targetY, int minDist, int[] outCoords) { + private static int distance(int x, int y, int targetX, int targetY, + int minDist, int[] outCoords) { int distance = minDist; - if (targetX >= 0 && targetX < 8 && targetY >= 0 && targetY < 13) { + if ((targetX >= 0) && (targetX < LevelManager.NUM_COLS) && + (targetY >= 0) && (targetY < LevelManager.NUM_ROWS)) { int dx = (targetX << 5) - ((targetY % 2) << 4) - x; int dy = targetY * 28 - y; @@ -131,18 +139,23 @@ private static int distance(int x, int y, int targetX, int targetY, int minDist, } /** - * Calculates the distance between real position and a specific point in the grid - * @param x real X-coord - * @param y real Y-coord - * @param targetX X target point (grid) - * @param targetY Y target point (grid) - * @param grid reference grid - * @return The real distance or the current minDist if the point is out of the grid or empty + * Calculates the distance between real position and a specific point + * in the grid. + * @param x real X-coord. + * @param y real Y-coord. + * @param targetX X target point (grid). + * @param targetY Y target point (grid). + * @param grid reference grid. + * @return The real distance or the current minDist if the point is + * out of the grid or empty. */ - private static boolean collision(int x, int y, int targetX, int targetY, BubbleSprite[][] grid) { + private static boolean collision(int x, int y, int targetX, int targetY, + BubbleSprite[][] grid) { boolean collision = false; - if (targetX >= 0 && targetX < 8 && targetY >= 0 && targetY < 13 && grid[targetX][targetY] != null) { + if ((targetX >= 0) && (targetX < LevelManager.NUM_COLS) && + (targetY >= 0) && (targetY < LevelManager.NUM_ROWS) && + grid[targetX][targetY] != null) { int dx = (targetX << 5) - ((targetY % 2) << 4) - x; int dy = targetY * 28 - y; @@ -153,14 +166,12 @@ private static boolean collision(int x, int y, int targetX, int targetY, BubbleS } /** - * Retrieves the set of position in the grid that are currently under the moving ball - * @param x real X-coord - * @param y real Y-coord - * @return + * Retrieves the set of positions in the grid that are currently under + * the moving ball. + * @param x real X-coord. + * @param y real Y-coord. */ - private static int[][] toCheck(int x, int y) { - int[][] toCheck = new int[4][2]; - + private static void toCheck(int x, int y, int[][] toCheck) { int topY = y / 28; int topX = (x + ((topY % 2) << 4)) >> 5; @@ -170,43 +181,45 @@ private static int[][] toCheck(int x, int y) { toCheck[1][1] = topY; toCheck[2][0] = topX + 1 - (topY % 2); toCheck[2][1] = topY + 1; - - toCheck[3][1] = topY + 1; + toCheck[3][1] = topY + 1; if (((x & 16) ^ (((topY & 1) << 4))) == 0) { toCheck[3][0] = topX - (topY % 2); } else { toCheck[3][0] = topX + 2 - (topY % 2); } - - return toCheck; } /** - * Check state of all bubbles - * @param x X-coord of the new bubble - * @param y Y-Coord of the new bubble - * @param color Color of new new bubble - * @param grid Grid of all known bubbles - * @return A grid with all the new states. If the new bubble doesn't change anything, values are only potential + * Check states of all bubbles. + * @param x X-coord of the new bubble. + * @param y Y-Coord of the new bubble. + * @param color Color of new new bubble. + * @param grid Grid of all known bubbles. + * @param outGrid Grid to store all the new states in. If the new + * bubble doesn't change anything, values are only potential. */ - public static int[][] checkState(int x, int y, int color, BubbleSprite[][] grid) { - int[][] outGrid = new int[8][13]; + public static void checkState(int x, int y, int color, BubbleSprite[][] grid, + int[][] outGrid) { + for (int i = 0; i < LevelManager.NUM_COLS; i++) { + for (int j = 0; j < LevelManager.NUM_ROWS; j++) { + outGrid[i][j] = STATE_UNDEFINED; + } + } + outGrid[x][y] = STATE_REMOVE; checkNeighbors(x, y, grid, outGrid, false); int nbRemove = 1; - boolean changed = true; while (changed) { changed = false; - for (int i = 0; i < 8; i++) { - for (int j = 0; j < 13; j++) { + for (int i = 0; i < LevelManager.NUM_COLS; i++) { + for (int j = 0; j < LevelManager.NUM_ROWS; j++) { if (outGrid[i][j] == STATE_CHECK_NEXT) { if (isColor(i, j, color, grid, null)) { outGrid[i][j] = STATE_REMOVE; nbRemove++; changed = true; - checkNeighbors(i, j, grid, outGrid, false); } else { outGrid[i][j] = STATE_INTERMEDIATE_CHECK; @@ -217,8 +230,9 @@ public static int[][] checkState(int x, int y, int color, BubbleSprite[][] grid) } // Check for positions that are (potentially) not attached anymore - for (int i = 0; i < 8; i++) { - if (grid[i][0] != null && (outGrid[i][0] == STATE_UNDEFINED || outGrid[i][0] == STATE_INTERMEDIATE_CHECK)) { + for (int i = 0; i < LevelManager.NUM_COLS; i++) { + if (grid[i][0] != null && (outGrid[i][0] == STATE_UNDEFINED || + outGrid[i][0] == STATE_INTERMEDIATE_CHECK)) { outGrid[i][0] = STATE_CHECK_NEXT; } } @@ -227,21 +241,22 @@ public static int[][] checkState(int x, int y, int color, BubbleSprite[][] grid) while (changed) { changed = false; - for (int i = 0; i < 8; i++) { - for (int j = 0; j < 13; j++) { + for (int i = 0; i < LevelManager.NUM_COLS; i++) { + for (int j = 0; j < LevelManager.NUM_ROWS; j++) { if (outGrid[i][j] == STATE_CHECK_NEXT) { outGrid[i][j] = STATE_ATTACHED; changed = true; - checkNeighbors(i, j, grid, outGrid, true); } } } } - for (int i = 0; i < 8; i++) { - for (int j = 0; j < 13; j++) { - if (grid[i][j] != null && (outGrid[i][j] == STATE_UNDEFINED || outGrid[i][j] == STATE_INTERMEDIATE_CHECK)) { + for (int i = 0; i < LevelManager.NUM_COLS; i++) { + for (int j = 0; j < LevelManager.NUM_ROWS; j++) { + if ((grid[i][j] != null) && + ((outGrid[i][j] == STATE_UNDEFINED) || + (outGrid[i][j] == STATE_INTERMEDIATE_CHECK))) { if (nbRemove >= 3) { outGrid[i][j] = STATE_DETACHED; } else { @@ -249,29 +264,28 @@ public static int[][] checkState(int x, int y, int color, BubbleSprite[][] grid) } } - if (outGrid[i][j] == STATE_REMOVE && nbRemove < 3) { + if (outGrid[i][j] == STATE_REMOVE && (nbRemove < 3)) { outGrid[i][j] = STATE_POTENTIAL_REMOVE; } } } - - return outGrid; } - private static void checkNeighbors(int x, int y, BubbleSprite[][] grid, int[][] outGrid, boolean ignoreStayState) { + private static void checkNeighbors(int x, int y, BubbleSprite[][] grid, + int[][] outGrid, boolean ignoreStayState) { if (x > 0) { changeState(x-1, y, grid, outGrid, ignoreStayState); } - if (x < 7) { + if (x < (LevelManager.NUM_COLS - 1)) { changeState(x+1, y, grid, outGrid, ignoreStayState); } if (y > 0) { changeState(x, y-1, grid, outGrid, ignoreStayState); if (y % 2 == 0) { - if (x < 7) { + if (x < (LevelManager.NUM_COLS - 1)) { changeState(x+1, y-1, grid, outGrid, ignoreStayState); } } @@ -282,10 +296,10 @@ private static void checkNeighbors(int x, int y, BubbleSprite[][] grid, int[][] } } - if (y < 11) { + if (y < (LevelManager.NUM_ROWS - 2)) { changeState(x, y+1, grid, outGrid, ignoreStayState); if (y % 2 == 0) { - if (x < 7) { + if (x < (LevelManager.NUM_COLS - 1)) { changeState(x+1, y+1, grid, outGrid, ignoreStayState); } } @@ -297,67 +311,18 @@ private static void checkNeighbors(int x, int y, BubbleSprite[][] grid, int[][] } } - private static void changeState(int x, int y, BubbleSprite[][] grid, int[][] outGrid, boolean ignoreStayState) { + private static void changeState(int x, int y, BubbleSprite[][] grid, + int[][] outGrid, boolean ignoreStayState) { if (ignoreStayState) { - if (grid[x][y] != null && (outGrid[x][y] == STATE_UNDEFINED || outGrid[x][y] == STATE_INTERMEDIATE_CHECK)) { + if (grid[x][y] != null && (outGrid[x][y] == STATE_UNDEFINED || + outGrid[x][y] == STATE_INTERMEDIATE_CHECK)) { outGrid[x][y] = STATE_CHECK_NEXT; } } else { if (grid[x][y] != null && outGrid[x][y] == STATE_UNDEFINED) { outGrid[x][y] = STATE_CHECK_NEXT; - } - } - } - - /** - * Check if a bubble falling at a given position has a neighbor of the same color - * @param x grid X-Coord of the bubble - * @param y grid Y-Coord of the bubble - * @param color Color of the bubble - * @param grid Grid of all known bubbles - * @param alreadyChecked Balls alread reviewed (may be null) - * @return - */ - private static boolean hasNeighbor(int x, int y, int color, BubbleSprite[][] grid, boolean[][] alreadyChecked) { - boolean neighbor = false; - - if (x > 0) { - neighbor |= isColor(x-1, y, color, grid, alreadyChecked); - } - - if (x < 7) { - neighbor |= isColor(x+1, y, color, grid, alreadyChecked); - } - - if (y > 0) { - neighbor |= isColor(x, y-1, color, grid, alreadyChecked); - if (y % 2 == 0) { - if (x < 7) { - neighbor |= isColor(x+1, y-1, color, grid, alreadyChecked); - } - } - else { - if (x > 0) { - neighbor |= isColor(x-1, y-1, color, grid, alreadyChecked); - } - } - } - - if (y < 11) { - neighbor |= isColor(x, y+1, color, grid, alreadyChecked); - if (y % 2 == 0) { - if (x < 7) { - neighbor |= isColor(x+1, y+1, color, grid, alreadyChecked); - } - } - else { - if (x > 0) { - neighbor |= isColor(x-1, y+1, color, grid, alreadyChecked); - } } } - - return neighbor; } /** @@ -369,69 +334,28 @@ private static boolean hasNeighbor(int x, int y, int color, BubbleSprite[][] gri * @param alreadyChecked * @return */ - private static boolean isColor(int x, int y, int color, BubbleSprite[][] grid, boolean[][] alreadyChecked) { + private static boolean isColor(int x, int y, int color, + BubbleSprite[][] grid, + boolean[][] alreadyChecked) { boolean isColor = false; + boolean checked = false; - if (grid[x][y] != null && grid[x][y].getColor() == color && (alreadyChecked == null || !alreadyChecked[x][y])) { - isColor = true; - if (alreadyChecked != null) { - alreadyChecked[x][y] = true; - } + if (alreadyChecked != null) { + checked = alreadyChecked[x][y]; } - return isColor; - } - - // TODO : A remplacer par une version prenant toutes les boules d'un coup??? - // XXX utiliser hasNeighbor - - /** - * @param grid - * @return {x, y, points} or null if no position is available - */ - public static int[] chainReaction(int color, BubbleSprite[][] grid) { - - int bestX = 0; - int bestY = 0; - int bestCount = 0; - - int[] output = null; - boolean[][] alreadyChecked = new boolean[8][13]; - - for (int j = 0; j < 13; j++) { - for (int i = 0; i < 8; i++) { - if (grid[i][j] == null && (i != 0 || (j & 1) == 0)) { - if (hasNeighbor(i, j, color, grid, alreadyChecked)) { - - // Check grid - int newCount = 0; - int[][] cGrid = checkState(i, j, color, grid); - - if (cGrid != null) { - for (int cj = 0; cj < 13; cj++) { - for (int ci = 0; ci < 8; ci++) { - if (cGrid[ci][cj] == STATE_REMOVE || cGrid[ci][cj] == STATE_DETACHED) { - newCount++; - alreadyChecked[ci][cj] = true; - } - } - } - - if (newCount > bestCount) { - bestX = i; - bestY = j; - bestCount = newCount; - } - } + if (grid != null) { + if (grid[x][y] != null) { + if ((grid[x][y].getColor() == color) && + ((alreadyChecked == null) || !checked)) { + isColor = true; + if (alreadyChecked != null) { + alreadyChecked[x][y] = true; } } } } - if (bestCount > 0) { - output = new int[] {bestX, bestY, bestCount}; - } - - return output; + return isColor; } } diff --git a/src/org/gsanson/frozenbubble/Freile.java b/src/org/gsanson/frozenbubble/Freile.java index 5b175ee..d0e53a0 100644 --- a/src/org/gsanson/frozenbubble/Freile.java +++ b/src/org/gsanson/frozenbubble/Freile.java @@ -53,18 +53,19 @@ package org.gsanson.frozenbubble; import org.jfedor.frozenbubble.BubbleSprite; +import org.jfedor.frozenbubble.LevelManager; import android.view.KeyEvent; public class Freile implements Opponent, Runnable { - /** Rotation of the launcher */ + /* Rotation of the launcher */ public static final double LAUNCHER_ROTATION = 0.05; - /** Minimum angle for launcher */ + /* Minimum angle for launcher */ public static final double MIN_LAUNCHER = -Math.PI / 2. + 0.12; - /** Maximum angle for launcher */ + /* Maximum angle for launcher */ public static final double MAX_LAUNCHER = Math.PI / 2. - 0.12; - /** Ball speed */ + /* Ball speed */ public static final double MOVE_SPEED = 3.; private static final int BONUS_POTENTIAL_DETACHED = 2; @@ -72,7 +73,7 @@ public class Freile implements Opponent, Runnable { private static final int BONUS_SAME_COLOR = 4; private static final int BONUS_DETACHED = 6; - /** Default option value */ + /* Default option values */ private static final int[][] BACKGROUND_GRID = {{0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, @@ -124,31 +125,66 @@ public void setOpponentListener (OpponentListener ol) { /* Thread running flag */ private boolean running; /* Best direction */ - private double bestDirection; - /* Best ball destination */ - private int[] bestDestination; + private double bestDirection; + /* Best location */ + private int[] bestLocation = {0, 0}; + /* Grid to compute best options */ + private int[][] gridOptions; + /* Grid to compute bubble states */ + private int[][] outGrid; + /* Neighbor bubble locations to check for collision */ + private int[][] toCheck = {{0, 0}, {0, 0}, {0, 0}, {0, 0}}; public Freile(BubbleSprite[][] grid) { - this.grid = grid; + this.grid = grid; + gridOptions = new int[LevelManager.NUM_COLS][LevelManager.NUM_ROWS]; + outGrid = new int[LevelManager.NUM_COLS][LevelManager.NUM_ROWS]; mOpponentListener = null; - running = true; + running = true; new Thread(this).start(); } - /** - * Checks if work is still in progress. - * @return true if the calculation is not yet finished - */ - public boolean isComputing() { - return computing; + public void compute(int currentColor, int nextColor, int compressor) { + this.color = currentColor; + this.nextColor = nextColor; + this.compressor = compressor; + computing = true; + + synchronized (this) { + notify(); + } } - public double getExactDirection(double currentDirection) { - /* - * currentDirection is not used here. - */ - return bestDirection; + private int computeOption(int posX, int posY, int color, + int[][] gridOptions, int[][] outGrid) { + if (gridOptions[posX][posY] == 0) { + int option = BACKGROUND_GRID[posX][posY]; + + CollisionHelper.checkState(posX, posY, color, grid, outGrid); + for (int i = 0; i < LevelManager.NUM_COLS; i++) { + for (int j = 0; j < (LevelManager.NUM_ROWS - 1); j++) { + if (i != posX || j != posY) { + switch (outGrid[i][j]) { + case CollisionHelper.STATE_REMOVE: + option += BONUS_SAME_COLOR; + break; + case CollisionHelper.STATE_POTENTIAL_REMOVE: + option += BONUS_POTENTIAL_SAME_COLOR; + break; + case CollisionHelper.STATE_DETACHED: + option += BONUS_DETACHED; + break; + case CollisionHelper.STATE_POTENTIAL_DETACHED: + option += BONUS_POTENTIAL_DETACHED; + break; + } + } + } + } + gridOptions[posX][posY] = option; + } + return gridOptions[posX][posY]; } public int getAction(double currentDirection) { @@ -176,31 +212,79 @@ else if (Math.abs(currentDirection - bestDirection) < 0.04) { direction = KeyEvent.KEYCODE_DPAD_LEFT; } } - return direction; } - public void compute(int currentColor, int nextColor, int compressor) { - this.color = currentColor; - this.nextColor = nextColor; - this.compressor = compressor; - computing = true; + public int[] getBubbleDestination() { + return bestLocation; + } - synchronized (this) { - notify(); + private boolean getCollision(double direction, int[] position) { + boolean collision = false; + double posX = 112.; + double posY = 350. - compressor * 28.; + double speedX = MOVE_SPEED * Math.cos(direction - Math.PI / 2.); + double speedY = MOVE_SPEED * Math.sin(direction - Math.PI / 2.); + + while (!collision) { + posX += speedX; + posY += speedY; + + if (posX < 0.) { + posX = - posX; + speedX = -speedX; + } else if (posX > 224.) { + posX = 448. - posX; + speedX = -speedX; + } + + /* + * Check top collision. + */ + if (posY < 0.) { + int valX = (int) posX; + + collision = true; + position[0] = valX >> 5; + + if ((valX & 16) > 0) { + position[0]++; + } + + position[1] = 0; + } else { + /* + * Check other collision. + */ + collision = CollisionHelper.collide((int) posX, (int) posY, + grid, toCheck, position); + } } + return collision; } - public int[] getBallDestination() { - return bestDestination; + public double getExactDirection(double currentDirection) { + /* + * currentDirection is not used here. + */ + return bestDirection; + } + + /** + * Checks if work is still in progress. + * @return true if the calculation is not yet finished + */ + public boolean isComputing() { + return computing; } public void run() { while (running) { if (computing) { computing = false; - if (mOpponentListener != null) + if (mOpponentListener != null) { mOpponentListener.onOpponentEvent(eventEnum.DONE_COMPUTING); + } } while (running && !computing) { @@ -216,164 +300,98 @@ public void run() { if (running) { /* - * Compute grid options. + * Initialize grid options. */ - int[][] gridOptions = new int[8][13]; - + for (int i = 0; i < LevelManager.NUM_COLS; i++) { + for (int j = 0; j < LevelManager.NUM_ROWS; j++) { + gridOptions[i][j] = 0; + } + } + /* * Check for best option. */ int bestOption = -1; - bestDirection = 0.; - colorSwap = false; - int newOption; - int[] position = null; + int[] position = {0, 0}; + + bestDirection = 0.; + bestLocation[0] = 0; + bestLocation[1] = 0; + colorSwap = false; for (double direction = 0.; direction < MAX_LAUNCHER; direction += LAUNCHER_ROTATION) { - position = getCollision(direction); + getCollision(direction, position); newOption = computeOption(position[0], position[1], - color, gridOptions); + color, gridOptions, outGrid); if (newOption > bestOption) { - bestOption = newOption; - bestDirection = direction; - bestDestination = position; + bestOption = newOption; + bestDirection = direction; + bestLocation[0] = position[0]; + bestLocation[1] = position[1]; } } for (double direction = -LAUNCHER_ROTATION; direction > MIN_LAUNCHER; direction -= LAUNCHER_ROTATION) { - position = getCollision(direction); + getCollision(direction, position); newOption = computeOption(position[0], position[1], - color, gridOptions); + color, gridOptions, outGrid); if (newOption > bestOption) { - bestOption = newOption; - bestDirection = direction; - bestDestination = position; + bestOption = newOption; + bestDirection = direction; + bestLocation[0] = position[0]; + bestLocation[1] = position[1]; } } if (color != nextColor) { for (double direction = 0.; direction < MAX_LAUNCHER; direction += LAUNCHER_ROTATION) { - position = getCollision(direction); + getCollision(direction, position); newOption = computeOption(position[0], position[1], - nextColor, gridOptions); + nextColor, gridOptions, outGrid); if (newOption > bestOption) { - bestOption = newOption; - bestDirection = direction; - bestDestination = position; - colorSwap = true; + bestOption = newOption; + bestDirection = direction; + bestLocation[0] = position[0]; + bestLocation[1] = position[1]; + colorSwap = true; } } for (double direction = -LAUNCHER_ROTATION; direction > MIN_LAUNCHER; direction -= LAUNCHER_ROTATION) { - position = getCollision(direction); + getCollision(direction, position); newOption = computeOption(position[0], position[1], - nextColor, gridOptions); + nextColor, gridOptions, outGrid); if (newOption > bestOption) { - bestOption = newOption; - bestDirection = direction; - bestDestination = position; - colorSwap = true; + bestOption = newOption; + bestDirection = direction; + bestLocation[0] = position[0]; + bestLocation[1] = position[1]; + colorSwap = true; } } } } } - } - - private int computeOption(int posX, int posY, int color, int[][] gridOptions) { - - if (gridOptions[posX][posY] == 0) { - int option = BACKGROUND_GRID[posX][posY]; - - int[][] states = CollisionHelper.checkState(posX, posY, color, grid); - for (int i = 0; i < 8; i++) { - for (int j = 0; j < 12; j++) { - if (i != posX || j != posY) { - switch (states[i][j]) { - case CollisionHelper.STATE_REMOVE: - option += BONUS_SAME_COLOR; - break; - case CollisionHelper.STATE_POTENTIAL_REMOVE: - option += BONUS_POTENTIAL_SAME_COLOR; - break; - case CollisionHelper.STATE_DETACHED: - option += BONUS_DETACHED; - break; - case CollisionHelper.STATE_POTENTIAL_DETACHED: - option += BONUS_POTENTIAL_DETACHED; - break; - } - } - } - } - - gridOptions[posX][posY] = option; - } - - return gridOptions[posX][posY]; - } - - private int[] getCollision(double direction) { - - int[] position = null; - - double speedX = MOVE_SPEED * Math.cos(direction - Math.PI / 2.); - double speedY = MOVE_SPEED * Math.sin(direction - Math.PI / 2.); - - double posX = 112.; - double posY = 350. - compressor * 28.; - - while (position == null) { - posX += speedX; - posY += speedY; - - if (posX < 0.) { - posX = - posX; - speedX = -speedX; - } else if (posX > 224.) { - posX = 448. - posX; - speedX = -speedX; - } - - /* - * Check top collision. - */ - if (posY < 0.) { - int valX = (int) posX; - - position = new int[2]; - position[0] = valX >> 5; - if ((valX & 16) > 0) { - position[0]++; - } - position[1] = 0; - } else { - /* - * Check other collision. - */ - position = CollisionHelper.collide((int) posX, (int) posY, grid); - } - } - - return position; + gridOptions = null; + outGrid = null; } /** * Stop the thread run() execution. - *

Interrupt the thread when it is suspended via - * wait(). + *

This method will call notify() to resume the thread + * if it is suspended via wait(). */ public void stopThread() { running = false; mOpponentListener = null; synchronized(this) { - this.notify(); + notify(); } } } diff --git a/src/org/gsanson/frozenbubble/MalusBar.java b/src/org/gsanson/frozenbubble/MalusBar.java index 93a3519..9e9a77b 100644 --- a/src/org/gsanson/frozenbubble/MalusBar.java +++ b/src/org/gsanson/frozenbubble/MalusBar.java @@ -53,6 +53,7 @@ package org.gsanson.frozenbubble; import org.jfedor.frozenbubble.BmpWrap; +import org.jfedor.frozenbubble.LevelManager; import org.jfedor.frozenbubble.Sprite; import android.graphics.Canvas; @@ -60,6 +61,7 @@ import android.os.Bundle; public class MalusBar extends Sprite { + public final static int MAX_ATTACK = LevelManager.NUM_COLS - 1; /* X-pos for tomatoes */ int minX; @@ -88,10 +90,9 @@ public class MalusBar extends Sprite { */ public MalusBar(int coordX, int coordY, BmpWrap banana, BmpWrap tomato) { super(new Rect(coordX, coordY, coordX + 33, coordY + 354)); - minX = coordX; - maxY = coordY + 354; + minX = coordX; + maxY = coordY + 354; releaseTime = 0; - this.banana = banana; this.tomato = tomato; } @@ -100,10 +101,10 @@ public MalusBar(int coordX, int coordY, BmpWrap banana, BmpWrap tomato) { public final void paint(Canvas c, double scale, int dx, int dy) { int count = nbMalus; int pos = maxY; - while (count >= 7) { + while (count >= MAX_ATTACK) { pos -= 13; drawImage(tomato, minX, pos, c, scale, dx, dy); - count -= 7; + count -= MAX_ATTACK; } while (count > 0) { pos -= 11; @@ -122,7 +123,7 @@ public void addBubbles(int toAdd) { * Clear the attack bubbles stored in the attack bubble array. */ public void clearAttackBubbles() { - for (int i = 0; i < 15; i++) + for (int i = 0; i < LevelManager.LANES; i++) this.attackBubbles[i] = -1; } @@ -149,7 +150,7 @@ public void removeAttackBubbles(int remove) { } public int removeLine() { - int nb = Math.min(7, nbMalus); + int nb = Math.min(MAX_ATTACK, nbMalus); nbMalus -= nb; return nb; } @@ -183,7 +184,7 @@ public void setAttackBubbles(int numBubbles, byte[] attackBubbles) { nbMalus = numBubbles; if (attackBubbles != null) - for (int i = 0; i < 15; i++) + for (int i = 0; i < LevelManager.LANES; i++) this.attackBubbles[i] = attackBubbles[i]; } } diff --git a/src/org/gsanson/frozenbubble/Opponent.java b/src/org/gsanson/frozenbubble/Opponent.java index d7d6c4e..4ac35a3 100644 --- a/src/org/gsanson/frozenbubble/Opponent.java +++ b/src/org/gsanson/frozenbubble/Opponent.java @@ -53,34 +53,38 @@ package org.gsanson.frozenbubble; public interface Opponent { - /** - * Checks whether opponent has a control command awaiting - * @return + * Make any necessary computation before next turn + * @param currentColor + * @param nextColor + * @param compressor */ - public boolean isComputing(); + public void compute(int currentColor, int nextColor, int compressor); /** - * Get the exact direction (radian value) pointer should reach + * Get the action the CPU opponent wants to make (aim left, aim right, + * fire). * @param currentDirection - * @return + * @return The action identifier of the next CPU action. */ - public double getExactDirection(double currentDirection); + public int getAction(double currentDirection); + + /** + * Get the final grid location of the next opponent bubble launch. + * @return The final grid location of the next opponent bubble launch. + */ + public int[] getBubbleDestination(); /** - * The action opponent want to make (left, right, fire) + * Get the exact direction (radian value) pointer should reach * @param currentDirection * @return */ - public int getAction(double currentDirection); + public double getExactDirection(double currentDirection); /** - * Make any necessary computation before next turn - * @param currentColor - * @param nextColor - * @param compressor + * Checks whether opponent has a control command awaiting + * @return */ - public void compute(int currentColor, int nextColor, int compressor); - - public int[] getBallDestination(); + public boolean isComputing(); } diff --git a/src/org/jfedor/frozenbubble/BubbleSprite.java b/src/org/jfedor/frozenbubble/BubbleSprite.java index 4379948..928b18c 100644 --- a/src/org/jfedor/frozenbubble/BubbleSprite.java +++ b/src/org/jfedor/frozenbubble/BubbleSprite.java @@ -247,7 +247,7 @@ void checkJump(Vector jump, BmpWrap compare) { void checkJump(Vector jump, Vector neighbors) { jump.addElement(this); - for (int i=0 ; i7) { - posX = 7; + if (posX > (LevelManager.NUM_COLS - 1)) { + posX = LevelManager.NUM_COLS - 1; } - if (posX<0) { + if (posX < 0) { posX = 0; } - if (posY<0) { + if (posY < 0) { posY = 0; } @@ -298,7 +298,7 @@ Vector getNeighbors(Point p) { list.addElement(grid[p.x-1][p.y]); } - if (p.x < 7) { + if (p.x < (LevelManager.NUM_COLS - 1)) { list.addElement(grid[p.x+1][p.y]); if (p.y > 0) { @@ -306,7 +306,7 @@ Vector getNeighbors(Point p) { list.addElement(grid[p.x+1][p.y-1]); } - if (p.y < 12) { + if (p.y < (LevelManager.NUM_ROWS - 1)) { list.addElement(grid[p.x][p.y+1]); list.addElement(grid[p.x+1][p.y+1]); } @@ -316,13 +316,13 @@ Vector getNeighbors(Point p) { list.addElement(grid[p.x][p.y-1]); } - if (p.y < 12) { + if (p.y < (LevelManager.NUM_ROWS - 1)) { list.addElement(grid[p.x][p.y+1]); } } } else { - if (p.x < 7) { + if (p.x < (LevelManager.NUM_COLS - 1)) { list.addElement(grid[p.x+1][p.y]); } @@ -334,7 +334,7 @@ Vector getNeighbors(Point p) { list.addElement(grid[p.x-1][p.y-1]); } - if (p.y < 12) { + if (p.y < (LevelManager.NUM_ROWS - 1)) { list.addElement(grid[p.x][p.y+1]); list.addElement(grid[p.x-1][p.y+1]); } @@ -344,7 +344,7 @@ Vector getNeighbors(Point p) { list.addElement(grid[p.x][p.y-1]); } - if (p.y < 12) { + if (p.y < (LevelManager.NUM_ROWS - 1)) { list.addElement(grid[p.x][p.y+1]); } } @@ -393,8 +393,10 @@ else if (realX<=190.) { * bubble corresponds to a fixed grid location. Otherwise just move * the bubble. */ - if ((currentPosition.x >= 0) && (currentPosition.x < 8) && - (currentPosition.y >= 0) && (currentPosition.y < 13)) { + if ((currentPosition.x >= 0) && + (currentPosition.x < LevelManager.NUM_COLS) && + (currentPosition.y >= 0) && + (currentPosition.y < LevelManager.NUM_ROWS)) { BubbleSprite[][] grid = frozen.getGrid(); if (grid[currentPosition.x][currentPosition.y] == null) @@ -490,14 +492,14 @@ else if (realX<=190.) { grid[currentPoint.x][currentPoint.y] = null; } - for (int i=0 ; i<8 ; i++) { + for (int i = 0; i < LevelManager.NUM_COLS; i++) { if (grid[i][0] != null) { grid[i][0].checkFall(); } } - for (int i=0 ; i<8 ; i++) { - for (int j=0 ; j<12 ; j++) { + for (int i = 0; i < LevelManager.NUM_COLS; i++) { + for (int j = 0; j < (LevelManager.NUM_ROWS - 1); j++) { if (grid[i][j] != null) { if (!grid[i][j].checked()) { frozen.addFallingBubble(grid[i][j]); diff --git a/src/org/jfedor/frozenbubble/FrozenBubble.java b/src/org/jfedor/frozenbubble/FrozenBubble.java index 3dc57b1..a0e3b65 100644 --- a/src/org/jfedor/frozenbubble/FrozenBubble.java +++ b/src/org/jfedor/frozenbubble/FrozenBubble.java @@ -586,15 +586,26 @@ private void cleanUpGameView() { mGameView = null; } - private int getScreenOrientation() { + /** + * Obtain the screen orientation. + * @param windowManager - used to get a reference to the display to + * obtain display information. + * @return The screen orientation, which can be among the following + * values:
+ * ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
+ * ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
+ * FrozenBubble.SCREEN_ORIENTATION_REVERSE_LANDSCAPE
+ * FrozenBubble.SCREEN_ORIENTATION_REVERSE_PORTRAIT
+ */ + public static int getScreenOrientation(WindowManager windowManager) { /* * The method getOrientation() was deprecated in API level 8. * * For API level 8 or greater, use getRotation(). */ - int rotation = getWindowManager().getDefaultDisplay().getOrientation(); + int rotation = windowManager.getDefaultDisplay().getOrientation(); DisplayMetrics dm = new DisplayMetrics(); - getWindowManager().getDefaultDisplay().getMetrics(dm); + windowManager.getDefaultDisplay().getMetrics(dm); int width = dm.widthPixels; int height = dm.heightPixels; int orientation; @@ -664,12 +675,12 @@ private int getScreenOrientation() { private void initGameOptions() { restoreGamePrefs(); - currentOrientation = getScreenOrientation(); + currentOrientation = getScreenOrientation(getWindowManager()); myOrientationEventListener = new OrientationEventListener(this, SensorManager.SENSOR_DELAY_NORMAL) { @Override public void onOrientationChanged(int arg0) { - currentOrientation = getScreenOrientation(); + currentOrientation = getScreenOrientation(getWindowManager()); } }; if (myOrientationEventListener.canDetectOrientation()) @@ -681,12 +692,8 @@ public void onOrientationChanged(int arg0) { */ public void newGame() { if (mGameThread != null) { - mGameThread.newGame(); - if (numPlayers > 1) { - mGameThread.startOpponent(); - } + mGameThread.newGame(true); } - playMusic(false); } @@ -1082,7 +1089,6 @@ private void startDefaultGame(Intent intent, Bundle savedInstanceState) { mGameThread.restoreState(savedInstanceState); } } - mGameThread.startOpponent(); mGameView.requestFocus(); } else { diff --git a/src/org/jfedor/frozenbubble/FrozenGame.java b/src/org/jfedor/frozenbubble/FrozenGame.java index 8e0d848..54cc1a6 100644 --- a/src/org/jfedor/frozenbubble/FrozenGame.java +++ b/src/org/jfedor/frozenbubble/FrozenGame.java @@ -70,9 +70,9 @@ import com.efortin.frozenbubble.VirtualInput; public class FrozenGame extends GameScreen { - private final int[] columnX = { 190, 206, 232, 248, 264, - 280, 296, 312, 328, 344, - 360, 376, 392, 408, 424 }; + private final int[] columnX = { 190, 206, 222, 238, 254, + 270, 286, 302, 318, 334, + 350, 366, 382, 398, 414 }; public final static int HORIZONTAL_MOVE = 0; public final static int FIRE = 1; @@ -234,7 +234,8 @@ public FrozenGame(BmpWrap background_arg, goingUp = new Vector(); jumping = new Vector(); - bubblePlay = new BubbleSprite[8][13]; + bubblePlay = new BubbleSprite[LevelManager.NUM_COLS] + [LevelManager.NUM_ROWS]; bubbleManager = new BubbleManager(bubbles); /* @@ -246,8 +247,8 @@ public FrozenGame(BmpWrap background_arg, return; } - for (int j = 0; j < 12; j++) { - for (int i = j%2; i < 8; i++) { + for (int j = 0; j < (LevelManager.NUM_ROWS - 1); j++) { + for (int i = j%2; i < LevelManager.NUM_COLS; i++) { if (currentLevel[i][j] != -1) { BubbleSprite newOne = new BubbleSprite( new Rect(190+i*32-(j%2)*16, 44+j*28, 32, 32), @@ -334,7 +335,7 @@ private void blinkLine(int number) { int move = number%2; int column = (number+1) >> 1; - for (int i = move; i < 13; i++) { + for (int i = move; i < LevelManager.NUM_ROWS; i++) { if (bubblePlay[column][i] != null) { bubblePlay[column][i].blink(); } @@ -344,8 +345,8 @@ private void blinkLine(int number) { public void calculateGridChecksum() { CRC16 gridCRC = new CRC16(0); - for (int i = 0; i < 8; i++) { - for (int j = 0; j < 12; j++) { + for (int i = 0; i < LevelManager.NUM_COLS; i++) { + for (int j = 0; j < (LevelManager.NUM_ROWS - 1); j++) { if (bubblePlay[i][j] != null) { gridCRC.update(bubblePlay[i][j].getColor()); } @@ -368,8 +369,8 @@ private boolean checkLost() { int steps = compressor.getSteps(); - for (int i = 0; i < 8; i++) { - if (bubblePlay[i][12 - steps] != null) { + for (int i = 0; i < LevelManager.NUM_COLS; i++) { + if (bubblePlay[i][(LevelManager.NUM_ROWS - 1) - steps] != null) { lost = true; break; } @@ -422,7 +423,7 @@ public void deleteJumpingBubble(BubbleSprite sprite) { private void frozenify() { frozenifyX--; if (frozenifyX < 0) { - frozenifyX = 7; + frozenifyX = LevelManager.NUM_COLS - 1; frozenifyY--; if (frozenifyY < 0) { @@ -437,7 +438,7 @@ private void frozenify() { while ((bubblePlay[frozenifyX][frozenifyY] == null) && (frozenifyY >= 0)) { frozenifyX--; if (frozenifyX < 0) { - frozenifyX = 7; + frozenifyX = LevelManager.NUM_COLS - 1; frozenifyY--; if (frozenifyY < 0) { @@ -529,8 +530,8 @@ private void initFrozenify() { this.addSprite(freezeLaunchBubble); this.addSprite(freezeNextBubble); - frozenifyX = 7; - frozenifyY = 12; + frozenifyX = LevelManager.NUM_COLS - 1; + frozenifyY = LevelManager.NUM_ROWS - 1; frozenify = true; } @@ -545,8 +546,8 @@ public void lowerCompressor(boolean playSound) { soundManager.playSound(FrozenBubble.SOUND_NEWROOT); } - for (int i = 0; i < 8; i++) { - for (int j = 0; j < 12; j++) { + for (int i = 0; i < LevelManager.NUM_COLS; i++) { + for (int j = 0; j < (LevelManager.NUM_ROWS - 1); j++) { if (bubblePlay[i][j] != null) { bubblePlay[i][j].moveDown(); @@ -725,7 +726,6 @@ else if (key_right && !key_left) { if (endOfGame && readyToFire) { if (move[FIRE] == KEY_UP) { if (playResult == gameEnum.WON) { - levelManager.goToNextLevel(); playResult = gameEnum.NEXT_WON; } else { @@ -958,12 +958,12 @@ private int releaseBubbles() { * bubble launches. */ if (isRemote) { - for (int i = 0; i < 15; i++) { + for (int i = 0; i < LevelManager.LANES; i++) { if (malusBar.attackBubbles[i] >= 0) { numBubblesLaunched++; int color = malusBar.attackBubbles[i]; BubbleSprite malusBubble = new BubbleSprite( - new Rect(columnX[i], 44+15*28, 32, 32), + new Rect(columnX[i], 44+(LevelManager.MAX_ROWS*28), 32, 32), START_LAUNCH_DIRECTION, color, bubbles[color], bubblesBlind[color], frozenBubbles[color], targetedBubbles, bubbleBlink, @@ -975,25 +975,25 @@ private int releaseBubbles() { malusBar.removeAttackBubbles(numBubblesLaunched); } else if (malusBar.getAttackBarBubbles() > 0) { - boolean[] lanes = new boolean[15]; + boolean[] lanes = new boolean[LevelManager.LANES]; int malusBalls = malusBar.removeLine(); int pos; while (malusBalls > 0) { - pos = random.nextInt(15); + pos = random.nextInt(LevelManager.LANES); if (!lanes[pos]) { lanes[pos] = true; malusBalls--; } } - for (int i = 0; i < 15; i++) { + for (int i = 0; i < LevelManager.LANES; i++) { if (lanes[i]) { numBubblesLaunched++; int color = random.nextInt(FrozenBubble.getDifficulty()); malusBar.setAttackBubble(i, color); BubbleSprite malusBubble = new BubbleSprite( - new Rect(columnX[i], 44+15*28, 32, 32), + new Rect(columnX[i], 44+(LevelManager.MAX_ROWS*28), 32, 32), START_LAUNCH_DIRECTION, color, bubbles[color], bubblesBlind[color], frozenBubbles[color], targetedBubbles, bubbleBlink, @@ -1107,9 +1107,10 @@ public void restoreState(Bundle map, Vector imageList) { int spriteIdx = map.getInt(String.format("%d-falling-%d", player, i)); falling.addElement(savedSprites.elementAt(spriteIdx)); } - bubblePlay = new BubbleSprite[8][13]; - for (int i = 0; i < 8; i++) { - for (int j = 0; j < 13; j++) { + bubblePlay = new BubbleSprite[LevelManager.NUM_COLS] + [LevelManager.NUM_ROWS]; + for (int i = 0; i < LevelManager.NUM_COLS; i++) { + for (int j = 0; j < LevelManager.NUM_ROWS; j++) { int spriteIdx = map.getInt(String.format("%d-play-%d-%d", player, i, j)); if (spriteIdx != -1) { @@ -1188,8 +1189,8 @@ public void saveState(Bundle map) { ((Sprite)falling.elementAt(i)).getSavedId()); } map.putInt(String.format("%d-numFallingSprites", player), falling.size()); - for (int i = 0; i < 8; i++) { - for (int j = 0; j < 13; j++) { + for (int i = 0; i < LevelManager.NUM_COLS; i++) { + for (int j = 0; j < LevelManager.NUM_ROWS; j++) { if (bubblePlay[i][j] != null) { bubblePlay[i][j].saveState(map, savedSprites, player); map.putInt(String.format("%d-play-%d-%d", player, i, j), @@ -1287,8 +1288,8 @@ public void setGrid(byte[][] newGrid, byte newSteps) { jumping.clear(); bubbleManager.initialize(); removeAllBubbleSprites(); - for (int i = 0; i < 8; i++) { - for (int j = 0; j < 13; j++) { + for (int i = 0; i < LevelManager.NUM_COLS; i++) { + for (int j = 0; j < LevelManager.NUM_ROWS; j++) { bubblePlay[i][j] = null; if (newGrid[i][j] != -1) { bubblePlay[i][j] = new BubbleSprite( @@ -1369,8 +1370,8 @@ public void synchronizeBubbleManager() { /* * Check the bubble sprite grid for occupied locations. */ - for (int i = 0; i < 8; i++) { - for (int j = 0; j < 13; j++) { + for (int i = 0; i < LevelManager.NUM_COLS; i++) { + for (int j = 0; j < LevelManager.NUM_ROWS; j++) { if (bubblePlay[i][j] != null ) { numBubblesPlay++; } @@ -1388,8 +1389,8 @@ public void synchronizeBubbleManager() { if (numBubblesManager != numBubblesPlay) { bubbleManager.initialize(); removeAllBubbleSprites(); - for (int i = 0; i < 8; i++) { - for (int j = 0; j < 13; j++) { + for (int i = 0; i < LevelManager.NUM_COLS; i++) { + for (int j = 0; j < LevelManager.NUM_ROWS; j++) { if (bubblePlay[i][j] != null ) { bubblePlay[i][j].addToManager(); this.addSprite(bubblePlay[i][j]); diff --git a/src/org/jfedor/frozenbubble/GameView.java b/src/org/jfedor/frozenbubble/GameView.java index ce06290..98aac80 100644 --- a/src/org/jfedor/frozenbubble/GameView.java +++ b/src/org/jfedor/frozenbubble/GameView.java @@ -102,10 +102,8 @@ import android.graphics.drawable.Drawable; import android.os.Bundle; import android.util.AttributeSet; -import android.util.DisplayMetrics; import android.view.KeyEvent; import android.view.MotionEvent; -import android.view.Surface; import android.view.SurfaceHolder; import android.view.SurfaceView; @@ -125,23 +123,15 @@ public class GameView extends SurfaceView public static final int GAMEFIELD_HEIGHT = 480; public static final int EXTENDED_GAMEFIELD_WIDTH = 640; - /* - * The following screen orientation definitions were added to - * ActivityInfo in API level 9. - */ - public final static int SCREEN_ORIENTATION_SENSOR_LANDSCAPE = 6; - public final static int SCREEN_ORIENTATION_SENSOR_PORTRAIT = 7; - public final static int SCREEN_ORIENTATION_REVERSE_LANDSCAPE = 8; - public final static int SCREEN_ORIENTATION_REVERSE_PORTRAIT = 9; - - private boolean mInterstitialShown = false; private boolean mBlankScreen = false; + private boolean mInterstitialShown = false; private boolean muteKeyToggle = false; private boolean pauseKeyToggle = false; private int numPlayers; private int numPlayer1GamesWon; private int numPlayer2GamesWon; private Context mContext; + private gameEnum game1Status; private GameThread mGameThread; private NetworkGameManager mNetworkManager; private RemoteInterface remoteInterface; @@ -801,7 +791,7 @@ public GameThread(SurfaceHolder surfaceHolder) { } mLevelManager = new LevelManager(0, FrozenBubble.getDifficulty()); - newGame(); + newGame(false); } public GameThread(SurfaceHolder surfaceHolder, byte[] customLevels, @@ -984,17 +974,7 @@ public GameThread(SurfaceHolder surfaceHolder, byte[] customLevels, mLevelManager = new LevelManager(customLevels, startingLevel); } - mFrozenGame1 = new FrozenGame(mBackground, mBubbles, mBubblesBlind, - mFrozenBubbles, mTargetedBubbles, - mBubbleBlink, mGameWon, mGameLost, - mGamePaused, mHurry, mPenguins, - mCompressorHead, mCompressor, mLauncher, - mSoundManager, mLevelManager, - mHighScoreManager); - mPlayer1.setGameRef(mFrozenGame1); - mFrozenGame2 = null; - mNetworkManager = null; - mHighScoreManager.startLevel(mLevelManager.getLevelIndex()); + newGame(false); } public void cleanUp() { @@ -1514,7 +1494,7 @@ private void drawLowScoreScreen(Canvas canvas, int level) { int indent = 10; int orientation = getScreenOrientation(); - if (orientation == SCREEN_ORIENTATION_REVERSE_PORTRAIT) + if (orientation == FrozenBubble.SCREEN_ORIENTATION_REVERSE_PORTRAIT) x += GAMEFIELD_WIDTH/2; else if (orientation == ActivityInfo.SCREEN_ORIENTATION_PORTRAIT) x -= GAMEFIELD_WIDTH/2; @@ -1563,7 +1543,7 @@ private void drawNetworkScreen(Canvas canvas) { int ysp = 26; int orientation = getScreenOrientation(); - if (orientation == SCREEN_ORIENTATION_REVERSE_PORTRAIT) + if (orientation == FrozenBubble.SCREEN_ORIENTATION_REVERSE_PORTRAIT) x += GAMEFIELD_WIDTH/2; else if (orientation == ActivityInfo.SCREEN_ORIENTATION_PORTRAIT) x -= GAMEFIELD_WIDTH/2; @@ -1712,75 +1692,8 @@ public int getCurrentLevelIndex() { } private int getScreenOrientation() { - /* - * The method getOrientation() was deprecated in API level 8. - * - * For API level 8 or greater, use getRotation(). - */ - int rotation = ((Activity) mContext).getWindowManager(). - getDefaultDisplay().getOrientation(); - DisplayMetrics dm = new DisplayMetrics(); - ((Activity) mContext).getWindowManager().getDefaultDisplay().getMetrics(dm); - int width = dm.widthPixels; - int height = dm.heightPixels; - int orientation; - /* - * The orientation determination is based on the natural orienation - * mode of the device, which can be either portrait, landscape, or - * square. - * - * After the natural orientation is determined, convert the device - * rotation into a fully qualified orientation. - */ - if ((((rotation == Surface.ROTATION_0 ) || - (rotation == Surface.ROTATION_180)) && (height > width)) || - (((rotation == Surface.ROTATION_90 ) || - (rotation == Surface.ROTATION_270)) && (width > height))) { - /* - * Natural orientation is portrait. - */ - switch(rotation) { - case Surface.ROTATION_0: - orientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT; - break; - case Surface.ROTATION_90: - orientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE; - break; - case Surface.ROTATION_180: - orientation = SCREEN_ORIENTATION_REVERSE_PORTRAIT; - break; - case Surface.ROTATION_270: - orientation = SCREEN_ORIENTATION_REVERSE_LANDSCAPE; - break; - default: - orientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT; - break; - } - } - else { - /* - * Natural orientation is landscape or square. - */ - switch(rotation) { - case Surface.ROTATION_0: - orientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE; - break; - case Surface.ROTATION_90: - orientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT; - break; - case Surface.ROTATION_180: - orientation = SCREEN_ORIENTATION_REVERSE_LANDSCAPE; - break; - case Surface.ROTATION_270: - orientation = SCREEN_ORIENTATION_REVERSE_PORTRAIT; - break; - default: - orientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE; - break; - } - } - - return orientation; + return FrozenBubble.getScreenOrientation(((Activity) mContext). + getWindowManager()); } private BmpWrap NewBmpWrap() { @@ -1790,7 +1703,13 @@ private BmpWrap NewBmpWrap() { return new_img; } - public void newGame() { + /** + * Start a new game. + * @param firstLevel if true, start a new game in + * puzzle mode beginning at the first level. + */ + public void newGame(boolean firstLevel) { + game1Status = gameEnum.PLAYING; synchronized(mSurfaceHolder) { if (numPlayers > 1) { malusBar1 = new MalusBar(GameView.GAMEFIELD_WIDTH - 164, 40, @@ -1801,7 +1720,9 @@ public void newGame() { else { malusBar1 = null; malusBar2 = null; - mLevelManager.goToFirstLevel(); + if (firstLevel) { + mLevelManager.goToFirstLevel(); + } } mImagesReady = false; @@ -1839,28 +1760,18 @@ public void newGame() { } mImagesReady = true; - - if (mHighScoreManager != null) { - mHighScoreManager.startLevel(mLevelManager.getLevelIndex()); - } } - } - private void nextLevel() { - mImagesReady = false; - mPlayer1.setGameRef(null); - mFrozenGame1 = new FrozenGame(mBackground, mBubbles, mBubblesBlind, - mFrozenBubbles, mTargetedBubbles, - mBubbleBlink, mGameWon, mGameLost, - mGamePaused, mHurry, mPenguins, - mCompressorHead, mCompressor, mLauncher, - mSoundManager, mLevelManager, - mHighScoreManager); - mPlayer1.setGameRef(mFrozenGame1); - mImagesReady = true; if (mHighScoreManager != null) { mHighScoreManager.startLevel(mLevelManager.getLevelIndex()); } + + startOpponent(); + } + + private void nextLevel() { + mLevelManager.goToNextLevel(); + newGame(false); } public void pause() { @@ -1947,6 +1858,7 @@ public void restoreState(Bundle map) { numPlayer2GamesWon = map.getInt("numPlayer2GamesWon", 0); if (mFrozenGame2 != null) { mFrozenGame2.restoreState(map, mImageList); + startOpponent(); } } if (mLevelManager != null) { @@ -2039,7 +1951,13 @@ else if ((mHighScoreManager != null) && mShowScores) { * inconsistent state. */ if (c != null) { - mSurfaceHolder.unlockCanvasAndPost(c); + try { + mSurfaceHolder.unlockCanvasAndPost(c); + } catch (IllegalStateException ise) { + /* + * Surface has already been released. + */ + } } } } @@ -2246,7 +2164,7 @@ public void setSurfaceSize(int width, int height) { } else { int orientation = getScreenOrientation(); - if ((orientation == SCREEN_ORIENTATION_REVERSE_PORTRAIT) || + if ((orientation == FrozenBubble.SCREEN_ORIENTATION_REVERSE_PORTRAIT) || (orientation == ActivityInfo.SCREEN_ORIENTATION_PORTRAIT)) { if (mLocalInput.playerID == VirtualInput.PLAYER2) { mDisplayDX = (int)(-mDisplayScale * gameWidth); @@ -2276,7 +2194,7 @@ public void setSurfaceSize(int width, int height) { /** * Create a CPU opponent object (if necessary) and start the thread. */ - public void startOpponent() { + private void startOpponent() { if (mOpponent != null) { mOpponent.stopThread(); mOpponent = null; @@ -2404,7 +2322,9 @@ else if (mShowScores) { setState(stateEnum.RUNNING); } else { - nextLevel(); + if (game1Status == gameEnum.WON) { + nextLevel(); + } if (getCurrentLevelIndex() != 0) { setState(stateEnum.RUNNING); } @@ -2554,16 +2474,13 @@ else if (game2Result != gameEnum.PLAYING) { } pause(); - newGame(); - - if (mRemoteInput.isCPU) { - startOpponent(); - } + nextLevel(); } } else if ((game1State == gameEnum.NEXT_LOST) || (game1State == gameEnum.NEXT_WON )) { if (game1State == gameEnum.NEXT_WON) { + game1Status = gameEnum.WON; mShowScores = true; pause(); if (FrozenBubble.getAdsOn() && @@ -2574,16 +2491,17 @@ else if ((game1State == gameEnum.NEXT_LOST) || } } else { - nextLevel(); + game1Status = gameEnum.LOST; + newGame(false); } + } - if (mGameListener != null) { - if (game1State == gameEnum.NEXT_WON) { - mGameListener.onGameEvent(eventEnum.GAME_WON); - } - else { - mGameListener.onGameEvent(eventEnum.GAME_LOST); - } + if (mGameListener != null) { + if (game1State == gameEnum.NEXT_WON) { + mGameListener.onGameEvent(eventEnum.GAME_WON); + } + else if (game1State == gameEnum.NEXT_LOST){ + mGameListener.onGameEvent(eventEnum.GAME_LOST); } } } diff --git a/src/org/jfedor/frozenbubble/InterstitialActivity.java b/src/org/jfedor/frozenbubble/InterstitialActivity.java index fb87206..595ee9f 100644 --- a/src/org/jfedor/frozenbubble/InterstitialActivity.java +++ b/src/org/jfedor/frozenbubble/InterstitialActivity.java @@ -21,7 +21,12 @@ public class InterstitialActivity extends Activity { protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE); - setContentView(R.layout.activity_interstitial); + try { + setContentView(R.layout.activity_interstitial); + } catch (OutOfMemoryError oome) { + finish(); + return; + } gotoPlayStoreButton = (Button) findViewById(R.id.gotobutton); continueButton = (Button) findViewById(R.id.continuebutton); imageView = (ImageView) findViewById(R.id.bannerview); @@ -45,7 +50,7 @@ public void onClick(View v) { Uri.parse("market://search?q=busy beaver")); try { startActivity(i); - } catch (ActivityNotFoundException anfe3) { + } catch (ActivityNotFoundException anfe2) { Toast.makeText(getApplicationContext(), "Could not access market. Are you connected to the internet?", Toast.LENGTH_SHORT).show(); diff --git a/src/org/jfedor/frozenbubble/LevelManager.java b/src/org/jfedor/frozenbubble/LevelManager.java index c87ad1a..4ddcbfa 100644 --- a/src/org/jfedor/frozenbubble/LevelManager.java +++ b/src/org/jfedor/frozenbubble/LevelManager.java @@ -58,6 +58,19 @@ import android.os.Bundle; public class LevelManager { + + /* + * Level row and column definitions. + */ + public static final int LANES = 15; + public static final int MAX_ROWS = 15; + public static final int NUM_COLS = 8; + public static final int NUM_ROWS = 13; + public static final int VS_ROWS = 5; + + /* + * Level difficulty (number of bubble colors) definitions. + */ public static final int EASY = 4; public static final int NORMAL = 5; public static final int MODERATE = 6; @@ -98,14 +111,14 @@ public void restoreState(Bundle map) { * level difficulty, e.g. EASY, HARD, etc. */ public LevelManager(long seed, int difficulty) { - this.randomMode = true; - this.randomSeed = seed; - this.currentLevel = difficulty; - currentLevel = ((currentLevel - 1) % INSANE) + 1; + randomMode = true; + randomSeed = seed; + currentLevel = difficulty; if (currentLevel < EASY) - this.currentLevel = EASY; - else - this.currentLevel = difficulty; + currentLevel = EASY; + else if (currentLevel > INSANE) { + currentLevel = INSANE; + } levelList = new Vector(); levelList.addElement(getLevel(null)); } @@ -150,10 +163,10 @@ public LevelManager(byte[] levels, int startingLevel) { } private byte[][] getLevel(String data) { - byte[][] temp = new byte[8][12]; + byte[][] temp = new byte[NUM_COLS][NUM_ROWS - 1]; - for (int j=0 ; j<12 ; j++) { - for (int i=0 ; i<8 ; i++) { + for (int j = 0; j < (NUM_ROWS - 1); j++) { + for (int i = 0; i < NUM_COLS; i++) { temp[i][j] = -1; } } @@ -171,23 +184,22 @@ else if (data.charAt(i) == 45) { temp[tempX][tempY] = -1; tempX++; } - - if (tempX == 8) { + + if (tempX == NUM_COLS) { tempY++; - - if (tempY == 12) { + + if (tempY == NUM_ROWS - 1) { return temp; } - + tempX = tempY % 2; } } } else { Random rand = new Random(randomSeed); - rand.nextInt(7); - for (int j=0 ; j<5 ; j++) { - for (int i=0 ; i<8 ; i++) { + for (int j = 0; j < VS_ROWS; j++) { + for (int i = 0; i < NUM_COLS; i++) { temp[i][j] = (byte)rand.nextInt(currentLevel); } }