Archivo de la etiqueta: apps hibridas

Tutorial de IONIC:Mini Juego de acertar n煤meros (actualizado)

En el siguiente enlace tienes el 铆ndice para acceder al resto de entradas de este tutorial:

Despu茅s de ver en el post anterior como modificar la plantilla de una p谩gina para simplemente mostrar el texto 鈥淗ola Mundo鈥, vamos a avanzar un poco m谩s en nuestro aprendizaje y vamos a programar nuestra primera aplicaci贸n interactiva.

Se trata de un simple juego de acertar el n煤mero secreto. La aplicaci贸n crear谩 un n煤mero aleatorio que nosotros debemos adivinar.

Por primera vez vamos a programar con Ionic. Por el camino aprenderemos conceptos como Data Binding, que nos permite actualizar valores entre el html y el controlador y recoger las acciones del usuario como聽 pulsar un bot贸n.

Bien, sin m谩s pre谩mbulos聽 vamos a empezar:

Vamos a crear un nuevo proyecto Ionic que en este caso le vamos a llamar adivina: Abrimos el terminal o consola de comandos y situ谩ndonos en la carpeta donde queremos crear nuestro proyecto escribimos:

ionic start adivina blank

 

Seleccionamos Angular como framework y esperamos a que se terminen de instalar los paquetes.

Nos situamos dentro de la carpeta del proyecto de acabamos de crear y聽una vez dentro ejecutamos ionic serve para ver en el navegador los cambios que vayamos haciendo en nuestra aplicaci贸n:

 ionic serve -l

 

Recuerda que si utilizas la opci贸n -l con ionic serve puedes visualizar como queda la app en todas las plataformas, la primera vez que ejecutes el comando en un proyecto nuevo te pedir谩 que instales @ionic/lab.

Ahora abrimos la carpeta del proyecto que acabamos de crear en el editor, entramos en src/app/home聽y abrimos el archivo home.page.html.

Editamos su contenido para que quede de la siguiente manera:

<ion-header>
  <ion-toolbar>
    <ion-title>
      Adivina el n煤mero secreto
    </ion-title>
  </ion-toolbar>
</ion-header>
 
<ion-content>
  <div class="ion-padding">
    <ion-input type="number" min="1" max="100" [(ngModel)]="num" placeholder="Introduce un n煤mero del 1 al 100"></ion-input>
    <p>El n煤mero secreto es {{ mayorMenor }} {{ num }}</p>
    <ion-button expand="block" (click)="compruebaNumero()">Adivina</ion-button>     
  </div>
</ion-content>

 

Si nunca antes has programado en angular ni en ionic es posible que el c贸digo te resulte extra帽o, no te preocupes, ahora vamos a ver lo que es cada cosa, si por el contrario ya has programado en angular o en versiones anteriores de ionic es probable este c贸digo te resulte familiar.

Tenemos una plantilla b谩sica de una p谩gina con ion-header, ion-navbar y ion-title donde hemos puesto el t铆tulo de nuestra aplicaci贸n 鈥淎divina el n煤mero secreto鈥. Hasta aqu铆 ninguna novedad con lo que ya hab铆amos visto en el cap铆tulo anterior.

Dentro de ion-content que como sabemos es donde va el contenido de la p谩gina tenemos un div al que le aplicamos la clase ion-padding que deja un espacio entre el borde de la pantalla y el contenido dentro de este div es donde est谩 lo interesante:

<ion-input type="number" min="1" max="100" [(ngModel)]="num" placeholder="Introduce un n煤mero del 1 al 100"></ion-input>


Primero tenemos un
ion-input que es muy parecido a un input de html, le decimos que sea de tipo number, le ponemos un rango m铆nimo a 1 y m谩ximo a 100.

El siguiente par谩metro [(ngModel)] es el encargado de hacer el Data Binding entre el valor del input y una variable llamada num que estar谩 definida como luego veremos en el controlador de la p谩gina. Este es un Data Binding bidireccional ya que si se introduce un valor en el input autom谩ticamente este ser谩 reflejado en la variable del controlador, del mismo modo si alg煤n proceso cambia el valor de esta variable en el controlador 茅ste autom谩ticamente aparecer谩 reflejado como valor del input.聽

