Fecha y hora actual: Martes 16 Jul 2019 01:57
Índice del Foro

Foros de programación informática, diseño gráfico y Web

En esta comunidad intentaremos dar soporte de programación a todos los niveles, desde principiantes a profesionales de la informática, desarrollo de programas, programación web y mucho más.

[JAVA] Bases y demo de un juego sencillo 2D

Responder al Tema Ir a página Anterior1234Siguiente

Índice del Foro > Programación de juegos o videojuegos > [JAVA] Bases y demo de un juego sencillo 2D

Autor Mensaje
Sierra
Usuario Iniciado


Registrado: 10 Ene 2012
Mensajes: 11

Mensaje Publicado: Martes 17 Ene 2012 14:54

Título del mensaje: Re: [JAVA] Bases y demo de un juego sencillo 2D

Responder citando

Me pinta la linea en un fondo blanco, y si pongo la instrucción después de pintar el fondo me la pinta encima pero he comprobado que si minimizo pierdo la imagen :S

Te copio el codigo de carga de las imagenes por si acaso pudiera ser eso:

Código:


/***********************************************************************************\

       METODO PARA CARGAR LAS IMAGENES
       
    \***********************************************************************************/
   
    //Crear una imagen Volatil
    public VolatileImage crearImagenVolatil( int ancho, int alto, int transparencia )
    {   
        imagenVolatil = gc.createCompatibleVolatileImage( ancho, alto, transparencia );
 
        int valido = imagenVolatil.validate(gc);
 
        if ( valido == VolatileImage.IMAGE_INCOMPATIBLE) {
            imagenVolatil = crearImagenVolatil( ancho, alto, transparencia );
            return imagenVolatil;
        }
 
        return imagenVolatil;
    }
   
    //Para cargar una imagen
    public VolatileImage cargarImagen( String filename )
    {
        GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
        GraphicsConfiguration gc = ge.getDefaultScreenDevice().getDefaultConfiguration();
       
       
        //Cargas la imagen desde un archivo con la clase ImageIO
        imagenJuego = cargarBufferedImage( filename );
       
 
        imagenVolatil = crearImagenVolatil( anchura, altura, Transparency.BITMASK );
        Graphics2D g = null;
 
        try {
            g = imagenVolatil.createGraphics();
            g.drawImage( imagenJuego, 0, 0, imagenVolatil.getWidth(), imagenVolatil.getHeight(), null);
        } finally
        {   
            // Siempre es bueno deshacerse del objeto Graphics
          g.dispose();
        }
 
        return imagenVolatil;
    }
   
    public BufferedImage cargarBufferedImage( String filename )
    {
        BufferedImage imagenBuffer = null;
        try
        {
             imagenBuffer = ImageIO.read( new File(filename) );
        }catch( IOException e ){}
        return imagenBuffer;
    }



Gracias WhiteSkull.

Volver arriba
Ver perfil del usuario Enviar mensaje privado
WhiteSkull
CoAdmin


Registrado: 20 Mar 2009
Mensajes: 3136
Ubicación: y*width+x

Mensaje Publicado: Domingo 22 Ene 2012 02:37

Título del mensaje: Re: [JAVA] Bases y demo de un juego sencillo 2D

Responder citando

Eso va ser un problema con el repintado, hay formas para solucionarlo, una por ejemplo es crear un bucle y llamar a la función para que vaya repintando, otra, quizás la más recomendada es que al objeto que pintes, el control o lo que sea, lo personalices, creándote una clase que herede de la que necesitas, y luego le sobreescribas el método paint, claro es más tedioso:

Código:
    @Override
    public void paint(Graphics g)
    {
        super.paint(g);
        //g.drawImage(imagen, 0, 0, null);

    } 


Prueba y me cuentas.

Volver arriba
Ver perfil del usuario Enviar mensaje privado Visitar sitio web del autor
Sierra
Usuario Iniciado


Registrado: 10 Ene 2012
Mensajes: 11

Mensaje Publicado: Martes 28 Feb 2012 14:26

Título del mensaje: Re: [JAVA] Bases y demo de un juego sencillo 2D

Responder citando

Ya solucione la parte del repintado hará un mes. Gracias!!.
Ahora tengo otro problema ( si, parece que se le reza a dios cuando a uno le van mal las cosas jeje ), el juego ya tiene implementado la parte de red con RMI.

Ahora bien, los disparos se crean en modo local para cada jugador. Le envió un vector posición tanto del click del ratón como de la posición del personaje que dispara. La bala es creada con una dirección y una velocidad fija. Así nos ahorramos trafico para refrescar la posición de la bala.

Por tanto, que debo hacer para que aunque la bala impacte en el jugador en todos los clientes a la vez ( o al menos así debería ser ) solo se le reste vida por un disparo XDD si cada cliente llama al servidor para actualizar la vida... le restaremos:

puntos-=(nºclientes x daño)!!!!!

Pues si, no se le avisa al servidor corremos el riesgo de que algún cliente tenga un retraso y no le alcanzase la bala y en unas partidas el jugador este muerto y en otras no. ¿Podría darse el caso verdad?

Espero haberme explicado bien. Gracias de nuevo.

Volver arriba
Ver perfil del usuario Enviar mensaje privado
WhiteSkull
CoAdmin


