/*
* Copyright (C) 2010 Ryan Morton
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.games.rm.patternpuzzler;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Random;
import android.app.Activity;
import android.content.Intent;
import android.graphics.Color;
import android.media.MediaPlayer;
import android.os.Bundle;
import android.os.Handler;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnTouchListener;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import android.widget.RelativeLayout;
import android.widget.TextView;
public class GameBoard5 extends Activity implements OnClickListener,OnTouchListener, CountdownTimerFinishedListener
{
private final float LEFT_VOLUME = GameBoard4.LEFT_VOLUME, RIGHT_VOLUME = GameBoard4.RIGHT_VOLUME;
//main layouts**********/
private RelativeLayout redButtonLayout;
private RelativeLayout yellowButtonLayout;
private RelativeLayout blueButtonLayout;
private RelativeLayout greenButtonLayout;
private RelativeLayout orangeButtonLayout;
private LinearLayout statusbarLayout;
private LinearLayout pauseMenuLayout;
private LinearLayout successLayout;
private LinearLayout failLayout;
private TextView countdownTimerText;
//buttons*************/
private ImageView redButtonTop;
private ImageView redButtonLight;
private ImageView yellowButtonTop;
private ImageView yellowButtonLight;
private ImageView blueButtonTop;
private ImageView blueButtonLight;
private ImageView greenButtonTop;
private ImageView greenButtonLight;
private ImageView orangeButtonTop;
private ImageView orangeButtonLight;
private ImageView forwardButton;
private ImageView replayButton;
private ImageView pauseButton;
private TextView resumeButton;
private RadioGroup fxRadioGroup;
private RadioButton fxOnRadioButton;
private RadioButton fxOffRadioButton;
//other things***********/
private TextView levelTextBox;
private boolean buttonsActive;
private boolean statusbarActive;
private boolean showingPattern;
private boolean isGameOver;
private boolean replayResetUsed;
private boolean soundFxOn;
private Animation[] animationCache;
private CountdownTimer myCountdownTimer;
private HashMap<Integer, ImageView> lightedButtonMap;
private ArrayList<Integer> myPattern;
private int currentPatternIndex; //this stores the current index of the pattern ... to check against user input
private Random randomGen;
private PatternPlayer myPatternPlayer;
private Savegame mySaveGame;
private HashMap<ImageView,MediaPlayer> soundCache;
HashMap<ImageView, MediaPlayer> patternPlayerSoundCache;
@Override
protected void onCreate(Bundle savedInstanceState)
{
//System.out.println("onCreate");
super.onCreate(savedInstanceState);
//set up the window properties
Utilities.setupActivityWindow(this);
//inflate the main layout
this.setContentView(R.layout.game_board_5);
//run the init();
this.init();
//go to onResume for what happens next
}
/***
* initialize the variables
*/
private void init()
{
//init animation cache
animationCache = new Animation[2];
animationCache[0] = AnimationUtils.loadAnimation(this, R.anim.fade_in_buttons);
animationCache[1] = AnimationUtils.loadAnimation(this, R.anim.fade_in_200);
//init layouts************/
redButtonLayout = (RelativeLayout)this.findViewById(R.id.GameBoard_5_Red_Button_Layout);
yellowButtonLayout = (RelativeLayout)this.findViewById(R.id.GameBoard_5_Yellow_Button_Layout);
blueButtonLayout = (RelativeLayout)this.findViewById(R.id.GameBoard_5_Blue_Button_Layout);
greenButtonLayout = (RelativeLayout)this.findViewById(R.id.GameBoard_5_Green_Button_Layout);
orangeButtonLayout = (RelativeLayout)this.findViewById(R.id.GameBoard_5_Orange_Button_Layout);
statusbarLayout = (LinearLayout)this.findViewById(R.id.GameBoard_5_StatusBar_Layout);
pauseMenuLayout = (LinearLayout)this.findViewById(R.id.GameBoard_5_Pause_Menu_Layout);
successLayout = (LinearLayout)this.findViewById(R.id.GameBoard_5_Success_Layout);
failLayout = (LinearLayout)this.findViewById(R.id.GameBoard_5_Fail_Layout);
countdownTimerText = (TextView)this.findViewById(R.id.GameBoard_5_Countdown);
//init buttons**************/
redButtonTop = (ImageView)redButtonLayout.findViewById(R.id.GameBoard_5_Red_Button);
redButtonLight = (ImageView)redButtonLayout.findViewById(R.id.GameBoard_5_Red_Button_On);
yellowButtonTop = (ImageView)yellowButtonLayout.findViewById(R.id.GameBoard_5_Yellow_Button);
yellowButtonLight = (ImageView)yellowButtonLayout.findViewById(R.id.GameBoard_5_Yellow_Button_On);
blueButtonTop = (ImageView)blueButtonLayout.findViewById(R.id.GameBoard_5_Blue_Button);
blueButtonLight = (ImageView)blueButtonLayout.findViewById(R.id.GameBoard_5_Blue_Button_On);
greenButtonTop = (ImageView)greenButtonLayout.findViewById(R.id.GameBoard_5_Green_Button);
greenButtonLight = (ImageView)greenButtonLayout.findViewById(R.id.GameBoard_5_Green_Button_On);
orangeButtonTop = (ImageView) orangeButtonLayout.findViewById(R.id.GameBoard_5_Orange_Button);
orangeButtonLight = (ImageView) orangeButtonLayout.findViewById(R.id.GameBoard_5_Orange_Button_On);
forwardButton = (ImageView)statusbarLayout.findViewById(R.id.GameBoard_5_StatusBar_Forward_Button);
replayButton = (ImageView)statusbarLayout.findViewById(R.id.GameBoard_5_StatusBar_Replay_Button);
pauseButton = (ImageView)statusbarLayout.findViewById(R.id.GameBoard_5_StatusBar_Pause_Button);
resumeButton = (TextView)pauseMenuLayout.findViewById(R.id.GameBoard_5_Pause_Menu_Resume_Game_Button);
fxRadioGroup = (RadioGroup)this.findViewById(R.id.GameBoard_5_Pause_Menu_FxGroup);
fxOffRadioButton = (RadioButton)fxRadioGroup.findViewById(R.id.GameBoard_5_Pause_Menu_Fx_Off);
fxOnRadioButton = (RadioButton)fxRadioGroup.findViewById(R.id.GameBoard_5_Pause_Menu_Fx_On);
/*according to the Android JAVA Doc, the code below increases performance:
"Setting a solid background color for the drawing cache's bitmaps will improve performance and memory usage.
Note, though that this should only be used if this view will always be drawn on top of a solid color."
*/
redButtonLight.setDrawingCacheBackgroundColor(Color.BLACK);
yellowButtonLight.setDrawingCacheBackgroundColor(Color.BLACK);
blueButtonLight.setDrawingCacheBackgroundColor(Color.BLACK);
greenButtonLight.setDrawingCacheBackgroundColor(Color.BLACK);
//set onTouch/onClick listeners
redButtonTop.setOnTouchListener(this);
yellowButtonTop.setOnTouchListener(this);
blueButtonTop.setOnTouchListener(this);
greenButtonTop.setOnTouchListener(this);
orangeButtonTop.setOnTouchListener(this);
forwardButton.setOnClickListener(this);
replayButton.setOnClickListener(this);
pauseButton.setOnClickListener(this);
resumeButton.setOnClickListener(this);
fxOffRadioButton.setOnClickListener(this);
fxOnRadioButton.setOnClickListener(this);
//init other things****************/
levelTextBox = (TextView)statusbarLayout.findViewById(R.id.GameBoard_5_StatusBar_Level_Text);
buttonsActive = false;
statusbarActive = false;
showingPattern = false;
isGameOver = false;
replayResetUsed = false;
soundFxOn = Utilities.loadSettings(this).isSoundOn();
randomGen = new Random(System.currentTimeMillis());
lightedButtonMap = new HashMap<Integer, ImageView>(5);
lightedButtonMap.put(1, redButtonLight);
lightedButtonMap.put(2, yellowButtonLight);
lightedButtonMap.put(3, blueButtonLight);
lightedButtonMap.put(4, greenButtonLight);
lightedButtonMap.put(5, orangeButtonLight);
//create gameboard sound caches... one for this, and one for the pattern player
soundCache = new HashMap<ImageView, MediaPlayer>(5);
patternPlayerSoundCache = new HashMap<ImageView, MediaPlayer>(5);
MediaPlayer currentMP = MediaPlayer.create(this, R.raw.fx_430);
currentMP.setLooping(true);
currentMP.setVolume(LEFT_VOLUME,RIGHT_VOLUME);
soundCache.put(redButtonTop, currentMP);
patternPlayerSoundCache.put(redButtonLight, currentMP);
currentMP = MediaPlayer.create(this, R.raw.fx_530);
currentMP.setLooping(true);
currentMP.setVolume(LEFT_VOLUME,RIGHT_VOLUME);
soundCache.put(yellowButtonTop, currentMP);
patternPlayerSoundCache.put(yellowButtonLight, currentMP);
currentMP = MediaPlayer.create(this, R.raw.fx_630);
currentMP.setLooping(true);
currentMP.setVolume(LEFT_VOLUME,RIGHT_VOLUME);
soundCache.put(blueButtonTop, currentMP);
patternPlayerSoundCache.put(blueButtonLight, currentMP);
currentMP = MediaPlayer.create(this, R.raw.fx_730);
currentMP.setLooping(true);
currentMP.setVolume(LEFT_VOLUME,RIGHT_VOLUME);
soundCache.put(greenButtonTop, currentMP);
patternPlayerSoundCache.put(greenButtonLight, currentMP);
currentMP = MediaPlayer.create(this, R.raw.fx_830);
currentMP.setLooping(true);
currentMP.setVolume(LEFT_VOLUME,RIGHT_VOLUME);
soundCache.put(orangeButtonTop, currentMP);
patternPlayerSoundCache.put(orangeButtonLight, currentMP);
myCountdownTimer = new CountdownTimer(countdownTimerText, new Handler());
//buttonLighter = new Handler();
myPatternPlayer = new PatternPlayer(Utilities.loadSettings(this).shouldSpeedIncrease(),
lightedButtonMap,patternPlayerSoundCache, this, new Handler());
myPattern = myPatternPlayer.getPattern();
myCountdownTimer.setTimerListener(this);
}
/***
* this is only called when the activity is first initialized/created
*/
private void startFirstRun()
{
//start button animations
redButtonLayout.startAnimation(animationCache[0]);
yellowButtonLayout.startAnimation(animationCache[0]);
blueButtonLayout.startAnimation(animationCache[0]);
greenButtonLayout.startAnimation(animationCache[0]);
orangeButtonLayout.startAnimation(animationCache[0]);
//start the countdown timer... delay execution for 1 sec.
new Handler().postDelayed(new Runnable() {
@Override
public void run()
{
GameBoard5.this.countdownTimerText.setVisibility(View.VISIBLE);
GameBoard5.this.myCountdownTimer.start();
}
}, 1000);
}
/***
* this starts the game after a savegame is loaded
*/
private void startFromSavedGame(boolean wasLevelCompleted)
{
//disable buttons
buttonsActive = false;
statusbarActive = false;
levelTextBox.setText(String.format("%03d",myPattern.size()));
if(wasLevelCompleted)
{
this.beginNewLevel();
return;
}
//restart the countdown timer... delay execution for 1 sec.
new Handler().postDelayed(new Runnable() {
@Override
public void run()
{
GameBoard5.this.countdownTimerText.setVisibility(View.VISIBLE);
GameBoard5.this.myCountdownTimer.restart();
}
}, 1000);
}
/***
* this starts the countdown timer at the beginning of levels != 1
*/
private void beginNewLevel()
{
//disable buttons
buttonsActive = false;
statusbarActive = false;
//increase the level number
final int currentLevel = Integer.parseInt(levelTextBox.getText().toString());
levelTextBox.setText(String.format("%03d",(currentLevel+1)));
//restart the countdown timer... delay execution for 1 sec.
new Handler().postDelayed(new Runnable() {
@Override
public void run()
{
GameBoard5.this.countdownTimerText.setVisibility(View.VISIBLE);
GameBoard5.this.myCountdownTimer.restart();
}
}, 1000);
}
@Override
public void onCountdownFinished()
{
countdownTimerText.setVisibility(View.GONE);
//start showing the pattern... delay for 500 ms
new Handler().postDelayed(new Runnable() {
@Override
public void run()
{
GameBoard5.this.showThePattern();
}
}, 500);
}
/***
* Starts the display of the lighted button sequence. When finished, the user
* is allowed to try and repeat the pattern.
*/
private void showThePattern()
{
showingPattern = true;
if(mySaveGame!=null)
{
if(!mySaveGame.getIsLevelComplete())
{
//just show the pattern
myPatternPlayer.playPattern(false);
mySaveGame = null;//important... so this code block isn't called again
return;
}
}
//add new button to the pattern
final int nextButton = this.getNextRandomNumber(1, 5);
//System.out.println(""+nextButton);
myPatternPlayer.add(nextButton);
myPatternPlayer.playPattern(false);
}
/***
* starts the portion of the game that allows for user input of the pattern guess
*/
public void startGame()
{
//make the replayButton visible every 5 turns if it isn't already
if(Integer.parseInt(levelTextBox.getText().toString())%5 == 1 && replayButton.getVisibility()==View.INVISIBLE && !replayResetUsed)
{
replayButton.setVisibility(View.VISIBLE);
replayResetUsed = true;
}
currentPatternIndex = 0;
//set the buttons active for user input
buttonsActive = true;
statusbarActive = true;
showingPattern = false;
}
/**
* ends the current game and allows the use to go back to the main menu
*/
private void gameOver()
{
Utilities.deleteSavegame(this);
Utilities.addHighScore(this, Utilities.GAME_TYPE_5_BUTTON, Integer.parseInt(levelTextBox.getText().toString()));
buttonsActive = false;
isGameOver = true;
failLayout.setVisibility(View.VISIBLE);
forwardButton.setVisibility(View.VISIBLE);
}
public boolean isSoundOn()
{
return soundFxOn;
}
/**
* Checks the if the user has entered the entire pattern
* @return true if the currentPatternIndex == the myPattern.size()... false otherwise
*/
private boolean isLevelComplete()
{
return (currentPatternIndex == myPattern.size());
}
/***
* The user has completed a level. This shows the appropriate message and sets conditions for the next level.
* The program will now wait for the user to touch the => icon to continue.
*/
private void levelUp()
{
System.gc();//good time to free up resources
buttonsActive = false;
successLayout.setVisibility(View.VISIBLE);
forwardButton.setVisibility(View.VISIBLE);
}
/***
* Returns a random number in the passed integer range
* @param min
* @param max
* @return an int between [min, max] (inclusive)
*/
private int getNextRandomNumber(int min, int max)
{
return (min + (int)(randomGen.nextDouble() * ((max - min) + 1)));
}
/***************Section Below Handles Touch/Click/Keypress Events (User Input)*******************/
@Override
public boolean onTouch(View v, MotionEvent e)
{
if(e.getAction() == MotionEvent.ACTION_DOWN && buttonsActive)
{
//play tones
if(soundFxOn && (v==redButtonTop || v==yellowButtonTop || v==blueButtonTop || v==greenButtonTop || v==orangeButtonTop))
{
soundCache.get(v).start();
}
if(v == redButtonTop)
{
redButtonLight.setVisibility(View.VISIBLE);
}
else if(v == yellowButtonTop)
{
yellowButtonLight.setVisibility(View.VISIBLE);
}
else if(v == blueButtonTop)
{
blueButtonLight.setVisibility(View.VISIBLE);
}
else if(v == greenButtonTop)
{
greenButtonLight.setVisibility(View.VISIBLE);
}
else if(v == orangeButtonTop)
{
orangeButtonLight.setVisibility(View.VISIBLE);
}
return true;
}
else if(e.getAction() == MotionEvent.ACTION_UP && buttonsActive)
{
//stop the tone
if(soundFxOn && (v==redButtonTop || v==yellowButtonTop || v==blueButtonTop || v==greenButtonTop || v==orangeButtonTop))
{
soundCache.get(v).pause();
}
if(v == redButtonTop)
{
redButtonLight.setVisibility(View.INVISIBLE);
//check against the pattern
if(this.validateInput(1))
{
//check for level end
if(this.isLevelComplete())
{
//level up
this.levelUp();
}
}
else
{
//end the game
this.gameOver();
}
}
else if(v == yellowButtonTop)
{
yellowButtonLight.setVisibility(View.INVISIBLE);
//check against the pattern
if(this.validateInput(2))
{
//check for level end
if(this.isLevelComplete())
{
//level up
this.levelUp();
}
}
else
{
//end the game
this.gameOver();
}
}
else if(v == blueButtonTop)
{
blueButtonLight.setVisibility(View.INVISIBLE);
//check against the pattern
if(this.validateInput(3))
{
//check for level end
if(this.isLevelComplete())
{
//level up
this.levelUp();
}
}
else
{
//end the game
this.gameOver();
}
}
else if(v == greenButtonTop)
{
greenButtonLight.setVisibility(View.INVISIBLE);
//check against the pattern
if(this.validateInput(4))
{
//check for level end
if(this.isLevelComplete())
{
//level up
this.levelUp();
}
}
else
{
//end the game
this.gameOver();
}
}
else if(v == orangeButtonTop)
{
orangeButtonLight.setVisibility(View.INVISIBLE);
//check against the pattern
if(this.validateInput(5))
{
//check for level end
if(this.isLevelComplete())
{
//level up
this.levelUp();
}
}
else
{
//end the game
this.gameOver();
}
}
return true;
}
return false;
}
/***
* Validates the button press against the stored pattern
* @param buttonPressed
* @return
*/
private boolean validateInput(int buttonPressed)
{
final int buttonExpected = myPattern.get(currentPatternIndex);
//System.out.println("Expected: "+buttonExpected+" Entered: "+buttonPressed);
if(buttonExpected == buttonPressed)
{
currentPatternIndex++;
return true;
}
//else
return false;
}
@Override
public void onClick(View v)
{
//check for clicks
//can use == instead of .equals(...)
if(v == resumeButton)
{
buttonsActive = true;
statusbarActive = true;
pauseMenuLayout.setVisibility(View.GONE);
}
else if(v==fxOffRadioButton)
{
if(fxOffRadioButton.isChecked())
{
soundFxOn = false;
}
}
else if(v==fxOnRadioButton)
{
if(fxOnRadioButton.isChecked())
{
soundFxOn = true;
}
}
else if(forwardButton == v && statusbarActive)
{
if(!isGameOver)
{
forwardButton.setVisibility(View.INVISIBLE);
successLayout.setVisibility(View.GONE);
this.beginNewLevel();
}
else
{
//return to the main menu
Intent myIntent = new Intent(this, Main.class);
//this.startActivityForResult(myIntent, 1);
this.startActivity(myIntent);
this.finish();
}
}
else if(v == replayButton && statusbarActive && !showingPattern &&
this.successLayout.getVisibility()!=View.VISIBLE && this.failLayout.getVisibility()!=View.VISIBLE)
{
statusbarActive = false;
buttonsActive = false;
myPatternPlayer.playPattern(true);//repeat, so don't decrease delay/display times
replayButton.setVisibility(View.INVISIBLE);
}
else if(v == pauseButton && statusbarActive)
{
buttonsActive = false;
statusbarActive = false;
pauseMenuLayout.startAnimation(animationCache[1]);
if(soundFxOn)
{
fxOnRadioButton.setChecked(true);
}
else
{
fxOffRadioButton.setChecked(true);
}
pauseMenuLayout.setVisibility(View.VISIBLE);
}
}
//intercept the back and menu key presses
@Override
public boolean onKeyDown(int keyCode, KeyEvent event)
{
if(keyCode == KeyEvent.KEYCODE_BACK)
{
if(pauseMenuLayout.getVisibility() == View.VISIBLE)
{
resumeButton.performClick();
return true;
}
}
else if(keyCode == KeyEvent.KEYCODE_MENU && buttonsActive)
{
pauseButton.performClick();
return true;
}
//else
return super.onKeyDown(keyCode, event);
}
/********************************************************************************************/
@Override
protected void onPause()
{
//System.out.println("onPause");
if(!this.isGameOver)
{
Utilities.saveCurrentGame(this, Utilities.GAME_TYPE_5_BUTTON, myPattern, this.isLevelComplete());
}
//stop any playing sounds in the patternplayer
myPatternPlayer.cancelPlayback();
//release resources for the mediaplayers
try
{
for(MediaPlayer mp : soundCache.values())
{
if(mp.isPlaying())
{
mp.stop();
}
mp.release();
}
}
catch (Exception e)
{
//nothing
}
super.onPause();
//close the app
this.finish();
}
@Override
protected void onResume()
{
//System.out.println("onResume");
mySaveGame = Utilities.loadSavegame(this);
//check the savegame
if(mySaveGame!=null)
{
myPatternPlayer.setPattern(mySaveGame.getPattern());
myPattern = myPatternPlayer.getPattern();
this.startFromSavedGame(mySaveGame.getIsLevelComplete());
}
else
{
//run the 1st-run components
this.startFirstRun();
}
super.onResume();
}
}
|