Lucha de Pokémon.1. Clase Pokémon2. Clase Stat y StatDetail (Estadísticas)3. Clase Move (Movimiento)4. Clase Ability (Habilidad)5. Clase Crie (Llorar)6. Clase Form (Forma)7. ¿Qué se nos proporciona ya para trabajar?8. ApiPokemon9. LuchaPokemon
Fecha | Versión | Descripción |
---|---|---|
18/02/2025 | 2.0.0 | Conexiones http, recogida de datos y parseo json |
Para el desarrollo de esta actividad partiremos de la información que ya tenemos de la explicación del funcionamiento de la APIrest de Pokémon.
Vamos a ampliar y realizar una pequeña aplicación que nos ayude a realizar un juego en el que luchen 2 Pokémon.
Esta clase nos va a permitir almacenar información de los Pokémon. No pretendemos almacenar toda la información de los mismos, pero si una parte de ella que nos será de gran utilidad para trabajar con estos.
Tanto esta clase como las restantes las generarás en el paquete pojo. Por defecto se te proporcionará un proyecto base con este.
Partimos de la base que de los Pokémon que descarguemos con a través de la llamada GET de la APIRest que nos proporciona generaremos un objeto con la siguiente información:
xpublic class Pokemon {
private String name;
private int id;
private int height;
private int weight;
private String type;
private List<Crie> crieList;
private List<Form> formList;
private List<Stat> stats;
private List<Move> moves;
private Ability ability;
Como puedes observar los atributos de los Pokémon son privados, de tal manera que sólo podrás ser accedidos desde fuera de la clase a través de getters y setters.
Los nombres está en inglés ya que hacen referencia a los tipos de datos de los objeto JSON con los que se va a trabajar.
Se recomienda el uso de Mozilla Firefox porque implementa un parseo de JSON que nos permitirá ver de una manera estructurada el contenido.
Accedemos al api y realizamos un get: https://pokeapi.co/api/v2/pokemon/ que por defecto nos va a devolver 20 Pokémon:
Este fichero Json tiene varias etiquetas:
count: nos indica el número de Pokémon que hay.
next: siguiente página, puesto que nos carga por defecto de 20 en 20.
results: Contiene un array de 20 pokemos. En cada entrada dispone de los siguientes atributos:
name: Nombre del Pokémon.
url: url de la llamada Api con la información del Pokémon. Esta es la que nos va a interesar por cada uno de los elementos de results.
Accedemos por ejemplo a la url de bulbasaur: https://pokeapi.co/api/v2/pokemon/1/
Podemos acceder, y más sencillo, así: https://pokeapi.co/api/v2/pokemon/bulbasaur/
Como se puede observar disponemos de mucha información de la clase Pokémon:
id: identificador del Pokémon
name: nombre del Pokémon
height: altura
weight: peso
Como se puede observar esta información es directa, es decir, después de una descarga inicial de X Pokemon, realizamos otra nueva conexión con la url y obtenemos esta información.
Nosotros como atributo tenemos type ... pero, nos aparecen types 😒 veamos con nuestro ejemplo de bulbasaur:
Dentro de types, tenemos type. Vemos que bulbasaur puede adoptar dos formas de Pokémon, de tipo hierba, grass o de tipo veneno, poison. Nosotros por defecto nos vamos a quedar con una única forma, la primera, es decir, la 0.
type: Recogeremos el valor de name.
Continuamos con el resto de atributos de Pokémon.
ability: Clase Abylity. Se trata de un atributo de tipo clase, en el cual sólo almacenaremos una habilidad del Pokémon. Esto es para no hacer complejo el funcionamiento de la aplicación.
crieList: List
formList: List
stats: List
moves: List
Esto que quiere decir, pues que nuestra clase Pokémon se va a formar de datos directos y de objetos que de otras clases almacenados en Listas.
Esta clase contendrá la siguiente información:
xxxxxxxxxx
public class Stat {
private int baseStat;
private StatDetail stat;
Dentro de esta observamos que nos hará falta otra clase, cuidado esta otra son los detalles de las estadísticas, se relaciona con las estadísticas.
xxxxxxxxxx
public class StatDetail {
private String name;
Sólo tienen un nombre.
No haremos uso luego realmente de las mismas, pero nos van a servir para parsear las estructuras JSON.
Veamos el ejemplo de bulbasaur:
Esta clase nos va a permitir representar los movimientos de los Pokémon. Contendrá los siguientes atributos:
xxxxxxxxxx
public class Move {
private String name;
private String type;
private int power;
De los movimientos nos quedaremos con un máximo de 10 movimientos. Más que nada para no saturar las peticiones http.
Continuamos con nuestro ejemplo de Bulbasaur y sus movimientos:
name: "razor-wind"
Ahora accedemos a la url, bien con las que nos proporciona ("https://pokeapi.co/api/v2/move/13/") o bien de manera más sencilla, con el name ("https://pokeapi.co/api/v2/move/razor-wind/")
Y obtenemos el resto de la información:
De aquí obtendremos:
power: 80
type: "normal"
La clase Ability va a disponer de los siguientes atributos:
xxxxxxxxxx
public class Ability {
private String name;
private String effect;
Nos quedaremos con la primera. De esta cogemos el nombre (name)
efect lo obtendremos accediendo de nuevo a la url que nos proporciona:
Nos quedaremos igualmente con el parametro efect de la primera entrada, la 0:
En esta clase dispondremos de los siguientes atributos:
xxxxxxxxxx
public class Crie {
private String latest;
private String legacy;
En esta clase almacenaremos la url para poder descargar el último sonido y el legacy.
Lo encontraremos dentro de cries:
En esta clase almacenaremos las diferentes formas que tiene el Pokémon. Realmente son las imágenes de este:
xxxxxxxxxx
public class Form {
private String back_default;
private String back_shiny;
private String front_default;
private String front_shiny;
Para acceder a estos, deberemos obtener la información de forms. En este tenemos la url que nos llevará a las formas del Pokémon:
Una vez estamos en esta, obtendremos las diferentes formas de la URL. Las cogeremos dentro del array sprites:
De aquí nos quedaremos con el back_default, el back_shiny, front_default y front_shiny.
Para facilitar el trabajo se nos proporcionará esta estructura:
ApiPokemon: Esta clase se va a encargar de implementar los métodos que conectarán con la Api de Pokémon, descargar y parsear los datos a la clase Pokemon. Antes de trabajar con la misma, es conveniente implementar las clases indicadas anteriormente. Se proporcionan los métodos de manera incompleta, de tal forma que se deberán implementar.
Pokemon: Esta clase contiene toda la implementación necesaria de la clase Pokémon. Se proporciona implementada, por lo tanto te debe servir de guía.
TipoEfectividad: Clase ya implementada. Como se va a implementar una lucha entre 2 Pokémon, lo que se proporciona es una clase con un método que genera un coeficiente modificador del daño provocado en función del tipo de ataque y defensa. No debes implementar nada. Esta la clase totalmente documentada.
Para trabajar con los Json vamos a hacer uso de un proyecto que se proporciona ya preconfigurado. Es un proyecto de Maven, en el pom.xml ya va la dependencia de Maven, sólo tendrás que refrescarlo por si acaso.
La clase ApiPokemon dispondrá de la siguiente estructura:
El método getConexion, encargado de realizar la conexión y devolver un objeto de tipo HttpURLConnection:
xxxxxxxxxx
public static HttpURLConnection getConexion(String cadena) {
// Este es el método más adecuado para generar una URL. new URL(cadena) está deprecated.
try {
URL url = new URI(cadena).toURL();
// Generamos la conexión
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
// Establecemos el método GET, es decir, que vamos a recibir datos
conn.setRequestMethod("GET");
// Establecemos que tipo de información vamos a procesar en el get, en nuestro caso va a ser un json
conn.setRequestProperty("Accept", "application/json");
// Comprobamos que el código sea 200, es decir, que ha funcionado. Si es distino, generamos una excepción.
if (conn.getResponseCode() != 200) {
throw new RuntimeException("Error HTTP: " + conn.getResponseCode());
}
// Devolvemos el objeto conexión.
return conn;
} catch (IOException | URISyntaxException e) {
throw new RuntimeException(e);
}
}
El método getPokemonData, que recibirá como parámetro una url, internamente llamará a getConexion, y devolverá un String con todo lo obtenido de la Api de Pokémon:
xxxxxxxxxx
public static String getPokemonData(String url) {
try{
HttpURLConnection conn = getConexion(url);
BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream()));
StringBuilder response = new StringBuilder();
String line;
while ((line = br.readLine()) != null) {
response.append(line);
}
br.close();
conn.disconnect();
return response.toString();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
El método recogePokemons, es el que tendrás que implementar. Recibe la url con la que trabajaremos y el número de pokemons a descargar. Parte del código se te proporcionará. Hay otra parte que deberás implementar. Fíjate en los comentarios, pues en estos se indica como podemos acceder a los datos.
xxxxxxxxxx
public static ArrayList<Pokemon> recogePokemons(String url, int limite) {
ArrayList<Pokemon> pokemonArrayList = new ArrayList<Pokemon>();
try {
// Fíjate. El método getPokemonData recibe la url. Sobre esta se le concatena el texto para indicar
// el número de pokémon
String jsonResponse = getPokemonData(url+"pokemon?limit=" + limite);
// Un String de por sí no sirve para nada, de tal manera que a partir de la información recibida
// generamos un objeto json. (JsonObject)
JsonObject jsonObject = gson.fromJson(jsonResponse, JsonObject.class);
// Una vez convertido a un jsonObject, podemos utilizar métodos que nos permiten acceder a propiedades
// y leer la información del mismo.
// Generamos un array (JsonArray) que llamamos results, como la propiedad
JsonArray results = jsonObject.getAsJsonArray("results");
// Bucleamos y dentro de estos results, de tipo element, sacamos uno a uno los JsonObject y trabajamos con ellos.
for (var element : results) {
JsonObject obj = element.getAsJsonObject();
// Lanzamos una nueva conexión para obtener la información del pokémon en cuestión, obj.get("name").getAsString()
String pokemonJson = getPokemonData(url+"pokemon/" + obj.get("name").getAsString());
// Lo serializamos con el método de gson: gson.fromJson(pokemonJson, JsonObject.class);
JsonObject pokemonData = gson.fromJson(pokemonJson, JsonObject.class);
// Obtener nombre (name)
// Obtener id (id)
// Obtener altura (height)
// Obtener peso (weight)
// Obtener tipo. Recuerda, es un array. De este solo nos hace falta el primero
String type = pokemonData.getAsJsonArray("types").
// Obtener estadísticas
List<Stat> stats = new ArrayList<>();
JsonArray statsArray = pokemonData.getAsJsonArray("stats");
// Debes buclear para poder obtener estas
for (var statElement : statsArray) {
JsonObject statObj = statElement.getAsJsonObject();
// Código para obtener el valor de "base_stat" que lo dejarás en la variable baseStat
// Código para obtener el valor de name, que lo dejarás en la variable statName
// Una vez obtenido, deberás almacenar este en la lista. Fíjate porque se hace así de una manera sencilla.
stats.add(new Stat(baseStat, new StatDetail(statName)));
}
// Obtener movimientos (limítalo a 10 para que sea jugable)
List<Move> moves = new ArrayList<>();
JsonArray movesArray = pokemonData.getAsJsonArray("moves");
int cont = Math.min(10, movesArray.size());
for (int i = 0; i < cont; i++) {
// Obtener el nombre del movimiento
JsonObject moveObj =
String moveName =
// Obtener detalles del movimiento
String moveJson = getPokemonData(url+"move/" + moveName);
JsonObject moveData = gson.fromJson(moveJson, JsonObject.class);
// Nombre del tipo de movimiento.
String moveType =
int power = moveData.has("power") && !moveData.get("power").isJsonNull()
? moveData.get("power").getAsInt()
: 40; // Default en caso de null
moves.add(new Move(moveName, moveType, power));
}
// Obtener habilidad
JsonObject abilityObj =
String abilityName = abilityObj.get("name").getAsString();
// Obtener detalles de la habilidad
String abilityJson =
JsonObject abilityData = gson.fromJson(abilityJson, JsonObject.class);
String abilityEffect =
Ability ability = new Ability(abilityName, abilityEffect);
// Gritos
List<Crie> chillito=new ArrayList<>();
JsonObject cries =
String latestCry = cries.has("latest") ? cries.get("latest").getAsString() : "N/A";
String legacyCry =
chillito.add(new Crie(latestCry,legacyCry));
List<Form> forms = new ArrayList<>();
JsonArray formsArray =
for (var formElement : formsArray) {
JsonObject formObj =
String formUrl =
// Hacer una petición extra a la API para obtener detalles de la forma
String formJson = getPokemonData(formUrl);
JsonObject formData = gson.fromJson(formJson, JsonObject.class);
// Extraer imágenes de la forma
JsonObject sprites =
String backDefault = sprites.has("back_default") && !sprites.get("back_default").isJsonNull()
? sprites.get("back_default").getAsString()
: "N/A";
String backShiny =
String frontShiny =
String frontDefault =
forms.add(new Form(backDefault,frontShiny,frontDefault,backShiny));
}
pokemonArrayList.add(new Pokemon(name,id, height, weight,type,chillito,forms,stats, moves, ability));
}
}catch (Exception e) {
e.printStackTrace();
}
return pokemonArrayList;
}
Esta clase se va a encargar de implementar una lucha entre 2 Pokémon. No debes implementarla, se proporciona ya:
xxxxxxxxxx
package org.pokemon.pojo;
import java.util.Random;
public class LuchaPokemon {
public static void lucha(Pokemon p1, Pokemon p2) {
System.out.println("\n⚔️ COMBATE: " + p1.getName() + " VS " + p2.getName() + " ⚔️");
Random rand = new Random();
Move move1 = p1.getMoves().get(rand.nextInt(p1.getMoves().size()));
Move move2 = p2.getMoves().get(rand.nextInt(p2.getMoves().size()));
double tipoefectividad1 = TipoEfectividad.getEfectividad(move1.getType(), p2.getType());
double tipoefectividad2 = TipoEfectividad.getEfectividad(move2.getType(), p1.getType());
int danyo1 = (int) (move1.getPower() * tipoefectividad1);
int danyo2 = (int) (move2.getPower() * tipoefectividad2);
System.out.println(p1.getName() + " usa " + move1.getName() + "! (Efectividad: " + tipoefectividad1 + ")");
System.out.println(p2.getName() + " usa " + move2.getName() + "! (Efectividad: " + tipoefectividad2 + ")");
if (danyo1 > danyo2) {
System.out.println("🏆 " + p1.getName() + " gana el combate!");
} else if (danyo2 > danyo1) {
System.out.println("🏆 " + p2.getName() + " gana el combate!");
} else {
System.out.println("🤝 ¡Empate!");
}
}
}
Entrega la actividad y haz que puedan luchar 2 Pokémon aleatoriamente.