Registrado: 20 Mar 2009
Mensajes: 3136
Ubicación: y*width+x

Mensaje Publicado: Martes 28 Feb 2012 17:19

Título del mensaje: Re: [JAVA] Bases y demo de un juego sencillo 2D

Responder citando

Lo que debes hacer es sincronizar todos los clientes ¿Cómo es esto? Pues se puede hacer de mil formas pero lo que tienes que conseguir es que todos los clientes vayan al mismo paso que el servidor (y no al revés). Un método podría ser por fuerza bruta, como el servidor dispone de todos los datos de cada cliente, atiende a los clientes que primero responden y los actualiza, osea, les dice por ejemplo donde están las última posiciones recibidas de los otros jugadores. ¿Qué pasa si la conexión de un jugador se queda atrás? Pues cuando sea actualizado por el servidor es posible que aparezca muerto Risa o que los personajes que estaban en su grupo hayan desaparecido, porque en vista de que ellos apreciaban que no quería moverse se han marchado. De verdad que jugando tantas veces on-line, no puedo creerme que no tengas una idea de como se hace. Ah, esos tiempos de partidas con lag, donde la peña se desplazaba por el mapa casi teletransportándose, que recuerdos más gratos.

Por eso es importante que el servidor, la aplicación y las infraestructuras de red, así como el hard sean idóneos y estén muy bien optimizados además que puedan soportar el tráfico salvaje de las partidas online. Aunque si es para un juego por turnos, tipo ajedrez no necesitas ni servidor (juego cliente/servidor), ni disponer de una super conexión.

Sierra escribió:
Pues si, no se le avisa al servidor corremos el riesgo de que algún cliente tenga un retraso y no le alcanzase la bala y en unas partidas el jugador este muerto y en otras no. ¿Podría darse el caso verdad?
El que manda es el servidor, es lo que te comenté al principio, si el jugador recibe con retraso la respuesta del servidor, este, el cliente, primero es actualizado, el servidor le indica los datos de los otros jugadores, y luego cuando cuando marcha, se lleva los datos de ese retrasado para enviársela a los demás. Lógicamente, pasará eso que describes, se econtrará la partida superdesfasada, hasta que la conexión vuelva a la normalidad. Por ejemplo, si te fijas bien, muchos servidores comerciales de juegos profesionales, de consola o PC, no admiten jugadores con mucho lag, para no cabrear a que se encuentran jugando, y si hay alguno en la partida que comienza a desincronizarse por lo que sea, igual, lo sacan de la partida.

Volver arriba
Ver perfil del usuario Enviar mensaje privado Visitar sitio web del autor
WhiteSkull
CoAdmin


Registrado: 20 Mar 2009
Mensajes: 3136
Ubicación: y*width+x

Mensaje Publicado: Martes 29 May 2012 22:26

Título del mensaje: Re: [JAVA] Bases y demo de un juego sencillo 2D

Responder citando

SPACE INVADERS

Si, aquel juego que jugaban los primos mayores. He aquí como hacerlo con unas pocas clases. El juego no precisa de gráficos, porque los genera en tiempo de ejecución.

Vamos por partes, anteriormente describíamos como usar clases bases para nuestro juego. En este juego se ha realizado de la misma forma, ya que en un juego donde participen objetos que se muevan por la pantalla, de seguro compartirán cosas en común.

Entonces nuestra primera clase será, la clase Sprite.

Código:
package invaders;

import java.awt.Graphics2D;

// La clase base de cualquier objeto visual que se mueva por la interfaz
public class Sprite{
    private int x,y; //coordenadas
    private boolean visible; // si esta visible o no

    public Sprite() //Constructor
    {
        visible=true;
        x=y=0;
    }

    public boolean isVisible()
    {
        return visible;
    }

    public void setVisible(boolean estado)
    {
        visible=estado;
    }

    public int getX() // Obtenemos la coordenada horizontal actual del Sprite
    {
        return x;
    }

    public void setX(int valor) //Asignamos la coordenada horizontal actual del Sprite
    {
        x=valor;
    }

    public int getY() // Obtenemos la coordenada vertical actual del Sprite
    {
        return y;
    }

    public void setY(int valor) // Asignamos la coordenada vertical actual del Sprite
    {
        y=valor;
    }

    public int getWidth() // Ancho del Sprite
    {
        return 0;
    }

    public int getHeight() // Alto del Sprite
    {
        return 0;
    }

    public void putSprite(Graphics2D grafico,int coordenadaHorizontal,int coordenadaVertical) 
    {
        // Pegamos el Sprite en la pantalla
    }

}


Esta clase nos servirá para definir los objetos principales del juego, el objeto de nuestra Nave, el Laser que sale de la nave, el Misil que sale de la nave alienígena y la nave alienígena en si. Dichos objetos tiene diferentes comportamientos y algunos similares, así que tomaremos la clase Sprite y definiremos los comportamientos para cada objeto, para ello comenzaremos con el protagonista, el personaje jugable, la Nave.

Código:
package invaders;

import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;

public class Nave extends Sprite implements KeyListener {
    private Interfaz interfaz;
    private boolean izquierda, derecha, disparo;

