Bienvenido a la Práctica

Por favor, ingresa tus datos para comenzar.

Teoría y Práctica 1 - Threads

Progreso

0%

Introducción a los Threads en Java

En Java, un Thread (hilo) es la unidad más pequeña de ejecución dentro de un proceso. Los hilos permiten la ejecución concurrente de tareas, lo que significa que múltiples tareas pueden ejecutarse al mismo tiempo dentro de un mismo programa. Esto es especialmente útil en aplicaciones que requieren multitarea, como servidores, interfaces gráficas, o juegos.

Características

  • Concurrencia: Los hilos permiten que varias tareas se ejecuten simultáneamente.
  • Independencia: Cada hilo tiene su propio flujo de ejecución, pila y estado.
  • Comunicación: Los hilos pueden comunicarse entre sí mediante métodos como wait(), notify(), y notifyAll().
  • Sincronización: Los hilos pueden sincronizarse para evitar condiciones de carrera y garantizar la consistencia de los datos.

Métodos principales de la clase Thread

  • start(): Inicia la ejecución del hilo.
  • run(): Contiene el código que el hilo ejecutará.
  • sleep(long millis): Pausa la ejecución del hilo durante un tiempo especificado.
  • join(): Espera a que el hilo termine su ejecución.
  • interrupt(): Interrumpe la ejecución del hilo.
  • isAlive(): Verifica si el hilo está en ejecución.
Diagrama introductorio de Threads

Figura 1: Representación de hilos de ejecución.

Práctica: Juego Básico con Threads

Objetivo

Conocer el funcionamiento de la programación concurrente (hilos, Threads) mediante la implementación de un juego básico donde un jugador debe esquivar obstáculos que caen desde la parte superior de la pantalla.

El jugador se moverá horizontalmente usando las teclas de flecha, y los obstáculos caerán a diferentes velocidades. Utilizaremos hilos para manejar el movimiento del jugador y la caída de los obstáculos. Todas las clases se desarrollan en el mismo paquete.

Boceto del juego

Figura 2: Estructura visual del juego a desarrollar.

Paso 1: Crear la clase Jugador

El jugador será representado por un objeto que se moverá horizontalmente.


public class Jugador extends Thread {
    private int posicionX;
    private boolean corriendo;

    public Jugador() {
        this.posicionX = 0;
        this.corriendo = true;
    }

    public void moverDerecha() {
        if (posicionX < 9) posicionX++;
    }

    public void moverIzquierda() {
        if (posicionX > 0) posicionX--;
    }

    public int getPosicionX() {
        return posicionX;
    }

