Juego de plataformas en Java (3): Personaje principal

En el articulo anterior agregamos la imagen del fondo de nuestro juego; en esta oportunidad vamos a incorporar al personaje principal al juego.

Para ello utilizaremos la librería de imágenes que descargamos anteriormente

Son sprites, por lo que cada imagen contiene todas las posiciones del personaje para determinada acción; para generar el movimiento solo mostraremos una parte de la imagen principal en determinado momento y lo iremos desplazando a medida que se desarrolle el juego. Algo similar a lo que realizamos con el fondo del juego.

Dentro de la carpeta de image, tenemos una carpeta llamada Characters y dentro de la misma, tenemos una carpeta por cada personaje disponible. La idea es construir una clase general que nos permita manejar a cualquiera de los personajes disponibles.

Comenzaremos creando una clase llamada Player en principio:

package gsampallo;

import java.awt.*;
import java.awt.Point;
import java.awt.image.BufferedImage;
import java.io.File;

import javax.imageio.ImageIO;

public class Player {
    
    private int type;
    private Point position;

    public Player(int type,Point initialPosition) {
        this.type = type;
        this.position = initialPosition;
    }

}

En función del tipo de personaje sera la ubicación de las imágenes que utilizaremos, debemos crear un método llamada loadImages() que se ocupara de cargar las imágenes necesarias:

    private BufferedImage imageIdle;
    private BufferedImage imageRun;
    private BufferedImage imageJump;
    private BufferedImage imageFall;
    private BufferedImage imageHit;

    private void loadImages() {

        String[] pathImages = {
            "image/characters/Mask Dude/",
            "image/characters/Ninja Frog/",
            "image/characters/Pink Man/",
            "image/characters/Virtual Guy/"
        };

        String pathIdle = pathImages[type]+"Idle.png";
        String pathRun = pathImages[type]+"Run.png";
        String pathJump = pathImages[type]+"Jump (32x32).png";
        String pathFall = pathImages[type]+"Fall (32x32).png";
        String pathHit = pathImages[type]+"Hit (32x32).png";        

        try {

            imageIdle = ImageIO.read(new File(pathIdle));
            imageRun = ImageIO.read(new File(pathRun));
            imageJump = ImageIO.read(new File(pathJump));
            imageFall = ImageIO.read(new File(pathFall));
            imageHit = ImageIO.read(new File(pathHit));
            
        } catch (Exception e) {
            System.err.println("No se pudieron cargar imagenes");
            System.err.println(e.getMessage());
            System.exit(0);
        }

    }

En este punto aclaro que elegir un personaje u otro, solo cambia la parte gráfica; el comportamiento en principio serán los mismos.

Incorporaremos también algunas variables globales para facilitarnos un poco el trabajo:

    public static int MASK_DUDE = 0;
    public static int NINJA_FROG = 1;
    public static int PINK_MAN = 2;
    public static int VIRTUAL_GUY = 3;

    public static int STATE_IDLE = 0;
    public static int STATE_RUN = 1;

    private int width = 32;
    private int height = 32;
    
    private int state;

El personaje puede tener varios estados RUN cuando esta corriendo, IDLE cuando esta detenido; por el momento serán los que utilizaremos.

Finalmente incorporamos los siguientes métodos que nos permite actualizar el personaje y dibujarlo en la pantalla.

    int imageReference = 0;

    public void updatePlayer() {
        if(state == STATE_RUN) {
            if(imageReference < ((imageRun.getWidth()/width)-1)) {
                imageReference++;
            } else {
                imageReference = 0;
            }
        } else if(state == STATE_IDLE) {
            if(imageReference < ((imageRun.getWidth()/width)-1)) {
                imageReference++;
            } else {
                imageReference = 0;
            }
        }
    }


    public BufferedImage getImagePlayer() {
        int x = imageReference*width;
        if(state == STATE_RUN) {   
            return imageRun.getSubimage(x, 0,width,height);
        } else {
            
            //Return Idle Image
            return imageIdle.getSubimage(x, 0,width,height);
        }
    }


    public int getX() {
        return position.x;
    }

    public int getY() {
        return position.y;
    }

Los métodos getX() y getY() permite ubicarlo en la pantalla del juego.

Finalmente debemos modificar los métodos updateGame() y paint() en RunnerOne para incorporar el personaje:

    public void updateGame() {

        /*
         * Background
         */
        background.updateBackground();

        /*
         * Player
         */ 
        player.updatePlayer();
    }

	public void paint(Graphics g) {
        g.drawImage(background.getImageBackground(), 0, 0, null);
        
        g.drawImage(player.getImagePlayer(),player.getX(),player.getY(), null);
    }

No olvidemos instanciarlo en el constructor:

Player player;

    public RunnerOne() {
		/* resto del codigo */

        /*
         * Player
         */
        player = new Player(Player.MASK_DUDE,new Point(50,410));
        

    }

Cuando lo ejecutamos obtenemos el personaje corriendo.

El gif puede demorar en cargar.



https://github.com/gsampallo/runnerone