    public Nave(Interfaz interfaz){
        super();
        this.setY(interfaz.getHeight()-15);
        this.interfaz=interfaz;
        interfaz.contenedorDeSprites().add(this);
    }
   
    @Override
    public void putSprite(Graphics2D grafico, int x, int y) {
        grafico.setColor(Color.GREEN);
        grafico.fillRect(x+6, y, 6, 5);       
        grafico.fillRect(x, y+5, 18, 5);
    }
   
    @Override
    public int getWidth() {
        return 18;
    }

    @Override
    public int getHeight() {
        return 11;
    }

    // Definimos el comportamiento en funcion de las teclas pulsadas
    public void actualiza() {
        if(izquierda) {
            this.setX(this.getX()-5);
            if (this.getX()<1) this.setX(1);
        } else if(derecha) {
            this.setX(this.getX()+5);
            if (this.getX()>interfaz.getWidth()-this.getWidth()) this.setX(interfaz.getWidth()-this.getWidth());
        }
       
        if (disparo) {
            disparo=false;
            new Laser(this);
        }
    }

    // tecla soltada
    @Override
    public void keyReleased(KeyEvent e) {
        switch (e.getKeyCode()) {
            case KeyEvent.VK_LEFT:
                izquierda = false;
                break;
            case KeyEvent.VK_RIGHT:
                derecha = false;
                break;
            case KeyEvent.VK_SPACE:
                disparo = false;
                break;
        }
    }

    //tecla presionada
    @Override
    public void keyPressed(KeyEvent e) {
        switch (e.getKeyCode()) {
            case KeyEvent.VK_LEFT:
                izquierda = true;
                break;
            case KeyEvent.VK_RIGHT:
                derecha = true;
                break;
            case KeyEvent.VK_SPACE:
                disparo = true;
                break;
        }
    }

    @Override
    public void keyTyped(KeyEvent e) { }

    // Permite conocer la interfaz donde se ejecuta el jugador
    public Interfaz interfaz() {
        return interfaz;
    }
}


Que a su vez dispara un Laser. El Laser y el resto de objetos, a diferencia de la Nave, que es controlada por el jugador, y que solamente responde a determinados eventos del teclado, requiere que se mueva o se comporta con total independencia de lo que el jugador haga, pero siempre cumpliendo las condiciones que el programador le imponga. Para ello recurriremos a un bucle infinito individual, osea, un bucle para cada objeto y para independizarlo de lo demás, usaremos un hilo, un hilo por objeto. Lo que mantendrá unido ese comportamiento con el juego, será el vínculo con el juego, que simboliza la misma interfaz, que es la que en todo momento sabe donde está cada uno y hará de arbitro, dicho vinculo lo obtiene cada objeto mediante referencia de sus padres.

Código:
package invaders;

import java.awt.Color;
import java.awt.Graphics2D;
import java.util.logging.Level;
import java.util.logging.Logger;

public class Laser extends Sprite {
    private Nave jugador;
    private static int laseresEnPantalla=0;
   
    public Laser(Nave jugador){
        super();
        if (laseresEnPantalla<3) {
            laseresEnPantalla++;             
            this.setY(jugador.getY()-11);
            this.setX(jugador.getX()+7);       
            jugador.interfaz().contenedorDeSprites().add(this);
            this.jugador=jugador;
            new Comportamiento(this).start();         
        }
    }

    private class Comportamiento extends Thread {
        Laser laser;
        public Comportamiento(Laser laser) {
            super();
            this.laser=laser;
        }

        @Override
        public void run() {
            // El ciclo de vida del laser es desde que sale de la nave
            // hasta que desaparece o sale de los limites
            while(laser.getY()>15 && laser.isVisible()){
                try {
                    Thread.sleep(100);
                } catch (InterruptedException ex) {
                    Logger.getLogger(Laser.class.getName()).log(Level.SEVERE, null, ex);
                }
                laser.setY(laser.getY()-10);   
            }
            laseresEnPantalla--;
            jugador.interfaz().contenedorDeSprites().remove(laser);
        }
    }
   
    // Definimos el grafico del laser (el mismo que el misil)
    @Override
    public void putSprite(Graphics2D grafico, int x, int y) {
        grafico.setColor(Color.BLUE);
        grafico.fillRect(x, y, 4, 10);
    }
   
    // Definimos el ancho
    @Override
    public int getWidth() {
        return 4;
    } 
}


Ahora el UFO o nave alienígena.

Código:
package invaders;

import java.awt.Color;
import java.awt.Graphics2D;

public class UFO extends Sprite {
    private Interfaz interfaz;
    private int disparo=1; // Inidcamos el numero de disparos que puede realizar el UFO
   
    public UFO(Interfaz interfaz){
        super();
        this.interfaz=interfaz;
        interfaz.contenedorDeSprites().add(this);
    }
   
    @Override
    public void putSprite(Graphics2D grafico, int x, int y) {
        grafico.setColor(Color.RED);
        grafico.fillRect(x+6, y, 6, 5);       
        grafico.fillRect(x, y+5, 18, 5);
    }
   
    @Override
    public int getWidth() {
        return 18;
    }

    @Override
    public int getHeight() {
        return 11;
    }
   
    public Interfaz interfaz() {
        return interfaz;
    }
   
    // Reiniciamos los disparos
    public void recargaDisparo(){
        disparo=1;
    }
   
