Activa JavaScript para disfrutar de los vídeos de la Mediateca.
TFG - Contenido educativo
Ajuste de pantallaEl ajuste de pantalla se aprecia al ver el vídeo en pantalla completa. Elige la presentación que más te guste:
Hola, somos Álvaro Ilzarbe, Jorge Navarro y Andrés Inche, y vamos a presentar nuestro
00:00:00
proyecto intermodular correspondiente al grado superior de Desarrollo de Aplicaciones Multipletaforma
00:00:04
en el IES Francisco de Quevedo.
00:00:08
Nuestro proyecto consiste en una aplicación multipletaforma relacionada con el ámbito
00:00:10
competitivo de Pokémon, desarrollada con Kotlin Multiplatform.
00:00:13
La aplicación permite crear, consultar y analizar equipos Pokémon utilizando datos
00:00:16
reales sobre Pokémon, movimientos, habilidades, objetos y también equipos utilizados en torneos
00:00:20
oficiales.
00:00:25
Para entender el contexto del proyecto, hay que tener en cuenta que en el competitivo
00:00:25
de Pokémon no basta con elegir Pokémon al azar. Los jugadores necesitan construir equipos
00:00:28
equilibrados, revisar estadísticas, comprobar eficacias de tipos, calcular daños aproximados
00:00:32
y analizar qué estrategias funcionan en partidas reales o torneos. Actualmente, una de las
00:00:36
herramientas más conocidas para esto es Pokémon Showdown, que se considera prácticamente
00:00:41
el estándar para crear equipos, probar estrategias y simular combates. Sin embargo, aunque es
00:00:44
una herramienta muy completa, no cuenta con una aplicación móvil específica. En móviles
00:00:49
lo habitual es acceder desde el navegador web, lo que puede resultar menos cómodo para
00:00:53
consultar datos, revisar equipos o trabajar con la interfaz durante mucho tiempo.
00:00:56
A partir de esa necesidad, decidimos crear una aplicación que reuniera varias funciones
00:00:59
útiles en un formato más adaptado a una experiencia multiplatforma.
00:01:03
La idea no era hacer solamente una Pokédex o una base de datos estática, sino una herramienta
00:01:05
que ayudara al usuario a crear equipos, consultar información relevante y apoyarse en ejemplos
00:01:09
reales de entorno competitivo.
00:01:13
La justificación del proyecto está precisamente en ofrecer una alternativa más cómoda y
00:01:15
organizada para este tipo de consultas, especialmente en dispositivos donde el uso de una web no
00:01:18
siempre es más práctico.
00:01:22
Además, el proyecto nos permitía aplicar muchos contenidos del ciclo
00:01:23
Como el desarrollo de interfaces en plataforma, el consumo de APIs externas, la organización cliente-servidor
00:01:27
La gestión de datos, el trabajo con backend y frontend y el uso de control de versiones en equipo
00:01:31
En cuanto a los datos, la aplicación obtiene información relacionada con Pokémon, movimientos, habilidades y objetos
00:01:36
Además, también incorpora la consulta de equipos presentados en torneos competitivos
00:01:40
Lo que permite al usuario tomar referencias reales, comparar estrategias y ver tendencias dentro del metajuego
00:01:44
Los objetivos principales del proyecto son
00:01:49
Desarrollar una aplicación multiplataforma funcional
00:01:50
Permitir la creación y consulta de equipos Pokémon
00:01:52
Implementar herramientas de análisis, como el cálculo de daño y eficacia
00:01:55
Integrar datos externos mediante APIs
00:01:59
Y organizar el proyecto con una estructura realista, separando responsabilidades entre las distintas partes de la aplicación
00:02:02
En resumen, nuestro proyecto combina una temática cercana y motivadora con un desarrollo técnico completo
00:02:07
No queremos hacer únicamente una aplicación de consulta, sino una herramienta que conectara datos, análisis y creación de equipos dentro de una experiencia multiplataforma
00:02:11
A continuación explicaremos con más detalle las tecnologías utilizadas, la estructura del proyecto y las principales funcionalidades desarrolladas.
00:02:18
Para el desarrollo del proyecto, lo primero que hicimos fue crear un repositorio compartido en GitHub, donde centralizamos todo el código, la documentación y el control de versiones.
00:02:24
Esto nos permitió trabajar de forma simultánea, diseñar cambios de manera ordenada y mantener un seguimiento claro de la evolución del proyecto.
00:02:30
Una vez preparado el entorno de trabajo, repartimos las distintas partes del proyecto entre los miembros del equipo.
00:02:35
Para coordinar las tareas utilizamos Taiga como herramienta de organización, lo que nos ayuda a distribuir el trabajo, planificar objetivos y llevar un control del progreso del desarrollo.
00:02:39
Como el objetivo era crear una aplicación móvil multiplataforma, utilizamos Android Studio como entorno principal de desarrollo.
00:02:46
Antes de empezar con el código diseñamos el diseño visual mediante Figma, lo que nos permitió definir la experiencia del usuario y organizar las diferentes pantallas antes de pasar al código.
00:02:51
Durante las prácticas y procesos de planificación se nos recomendó utilizar Kotlin Multiplatform, ya que se ajustaba especialmente bien a la idea del proyecto.
00:02:59
Esta tecnología nos permitía compartir lógica de negocio entre distintas plataformas, manteniendo una arquitectura más eficiente, modular y preparada para un desarrollo multiplataforma realista.
00:03:05
Además, encajaba con uno de los principales objetivos del proyecto, aplicar tecnologías actuales relacionadas con el desarrollo multiplataforma.
00:03:13
En cuanto a la parte del servidor y gestión de datos, optamos por utilizar Kator,
00:03:18
que es el backend, encargándose de la comunicación cliente-servidor.
00:03:21
Para la persistencia de datos, empleamos MySQL como sistema de base de datos,
00:03:24
donde almacenamos información relacionada con los usuarios, equipos y distintos elementos necesarios para el funcionamiento interno del sistema.
00:03:28
Respecto a la seguridad de la aplicación, implementamos autenticación basada en JWT,
00:03:34
JSON Web Token.
00:03:38
Esto nos permitió gestionar el acceso de usuarios de forma segura, controlar las sesiones y validar las peticiones autenticadas entre cliente y servidor.
00:03:39
De esta forma conseguimos una estructura más cercana a un entorno de desarrollo profesional incorporando mecanismos reales de autenticación y protección de datos.
00:03:45
A continuación mi compañero Jorge explicará cuáles fueron los problemas que nos encontramos durante el desarrollo.
00:03:52
En esta parte de la defensa vamos a explicar los principales problemas que tuvimos durante el desarrollo de la aplicación,
00:03:56
de qué forma conseguimos solucionarlos y especialmente qué aprendizaje sacamos de todos y cada uno de ellos.
00:04:01
Uno de nuestros principales problemas fue que, dado que ninguno de los tres integrantes del grupo tenemos experiencia realmente en Kotlin multiplatform, pues carecíamos realmente de la experiencia para entrar de lleno en el desarrollo y, sobre todo, en cómo funcionan los módulos en una aplicación de este tipo, qué responsabilidad tiene cada módulo.
00:04:07
Al final, un poco también por prueba y error, casi acabamos decidiendo que nuestros tres principales módulos, que iban a ser el server, el módulo server, que es el que tiene el backend independiente, hecho con Cator, el de JadeBrainz, y el tendríamos el módulo shared, que tendrían estructuras redutilizables, pero sobre todo tendríamos ComposeApp como módulo en el que se va a compartir casi todo el código común a todas las versiones de la aplicación.
00:04:26
porque, claro, a su vez
00:04:52
una aplicación multiplataforma tenemos que
00:04:54
organizar cómo funcionan los targets
00:04:56
y problemas que nacen de la compatibilidad
00:04:57
entre versiones de librerías, de según
00:05:00
dónde se vaya a ejecutar y este tipo de
00:05:02
proyecto, pues eso es fundamental. La solución
00:05:04
fue ir estabilizando poco a poco
00:05:06
la configuración del Gradle
00:05:07
separando responsabilidades y
00:05:09
aprendiendo la arquitectura
00:05:12
que es necesaria para una aplicación
00:05:14
de estas características. Otro problema
00:05:15
que tuvimos durante el desarrollo
00:05:17
de la aplicación fue poner en práctica
00:05:19
lo que hemos aprendido durante todo el año en la clase
00:05:21
de acceso a datos. Una vez
00:05:23
las tres tablas principales que utilizamos, que son
00:05:25
usuarios, equipos y equipos lots,
00:05:27
estaban disponibles y funcionaban
00:05:29
perfectamente, nuestra primera decisión
00:05:31
en realidad importante
00:05:33
al respecto de cómo íbamos a realizar
00:05:35
a trabajar con la database
00:05:37
fue crear una clase en la que
00:05:39
teníamos lógica centralizada de las operaciones
00:05:41
que realizamos sobre la database para que
00:05:43
cualquiera pudiera, cualquiera miembro del equipo
00:05:45
pudiera mirarlo en cualquier momento, que es
00:05:47
la database operations.kt
00:05:49
y esto nos permitió gestionar
00:05:51
de forma clara las operaciones que íbamos a hacer
00:05:52
y el aprendizaje aquí fue básicamente
00:05:54
separar rutas y lógica
00:05:56
de datos y
00:05:59
realizar al final
00:06:00
operaciones complejas en
00:06:02
una sola clase para que el código sea
00:06:05
mantenible y menos propenso a errores
00:06:07
uno de los problemas más importantes que tuvimos
00:06:08
al final fue decidir cómo íbamos
00:06:11
a enfrentar la seguridad
00:06:13
de la aplicación, evidentemente al principio
00:06:14
lo más básico era
00:06:16
leer usuario y contraseña
00:06:18
y buscar a ver que hiciera un match
00:06:21
evidentemente tuvimos que
00:06:22
decidir pues que seguridad
00:06:25
íbamos a implementar
00:06:27
en nuestra aplicación
00:06:28
lo primero al final lo hicimos
00:06:30
utilizando la librería Bcrypt
00:06:32
para jasear las contraseñas
00:06:34
y que compruebe la contraseña
00:06:36
del usuario durante el login
00:06:38
nosotros en nuestra base de datos
00:06:39
si otra persona se hace un usuario
00:06:43
realmente crea un usuario, nosotros no podemos ver
00:06:45
realmente la contraseña como texto plano, evidentemente,
00:06:47
porque para eso estaba Bacrit, para hashearla.
00:06:51
Otra cosa que implementamos también fue realizar una protección
00:06:54
un poco más robusta de las rutas privadas utilizando Authenticate
00:06:58
y sobre todo lo más importante en cuanto a la seguridad
00:07:01
fue implementar una autenticación mediante JSON Web Token.
00:07:04
Básicamente el servidor genera un token
00:07:08
y cuando el usuario inicia sesión correctamente
00:07:11
y es ese token el que se utiliza para acceder a todas las rutas protegidas.
00:07:13
nuestra implementación al final
00:07:16
nos permite tener una autenticación
00:07:19
stateless, que
00:07:21
significa que al final
00:07:22
no dependemos de que se guarde
00:07:23
una sesión
00:07:27
por así decirlo en el servidor
00:07:28
y al final
00:07:30
una de las mejoras más importantes
00:07:32
fue que decidí que
00:07:35
no íbamos a depender de enviar un
00:07:37
user ID desde el cliente
00:07:38
ya que el backend
00:07:41
obtiene el usuario autenticado directamente
00:07:42
desde el token. Esto al final es clave
00:07:44
porque si no, evidentemente, pues
00:07:46
un cliente podría mandar cualquier
00:07:48
user ID cambiando
00:07:50
un parámetro. El aprendizaje
00:07:52
principal que sacamos de
00:07:55
este problema en específico
00:07:56
fue aprender a hacer un login
00:07:58
en condiciones como
00:08:00
almacenar contraseñas en una base de datos,
00:08:02
implementar un hasheo
00:08:05
y sobre todo
00:08:06
aprender a validar la identidad
00:08:09
desde el backend
00:08:10
y garantizar que cada usuario
00:08:11
y solo puede acceder a sus propios datos.
00:08:14
El problema que tuvimos fue aprender a conectar correctamente
00:08:16
el frontend con el backend de la aplicación.
00:08:20
Dependiendo además de si se va a ejecutar en Android,
00:08:22
en el emulador, en el escritorio, el host puede cambiar.
00:08:24
Para ello, bueno, centralizamos host y ruta dentro de constante
00:08:27
para no tener las URLs repartidas por toda la aplicación
00:08:30
y garantizar, pues al final, una mantenibilidad y una legibilidad.
00:08:33
Separamos llamadas de autenticación en una clase específica.
00:08:36
Era importante manejar correctamente los errores
00:08:40
Para que, bueno, si el servidor no está disponible, que la aplicación mostrara un mensaje elegible.
00:08:43
Y para los equipos hicimos algo parecido también.
00:08:50
Separamos las llamadas relacionadas con equipos en su propia API.
00:08:52
Tomamos la decisión de que enviamos el token en la cabecera authorization como un better token.
00:08:56
También implementamos un fallback en posibles hosts o llamadas.
00:09:02
Tuvimos el problema de actualizar los equipos después de iniciar sesión o después de modificar datos.
00:09:07
y añadimos un estado para mostrar errores relacionados con los equipos
00:09:12
en vez de dejar un poco que el usuario no supiera que había pasado.
00:09:16
Como extra, en la versión en Android tuvimos que declarar permisos como Internet
00:09:19
y permitir ciertas conexiones durante el desarrollo.
00:09:23
Aquí nuestro principal aprendizaje fue conectar frontend y backend
00:09:26
yendo más allá de hacer simplemente peticiones HTTP y contemplar los distintos entornos,
00:09:30
la sesión, los tokens, los errores de red, el feedback visual que le estamos dando al usuario en general.
00:09:37
Uno de los bloques más complejos, a su vez, de todo el proyecto fue el motor del combate. La mejor idea era separar la lógica del combate en varias clases que tengan distintas responsabilidades.
00:09:41
Este problema lo solucionamos a base de tener la clase Battle Engine, que actúa como el coordinador principal del combate y que básicamente resuelve turno, decide qué va a ocurrir y se apoya para cosas específicas en clases específicas.
00:09:53
Como por ejemplo la Damage Calculator, que es un que hace el cálculo de daño, una parte matemática muy específica con muchos modificadores posibles y que lo mantuvimos en su clase individual.
00:10:09
Otra de las clases en las que asignamos una responsabilidad es muy específica, la de Ability Effect Resolver, que básicamente lo que hace es resolver el efecto de una habilidad concreta, dado que las habilidades interactúan con cualquier aspecto de la batalla, tanto con estadísticas, con el porcentaje de daño, efectos variopintos.
00:10:22
Tenemos PokeAPI Battle Data Source. Lo que hacemos en esta clase es asignarle la responsabilidad específica de cargar datos relacionados con Pokémon y los movimientos para que pueda trabajar con la información oficial de la PokeAPI.
00:10:42
Y finalmente, para una lógica de este calibre, decidimos hacer una clase que era Battle Engine Test para hacer test y comprobar que el motor se comporta como esperamos.
00:10:59
El aprendizaje principal que sacamos de aquí fue al final entender que cuando una lógica de dominio es muy compleja, la mejor forma de lidiar con ella es irla dividiendo en piezas muy pequeñas y así el código es más fácil de entender, de explicar, de probar y de ampliar.
00:11:10
En este apartado ahora lo que vamos a hacer va a ser hablar de las diferentes partes que consideramos más importantes dentro de nuestro proyecto.
00:11:31
El objetivo de haber creado una aplicación con una estructura multiplatform consiste en poder llegar a reutilizar la mayor parte de código posible.
00:11:37
Durante las prácticas recibimos la recomendación de utilizar este tipo de arquitectura porque nos permitía poder utilizar el mismo código para poder crear una aplicación web, una aplicación móvil, una aplicación iOS y cosas similares.
00:11:45
En esta ocasión en el proyecto se encuentran divididos en tres módulos principales
00:11:57
Pero vamos a explicar un poquito
00:12:00
El módulo Shared, que consiste en un módulo pequeño transversal
00:12:02
Que tiene unas utilidades básicas
00:12:06
Tenemos aquí cosas como constantes, clases básicamente de demo
00:12:08
Y un poquito de información sobre la plataforma
00:12:12
Una clase un poquito más secundaria
00:12:14
Porque la principal clase que tenemos dentro de la estructura de CodeMultiplatform
00:12:16
Consiste en el módulo ComposeUp
00:12:20
En esta clase podemos ver dentro del despliegue del SRC las diferentes estructuras, que aquí es donde se encuentran las pantallas del Android, del apartado web, del apartado aplicación pura y del apartado iOS.
00:12:23
que todas estas aplicaciones, todos estos módulos
00:12:36
lo que hacen es tirar del propio módulo
00:12:38
del Common Main, que es básicamente donde se
00:12:40
encuentra la interfaz visual
00:12:42
de todas las clases con toda
00:12:44
la estructura que se ha ido utilizando
00:12:46
para poder generar todas las diferentes
00:12:48
funcionalidades
00:12:50
dentro de lo que viene siendo la propia aplicación
00:12:52
y luego por último tenemos el módulo
00:12:54
Server, que básicamente es un backend independiente
00:12:56
que utiliza Cator, que expone
00:12:58
el API REST que estamos utilizando
00:13:00
o en este caso más de un API REST
00:13:02
se encarga de dar persistencia a los datos
00:13:03
autentificar usuarios y servir la información que consumen o que utiliza la aplicación a los
00:13:05
clientes el resultado final consiste en crear una única aplicación que se desarrolla en diferentes
00:13:12
plataformas a la vez como hemos podido ver en plataformas como el propio ordenador web android
00:13:18
ios de acuerdo la lógica es común ya que se escribe solamente una única vez como hemos podido
00:13:23
ver en la parte del común main esto es mucho más práctico mucho más sencillo a la larga porque si
00:13:28
Si se encuentra un bug en la lógica, se corrige una única vez para todas las plataformas
00:13:33
y no hay que ir modificando cada plataforma de forma unitaria.
00:13:38
La base de datos que hemos creado para este proyecto es una base de datos de MySQL
00:13:43
con 10 tablas principales que lo que hacen es modelar el sistema completo de nuestra aplicación.
00:13:46
Por un lado tenemos las datos más principales, los datos maestros,
00:13:52
que son las tablas de los tipos, donde se almacenan los 18 tipos principales que hay de Pokémon,
00:13:55
la tabla de habilidades, donde se almacenan todas las habilidades existentes en los Pokémon,
00:13:59
la tabla de los objetos que te permite almacenar todos los objetos de forma individual
00:14:03
la tabla de movimientos donde te permite almacenar todos los ataques que existen
00:14:06
en la versión de la franquicia de los juegos de Pokémon
00:14:10
por otro lado también tenemos lo que es la tabla de las especies
00:14:12
que consiste básicamente en uno de los puntos más importantes que podemos definir
00:14:14
de la aplicación porque es la que te permite tener localizado un Pokémon
00:14:18
con sus características individuales
00:14:22
ya que cada Pokémon tiene un valor de 6 características diferentes
00:14:24
que son vida, ataque, defensa, ataque especial, defensa especial y velocidad
00:14:27
Por otro lado, la tabla de usuarios, donde tenemos la información de cada usuario que utiliza la aplicación con su contraseña y su correo electrónico identificatorio.
00:14:30
También tenemos lo que vienen siendo los equipos de cada usuario, que están asociados por el ID de cada usuario que se genera, a lo que viene siendo el equipo, de tal forma que equipo 1 tenga el ID de X jugador, equipo 2 puede tener el de X jugador o el de Y jugador.
00:14:39
Por otro lado, tenemos la tabla de lo que son los equipos slots, que son datos persistidos de cada Pokémon en el equipo, ¿vale?
00:14:52
De tal forma que son los movimientos propios, habilidades propias con los que estén usando, el objeto que haya equipado la persona, los puntos individuales y cosas similares.
00:14:59
Datos de información que el usuario le ha metido a su propio equipo.
00:15:07
Y luego tenemos lo que viene siendo, por último, la tabla de Pokémon movimientos, que básicamente lo que te hacen es una correlación entre la tabla de Pokémon y la tabla de ataques,
00:15:10
permitiéndote decir que X Pokémon tiene acceso a estos determinados ataques
00:15:20
porque si no, cada Pokémon podría tener acceso a los 800.000 ataques que existen dentro de la Database
00:15:24
con lo cual, esta tabla es bastante, bastante necesaria, todavía sé
00:15:31
La base de datos indica también a normalizar lo que me he mencionado, los datos al máximo
00:15:35
Voy a poner un ejemplo de a lo que me refiero
00:15:38
No tendría sentido que si tenemos un Pikachu y un Raichu, que son ambos del mismo tipo
00:15:40
se duplicara el dato de que son de tipo eléctrico
00:15:46
Con lo cual, lo que se hace es usar una referencia a ese tipo y solamente se utiliza una vez ese dato y no dos veces.
00:15:50
¿Esto qué es lo que nos permite tener?
00:15:56
Nos permite tener por un lado una integridad referencial, es decir, no hay Pokémon con tipos inválidos,
00:15:58
una mayor eficiencia, ya que permite que si a futuro se produjera el cambio de un Pokémon o de un nombre de un tipo,
00:16:04
se podrá cambiar solamente una referencia y no tendrías que ir mil Pokémon revisando cuál sería la referencia correspondiente.
00:16:11
y una mayor escalabilidad, ya que permite poder estar preparado para poder hacer millones de registros
00:16:19
en vez de solamente uno al momento y da mayor facilidad a la hora de funcionar.
00:16:26
También hay que mencionar que el servidor se conecta utilizando Exposed,
00:16:31
que es básicamente para unas operaciones de tipo de type 6, ¿vale?
00:16:34
Que se ejecutan directamente contra la base de datos, que esto es una funcionalidad propia de Kotlin.
00:16:38
Vamos a hablar ahora de una cuestión de lo que viene siendo el corazón principal del proyecto,
00:16:43
que es el motor interno de peleas, ¿vale?
00:16:46
Es un motor que simula las batallas de los Pokémon
00:16:48
Lo que viene siendo de la misma forma que en el juego
00:16:51
Y se encuentra dividido principalmente en cuatro capas
00:16:53
La primera de ellas es el Battle Engine
00:16:55
Que es el director de orquesta, por así definirlo
00:16:58
Es el que maneja los hilos
00:17:00
Es la clase principal en la cual se dedica a gestionar el combate
00:17:02
Ya que recibe la información de la pelea
00:17:05
De, por un lado, los equipos de ambos jugadores
00:17:07
Y, por otro lado, los datos de la batalla
00:17:11
Es decir, los datos internos que tiene cada Pokémon
00:17:12
Las estadísticas, unidades, etcétera
00:17:15
¿De acuerdo? ¿Cómo funciona? Pues lo que se dedica a hacer esta clase es Tom, que genera un estado inicial, que es lo que se denomina en los juegos como Battle Preview, ¿vale?
00:17:17
Que ves a todos los Pokémon entrando y visualmente quedan ahí registrados, recibe las acciones de los jugadores y determina el orden de actuación, ya que aquí hay que tener en cuenta que los Pokémon van por velocidades, ¿vale?
00:17:27
Luego pasa el tema de los valores de los daños al Damage Calculator
00:17:39
Que ahora hablaremos de ello
00:17:43
Y el tema de aplicar los efectos de las habilidades al Ability Effect Resolver
00:17:44
Luego gestiona, lo que viene siendo los cambios de los Pokémon y las acciones entre turnos
00:17:51
Pero básicamente se dedica a dirigir todo este tipo de acciones
00:17:55
Y pasar a las clases siguientes los datos correspondientes
00:17:58
¿Qué cuáles son las clases siguientes?
00:18:02
Pues mira, vamos a empezar primero con el Damage Calculator
00:18:04
Que es básicamente el cerebro matemático
00:18:06
En Pokémon cada golpe no genera el mismo valor de daño al oponente, genera un baremo de A a B y entre A y B hay 16 valores diferentes que puede llegar a dar ese ataque.
00:18:09
Con lo cual hemos visto bastante necesario crear una calculadora interna, vamos a decirlo así, para poder llevar a cabo ese valor y dar fidelidad a los resultados.
00:18:25
Por eso hemos visto la necesidad de crear esta clase
00:18:34
Ya que a fin de cuentas es la que aplica
00:18:36
Esa fórmula, ¿vale?
00:18:38
Porque a fin de cuentas es una fórmula bastante compleja
00:18:40
Porque tiene en cuenta diferentes baremos
00:18:42
Diferentes multiplicadores
00:18:45
Diferentes multiplicadores en negativo
00:18:46
Es bastante complejo
00:18:49
Y era bastante, bastante necesario esta parte
00:18:51
Pero hay una forma que es bastante necesario
00:18:53
El apartado del Ability Effect Resort
00:18:55
Porque hay muchos Pokémon que sus habilidades
00:18:57
Interactúan directamente con el cálculo de daño
00:18:59
De las peleas
00:19:01
Por ejemplo, hay algunos que tienen habilidades que bajan las estadísticas del rival. Hay otros que se dedican a modificar el clima de la batalla haciendo que haya otros ataques que sean más fuertes o menos fuertes, que permitan cambiar el terreno.
00:19:02
Vale, todo esto tenemos que gestionar de alguna forma y hemos creado una clase que se dedica a gestionarlo para saber qué efecto se genera dependiendo de la situación.
00:19:14
Y por último, sucede lo mismo con los objetos
00:19:21
Hay objetos que se dedican a subir las características o bajar las características de los ataques del propio Pokémon
00:19:24
De tal forma que era bastante necesario crear una clase que se dedicara a gestionar de forma interna
00:19:30
Ese tipo de objetos para saber luego en el cálculo de daño cómo poder llegar a manejarlo
00:19:37
El siguiente punto que vamos a tratar va a ser el tema de las API REST
00:19:42
Para explicar y para partir de un punto inicial vamos a decir que los API REST son un conjunto de URLs
00:19:44
que el cliente, dependiendo
00:19:51
de donde sea, que en este caso
00:19:53
como tenemos holding multiplatform, va a ser de diferentes
00:19:55
sitios, consulta para poder
00:19:57
obtener o guardar los datos de forma
00:19:59
propia. Para poder llevar a cabo
00:20:01
esto, hemos creado una serie de endpoints
00:20:03
organizados en cinco categorías diferentes
00:20:05
que cada uno va hacia
00:20:07
un punto diferente. El primero
00:20:09
de ellos es la autentificación, lo que es el login
00:20:11
que hemos hecho lo que es básicamente
00:20:13
un post, un post
00:20:14
tirando los datos
00:20:17
hacia el login con el JWT
00:20:19
para poder hacer que el usuario
00:20:21
utilizando el token que se genera
00:20:23
pueda loguearse, eso por un lado
00:20:25
luego, una de las principales
00:20:27
puntos que
00:20:29
más información nos proporciona
00:20:31
es utilizar el API REST de la PokeAPI
00:20:33
que es una de las dos APIs principales
00:20:35
que hemos utilizado
00:20:38
¿por qué? porque de la PokeAPI hemos hecho
00:20:39
diferentes GET para poder obtener tanto tipos
00:20:41
como habilidades, como movimientos, como las especies
00:20:43
de los Pokémon, porque si no, íbamos a tener
00:20:45
que haber metido a mano una cantidad de datos que era
00:20:47
inhumana, vamos a ser honestos
00:20:49
luego el siguiente punto del cual vamos a hablar
00:20:51
es la otra API REST, es la API REST de
00:20:53
Limitless, que es una página
00:20:55
donde puedes obtener la información de
00:20:57
los equipos que se han estado jugando
00:20:59
de tal forma que es lo que genera
00:21:01
una database interna dentro de la
00:21:03
aplicación del móvil de los datos
00:21:05
de cada torneo, pudiendo consultar
00:21:07
la información de que jugador
00:21:09
ha jugado, que y que equipo ha quedado
00:21:11
en que posición en un determinado
00:21:13
torneo, luego por otro lado
00:21:16
para poder mostrar la información de lo que viene siendo
00:21:17
el propio usuario, hemos creado un endpoint
00:21:19
que apunta al usuario utilizando el propio
00:21:21
ID del usuario por medio
00:21:23
del uso de un GET, ¿vale?
00:21:24
Y luego, por último, pero no menos importante
00:21:27
un GET para saber
00:21:29
qué equipos tiene qué usuario
00:21:30
como hemos dicho, hemos utilizado
00:21:33
el propio ID del usuario para poder
00:21:34
asignárselo a unos equipos, como he
00:21:37
dicho antes cuando explicaba la parte de la database
00:21:39
de tal forma que haciendo un GET
00:21:41
podemos hacer que ese GET nos dé
00:21:43
el equipo del usuario determinado
00:21:45
que estamos usando ese id como digo apartado queremos hablar del tema de la seguridad vale
00:21:47
que consideramos que es un tema muy importante a la hora de poder crear una aplicación ya no sea
00:21:51
móvil sino multiplatform como es nuestro caso que hemos basado la seguridad principalmente en
00:21:55
dos elementos importantes por un lado es el paseo de las contraseñas vale para poder dar esa
00:22:00
seguridad a los usuarios de que las contraseñas no van a ser liqueadas con una facilidad alta y
00:22:06
Y por otro lado, lo que viene siendo el logueo de los usuarios, que lo hemos hecho mediante un JWT, es decir, un JSON Web Token.
00:22:15
Vamos a explicar un poquito rápidamente el flujo de cómo funciona este sistema, que básicamente sería,
00:22:25
el usuario hace el logueo con lo que viene siendo tanto su nombre de usuario como la contraseña.
00:22:29
Se mandan al servidor. Primero, se hace una comprobación de si este usuario está en la base de datos.
00:22:35
¿Existe? Sí
00:22:40
¿Tiene la contraseña correcta? Sí
00:22:42
Perfecto, se genera el JWT
00:22:44
Para poder utilizar las diferentes acciones
00:22:46
Posteriores, ya sea
00:22:48
Del equipo, del IDE
00:22:50
Etcétera, etcétera
00:22:52
¿Cómo funciona esto a la hora de crear un usuario?
00:22:53
Pues a la hora de crear un usuario
00:22:56
Se hace primero la comprobación de si ese usuario
00:22:57
Está en la base de datos
00:23:00
Si no está en la base de datos, se va a generar un usuario
00:23:01
Pidiendo al usuario que introduzca la contraseña
00:23:04
La cual va a almacenarse
00:23:06
Por medio de un raseo de contraseñas
00:23:07
no se van a guardar en ningún momento en texto plano ni de forma similar
00:23:10
porque eso no es una práctica segura y eso lo hemos podido ver también en clase
00:23:13
de que es mucho más seguro aplicar el hashable
00:23:16
y el funcionamiento ha sido similar al que hemos hecho en clase
00:23:20
con lo cual nos parecía mucho más apropiado poder optar por ese tipo de almacenamiento
00:23:23
para poder dar esa seguridad al usuario
00:23:29
y una vez se ha almacenado la base de datos se genera el usuario y ya el usuario puede lograrse
00:23:31
A continuación os haré una demostración de lo que es capaz de hacer nuestra aplicación
00:23:35
Lo primero que vemos al iniciar es el formulario de inicio de sesión con el botón de crear cuenta.
00:23:38
Al darle, se abrirá el formulario para crear una nueva cuenta.
00:23:43
Al rellenar el formulario y darle al botón de crear cuenta, nuestra cuenta será creada y nos dejará acceder.
00:23:46
Una vez acceda a la aplicación, llegas al menú principal, donde hay 7 opciones disponibles.
00:23:52
La primera opción es el Team Builder, que como su nombre indica, nos permite crear nuestro propio equipo.
00:23:56
Esta de aquí es una función que tiene la aplicación y facilita mucho el trabajo al momento de crear tu equipo, el autocompletado.
00:24:01
No solo lo tiene Pokémon, sino también el objeto que puede llevar
00:24:05
Otra función que tiene la aplicación es mostrarte la cantidad de habilidades que tiene un Pokémon
00:24:09
Si bajamos un poco más abajo podemos ver los movimientos
00:24:13
Que al igual que el nombre y los objetos, también tiene autocompletado
00:24:15
Si bajamos más abajo tenemos los puntos de esfuerzo
00:24:17
Los cuales nos permiten darle ciertas características a nuestros Pokémon
00:24:20
Si seguimos bajando podemos ver los botones
00:24:23
El de guardar equipo y el de cambiar el meta
00:24:25
Si le damos a guardar equipo podemos ver cómo se ha creado el equipo y también se ha guardado
00:24:27
La siguiente opción sería equipos propios
00:24:31
Nos permite ver los equipos que tenemos
00:24:33
Eso sí, el Team Builder nos da una forma de añadir equipos a esta aplicación
00:24:34
Si la damos aquí, podemos importar un Pokémon siguiendo el mismo estilo de importación de Shodown
00:24:37
Y después podemos pegar el texto de Shodown abajo
00:24:41
Al darle a importar, se nos crea justo debajo el equipo que acabamos de importar
00:24:44
Pasando con la tercera opción, tenemos el simulador de batallas
00:24:50
Nos permite seleccionar uno de los equipos que tengamos
00:24:52
El botón de simulador de batallas nos lleva al simulador de batallas
00:24:54
Aunque el nombre diga jugador 1 y jugador 2, realmente es el usuario que controla los dos equipos
00:24:56
Esto le permite crear situaciones que de otro modo no se podrían dar
00:25:00
El simulador de combate funciona como los juegos originales
00:25:02
Tras elegir las acciones contra el primer equipo, puedes darle al botón Cambiar Jugador para tomar las acciones del segundo jugador
00:25:05
Tras seleccionar las acciones de los dos equipos, podrás darle al botón de Jugar Turno, el cual las ejecutará
00:25:10
En el recuadro de encima, se puede ver los movimientos que se han realizado y en el orden en el que se ha hecho
00:25:14
El botón de calculadora te permite ir a la calculadora de daño y guardar el replay te permite guardar la repetición del combate
00:25:18
Nuestra cuarta opción es la tabla de tipos
00:25:23
Una vez aquí podrás seleccionar cualquiera de los 18 tipos y te dirá sus debilidades, sus naturalidades, sus resistencias y sus inmunidades
00:25:25
Como en Pokémon, los Pokémon pueden tener hasta dos tipos
00:25:31
Puedes seleccionar tus equipos y verás la combinación de sus debilidades y resistencias
00:25:33
La quinta opción es la base de datos de los torneos
00:25:36
Aquí puedes filtrar por meta y seleccionar cualquier torneo
00:25:38
Donde verás los jugadores que participaron en este
00:25:40
Puedes guardarte sus equipos y utilizarlos en la aplicación
00:25:42
Nuestra quinta opción es la calculadora de daño
00:25:46
Utilizan todos los datos de los Pokémon para calcular el daño que realizarían en una situación concreta
00:25:48
Nos dirigimos abajo para seleccionar el ataque que queremos hacer
00:25:52
Podemos elegir las condiciones del campo y cuando ya esté todo listo le damos a calcular daño
00:25:54
Al dar a calcular daño nos aparece una ventana emergente
00:25:58
Con el nombre del ataque, el daño mínimo que se podría haber hecho, el daño máximo que se podría haber hecho, la media del daño, la cantidad de DPS que le podrías haber quitado al Pokémon y cuántos golpes habría que darle para derrotarlo.
00:26:00
Por último, tenemos el Replace, donde podemos ver la repetición de los combates que hayamos guardado en el simulador de batallas.
00:26:09
Darle, podemos ir turno por turno y ver lo que fue ocurriendo.
00:26:15
Vayamos con las conclusiones.
00:26:19
En conclusión, el desarrollo de este proyecto nos ha permitido aplicar de forma práctica gran parte de los conocimientos adquiridos durante el ciclo de desarrollo de aplicaciones múltiples de forma,
00:26:21
integrando tantas tecnologías de frontend como de backend dentro de una arquitectura completa y funcional.
00:26:28
Podemos afirmar que se han cumplido los objetivos principales que se han planteado desde el inicio del proyecto.
00:26:33
Hemos conseguido desarrollar una aplicación multiplataforma orientada al competitivo de Pokémon
00:26:36
capaz de gestionar equipos, consultar información relevante
00:26:40
y ofrecer una experiencia más cómoda y adaptada al entorno móvil que las soluciones actualmente disponibles.
00:26:43
Además del resultado funcional obtenido, el proyecto ha supuesto una experiencia muy importante
00:26:48
de aprendizaje técnico y organizativo.
00:26:51
El uso de Kotlin Multiplatform nos permitió comprender mejor los beneficios y desafíos del entorno multiplataforma, especialmente en aspectos relacionados con la reutilización de lógica de negocio, la modularidad del código y la compatibilidad de tecnologías.
00:26:54
Desde el punto de vista técnico, tecnologías como Kator, MySQL y JWT han sido fundamentales para construir una herramienta robusta, segura y organizada.
00:27:06
La implementación de autenticación mediante tokens, la gestión estructurada de la base de datos y la separación cliente y servidor nos han permitido acercarnos a un modelo de desarrollo similar al utilizado en aplicaciones reales del sector.
00:27:13
A lo largo del proceso, también hemos encontrado diferentes dificultades
00:27:23
relacionadas principalmente con la configuración del entorno
00:27:26
de la plataforma, la integración del frontend y backend
00:27:28
y la adaptación de ciertas dependencias y librerías.
00:27:30
Sin embargo, la resolución de estos problemas
00:27:32
ha sido precisamente una de las partes
00:27:34
más enriquecedoras del proyecto, ya que nos ha obligado
00:27:36
a investigar, experimentar y mejorar nuestra capacidad
00:27:38
de análisis de los usos y resolución de problemas.
00:27:40
Finalmente, consideramos que este proyecto no sólo
00:27:42
cumple los requisitos académicos planteados, sino que
00:27:44
también demuestra el potencial que puede tener una aplicación
00:27:46
de este tipo dentro de un nicho concreto, como el competitivo
00:27:48
de Pokémon. Además, dejará abiertas las posibles
00:27:50
líneas de mejora futuras como la ampliación de funcionalidades, la integración de nuevas APIs
00:27:52
o la expansión completa hacia otras plataformas soportadas por Kotlin Bully Platform.
00:27:55
En definitiva, este trabajo supuso una experiencia completa de desarrollo de software,
00:28:00
combinando planificación, diseño, programación, trabajo en equipo y resolución de problemas
00:28:03
dentro de un proyecto técnico realista y cercano al ámbito profesional.
00:28:07
- Materias:
- Informática
- Niveles educativos:
- ▼ Mostrar / ocultar niveles
- Formación Profesional
- Ciclo formativo de grado superior
- Primer Curso
- Segundo Curso
- Subido por:
- Johnny Andrés S.
- Moderado por el profesor:
- Lucia San Miguel López (lucia.sanmiguel)
- Licencia:
- Todos los derechos reservados
- Visualizaciones:
- 9
- Fecha:
- 19 de mayo de 2026 - 6:15
- Visibilidad:
- Público
- Centro:
- IES FRANCISCO DE QUEVEDO
- Duración:
- 28′ 12″
- Relación de aspecto:
- 1.78:1
- Resolución:
- 1920x1080 píxeles
- Tamaño:
- 1.73