/* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. Copyright 2015 Jose A. Gonzalez Cervera Copyright 2015 Juan A. Fernández Sánchez */ package butterflydevs.brainstudio; import android.app.AlertDialog; import android.content.DialogInterface; import android.content.Intent; import android.graphics.Color; import android.os.Bundle; import android.os.CountDownTimer; import android.support.v7.app.ActionBarActivity; import android.view.Gravity; import android.view.KeyEvent; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.view.WindowManager; import android.view.animation.Animation; import android.view.animation.AnimationUtils; import android.widget.Button; import android.widget.LinearLayout; import com.akexorcist.roundcornerprogressbar.RoundCornerProgressBar; import com.facebook.AppEventsLogger; import com.github.premnirmal.textcounter.CounterView; import com.github.premnirmal.textcounter.Formatter; import java.text.NumberFormat; import java.util.Locale; import java.util.Random; import butterflydevs.brainstudio.extras.Jugada; import butterflydevs.brainstudio.extras.MySQLiteHelper; import butterflydevs.brainstudio.extras.matrixHelper; import butterflydevs.brainstudio.extras.utilidades; /** * Clase para el Juego1 en todos sus niveles. Actualmente sólo 3. */ public class Juego1niveln extends ActionBarActivity { //Constantes que definen el tamaño del grid private int numFilas = 6; private int numColumnas = 4; //Variables de elementos visuales que necesitan referenciación private RoundCornerProgressBar barraProgreso; private int progress2 = 100; private Button botonBack; private Button botonHelp; private boolean puedeMostrarBarra=true; //Matrices usadas en el juego: //Matriz aleatoria con el número de celdas a adescubrir creada por el matrixHelper private boolean matrizJugada[]; //Matriz que se inicializa a false private boolean matrizRespuesta[]; private int numCeldasActivadas = 0; private int numRepeticionActual; private int numRepeticionesMaximas; private int numMaximoCeldas; private float puntuacion; private int numGridsJugados; private int numCeldas = 2; //Variables para el reloj: private CountDownTimer countDownTimer; private CounterView counterView; private int time; private float timeNow; private int level; //Variables para la configuración del grid de botones en tiempo de ejecución //El tamaño de los botones, usado para el alto y el ancho. private int tamButtons = 120; //Para referenciar el layout grande donde van todos los layout que componen las filas private LinearLayout layoutGridBotones; //Filas del grid de botones: private LinearLayout[] filasLinearLayout; //Cada fila de botones es un linearLayout //Vector de botones (solo uno, no habra un vector por fila, para el procesamiento posterior es mejor tenerlos todos en un solo vector) private Button[] botones; Intent intent; //Colores String[] colores; int colorMarcado; int colorFondo; //Variables para las animaciones del grid. Animation animacion1, animacion2; public Juego1niveln() { time = 15; numRepeticionesMaximas = 4; numRepeticionActual = 1; numMaximoCeldas = 20; puntuacion = 0; numGridsJugados=0; } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_juego_1_nivel_n); //Con esta orden conseguimos hacer que no se muestre la ActionBar. getSupportActionBar().hide(); //Con esta hacemos que la barra de estado del teléfono no se vea y la actividad sea a pantalla completa. getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); colores= getResources().getStringArray(R.array.colores); //Obtenemos los datos que se le pasa a la actividad. intent=getIntent(); //Obtenemos la información del intent que nos evía la actividad que nos crea. level=intent.getIntExtra("nivel",0); System.out.println("recibiod de la actividad llamante: "+level); ajustarNivel(level); //Cargamos el fichero que define la animación 1 animacion1 = AnimationUtils.loadAnimation(this, R.anim.animacionbotongrid12); //Especificamos el comportamiento al empezar y al finalizar animacion1.setAnimationListener(new Animation.AnimationListener() { @Override public void onAnimationStart(Animation animation) { System.out.println("La animación empieza"); barraProgreso.setProgress(100f); updateProgressTwoColor(100f); } //Especificamos que ocurre cuando la animación1 termina @Override public void onAnimationEnd(Animation animation) { System.out.println("La animacion acaba"); //Cuando la animación 1 termina volvemos todos los botones transparentes. for (int i = 0; i < numFilas * numColumnas; i++) botones[i].setBackgroundColor(Color.TRANSPARENT); //Cuando la animacion 1 acaba se encarga de lanzar la animacion 2 for (int i = 0; i < numFilas * numColumnas; i++) botones[i].startAnimation(animacion2); puedeMostrarBarra=true; } @Override public void onAnimationRepeat(Animation animation) { } }); //Cargamos el fichero que define la animación 2, que se lanza al acabar la animación 1 animacion2 = AnimationUtils.loadAnimation(this, R.anim.animacionbotongrid12_2); //Especificamos el comportamiento al empezar y al finalizar animacion2.setAnimationListener(new Animation.AnimationListener() { @Override public void onAnimationStart(Animation animation) { System.out.println("La animación empieza"); //En la animación 2 volvemos todos los botones grises cuando empieza. for (int i = 0; i < numFilas * numColumnas; i++) botones[i].setBackgroundColor(getResources().getColor(R.color.darkgray)); } @Override public void onAnimationEnd(Animation animation) { System.out.println("La animacion acaba"); //Cuando la segunda animación termina el tiempo comienza a correr. countDownTimer.start(); //countDownTimer. } @Override public void onAnimationRepeat(Animation animation) { } }); /** * Error grave para resolver: * * Cuando el temporizador arranca queda funcionando aunque nos salgamos de la actividad porque pulsemos atrás * o porque nos salgamos por cualquier otro motivo. El problema está en que cuando el tiempo acaba (el * tiempo está ejecutándose en otra hebra se intenta destruir y no puede porque ha perdido la referencia * y devuelve un error muy feo. */ //Configuracion del temporizador. //Le pasamos al constructor la variable tiempo para ajustarlo a nuestro gusto. countDownTimer = new CountDownTimer(time*1000, 1000) { //Lo que hacemos en cada tick del reloj. public void onTick(long millisUntilFinished) { if(puedeMostrarBarra) //Evita mostrar la barra corriendo cuando no debe barraProgreso.setProgress(reglaTres((int)millisUntilFinished / 1000)); updateProgressTwoColor((int)millisUntilFinished / 1000); System.out.println("reloj:" + (int)millisUntilFinished / 1000); timeNow= millisUntilFinished; } //Comportamiento al acabarse el timepo. public void onFinish(){ barraProgreso.setProgress(0f); //updateProgressTwoColor(); finalizarPartida(); //Si el mensaje anterior queda ahí se añade muchisimas veces la puntuación otenida. } }; asociarElementosVista(); //Inicializamos el vector de filas. filasLinearLayout = new LinearLayout[numFilas]; //Inicializamos el vector de botones: botones = new Button[numFilas * numColumnas]; //Inicializamos los botones for (int i = 0; i < numFilas * numColumnas; i++) { //Inicializamos cada uno de los elementos del vector botones[i] = new Button(this); //Establecemos parametros de layout a cada uno: botones[i].setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT)); LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(tamButtons, tamButtons); params.setMargins(5, 5, 5, 5); botones[i].setLayoutParams(params); botones[i].setBackgroundColor(getResources().getColor(R.color.darkgray)); } //Inicializamos los LinearLayout (filas) for (int i = 0; i < numFilas; i++) { filasLinearLayout[i] = new LinearLayout(this); filasLinearLayout[i].setOrientation(LinearLayout.HORIZONTAL); filasLinearLayout[i].setGravity(Gravity.CENTER); } // prueba=new Button(this); //prueba.setText("prueba"); //prueba.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT)); //prueba.setWidth(50); //prueba.setHeight(50); //Asociamos el layout principal layoutGridBotones = (LinearLayout) findViewById(R.id.gridBotones); //Le especificamos una horientación layoutGridBotones.setOrientation(LinearLayout.VERTICAL); //Añadimos todos los layout de filas al layout principal for (int i = 0; i < numFilas; i++) layoutGridBotones.addView(filasLinearLayout[i]); //Añadimos un boto de prueba //filasLinearLayout[0].addView(botones[0]); //filasLinearLayout[1].addView(botones[1]); //filasLinearLayout es un vector de filas! //Añadimos los botones a los layouts. int numBoton = 0; for (int i = 0; i < numFilas; i++) //i sera el numero de fila for (int j = 0; j < numColumnas; j++) { filasLinearLayout[i].addView(botones[numBoton]); //no usamos numColumnas porque es 5 y tendriamos que reajustar numBoton++; } //Configuramos el comportamiento del grid de botones con un Listener específico. for (int i = 0; i < numFilas * numColumnas; i++) { System.out.println("Boton: " + i); botones[i].setOnClickListener(new MyListener(i)); } botonBack.setOnClickListener( new View.OnClickListener() { @Override public void onClick(View v) { //Para evitar errores con la variable de tiempo lo paramos: countDownTimer.cancel(); //Creamos el Intent Intent intent = new Intent(Juego1niveln.this, Juego1.class); //Iniciamos la nueva actividad startActivity(intent); } } ); botonHelp.setOnClickListener( new View.OnClickListener() { @Override public void onClick(View v) { //Paramos el cronómetro del juego para evitar problemas countDownTimer.cancel(); Intent intent = new Intent(Juego1niveln.this, Help.class); Bundle bundle = new Bundle(); bundle.putString("Zona_llamada","Juego"); bundle.putInt("Numero_zona", 1); //Introducimos la informacion en el intent para enviarsela a la actívity. intent.putExtras(bundle); startActivityForResult(intent, 1); } } ); //Hacemos transparente el fondo de la barra de progreso. barraProgreso.setBackgroundColor(Color.TRANSPARENT); utilidades.cargarColorFondo(this); } /** * Función de ajuste de nivel del juego. Es la más importante pués según configure las variables se configurará después * el aspecto y jugabilidad de todas los grids que se vayan creando. Tambien afecta a la fomra en la que se calcula * el porcentaje completado del juego. * @param level */ public void ajustarNivel(int level){ if(level==1){ //1º Establecemos el tamaño del grid numFilas=4; numColumnas=3; //Inicializamos la matriz matrizRespuesta = new boolean[numFilas * numColumnas]; //La inicializamos a false for(int i=0; i<numFilas*numColumnas; i++) matrizRespuesta[i]=false; //2º Establecemos el número máximo de celdas a preguntar numMaximoCeldas=6; //3º Ajustar el tamaño de los botones tamButtons = 150; }else if(level==2){ //1º Establecemos el tamaño del grid numFilas=6; numColumnas=4; //Inicializamos la matriz matrizRespuesta = new boolean[numFilas * numColumnas]; //La inicializamos a false for(int i=0; i<numFilas*numColumnas; i++) matrizRespuesta[i]=false; //2º Establecemos el número máximo de celdas a preguntar numMaximoCeldas=12; //3º Ajustar el tamaño de los botones tamButtons = 110; }else if(level==3){ //1º Establecemos el tamaño del grid numFilas=8; numColumnas=5; //Inicializamos la matriz matrizRespuesta = new boolean[numFilas * numColumnas]; //La inicializamos a false for(int i=0; i<numFilas*numColumnas; i++) matrizRespuesta[i]=false; //2º Establecemos el número máximo de celdas a preguntar numMaximoCeldas=20; //3º Ajustar el tamaño de los botones tamButtons = 80; } } public float reglaTres(int x){ return (x*100)/(time-1); } private void updateProgressTwoColor(float time ) { if(time <= 2) { barraProgreso.setProgressColor(getResources().getColor(R.color.custom_progress_red_progress)); } else if(time > 2 && time <= 6) { barraProgreso.setProgressColor(getResources().getColor(R.color.custom_progress_orange_progress)); } else if(time > 6) { barraProgreso.setProgressColor(getResources().getColor(R.color.custom_progress_green_progress)); } } public void asociarElementosVista(){ barraProgreso=(RoundCornerProgressBar)findViewById(R.id.progress_two); botonBack=(Button)findViewById(R.id.botonBack); botonHelp=(Button)findViewById(R.id.botonHelp); //CounterView es el texto de puntos que va aumentando counterView=(CounterView)findViewById(R.id.counter); counterView.setAutoFormat(false); counterView.setFormatter(new Formatter() { @Override public String format(String prefix, String suffix, float value) { return prefix + NumberFormat.getNumberInstance(Locale.US).format(value) + suffix; } }); counterView.setAutoStart(false); counterView.setStartValue(0); counterView.setEndValue(0); counterView.setIncrement(1f); // the amount the number increments at each time interval counterView.setTimeInterval(2); // the time interval (ms) at which the text changes counterView.setPrefix(""); counterView.setSuffix(""); counterView.start(); } /** * Función para animar el grid al entrar en la actívity */ public void animarGrid() { //Cargamos la animación "animacion1" a cada uno de los botones que componen el grid. for (int i = 0; i < numFilas * numColumnas; i++) botones[i].startAnimation(animacion1); } /** * Método que se ejecuta cuando la actividad se ha cargado y comienza a funcionar. */ @Override protected void onStart() { super.onStart(); //1º Obtenemos la matriz de la jugada que el jugador debe resolver con la clase matrixHelper matrizJugada = matrixHelper.obtenerMatrizJugada(numCeldas, numFilas, numColumnas); //2º Coloreamos los botones del grid según el contenido de la matriz de booleanos for (int i = 0; i < numFilas * numColumnas; i++) if (matrizJugada[i] == true) botones[i].setBackgroundColor(Color.parseColor(colores[colorMarcado])); else botones[i].setBackgroundColor(getResources().getColor(R.color.darkgray)); //3º Con los botones configurados como la matriz llamamos a animarGrid para que anime la visualización animarGrid(); } /** * Programación personalizada del comportamiento de los botones físicos del terminal. * @param keyCode * @param event * @return */ @Override public boolean onKeyDown(int keyCode, KeyEvent event){ //Si pulsamos el botón back nos devuelve a la pantalla principal!: if(keyCode== KeyEvent.KEYCODE_BACK){ //Al pulsar sobre el botón atrás físico del terminal cancelamos el tiempo para evitar problemas //De referencia después. countDownTimer.cancel(); //Despues de parar el tiempo salimos a la pantalla aterior. Intent intent = new Intent(Juego1niveln.this, Juego1.class); //Iniciamos la nueva actividad startActivity(intent); return true; } return super.onKeyDown(keyCode, event); } public void siguienteJugada() { nuevosColores(); /* *Dependiendo del estado de nivel se configura el grid de una manera u otra */ //Si se ha llegado al maximo numero de repeticiones para este numero de celdas se aumenta el numero de celdas. System.out.println("##JUGADA## Celdas: " + numCeldas + " Repeticiones: " + numRepeticionActual + " de máx " + numRepeticionesMaximas); if (numRepeticionActual == numRepeticionesMaximas) { System.out.println("pasando a 3 celdas"); numCeldas++; numRepeticionActual = 0; /* Numero de celdas se usara a continuacion apra configurar la matriz de la jugada (la que tiene que recordar el jugador) */ } if (numCeldas == numMaximoCeldas + 1) salirNivel(); //Ajuste de variables: //Cuando se acierta se reinicia el proceso. for (int i = 0; i < numFilas * numColumnas; i++) { matrizJugada[i] = false; matrizRespuesta[i] = false; } numCeldasActivadas = 0; //Obtenemos la matriz de la jugada que el jugador debe resolver matrizJugada = matrixHelper.obtenerMatrizJugada(numCeldas, numFilas, numColumnas); //Seteamos el grid visual con la matriz obtenida. for (int i = 0; i < numFilas * numColumnas; i++) if (matrizJugada[i] == true) botones[i].setBackgroundColor(Color.parseColor(colores[colorMarcado])); else botones[i].setBackgroundColor(getResources().getColor(R.color.darkgray)); //Ilumina el grid animarGrid(); //Aumentamos el valor de repeticion actual: numRepeticionActual++; //Calculamos los siguiente colores: } public void nuevosColores(){ /** * Para que funcione tienen que existir al menos dos colores en el array xml en colors.xml */ Random rnd = new Random(); colorMarcado=(int)(rnd.nextDouble() * 3 + 0); System.out.println("Color seleccionado "+colorMarcado); //this.colorFondo=Color.DKGRAY; } public void salirNivel() { //Avisar de que se ha acabado el juego y salir al panel de niveles. //¿Mostrar un fragment con la puntuación y y el porcentaje completado? new AlertDialog.Builder(this) .setTitle("TERMINADO") .setMessage("has llegado al final del nivel") .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { // continue with delete grabarDatosBD(); //Creamos el Intent Intent intent = new Intent(Juego1niveln.this, Juego1.class); //Iniciamos la nueva actividad startActivity(intent); } }) .setIcon(android.R.drawable.ic_dialog_alert) .show(); } public void calculaPuntuacion() { System.out.println("Tiempo al acabar: " + (float) timeNow / 1000); //Ajustamos el tiempo a segundos con un decimal: String tiempo = Float.toString((float) timeNow / 1000); if(tiempo.length()>=4) tiempo = tiempo.substring(0, 4); timeNow = Float.parseFloat(tiempo); counterView.setStartValue(puntuacion); counterView.setPrefix(""); counterView.setSuffix(""); puntuacion += timeNow * numCeldas; counterView.setEndValue(puntuacion); counterView.start(); System.out.println("Puntuacón : " + puntuacion); //Ponemos la puntuación en pantalla //textPuntos.setText(Float.toString(puntuacion)); //puntuacion=numCeldas* } public int calculaPorcentaje(){ int resultado; int gridsTotales=(numMaximoCeldas-1)*numRepeticionesMaximas; //Una regla de tres simple resultado=(int)(100*numGridsJugados)/gridsTotales; System.out.println("numGridJugados "+numGridsJugados); return resultado; } /** * Para grabar los datos en la base de datos cuando se acaba la partida */ public void grabarDatosBD(){ MySQLiteHelper db = new MySQLiteHelper(this); /* Realizamos la insercción en la base de datos. --> Estamos haciendo un redondeo de la puntuación (esto hay que modificarlo) */ //System.out.println("GRabando "+(int)puntuacion+" puntos "+calculaPorcentaje()+"%"); db.addJugada(new Jugada((int) puntuacion, calculaPorcentaje()), level,1); } public void finalizarPartida(){ mensajeFin(); } public void mensajeFin() { new AlertDialog.Builder(this) .setTitle("YOU ARE DEAD") .setMessage("Se te acabó el tiempo!") .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { // continue with delete grabarDatosBD(); //Creamos el Intent Intent intent = new Intent(Juego1niveln.this, Juego1.class); //Iniciamos la nueva actividad startActivity(intent); } }) .setIcon(android.R.drawable.ic_dialog_alert) .show(); } class MyListener implements Button.OnClickListener { private int numBoton; public MyListener(int numBoton) { this.numBoton = numBoton; } @Override public void onClick(View v) { //Acciones a realizar al pulsar sobre un botón: /*1º Cambiamos de color el boton en función de su estado y por consiguiente la matriz del jugador haciendo true la celda en caso de que estuviera a false y viceversa. */ if (matrizRespuesta[numBoton] == false) { //botones[numBoton].setBackgroundColor(getResources().getColor(R.color.kiwi)); botones[numBoton].setBackgroundColor(Color.parseColor(colores[colorMarcado])); matrizRespuesta[numBoton] = true; numCeldasActivadas++; } else { botones[numBoton].setBackgroundColor(getResources().getColor(R.color.darkgray)); matrizRespuesta[numBoton] = false; numCeldasActivadas--; } //2º Comparamos ambas matrices /* Lo ideal sería llevar el control del número de celdas pulsadas para no realizar comprobaciones antes de tiempo. */ System.out.println("Celdas Activadas: " + numCeldasActivadas); if (numCeldasActivadas == numCeldas) { System.out.println("Hay que comparar matrices"); //Se ha completado el grid if (matrixHelper.compruebaMatrices(matrizJugada, matrizRespuesta, numFilas, numColumnas)) { System.out.println("SUCESS"); //Aumentamos el número de grids que el jugador a superado. numGridsJugados++; barraProgreso.setProgress(100f); puedeMostrarBarra=false; //Se calcula la puntuación obtenida calculaPuntuacion(); //Se pasa a la siguiente jugada siguienteJugada(); } else System.out.println("FAIL"); } } } @Override protected void onPause() { super.onPause(); // Logs 'app deactivate' App Event. AppEventsLogger.deactivateApp(this); } }