Programación Avanzada Help

Actividad 5: Actualizando la clase Sprite

Objetivo

Para este ejercicio, debes actualizarse la clase Sprite definir la posición de dibujo de la imagen de cada uno de los elementos de la clase, dentro del área de juego.

Clases de Cache

package org.brick_breaker.cache; import javax.swing.*; import java.awt.image.BufferedImage; import java.util.HashMap; /** * Clase que se encarga de almacenar las imágenes que se van a utilizar en la aplicación. */ public class SpriteCache { /** * Caché de imágenes. Se almacenan las imágenes cargadas en la aplicación. */ private final HashMap<String, BufferedImage> cache = new HashMap<>(); /** * Caché de imágenes GIF. Se almacenan las imágenes GIF cargadas en la aplicación. */ private final HashMap<String, ImageIcon> gifCache = new HashMap<>(); /** * Instancia de la caché de imágenes. */ private static final SpriteCache INSTANCE = new SpriteCache(); /** * Constructor privado de la clase para evitar instanciación. */ private SpriteCache() { } /** * Función que se encarga de obtener la instancia de la caché de imágenes. * * @return Instancia de la caché de imágenes. */ public static SpriteCache getInstance() { return INSTANCE; } /** * Función que se encarga de añadir una imagen a la caché. * * @param name Nombre de la imagen. * @param image Imagen a añadir a la caché. */ public void addImage(String name, BufferedImage image) { cache.putIfAbsent(name, image); } /** * Función que se encarga de añadir una imagen GIF a la caché. * * @param name Nombre de la imagen. * @param image Imagen a añadir a la caché. */ public void addImage(String name, ImageIcon image) { gifCache.putIfAbsent(name, image); } /** * Función que se encarga de obtener una imagen de la caché. * * @param name Nombre de la imagen. * @return Imagen a retornar de la caché o null en caso de que la imagen a buscar no exista. */ public BufferedImage getImage(String name) { return cache.getOrDefault(name, null); } /** * Función que se encarga de obtener una imagen GIF de la caché. * * @param name Nombre de la imagen. * @return Imagen a retornar de la caché o null en caso de que la imagen a buscar no exista. */ public ImageIcon getImageIcon(String name) { return gifCache.getOrDefault(name, null); } }
package org.brick_breaker.cache; import javax.imageio.ImageIO; import javax.swing.*; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; /** * Clase que se encarga de cargar las imágenes del juego. */ public class SpriteLoader { /** * Ruta de las imágenes. */ private static final String SPRITES_PATH = "image/"; /** * Función que se encarga de cargar una imagen en formato png. * * @param fileName Nombre de la imagen a cargar con formato png. * @return Imagen cargada. */ public static BufferedImage loadImage(String fileName) { try { return ImageIO.read(new File(SPRITES_PATH + fileName)); } catch (IOException e) { JOptionPane.showConfirmDialog(null, "Error al cargar la imagen: " + fileName, "Error", JOptionPane.DEFAULT_OPTION, JOptionPane.ERROR_MESSAGE); } return null; } /** * Función que se encarga de cargar una imagen en formato gif. * * @param fileName Nombre de la imagen a cargar con formato gif. * @return Imagen cargada. */ public static ImageIcon loadGif(String fileName) { try { return new ImageIcon(SPRITES_PATH + fileName); } catch (Exception e) { JOptionPane.showConfirmDialog(null, "Error al cargar la imagen: " + fileName, "Error", JOptionPane.DEFAULT_OPTION, JOptionPane.ERROR_MESSAGE); return null; } } }

Estructura de clases

La estructura de clases del paquete sprites es la siguiente:

📦 org.brick_breaker.sprites ├─ bonus │  ├─ Bonus.java │  └─ BonusType.java ├─ bricks │  ├─ Brick.java │  └─ BrickType.java ├─ paddles │  ├─ Paddle.java │  └─ PaddleType.java ├─ Ball.java ├─ Borders.java ├─ Missile.java ├─ MovingSprite.java ├─ Resettable.java └─ Sprite.java

©generated by Project Tree Generator

Actualizando la clase Sprite.java

  1. Verifica que la clase sea abstracta y cuente con los siguientes atributos:

    • Point position: posición vertical del sprite.

    • Dimension size: dimensiones del sprite.

    • String spriteName: imagen que representa el sprite.

  2. Define la función draw de la siguiente manera:

    public void draw(Graphics2D g2d) { g2d.drawImage(getImage(), position.x, position.y, null); }
  3. Verifica la existencia de la función abstracta addImageToCache que permite almacenar una imagen en caché, para que no sea necesario cargarla cada vez que se dibuje el sprite.

  4. Verifica la existencia de las funciones:

    • public Rectangle getBounds() { return new Rectangle(position, size); } public BufferedImage getImage() { return SpriteCache.getInstance().getImage(imageName); }
  5. Verifica la existencia de las funciones get para la posición, el tamaño y el nombre de la imagen.

  6. Verifica la existencia de la función setSize que permite establecer el tamaño del sprite.