Por 煤ltimo el input tiene un placeholder indicando que se introduzca un valor entre 1 y 100.

La siguiente l铆nea es un p谩rrafo que contiene lo siguiente:

聽<p>El n煤mero secreto es {{ mayorMenor }} {{ num }}</p>

Si ya conoces ionic o angular sabes de qu茅 se trata. En este caso con las dobles llaves 鈥渰{ }}鈥澛 hacemos un Data Binding unidireccional, mayorMenor es una variable que estar谩 definida en el controlador y con las dobles llaves muestra su valor.聽

La variable contendr谩 el texto 鈥渕ayor que鈥 en caso de que el n煤mero secreto sea mayor al introducido, 鈥渕enor que鈥 en caso de ser menor e 鈥渋gual a鈥 en caso de ser igual.

En las 煤ltimas llaves mostramos el valor de la variable num, veremos c贸mo al introducir un n煤mero este se actualiza autom谩ticamente.

Por 煤ltimo tenemos un bot贸n para comprobar si el n煤mero introducido coincide con el n煤mero secreto:

<ion-button expand=”block” (click)=”compruebaNumero()”>Adivina</ion-button>

En la documentaci贸n oficial de ionic pod茅is ver m谩s sobre c贸mo crear distintos tipos de botones con ionic:https://ionicframework.com/docs/api/button

De momento esto es todo lo que necesitamos en la plantilla de nuestro juego.

Ahora necesitamos programar el comportamiento en el controlador de la p谩gina.

Si abrimos el archivo home.page.ts que se genera autom谩ticamente al crear un proyecto en blanco veremos el siguiente c贸digo:

import { Component } from '@angular/core';

@Component({
  selector: 'app-home',
  templateUrl: 'home.page.html',
  styleUrls: ['home.page.scss'],
})
export class HomePage {

  constructor() {}

}

 

Este c贸digo esta es typeScript. Como ya hemos comentado TypeScript permite utilizar elementos de las 煤ltimas versiones del est谩ndar ECMAscript aunque todav铆a no est茅n implementadas en el navegador que estemos utilizando. Tambi茅n nos permite utilizar variables tipadas.

Como hemos comentado anteriormente con Ionic vamos a utilizar Angular que a su vez utiliza TypeScript, as铆 que es muy beneficioso conocer Angular y typescript.

Aqu铆 vamos a explicar a groso modo las cuestiones m谩s importantes para poder desenvolvernos con ionic pero para saber m谩s sobre Angular y sacarle el m谩ximo pod茅is encontrar en la red muchos recursos para aprender Angular.

Analicemos el c贸digo de home.page.ts:

Lo primero que vemos es una l铆nea import:

import { Component } from ‘@angular/core’;

Import se utiliza para importar m贸dulos que contienen librer铆as y clases para poder utilizarlas en nuestro proyecto. Podemos importar m贸dulos propios de Ionic que ya se incorporan al crear un proyecto, librer铆as de Angular, librer铆as de terceros que podemos instalar o nuestras propias聽 librer铆as.

En este caso se importa el elemento Component de @angular/core.

Las p谩ginas son componentes de Angular, por eso necesitamos importar Component.

Despu茅s vemos el siguiente c贸digo:

@Component({
  selector: 'app-home',
  templateUrl: 'home.page.html',
  styleUrls: ['home.page.scss'],
}) 

 

@Component es un decorador de Angular. Angular usa los decoradores para registrar un componente.

Los decoradores empiezan con @.

Los decoradores se colocan antes de la clase y definen c贸mo se va a comportar esta.

Existen los siguientes聽 decoradores:

  • @Component
  • @Injectable
  • @Pipe
  • @Directive

De momento nos interesa @Component.