    // Indica si puede seguir disparando
    public boolean dispara(){
        if (disparo>0) {
            disparo--;
            return true;
        } else
            return false;
    }
}


Y como no, el misil disparado por la nave alienígena.

Código:
package invaders;

import java.awt.Color;
import java.awt.Graphics2D;
import java.util.logging.Level;
import java.util.logging.Logger;

public class Misil extends Sprite{
    private UFO naveAlienigena;
   
    // El misil sale del UFO
    public Misil(UFO naveAlienigena){
        super();
        // Impedimos que el UFO lanze otro misil mientras exista uno lanzado
        if (naveAlienigena.dispara()) {         
            // En caso de no haber un misil lanzado lo lanzamos por debajo del UFO
            this.setY(naveAlienigena.getY()+11);
            this.setX(naveAlienigena.getX()+7);       
            // Lo añadimos al contenedor de Sprites para poder visualizarlo y sirva de referencia
            naveAlienigena.interfaz().contenedorDeSprites().add(this);
            this.naveAlienigena=naveAlienigena;
            // Comienza el cliclo de vida del misil
            new Misil.Comportamiento(this).start();         
        }   
    }
 
    // Definimos el comportamiento del misil en un hilo
    private class Comportamiento extends Thread {
        private Misil misil;
        public Comportamiento(Misil misil) {
            super();
            this.misil=misil;
        }

        @Override
        public void run() {
            // Mientras el misil no llegue hasta a la "tierra" existirá el misil
            while(misil.getY()<naveAlienigena.interfaz().getHeight()){
                try {
                    Thread.sleep(100); // retardo
                } catch (InterruptedException ex) {
                    Logger.getLogger(Laser.class.getName()).log(Level.SEVERE, null, ex);
                }
                misil.setY(misil.getY()+10);   
            }
            // Finaliza el cliclo de vida del misil
            naveAlienigena.interfaz().contenedorDeSprites().remove(misil);
            naveAlienigena.recargaDisparo(); // indicamos al UFO que puede realizar otro disparo
        }
    }
   
    // Definimos el grafico del misil
    @Override
    public void putSprite(Graphics2D grafico, int x, int y) {
        grafico.setColor(Color.MAGENTA);
        grafico.fillRect(x, y, 4, 10);
    }
   
    // Definimos el ancho
    @Override
    public int getWidth() {
        return 4;
    }
}


Mientras diseñaba el juego, pensaba en el comportamiento del juego original y pensaba, las naves enemigas se comportan como un escuadrón, osea, el movimiento de va y viene de un lado a otro es sincronizado, por lo que no sería mala idea crear una clase, que se encargara del comportamiento de todas naves, y decidiera que nave debe disparar. Fíjese además, que los disparos están limitados adrede, tanto para el jugador como para la máquina. Porque de otra forma sería casi imposible escapar, pero igualmente se puede jugar con esta característica para hacer más difícil el juego en caso de crear niveles.

Clase EscuadronUFO.
Código:
package invaders;

import java.util.ArrayList;
import java.util.Random;
import java.util.logging.Level;
import java.util.logging.Logger;

public class EscuadronUFO {
    private ArrayList escuadronUFO=new ArrayList();
   
    public EscuadronUFO(Interfaz interfaz,int columnas,int filas){
        UFO enemigo=new UFO(interfaz); // Generamos un UFO de prueba para conocer calcular la distancia
        // entre las naves
        int espacioEntreNaves=(interfaz.getWidth()-((columnas+1)*enemigo.getWidth()))/(columnas+1);
        interfaz.contenedorDeSprites().remove(enemigo); // Luego lo eliminamos
        for (int f=0;f<filas;f++)
            for (int c=0;c<columnas;c++) {
                enemigo=new UFO(interfaz);
                enemigo.setX((enemigo.getWidth()+espacioEntreNaves)*(c+1));
                enemigo.setY((enemigo.getHeight()+5)*(f+2));
                escuadronUFO.add(enemigo);
            }       
        // Una vez creado el escuadron, este actua como uno solo y se encarga del comportamiento de las naves
        new EscuadronUFO.Comportamiento(interfaz).start();         
    }

    private class Comportamiento extends Thread {
        Interfaz interfaz;
        public Comportamiento(Interfaz interfaz) {
            super();
            this.interfaz=interfaz;
        }