Actualizando la clase MovingSprite.java

  1. Verifica que la clase MovingSprite sea abstracta extienda de Sprite.

  2. Verifica que la clase cuente con los siguientes atributos:

    • int dx: velocidad horizontal del sprite.

    • int dy: velocidad vertical del sprite.

  3. Verifica la existencia de la función abstracta move que permite mover el sprite en función de su velocidad.

  4. Verifica la existencia de los getters y setters para los atributos dx y dy.

Toma en cuenta la tabla de direcciones de la siguiente manera:

Dirección

dx

dy

Arriba

0

-1

Abajo

0

1

Izquierda

-1

0

Derecha

1

0

Arriba-Izquierda

-1

-1

Arriba-Derecha

1

-1

Abajo-Izquierda

-1

1

Abajo-Derecha

1

1

Agregando la interfaz Resettable.java

  1. Crea la interfaz Resettable.

  2. Define el método resetPosition que permite restablecer la posición del sprite a su posición inicial.

Actualizando la clase Ball.java

  1. Verifica que la clase Ball extienda de MovingSprite e implemente la interfaz Resettable.

  2. Verifica que la clase cuente con los siguientes atributos:

    • public static final int BALL_WIDTH = 20; public static final int INITIAL_BALL_X = 224; public static final int INITIAL_BALL_Y = 570; public static final Point INITIAL_BALL_POSITION = new Point(INITIAL_BALL_X, INITIAL_BALL_Y); public static final Dimension BALL_SIZE = new Dimension(BALL_WIDTH, BALL_WIDTH); private int speed; private boolean stop; private int dxStop;
  3. Verifica la existencia del siguiente constructor:

    public Ball() { super(INITIAL_BALL_POSITION, "ball", BALL_SIZE, 1, -1); speed = 3; stop = true; dxStop = 0; }
  4. Sobreescribe la función draw de la siguiente manera:

    @Override public void draw(Graphics2D g2d) { g2d.drawImage(getImageIcon().getImage(), position.x, position.y, null); }
  5. Sobrescribe la función addImageToCache de la siguiente manera:

    @Override protected void addImageToCache() { SpriteCache.getInstance().addImage(imageName, SpriteLoader.loadGif("ball.gif")); }
  6. Sobreescribe la función move de la siguiente manera:

    @Override public void move() { if (stop) { position.x += dxStop * speed; } else { position.x += dx * speed; position.y += dy * speed; } }
  7. Verifica la existencia de la función resetPosition que permite restablecer la posición del sprite a su posición inicial.

    @Override public void resetPosition() { position.x = INITIAL_BALL_X; position.y = INITIAL_BALL_Y; dx = 1; dy = -1; stop = true; }
  8. Define la función getImageIcon que permite obtener la imagen del sprite de la siguiente manera:

    public ImageIcon getImageIcon() { return SpriteCache.getInstance().getImageIcon(getImageName()); }

Agregando la clase Borders.java

  1. Crea la clase Borders que extiende de Sprite.

  2. Define el constructor de la clase Borders el nombre de la imagen y la posición del sprite.

  3. Define la función addImageToCache que permite almacenar la imagen en caché de las siguiente manera:

    • @Override protected void addImageToCache() { SpriteCache spriteCache = SpriteCache.getInstance(); BufferedImage image = SpriteLoader.loadImage(imageName + ".png"); spriteCache.addImage(imageName, image); if (image != null) { setSize(new Dimension(image.getWidth(), image.getHeight())); } }
  4. Define las siguientes constantes:

    • TOP_BAR: posición del borde superior.

    • BOTTOM_BAR: posición del borde inferior.

    • LEFT_BAR: posición del borde izquierdo.

    • RIGHT_BAR: posición del borde derecho.

    • public static final Borders LEFT_BAR = new Borders("leftBar", new Point(0, 0)); public static final Borders RIGHT_BAR = new Borders("rightBar", new Point(438, 0)); public static final Borders TOP_BAR = new Borders("topBar", new Point(18, 0)); public static final Borders BOTTOM_BAR = new Borders("topBar", new Point(18, 622));

Los Bonus

  1. Verifica que la clase Bonus extienda de MovingSprite e implemente la interfaz Resettable y Serializable.

  2. Verifica que la clase cuente con los siguientes atributos:

    • boolean active: indica si el bonus está activo o no.

    • BonusType type: tipo de bonus.

  3. Verifica la existencia del siguiente constructor:

    public Bonus(Point startPosition, BonusType type) { super(startPosition, type.getImageName(), Brick.BRICK_SIZE, 0, 1); this.type = type; this.active = false; }
  4. La implementación como tal de la función addImageToCache no es necesaria, ya que la imagen del bonus se cargará posteriormente.

  5. Verifica que el enumerado BonusType cuente con los siguientes atributos:

    • String imageName: nombre de la imagen del bonus.

  6. Define la función abstracta activateBonus que permite activar el bonus.

  7. Agrega al menos 3 tipos de bonus:

    • BonusType.BALL_SPEED: aumenta la velocidad de la bola.

    • BonusType.PADDLE_SPEED: aumenta la velocidad de la paleta.

    • BonusType.MISSILE: permite disparar un misil.

  8. De tal manera que deberán quedar de la siguiente manera en el tipo enumerado:

    BALL_SPEED("ballSpeed"){ @Override public void activateBonus() { } }, PADDLE_SPEED("paddleSpeed"){ @Override public void activateBonus() { } }, MISSILE("missile"){ @Override public void activateBonus() { } };