https://youtu.be/HuLxfCf34ic

Juego de plataformas en Java: Entorno de desarrollo

Mi intención es armar un sencillo juego de plataformas en java, a modo de desafió personal y para poder invertir algo de tiempo en mejorar mi capacidad como programador.

No espero terminar el juego, voy a ir avanzando a medida que tenga tiempo y energías, esto lo comencé hace poco más de una semana y recién ahora lo estoy registrando en el blog; en plena cuarentena,

Creación del proyecto

Estoy utilizando VSCode como mi IDE principal, para este tipo de desarrollos me parece excelente, es rápido y puedo usarlo tanto en mi pc de escritorio con Windows como en la notebook con Ubuntu.

Tengo instalada la version JDK 1.8 en este momento, y como plugins de VSCode para Java:

  • Java Dependency Viewer
  • Java Extension Pack
  • Java Test Runner
  • Maven for Java
  • Language support for Java ™ for Visual Studio Code

De todas formas utilicen las extensiones o el IDE que les resulte más sencillo, si solo van a trabajar con Java puede que Eclipse o Netbeans sean mejores soluciones; dependiendo el tipo de desarrollo que realicen; Java es amplio y se pueden hacer muchas cosas.

Esta sección si no utilizan VSCode pueden saltearla, voy a ir detallando lo que fui haciendo para crear el proyecto.

Vamos a comenzar creando una carpeta llamada «Proyectos», será donde guardaremos los proyectos de Java hechos con VSCode, luego podemos cambiarla sin problemas.

Luego abrimos una nueva ventana de VSCode y presionamos Ctrol+Shift+P para abrir la paleta de comandos y elegimos «Java: Create New Project»:

Acto seguido nos solicita selecciona la carpeta «Proyectos», va a solicitarnos el nombre del proyecto, tipeamos «RunnerOne», el nombre de nuestro juego.

VSCode va a crear la carpeta de src para el código fuente, bin para los archivos compilados (.class) y otros archivos relacionados al proyecto. Van a encontrar que creo el siguiente contenido:

Con F5 podemos compilar y ejecutar el programa, si lo hacemos vamos a obtener el siguiente cuadro:

Dependiendo de las extensiones que tengan instaladas serán las opciones, para este caso, seleccionamos Java.

Compila el código de ejemplo y tenemos el resultado en la consola inferior:

Con esto tenemos creado el proyecto y ya podemos comenzar a programar el juego.

Gestión de versiones: GIT

Voy a utilizar git como gestor de versiones para ir llevando el proyecto y para que sea más sencillo si quieren descargar el código del juego y probarlo.

Para crear un nuevo repositorio desde VSCode debemos ir a la sección de Control de Código Fuente o presionar Ctrol+Shift+G y basta con hacer clic en el botón «Inicialice el repositorio»

Inmediatamente va a crear una carpeta llamada .git en la carpeta de nuestro proyecto (esta oculta, tienen que habilitar la opción en el navegador) donde va a ir marcando todos los cambios.

No me interesa seguir los cambios de los archivos .class por lo que podemos seleccionar el archivo App.class, hacemos clic derecho y luego tildamos la opción «Añadir a .gitignore». El archivo .gitignore le dice a git cuales son los archivos que no nos interesa seguir los cambios, por lo cual no estarán en el registro.

Como vamos a tener muchos archivos .class, editamos el archivo .gitignore para que omita todos los archivos con esa extension.

En este punto podemos hacer los primeros cambios al archivo java para, voy a renombrar el archivo App.java a RunnerOne.java y cambiar el package donde esta ubicado:

VSCode les va a indicar que el archivo RunnerOne esta dentro de la carpeta App, si deseamos renombrar la carpeta o cambiar el package; se debe renombrar la carpeta App a gsampallo (o el nombre de package que hayan elegido).

Guardamos el archivo y realizamos el primer commit; lo hacemos desde el modulo de Git. El texto en la descripción use «Primer commit» pero pueden indicarle el que deseen.


Luego simplemente hace clic en la tilde y los cambios quedan registrados.

GitHub

Voy a crear un repositorio en GitHub, para que este disponible en la nube; para ello una vez que se hayan registrado en GitHub, van a la opción de New:

Nos presenta el siguiente formulario:

Luego de hacer clic en «Create repository», ya tendríamos listo nuestro repositorio en GitHub. Se presenta la pantalla inferior. Solo nos queda asociarlo con el que tenemos en nuestra pc.

Para asociar con el repositorio local, debemos ir a la carpeta del proyecto desde la consola (simbolo del sistema) y tipeamos lo que figura debajo de la opcion: or push an existing repository from the command line:

Si ahora actualizamos la página de nuestro repositorio, encontraremos que se subió el proyecto:

Con esto estamos listos para comenzar.

Pueden encontrar el repositorio aquí:
https://github.com/gsampallo/RunnerOne

En el siguiente articulo comenzaremos a escribir el juego y desarrollar parte de la gráfica.

https://youtu.be/DASRQftG3k8