        @Override
        public void run() {
            Random rnd = new Random(System.currentTimeMillis());
            UFO naveAlienigena;
            boolean paUnLao=true,gameOver=false,aux=paUnLao;
            do { // Mientras exista algún UFO, existira la maldad XD
                try {
                    Thread.sleep(300); // Retardo
                } catch (InterruptedException ex) {
                    Logger.getLogger(Laser.class.getName()).log(Level.SEVERE, null, ex);
                }
                // Comprueba que naves alienigenas siguen con vida en el escuadron         
                for (int i=0;i<escuadronUFO.size();i++)
                    if (!interfaz.contenedorDeSprites().contains(escuadronUFO.get(i)))
                        escuadronUFO.remove(escuadronUFO.get(i));
               
                // Movemos el escuadron hacia un lado y luego hacia otro (y a la vez descendemos)
                for (Object objeto: escuadronUFO) {
                    naveAlienigena=(UFO)objeto;
                    naveAlienigena.setY(naveAlienigena.getY()+1);
                    // Si algún UFO llega a la tierra, acaba la partida :(
                    if (naveAlienigena.getY()>(interfaz.getHeight()-(naveAlienigena.getHeight()*2))) gameOver=true;
                    // Si alguna nave llega a los limites de la pantalla, indicamos al escuadron que cambie de direccion
                    if (paUnLao) {
                        naveAlienigena.setX(naveAlienigena.getX()+10);
                        if (naveAlienigena.getX()>interfaz.getWidth()-naveAlienigena.getWidth()) aux=false;
                    } else {
                        naveAlienigena.setX(naveAlienigena.getX()-10);
                        if (naveAlienigena.getX()<1) aux=true;
                    }     
                    // Aleatoriamente abriran fuego contra la tierra
                    if(rnd.nextInt(escuadronUFO.size())==1) new Misil(naveAlienigena);
                }
                paUnLao=aux;
            } while(escuadronUFO.size()>0 && !gameOver);
            interfaz.contenedorDeSprites().removeAll(escuadronUFO);
            escuadronUFO.clear();
        }
    }
}


Y ya por último tenemos la clase madre, el frame donde se imprimen los gráficos, la clase Interfaz. Esta clase, como antes se comentó, se encarga de controlar quien muere y quien vive, dicho de otra forma controla las colisiones y se encarga de que los sprites se impriman encima de ella, los actualiza.

Código:
package invaders;

import java.awt.Frame;
import java.awt.Graphics2D;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;

public class Interfaz extends Frame implements Runnable {
    // Creamos el contenedor de los sprites, que permitira a la interfaz visualizarlos
    // y gestionarlos, así como también creamos un método público que permita
    // compartir dicho contenedor con el fin de que pueda ser gestionado
    private ArrayList sprites=new ArrayList();
    public ArrayList contenedorDeSprites(){
        return sprites;
    }
   