    @Override
    public void run() {
        while (corriendo) {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public void detener() {
        corriendo = false;
    }
}
                    
Implementación del jugador

Paso 2: Crear la clase Obstaculo

Los obstáculos caerán desde la parte superior de la pantalla.


class Obstaculo extends Thread {
    private int posicionX;
    private int posicionY;
    private int velocidad;
    private boolean activo;

    public Obstaculo(int velocidad, int posicionX) {
        this.posicionX = posicionX;
        this.posicionY = 0;
        this.velocidad = velocidad;
        this.activo = true;
    }

    public int getPosicionX() { return posicionX; }
    public int getPosicionY() { return posicionY; }

    @Override
    public void run() {
        while (activo && posicionY < 10) {
            posicionY++;
            try {
                Thread.sleep(velocidad);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        activo = false;
    }

    public boolean estaActivo() { return activo; }
}
                    
Implementación de obstáculos

Paso 3: Crear la clase Juego

Esta clase manejará la lógica del juego y la interacción entre el jugador y los obstáculos.


import javax.swing.*;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

public class Juego {
    private Jugador jugador;
    private List<Obstaculo> obstaculos;
    private JFrame ventana;
    private PanelJuego panelJuego;
    private boolean juegoActivo;

    public Juego() {
        jugador = new Jugador();
        obstaculos = new ArrayList<>();
        juegoActivo = true;

        ventana = new JFrame("Juego con Threads");
        ventana.setSize(500, 500);
        ventana.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        panelJuego = new PanelJuego(jugador, obstaculos);
        ventana.add(panelJuego);

        ventana.addKeyListener(new KeyAdapter() {
            @Override
            public void keyPressed(KeyEvent e) {
                if (e.getKeyCode() == KeyEvent.VK_LEFT) {
                    jugador.moverIzquierda();
                } else if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
                    jugador.moverDerecha();
                }
            }
        });

        ventana.setFocusable(true);
        ventana.setVisible(true);
    }

    public void iniciar() {
        jugador.start();

        Thread generadorObstaculos = new Thread(() -> {
            Random random = new Random();
            while (juegoActivo) {
                Obstaculo obstaculo = new Obstaculo(random.nextInt(500) + 100, random.nextInt(10));
                obstaculos.add(obstaculo);
                obstaculo.start();
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        generadorObstaculos.start();

        while (juegoActivo) {
            panelJuego.repaint();

            for (Obstaculo obstaculo : obstaculos) {
                if (obstaculo.getPosicionY() == 9 && jugador.getPosicionX() == obstaculo.getPosicionX()) {
                    juegoActivo = false;
                    JOptionPane.showMessageDialog(ventana, "¡Colisión! Fin del juego.");
                    jugador.detener();
                    for (Obstaculo o : obstaculos) { o.interrupt(); }
                    return;
                }
            }

            obstaculos.removeIf(obstaculo -> !obstaculo.estaActivo());

            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
                    
Implementación del hilo principal

Paso 4: Crear la clase PanelJuego

Esta clase servirá para visualizar el juego en la pantalla.


import javax.swing.*;
import java.awt.*;
import java.util.List;

public class PanelJuego extends javax.swing.JPanel {
    private Jugador jugador;
    private List<Obstaculo> obstaculos;

    public PanelJuego(Jugador jugador, List<Obstaculo> obstaculos) {
        this.jugador = jugador;
        this.obstaculos = obstaculos;
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);

        g.setColor(Color.BLUE);
        g.fillRect(jugador.getPosicionX() * 50, 450, 50, 50);

        g.setColor(Color.RED);
        for (Obstaculo obstaculo : obstaculos) {
            if (obstaculo.estaActivo()) {
                g.fillRect(obstaculo.getPosicionX() * 50, obstaculo.getPosicionY() * 50, 50, 50);
            }
        }
    }
}
                    
Renderizado Gráfico

Paso 5: Desarrollar la clase main() y ejecutar

La clase main es la clase principal. En esta se realizan las instancias para que el juego se pueda ejecutar.


public class Threads {
    public static void main(String[] args) {
        Juego MiJuego = new Juego();
        MiJuego.iniciar();
    }
}
                    

Actividad

Identifica en cada una de las clases codificadas el uso de los hilos. Haz una lista de líneas de código que utilizaron hilos y explica qué función tiene cada línea. Escribe tus respuestas en el panel de notas de la derecha.

Conclusión y Recomendaciones

Resumen

Threads permiten la ejecución concurrente de tareas en Java. En esta práctica, utilizamos hilos para manejar el movimiento del jugador y la caída de los obstáculos en un juego básico. Los métodos start(), run(), sleep(), y interrupt() son fundamentales para controlar la ejecución de los hilos.

Recomendaciones

  1. Sincronización: Asegúrate de sincronizar el acceso a recursos compartidos para evitar condiciones de carrera.
  2. Manejo de excepciones: Siempre maneja las excepciones en los hilos para evitar que el programa se detenga inesperadamente.
  3. Evitar bloqueos: Diseña cuidadosamente la lógica de los hilos para evitar bloqueos (deadlocks).
  4. Utiliza join() cuando necesites esperar a que un hilo termine antes de continuar con la ejecución.

¡Bienvenidos al Sprint Challenge! ⏱️

Tiempo máximo: 40 min

El día de hoy pondremos a prueba su capacidad de respuesta en el dominio de MultiThreads y la creatividad visual en una carrera contra el reloj.

El Desafío

Partiendo de su proyecto base de juego con hilos, deberán realizar las siguientes modificaciones en un máximo de 40 minutos:

  • Modo Multijugador: Implementar un hilo adicional de ejecución para controlar a un segundo jugador de forma independiente.
  • Modo Multiobstáculos: Implementar un hilo adicional de ejecución para controlar a un segundo obstáculo de forma independiente.
  • Rediseño Visual: Modificar creativamente los assets (imágenes/sprites) de los obstáculos y de ambos jugadores. No se permite el diseño original. Puedes usar alguna herramienta de IA.
  • Lógica Funcional: Ambos jugadores deben poder interactuar con el entorno (colisiones y movimiento) sin interferir negativamente con el hilo del otro.

Criterios de Evaluación

Criterio Puntuación Esperada (1-5)
Sincronización: Funcionamiento fluido de los hilos sin bloqueos.[ 1 - 2 - 3 - 4 - 5 ]
Lógica de Colisión: Detección correcta de impactos para ambos jugadores.[ 1 - 2 - 3 - 4 - 5 ]
Identidad Visual: Creatividad y originalidad en el cambio de imágenes.[ 1 - 2 - 3 - 4 - 5 ]
Jugabilidad: Controles claros y experiencia de juego estable.[ 1 - 2 - 3 - 4 - 5 ]

Instrucciones de Entrega 📱

Entregar el juego funcionando, con los requerimientos solicitados.

ocurre

Panel de Notas

Escribe aquí tus apuntes, resoluciones o dudas.

ⓒ Copyright EduCer, Dr. Niels Henryk Aranda Cuevas