Actualizando la clase Paddle.java

  1. Verifica que la clase Paddle extienda de MovingSprite e implemente la interfaz Resettable.

  2. Verifica que la clase cuente con los siguientes atributos:

    public static final int INITIAL_PADDLE_X = 202; public static final int INITIAL_PADDLE_Y = 588; public static final Point INITIAL_PADDLE_POSITION = new Point(INITIAL_PADDLE_X, INITIAL_PADDLE_Y); private PaddleType type;
  3. Verifica la existencia del siguiente constructor:

    public Paddle(PaddleType type) { super(INITIAL_PADDLE_POSITION, type.getImageName(), type.getSize(), 0, 0); this.type = type; }
  4. Verifica la existencia de la función addImageToCache que permite almacenar la imagen en caché de las siguiente manera:

    @Override protected void addImageToCache() { SpriteCache spriteCache = SpriteCache.getInstance(); spriteCache.addImage(PaddleType.SMALL.getImageName(), SpriteLoader.loadImage("paddle.png")); spriteCache.addImage(PaddleType.MEDIUM.getImageName(), SpriteLoader.loadImage("paddle.png")); spriteCache.addImage(PaddleType.LARGE.getImageName(), SpriteLoader.loadImage("paddle-large.png")); spriteCache.addImage(PaddleType.SHOOTER.getImageName(), SpriteLoader.loadImage("paddle-laser.png")); }
  5. Verifica la existencia de la función resetPosition que permite restablecer la posición del sprite a su posición inicial.

    @Override public void resetPosition() { position.x = INITIAL_PADDLE_X; position.y = INITIAL_PADDLE_Y; dx = 0; dy = 0; }
  6. Define la función changeType que permite cambiar el tipo de paleta.

    public void changeType(PaddleType type) { this.type = type; setSize(type.getSize()); this.imageName = type.getImageName(); }
  7. Verifica la existencia de la función getType que permite obtener el tipo de paleta.

    public PaddleType getType() { return type; }
  8. Verifica que el enumerado PaddleType se vea de la siguiente manera:

    package org.brick_breaker.sprites.paddles; import java.awt.*; public enum PaddleType { SMALL(new Dimension(32, 16)), MEDIUM(new Dimension(64, 16)), LARGE(new Dimension(128, 16)), SHOOTER(new Dimension(64, 16)); private final Dimension size; PaddleType(Dimension size) { this.size = size; } public Dimension getSize() { return size; } public String getImageName() { return name().toLowerCase() + "Paddle"; } }

Actualizando la clase Brick.java

  1. Verifica que la clase Brick extienda de Sprite e implemente la interfaz Resettable y Serializable.

  2. Verifica que la clase cuente con los siguientes atributos:

    public final static int BRICK_WIDTH = 42; public final static int BRICK_HEIGHT = 20; public final static Dimension BRICK_SIZE = new Dimension(BRICK_WIDTH, BRICK_HEIGHT); private final BrickType type; private int life; private boolean destroyed;
  3. Verifica la existencia del siguiente constructor:

    public Brick(Point position, String imageName, BrickType type) { super(position, imageName, BRICK_SIZE); this.type = type; this.life = type.getLife(); this.destroyed = false; }
  4. Verifica la existencia de la función addImageToCache que permite almacenar la imagen en caché de las siguiente manera:

    @Override protected void addImageToCache() { if (type != null) type.loadSprite(imageName); }
  5. Verifica la existencia de la función hit que permite golpear el ladrillo.

    public void hit() { life--; if (life <= 0) { destroyed = true; } }
  6. Verifica la existencia de la existencia de los getters y setters para los atributos life y destroyed.

  7. Verifica que el enumerado BrickType cuente con los siguientes atributos:

    • int life: vida del ladrillo.

    • int score: puntaje del ladrillo.

  8. Verifica la existencia de la función loadSprite de la siguiente manera:

    public void loadSprite(String imageName) { SpriteCache spriteCache = SpriteCache.getInstance(); BufferedImage image = SpriteLoader.loadImage(imageName + ".png"); spriteCache.addImage(imageName, image); }
  9. Verifica la existencia de los getters de los atributos life y score.

  10. Crea al menos 3 ladrillos:

    • BrickType.RED: ladrillo rojo.

    • BrickType.GREEN: ladrillo verde.

    • BrickType.BLUE: ladrillo azul.

Consideraciones finales

  • Recuerda que estos componentes serán usados posteriormente para dibujar los elementos en el área de juego.

  • Recuerda adecuar la clase FileManager para que cargue los elementos de la clase Sprite y sus respectivos atributos al momento de crear el archivo del nivel.

Last modified: 11 April 2025