    // Definimos la interfaz, que es el marco gráfico donde se ejecuta el juego
    public Interfaz(){
        // Tamaño de la ventana
        this.setBounds(0, 0, 520, 310);
        // Centramos la ventana
        this.setLocation((java.awt.Toolkit.getDefaultToolkit().getScreenSize().width/2)-(this.getWidth()/2)
        , (java.awt.Toolkit.getDefaultToolkit().getScreenSize().height/2)-(this.getHeight()/2));
        // Impedimos que se altere el tamaño de la ventana
        this.setResizable(false);
        this.setTitle("Space Invaders");
        this.setVisible(true);
        // Todos los eventos de la ventana recogidos en los metodos de esta clase
        this.addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                System.out.println("Cerrando");
                System.exit(0);
            }
        });
    }
   
    // Hilo del juego
    @Override
    public void run() {
        // Creamos la nave del jugador y le pasamos los eventos del teclado para
        // que el jugador pueda interactura con ella
        Nave jugador=new Nave(this);
        this.requestFocus(); // Focalizamos hacia nuestro objeto
        this.addKeyListener(jugador); // Direccionamos la captura de teclas al Jugaodr
       
        // Generamos un escuadron de UFOs, el primer argumento toma la interfaz
        // el segundo las columnas y el tercero las filas, así podemos personalizar la partida
        new EscuadronUFO(this,7,4);
       
        // Bucle principal, donde trasncurre la partida
        while(actualizar()) {// Actualizar gestiona la partida       
            try {
                Thread.sleep(25); // Retardo, permite ejecutarse igual en cualquier equipo
            } catch (InterruptedException ex) {
                Logger.getLogger(Interfaz.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
        // GameOver
        System.exit(0);
    }
   
    // Gestor de la partida que controla el pintado de los sprites, los impactos y
    // determina segun los casos si la partida finaliza.
    private boolean actualizar(){
         // Buffer que permite evitar el parpadeo cada vez que se limpia la pantalla,
         // además es el objeto donde se intaran los sprites
         BufferedImage pantalla=new BufferedImage(this.getWidth(),this.getHeight(), BufferedImage.TYPE_INT_RGB);
         pantalla.getGraphics().fillRect(0, 0, pantalla.getWidth(), pantalla.getHeight());
         // banderas del control de la partida
         boolean gameOver=true,jugadorVivo=false;
         
         // Gestionamos TODOS los sprites
         for (int i=0;i<sprites.size();i++) {
             try {// Pintamos el sprite
                ((Sprite)sprites.get(i)).putSprite((Graphics2D)pantalla.getGraphics(),((Sprite)sprites.get(i)).getX(), ((Sprite)sprites.get(i)).getY());

                // En caso de que el sprite sea la NAVE del jugador
                if (sprites.get(i).getClass()==Nave.class) {
                    ((Nave)sprites.get(i)).actualiza(); // Mueve la nave acorde a las teclas pulsadas
                    // Comprueba si hay algun MISIL que impacte con la nave
                    jugadorVivo=compruebaImpactoMisil(((Nave)sprites.get(i)));
                // En caso de que el sprite sea un LASER disparado por el jugador
                } else if (sprites.get(i).getClass()==Laser.class) {
                    // Comprobamos si hay impacto del LASER con un UFO
                    if (((Laser)sprites.get(i)).isVisible()) compruebaImpactoDelLaser((Laser)sprites.get(i));
                    // En caso de impacto eliminamos el LASER
                    else sprites.remove(i);
                // En caso de que el sprite sea un UFO o una nave alienigena
                } else if (sprites.get(i).getClass()==UFO.class) {
                    // Significará que la partida todavía no ha acabado y qeu faltan UFOs por destruir
                    gameOver=false;
                    // Si el UFO fue impactado por el LASER (invisible) lo eliminamos
                    if (!((UFO)sprites.get(i)).isVisible()) sprites.remove(i);
                }
             } catch(IndexOutOfBoundsException ioex){
             
             }
         }
         // Volcamos el buffer visual donde se dibujan los sprites a la ventana
         this.getGraphics().drawImage(pantalla, 0, 0, this);
         return (!gameOver && jugadorVivo);
    }
   
    // En caso de impacto hacemos invisble el LASER y el UFO
    private void compruebaImpactoDelLaser(Laser laserJugador){
        for (int i=0;i<sprites.size();i++)
            if (sprites.get(i).getClass()==UFO.class) if (((UFO)sprites.get(i)).isVisible()) {
                UFO enemigo=(UFO)sprites.get(i);
                if ((laserJugador.getX()>enemigo.getX() && laserJugador.getX()+laserJugador.getWidth()<enemigo.getX()+enemigo.getWidth()) &&
                   (laserJugador.getY()<enemigo.getY()+enemigo.getHeight() && laserJugador.getY()>enemigo.getY()))
                {    enemigo.setVisible(false);
                     laserJugador.setVisible(false);
                     break;
                }
            }
    }
   
    // En caso de ser alcanzado por un MISIL lo notificamos devolviendo FALSE
    private boolean compruebaImpactoMisil(Nave jugador){
        for (int i=0;i<sprites.size();i++)
            if (sprites.get(i).getClass()==Misil.class) {
                Misil laserEnemigo=(Misil)sprites.get(i);
                if ((laserEnemigo.getX()>jugador.getX() && laserEnemigo.getX()+laserEnemigo.getWidth()<jugador.getX()+jugador.getWidth()) &&
                   (laserEnemigo.getY()<jugador.getY()+jugador.getHeight() && laserEnemigo.getY()>jugador.getY()))
                    return false;
             }
        return true;
    }
}


Y ya, para finalizar, solamente nos queda ejecutar la clase Interfaz para observar el resultado. Solamente hay que hacerle un run(), como cuando uno ejecutaba antiguamente las cintas de cassette. El movimiento abrupto hacia los laterales es intencionado, tal como hacía la máquina original o que yo recuerde se movía así.

Código:
package invaders;

public class Invaders {
    public static void main(String[] args) {
        // Instaciamos la clase principal y la ejecutamos
        new Interfaz().run();
    }
}


Que lo disfruten...



Ultima edición por WhiteSkull el Martes 29 May 2012 23:38; editado 1 vez
Volver arriba
Ver perfil del usuario Enviar mensaje privado Visitar sitio web del autor
marlanga
Usuario Iniciado


Registrado: 28 May 2012
Mensajes: 22
Ubicación: Murcia - España

Mensaje Publicado: Martes 29 May 2012 23:32

Título del mensaje: Re: [JAVA] Bases y demo de un juego sencillo 2D

Responder citando

Buen juego, pero dos detalles.
-Es el Space Invaders. El Arkanoid era aquél de la bolita que rompe ladrillos Risa
-En vez de usar Threads, hay una técnica que te permitirá multiplicar por mil el número de "entidades" que aguanten sin desfallecer tus juegos: El tiempo delta.

Básicamente es tener un sólo thread, el juego principal. En el bucle principal que mueve el juego, creas una variable local donde calculas el tiempo transcurrido desde la última ejecución del bucle. Y le pasas ese tiempo, usualmente en milisegundos, a las entidades que deban moverse. Cada entidad tendrá una velocidad de píxeles por milisegundo. Asi que multiplicas su velocidad por el tiempo transcurrido, y obtienes así la cantidad de píxeles que tiene que desplazarse esa figura en esa vuelta del bucle.

Yo programé un PACMAN usando treads para cada fantasma. A partir de los 50 fantasmas,el juego se congestionaba de mala manera. Con el tiempo delta, movía sin problemas cientos y miles de fantasmas.

Volver arriba
Ver perfil del usuario Enviar mensaje privado
WhiteSkull
CoAdmin


Registrado: 20 Mar 2009
Mensajes: 3136
Ubicación: y*width+x

Mensaje Publicado: Martes 29 May 2012 23:41

Título del mensaje: Re: [JAVA] Bases y demo de un juego sencillo 2D

Responder citando

marlanga escribió:
-Es el Space Invaders. El Arkanoid era aquél de la bolita que rompe ladrillos
jajaja lo hice adrede, me decía : "que raro, está tardando en corregirme" Risa

marlanga escribió:
Básicamente es tener un sólo thread, el juego principal. En el bucle principal que mueve el juego, creas una variable local donde calculas el tiempo transcurrido desde la última ejecución del bucle. Y le pasas ese tiempo, usualmente en milisegundos, a las entidades que deban moverse. Cada entidad tendrá una velocidad de píxeles por milisegundo. Asi que multiplicas su velocidad por el tiempo transcurrido, y obtienes así la cantidad de píxeles que tiene que desplazarse esa figura en esa vuelta del bucle.

Interesante técnica, donde la aprendiste?

Volver arriba
Ver perfil del usuario Enviar mensaje privado Visitar sitio web del autor
marlanga
Usuario Iniciado


Registrado: 28 May 2012
Mensajes: 22
Ubicación: Murcia - España

Mensaje Publicado: Martes 29 May 2012 23:54

Título del mensaje: Re: [JAVA] Bases y demo de un juego sencillo 2D

Responder citando

No recuerdo, pero tiene página propia en la wikipedia en inglés, porque es una técnica muy usada y muy vieja. "Delta Timing".
Seguramente la vería en algún tutorial de juegos en inglés, de cuando empecé a interesarme por este mundillo.
Desde entonces, no he vuelto a usar otra técnica. La ventaja en eficiencia que tiene sobre cualquier otra técnica es enorme.

En los tutoriales de mi blog, hago uso de ella siempre.

Como no puedo poner enlaces aún Risa tonta tendreis que usar el amigo google para buscar ejemplos.

Volver arriba
Ver perfil del usuario Enviar mensaje privado
WhiteSkull
CoAdmin


Registrado: 20 Mar 2009
Mensajes: 3136
Ubicación: y*width+x

Mensaje Publicado: Miércoles 30 May 2012 00:04

Título del mensaje: Re: [JAVA] Bases y demo de un juego sencillo 2D

Responder citando

Esta explicada, no te preocupes...
Cita:
Básicamente es tener un sólo thread, el juego principal. En el bucle principal que mueve el juego, creas una variable local donde calculas el tiempo transcurrido desde la última ejecución del bucle. Y le pasas ese tiempo, usualmente en milisegundos, a las entidades que deban moverse. Cada entidad tendrá una velocidad de píxeles por milisegundo. Asi que multiplicas su velocidad por el tiempo transcurrido, y obtienes así la cantidad de píxeles que tiene que desplazarse esa figura en esa vuelta del bucle.

...cuando tenga tiempo la pondré en práctica, gracias.

Respecto a lo otro... paciencia Risa tonta

Volver arriba
Ver perfil del usuario Enviar mensaje privado Visitar sitio web del autor
enanogm
Usuario Iniciado


Registrado: 29 Ago 2012
Mensajes: 14

Mensaje Publicado: Domingo 02 Sep 2012 06:03

Título del mensaje: Re: [JAVA] Bases y demo de un juego sencillo 2D

Responder citando

hola, como va?

muy bueno el aporte
muy util para empezar y muy bien explicado

ahora, te comento
fui siguiendo los pasos y fui viendo de a poco los progresos que fuiste mostrando y funciona todo bien, hasta el ultimo
por alguna razon, cuando agrego la clase lorna y modifico la clase sprite me sale el error de que no encuentra la imagen del personaje
verifique las rutas en todas las clases y nada

no se porque sera...

igualmente tu aporte me ayudo mucho a entender algunas cosas que necesitaba para un proyecto que quiero empezar

Saludos

Volver arriba
Ver perfil del usuario Enviar mensaje privado
WhiteSkull
CoAdmin


Registrado: 20 Mar 2009
Mensajes: 3136
Ubicación: y*width+x

Mensaje Publicado: Domingo 02 Sep 2012 17:09

Título del mensaje: Re: [JAVA] Bases y demo de un juego sencillo 2D

Responder citando

Posiblemente porque tengas que hacer un clean & rebuild del proyecto, de todas formas hay otras alternativas en la carga de gráficos. En la clase Sprite se basa en cada vez que hay que pegar el gráfico, lo toma de la carpeta de recursos y lo convierte a imagen, con lo que nos puede servir para dispositivos que no disponen de mucha memoria, en cambio es un proceso poco óptimo.
Código:
  1. ...
  2. public void putSprite(Graphics grafico,int coordenadaHorizontal,int coordenadaVertical) // Pegamos el Sprite en la pantalla
  3. {
  4. ...
  5. ...
  6. if (visible) grafico.drawImage(new ImageIcon(getClass().getResource(sprite)).getImage(), x, y, null);
  7. }
  8. ...
  9.  

Otra forma sería conservar el gráfico en memoria, por ejemplo así:
Código:
  1. ...
  2. URL url = null;
  3. try {
  4. url = getClass().getClassLoader().getResource(nombre);
  5. grafico= ImageIO.read(url); // Donde grafico sería de tipo BufferedImage
  6. } catch (Exception e) {
  7. ...
  8. }
  9. ...

Si te fijas he obtenido el recurso de dos formas diferentes, en el primero obtengo la imagen directamente pasando la ruta local(dentro del paquete) y nombre de la imagen(con su extensión), y el segundo devuelve la ruta del recurso usando el nombre de la imagen(con su extensión). Así pues, si tienes problemas con la localización de los recursos, que no deberías(quien mejor sabe donde pones las cosas que tu mismo), pues puedes probar a usar la segunda forma.

No quiero entrar a fondo en las cuestiones de Java, porque se da por sentado que tienes conocimientos suficientes en este lenguaje, por lo menos para montar un proyecto... por eso quedaría absurdo que te explicara que es el clean & Build o rebuild, es obvio si ya has programado alguna vez y ya no solamente en Java.

Este hilo solamente está orientado a poner las bases del desarrollo de un juego 2D, pero no a la enseñanza de Java. Si quieres puedo facilitarte un enlace que aborda la carga de recursos gráficos.

http://docs.oracle.com/javase/tutorial/uiswing/components/icon.html

suerte Ok

Volver arriba
Ver perfil del usuario Enviar mensaje privado Visitar sitio web del autor
rustinpeace



Registrado: 07 Feb 2013
Mensajes: 5
Ubicación: Ciudad Autónoma de Buenos Aires - Argentina

Mensaje Publicado: Jueves 07 Feb 2013 02:50

Título del mensaje: Problema al dibujar la imagen

Responder citando

Hola WhiteSkull, me gustó tu tutorial, muy claro.
Estoy teniendo problemas para dibujar la imagen. Creo que es por la ruta que le paso. Copie tu clase Sprite y juego y las corrí(cambiando la ruta por la de una imagen existente en mi compu) y al llegar el putSprite() me tira el error NullPointerException en el constructor del ImageIcon.
¿Tendrás idea de qué es lo que puedo hacer para solucionarlo o mejor dicho, de qué es lo que me esta impidiendo cargar la imagen?

Muchas gracias

Volver arriba
Ver perfil del usuario Enviar mensaje privado Enviar correo
WhiteSkull
CoAdmin


Registrado: 20 Mar 2009
Mensajes: 3136
Ubicación: y*width+x

Mensaje Publicado: Jueves 07 Feb 2013 16:44

Título del mensaje: Re: [JAVA] Bases y demo de un juego sencillo 2D

Responder citando

Mu posiblemente sea la dirección o path del recurso que no sea correcta, por lo que no apunta a ningún recurso y salta el conocido Nullpointer

Volver arriba
Ver perfil del usuario Enviar mensaje privado Visitar sitio web del autor
rustinpeace



Registrado: 07 Feb 2013
Mensajes: 5
Ubicación: Ciudad Autónoma de Buenos Aires - Argentina

Mensaje Publicado: Jueves 07 Feb 2013 23:38

Título del mensaje: Re: [JAVA] Bases y demo de un juego sencillo 2D

Responder citando

Gracias por responder tan rapido. Estoy programando en windows 7, sería correcta una ruta como esta: "C:/Users/Public/Pictures/imagen.png"?
La ruta original es "C:\Users\Public\Pictures\imagen.png" pero reemplazé los backslash por slash debido a que los interpreta como caracteres de control(no estoy seguro que asi se llamen), puede ser es el motivo del error, pero no se cómo solucionarlo
Muchas gracias

Volver arriba
Ver perfil del usuario Enviar mensaje privado Enviar correo
WhiteSkull
CoAdmin


Registrado: 20 Mar 2009
Mensajes: 3136
Ubicación: y*width+x

Mensaje Publicado: Viernes 08 Feb 2013 01:06

Título del mensaje: Re: [JAVA] Bases y demo de un juego sencillo 2D

Responder citando

No hombre, la ruta que toma es desde donde se encuentran los recursos.

La carpeta de recursos gráficos se crea en la misma donde se encuentran las clases, en la carpeta src, una vez que compilas se crea un fichero empaquetado que contiene esa carpeta, por eso la ruta no puede ser absoluta en ese caso, ya que debe especificar la ruta del recurso dentro del fichero empaquetado... además la barra usada es la invertida.

Este enlace te explica mejor todo eso:
http://docs.oracle.com/javase/tutorial/uiswing/components/icon.html#getresource

Volver arriba
Ver perfil del usuario Enviar mensaje privado Visitar sitio web del autor
Responder al Tema Ir a página Anterior1234Siguiente
Mostrar mensajes anteriores:   
Ir a:  
Todas las horas están en GMT + 2 Horas

Temas relacionados

Tema Autor Foros Respuestas Publicado
El foro no contiene ningún mensaje nuevo

Juego Liguita de futbol

Octavio Programación de juegos o videojuegos 1 Sábado 01 Jun 2019 05:03 Ver último mensaje
El foro no contiene ningún mensaje nuevo

¿Cómo instalar correctamente JDK (Java Develope...

Alfonso Lara Temas generales 2 Martes 07 May 2019 22:09 Ver último mensaje
El foro no contiene ningún mensaje nuevo

Agregar un volante al juego F1 2018

Miguelinho53 Programación de juegos o videojuegos 0 Domingo 11 Nov 2018 17:34 Ver último mensaje
El foro no contiene ningún mensaje nuevo

Ayuda con TestNG Parametrico en java netbeans

baltigo Java 0 Sábado 30 Jun 2018 01:37 Ver último mensaje
El foro no contiene ningún mensaje nuevo

Duda codigo en Python - Red Neuronal con numpy ...

Daniel_wUNTG Python 1 Sábado 21 Oct 2017 22:27 Ver último mensaje
Panel de Control
No puede crear mensajes, No puede responder temas, No puede editar sus mensajes, No puede borrar sus mensajes, No puede votar en encuestas,