En el c贸digo vemos que @Component contiene un objeto con dos atributos, selector:鈥檃pp-home鈥, que es el selector que se va a aplicar a la p谩gina,聽 templateUrl:鈥檋ome.page.html鈥 que es la plantilla html que va a renderizar la p谩gina y styleUrls: [鈥榟ome.page.scss鈥橾 donde se indica d贸nde se encuentran los estilos que se van a aplicar al componente, es decir,聽 en este caso a la p谩gina.

Por 煤ltimo se exporta una clase llamada HomePage:

export class HomePage {

  constructor() {}

}

 

Podemos a帽adir a la clase un constructor en caso de que necesitemos iniciar atributos de la clase, inyectar dependencias o realizar alguna operaci贸n en el momento de crear la clase, en este ejemplo no lo vamos a necesitar, lo veremos m谩s adelante en otros ejemplos.

En TypeScript la creaci贸n de clases es muy similar a c贸mo ser铆a en otros lenguajes de programaci贸n orientado a objetos como Java.

Todos los datos que se muestran en la plantilla y todas las funciones a las que se llame por ejemplo al hacer clic en un bot贸n deben formar parte de la clase HomePage que es el controlador de la p谩gina.

Como ya hemos visto en la plantilla home.page.html utilizamos [(ngModel)]=鈥漬um鈥 para recoger en la variable num el valor que se introduzca en el campo input, tambi茅n mostramos otra variable llamada mayorMenor que indicar谩聽 si el n煤mero introducido es mayor o menor que el n煤mero que hay que adivinar y mostramos la variable num que se actualizar谩 instant谩neamente al introducir un n煤mero.

<ion-input type="number" min="1" max="100" [(ngModel)]="num" placeholder="Introduce un n煤mero del 1 al 100"></ion-input>
<p>El n煤mero secreto es {{ mayorMenor }} {{ num }}</p>


Por lo tanto estas variables deben de estar definidas en el controlador dentro de la clase
HomePage del archivo home.page.ts:

import { Component } from '@angular/core';
 
@Component({
 selector: 'app-home',
 templateUrl: 'home.page.html',
 styleUrls: ['home.page.scss'],
})
export class HomePage {
 
 num:number;
 mayorMenor = '...';
 
  constructor() {}
 
}

 

C贸mo podemos observar para definir una variable ponemos el nombre de la variable y seguido de dos puntos 鈥:鈥 el tipo de valor que va a contener. Si lo deseamos podemos inicializar la variable con un valor en el momento de declararla.聽

En este caso num es de tipo number y mayorMenor de tipo string聽 aunque no es necesario ponerlo ya que al inicializarla con una cadena de texto autom谩ticamente se le asigna el tipo string.

La variable mayorMenor va a contener un texto con la palabra 鈥淢ayor鈥, 鈥淢enor鈥 o 鈥淚gual鈥 seg煤n sea el caso. Inicializamos la variable mayorMenor con tres puntos suspensivos 鈥溾︹.

Los tipos primitivos聽 de variable que podemos definir son:

  • number (Num茅rico).
  • string (cadenas de texto).
  • boolean (Booleano: true o false).
  • any (cualquier tipo).
  • Array.

Tambi茅n vamos a necesitar otra variable que contenga el n煤mero secreto que debemos adivinar, le vamos a llamar numSecret y c贸mo valor le vamos a asignar la respuesta a la llamada a una funci贸n llamada numAleatorio que crearemos a continuaci贸n.

Vamos a definir la variable numSecret de tipo number debajo de las dos variables anteriores:

numSecret: number = this.numAleatorio(0,100);

 

Hacemos referencia a la聽 funci贸n numAleatorio con this porque va a ser un m茅todo de la propia clase.

Ahora vamos a聽 crear la funci贸n numAleatorio que como su nombre indica nos devolver谩 un n煤mero aleatorio entre dos n煤meros:

numAleatorio(a,b)
{
    return Math.round(Math.random() * (b - a) + parseInt(a, 10));
}

 

Esta funci贸n recibe como par谩metros dos valores que ser谩n el rango m铆nimo y el m谩ximo para el n煤mero aleatorio, es este caso le estamos pasando 0 y 100 por lo que obtendremos un n煤mero aleatorio entre 0 y 100.

Por 煤ltimo vamos a crear la funci贸n compruebaNumero que se llama al pulsar el bot贸n Adivina que en la parte html como recordar谩s lo hemos definido as铆:

<ion-button expand="block" (click)="compruebaNumero()">Adivina</ion-button>

 

Y ahora en home.page.ts definimos la funci贸n dentro de la clase HomePage:

compruebaNumero(){
    if(this.num)
    {
      if(this.numSecret < this.num)
      {
        this.mayorMenor = 'menor que';
      }
      else if(this.numSecret > this.num)
      {
        this.mayorMenor = 'mayor que';
      }
      else{
        this.mayorMenor = '';
      }
    }
  }

 

Esta funci贸n compara el n煤mero secreto que est谩 contenido en la variable numSecret con el n煤mero introducido por el usuario que se aloja en la variable num y le asigna a la variable mayorMenor el texto 鈥渕enor que鈥, 鈥渕ayor que鈥 o 鈥渋gual a鈥 en funci贸n de si es menor, mayor o igual que esta.

Observa que debemos utilizar this para las variables ya que son atributos de la propia clase.

El c贸digo completo de home.page.ts quedar谩 de esta manera:

import { Component } from '@angular/core';
 
@Component({
  selector: 'app-home',
  templateUrl: 'home.page.html',
  styleUrls: ['home.page.scss'],
})
export class HomePage {
 
  num: number;
  mayorMenor = '...';
  numSecret: number = this.numAleatorio(0,100);
 
  constructor() {}
 
  numAleatorio(a, b) {
    return Math.round(Math.random() * (b - a) + parseInt(a, 10));
  }
 
  compruebaNumero(){
    if(this.num)
    {
      if(this.numSecret < this.num)
      {
        this.mayorMenor = 'menor que';
      }
      else if(this.numSecret > this.num)
      {
        this.mayorMenor = 'mayor que';
      }
      else{
        this.mayorMenor = '';
      }
    }
  }
}

 

Ahora si lo ejecutamos en el navegador con ionic serve -l (si no lo ten铆as ya en marcha), podemos ver un campo para introducir un n煤mero, y debajo un texto que dice 鈥渆l n煤mero secreto es 鈥 鈥, en estos momentos聽 no hay introducido ning煤n n煤mero por lo que aparecen los puntos suspensivos.

Si introducimos un n煤mero vemos que autom谩ticamente en el texto aparece ese n煤mero el mismo tiempo que lo escribimos. Eso es porque estamos realizando un Data Binding con la variable num. Al utilizar [(ngModel)]=鈥漬um鈥 en el campo input le estamos indicando que la variable coja el valor que introducimos en el input y lo refresque autom谩ticamente en todos los sitios donde se utilice, por ejemplo en el texto de debajo.Lo mismo ocurre si cambiamos el valor de la variable desde el c贸digo.

Por 煤ltimos si pulsamos el bot贸n adivina obtendremos algo como esto:

Al pulsar el bot贸n se ha ejecutado la funci贸n compruebaNumero(), dentro de la funci贸n se ha comprobado que el n煤mero secreto es mayor a 12 por lo que a la variable mayorMenor se le asigna el texto 鈥渕ayor que鈥.

Cuando acertemos el n煤mero secreto el texto dir谩 que el n煤mero secreto es el n煤mero introducido. Esto es un poco soso, vamos a hacer algunos cambios para que cuando acertemos el n煤mero nos muestre un mensaje felicit谩ndonos por haber acertado.

Este mensaje lo ponemos en la plantilla html pero solo se debe mostrar cuando se cumpla una condici贸n y es que la variable mayorMenor no contenga ning煤n texto, eso ocurre cuando hemos acertado ya que si el n煤mero introducido no es ni mayor ni menor, es decir que es es igual al n煤mero secreto hacemos la siguiente asignaci贸n this.mayorMenor = ”.

Vamos a a帽adir lo siguiente en home.page.html justo antes del bot贸n 鈥淎divina鈥:

<ion-card *ngIf="mayorMenor==''">
  <ion-card-header>
  隆隆隆Enhorabuena!!!
</ion-card-header>
<ion-card-content>
    Has acertado, el n煤mero secreto es el {{ num }}
</ion-card-content>
</ion-card>

 

Aprovecho la ocasi贸n para introducir otro componente de ionic: ion-card, las cards o 鈥渢arjetas鈥 son componentes que muestran la informaci贸n en un recuadro. Como vemos dentro contiene otros dos componentes <ion-card-header> y <ion-card-content>, Como habr谩s adivinado el primero permite mostrar una cabecera dentro de la tarjeta y el segundo el contenido que deseemos.

En la documentaci贸n oficial de ionic pod茅is ver todas las posibilidades que tiene ion-card: https://ionicframework.com/docs/v2/components/#cards

Queremos que est谩 card se muestre solo cuando la variable de nuestro controlador mayorMenor contenga una cadena vac铆a despu茅s de hacer la comprobaci贸n.

Aqu铆 entra en juego la directiva condicional *ngIf:

<ion-card *ngIf=“mayorMenor==””>

La directiva *ngIf es una directiva estructural, lo que significa que nos permite alterar el DOM (Document Object Model), estas directivas llevan un asterisco 鈥*鈥 delante.

Con *ngIf le estamos indicando que el elemento donde se encuentra, ion-card en este caso, solo se muestre si se cumple la condici贸n que tiene definida entre las dobles comillas. En este caso le estamos diciendo que solo se muestre el elemento ion-card cuando mayorMenor==鈥欌.

Sabiendo esto vamos a darle otra vuelta de tuerca m谩s y vamos a a帽adir un bot贸n para volver a jugar una vez que hemos acertado, este bot贸n llamar谩 a una funci贸n para volver a generar un nuevo n煤mero aleatorio y reiniciar谩 las variables para que se oculte el ion-card. Este bot贸n debe permanecer oculto hasta que hayamos acertado, y cuando se muestra debe ocultarse el bot贸n Adivina para que no podamos pulsarlo despu茅s de haber adivinado el n煤mero hasta que empecemos una nueva partida.

Editamos home.page.html y a帽adimos *ngIf al bot贸n Adivina para que solo se聽 muestre cuando no hemos acertado el n煤mero:

<ion-button *ngIf="mayorMenor!=''" expand="block" (click)="compruebaNumero()">Adivina</ion-button>

 

Ahora a帽adimos el bot贸n 鈥淰olver a Jugar鈥 justo despu茅s del de Adivina en home.page.html:

<ion-button *ngIf="mayorMenor==''" expand="block" (click)="reinicia()">Volver a Jugar</ion-button>

 

Con *ngIf indicamos que solo se muestre cuando hayamos acertado el n煤mero, es decir cuando la variable mayorMenor est茅 vac铆a, y en el evento (click) le indicamos que ejecute la funci贸n reinicia().

Por lo tanto ahora聽 vamos a editar nuestro controlador (home.page.ts) y a帽adimos la funci贸n reinicia(), que como hemos dicho debe reiniciar las variables para poder comenzar el juego:

 reinicia(){
   // reiniciamos las variables
   this.num = null;
   this.mayorMenor = '...';
   this.numSecret = this.numAleatorio(0,100);
 }

 

Si acertamos el n煤mero veremos algo como esto:

Vista de nuestro juego al acertar.
Vista de nuestro juego al acertar.

Ahora ya podemos volver a jugar una vez de que hemos adivinado el n煤mero.

Este juego se podr铆a mejorar a帽adiendo un contador de intentos. Podr铆amos limitar el n煤mero de intentos y mostrar un mensaje si se han consumido todos los intentos sin acertar el n煤mero secreto. Esto lo dejo como deberes para el que quiera practicar m谩s, sin duda experimentar y tratar de modificar el juego es una de las mejores formas de aprender.

Puedes descargar o clonar este proyecto desde GitHub en el siguiente link:

https://github.com/edurevilla/libro-ionic-adivina.git.

聽 Eso es todo por hoy,聽 nos vemos en el pr贸ximo post :).