Foro de elhacker.net

Programación => Java => Mensaje iniciado por: DarkSorcerer en 12 Marzo 2013, 07:52 am



Título: Problema en mi videojuego programado en JAVA, usando librerias Swing/AWT
Publicado por: DarkSorcerer en 12 Marzo 2013, 07:52 am
Para poner en practica mis conocimientos, me anime en crear un pequeño videojuego, que consiste en un Space Invaders, donde las naves alienigenas se mueven horizontalmente (por ahora, despues pienso si moverlo verticalmente, solo es un prototipo), se mueven de tal manera que no se salga de la vista del jugador, cuando toca los bordes de la ventana, cambia de direccion, por ahora solo tiene naves enemigas, pronto le agregare la Nave Heroe (el que el jugador lo controla por teclado) y un contador de puntaje y barras de estado.

Mi juego constate por ahora de 3 clases, la clase principal obviamente con su respectivo main, una clase Panel que consiste en el escenario espacial, donde se mueven las naves enemigas y la nave heroe, y por ultimo la clase Nave, que representan a las naves enemigas.

Bueno, AQUI VA MI GRAN PROBLEMA, quise implementar ActionListener en la clase JPanel y utilizar la clase Timer de (javax.swing.Timer) que llama a actionPerformed para actualizar en un tiempo determinado, para que las naves se muevan con respecto al tiempo, lo cree en el constructor (por si acaso, esto lo aprendi en el libro "Como programar en Java" por Deitel), Y AQUI VIENE LO QUE QUIERO SOLUCIONAR, pues si bien, las naves se mueven a la velocidad que quiero, solamente lo hace en unos instantes, por que hay momentos que las naves "aceleran" mas de lo normal por unas milesimas o centesimas de segundo pero despues vuelve a su velocidad normal, despues vuelve a acelerar y despues vuelve a su velocidad normal y asi sucesivamente, y lo que yo quiero es que ande siempre a la misma velocidad, no se si sera problema de la velocidad de mi computadora o quizas sea algun error que cometi en la codificacion, por eso les pido ayuda, les dejo mi codigo, una captura del juego, el sprite de la nave y el fondo espacial.

Solamente llevo 1 año y 3 meses programando en Java, pero si me ayudan, podre surgir mas rapido :D

NOTA 1: El compilador que use es el Netbeans 7.2

NOTA 2: Si el programa les lanza una excepcion, es por que las imagenes que les acabo de mandar no tiene el mismo nombre a como sale especificado en el programa, o por que quizas no lo guardaron en donde se almacenan las clases (Ya que esta programado para que las imagenes las obtengan en la carpeta donde se guardan las clases)

LA CLASE PRINCIPAL

Código:
package ejercicio267;

import javax.swing.JFrame;

public class Ejercicio267 {

    public static void main(String[] args) {
        
        JFrame ventana = new JFrame("Naves espaciales");
        Panel panel = new Panel();
        
        ventana.add(panel);
        ventana.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        ventana.setSize(panel.getWidth(),panel.getHeight());
        ventana.setResizable(false);
        ventana.setVisible(true);
        
    }
}

LA CLASE PANEL

Código:
package ejercicio267;

import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.ImageIcon;
import java.awt.Image;
import java.awt.Graphics;
import java.awt.Color;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;

public class Panel extends JPanel implements ActionListener {
    
    private Image fondoEspacial;
    private Nave naves[] = new Nave[5];
    private int contadorNaves = 0;
    
    /* Constructor del Panel, inicializa su dimension, su fondo espacial y crea
     * las naves
     */
    
    public Panel(){
        
        setSize(500,500);
        fondoEspacial = (new ImageIcon(getClass().getResource("espacio.gif"))).getImage();
        
        naves[0] = new Nave(210,20);
        naves[1] = new Nave(80,75);
        naves[2] = new Nave(420,130);
        contadorNaves += 3;
        
        Timer temporizador = new Timer(1,this);
        temporizador.start();
        
    }
    
    // Metodo llamado por Timer para actualizar y mover las naves
    
    public void actionPerformed(ActionEvent evento){
        
        for(int i=0; i<contadorNaves;i++){
            
            if(naves[i].getCoordenadaX() == getWidth() - 45){
                
                naves[i].setDireccion(-1);
                
            }else{
                
                if(naves[i].getCoordenadaX() == 0){
                    
                    naves[i].setDireccion(-1);
                    
                }
            }
            
            if(naves[i].getDireccion() == 1){
                
                naves[i].setCoordenadaX(1);
                naves[i].setCoordenadaY(0);
                repaint();
                
            }else{
                
                if(naves[i].getDireccion() == -1){
                    
                    naves[i].setCoordenadaX(-1);
                    naves[i].setCoordenadaY(0);
                    repaint();
                    
                }
            }

        }
        
        
    }
    
    // Metodo que actualiza y dibuja en el Panel
    
    public void paintComponent(Graphics g){
        
        super.paintComponent(g);
        
        g.drawImage(fondoEspacial,0,0,getWidth(),getHeight(),this);
        
        for(int i=0; i<contadorNaves; i++){
            
            naves[i].moverNave(g,this);
            
        }
        
    }
    
}

LA CLASE NAVE

Código:
package ejercicio267;

import javax.swing.ImageIcon;
import java.awt.Image;
import java.awt.Graphics;

public class Nave {
    
    //Posicion X de la nave en el espacio
    private int coordenadaX;
    
    //Posicion Y de la nave en el espacio
    private int coordenadaY;
    
    //Puntos de salud de la nave    
    private int hpNave;
    
    //Puntos de ataque de la nave
    private int apNave;
    
    //La direccion que se mueve la nave, 1 a la derecha y -1 a la izquierda
    private int direccionNave;
    
    //El respectivo sprite de la nave
    private Image naveSprite;
    
    /* Constructor de la clase, inicializa sus coordenadas de partida, su respec
     * tivo sprite, ademas de su direccion de movimiento
     */  
    public Nave(int coordenadaX, int coordenadaY){
        
        this.coordenadaX = coordenadaX;
        this.coordenadaY = coordenadaY;
        naveSprite = (new ImageIcon(getClass().getResource("nave.png"))).getImage();
        direccionNave = 1;
        
    }
    
    // Metodo que establece una nueva coordenada X
    public void setCoordenadaX(int coordenadaX){
        
        this.coordenadaX += coordenadaX;
        
    }
    
    // Metodo que establece una nueva coordenada Y  
    public void setCoordenadaY(int coordenadaY){
        
        this.coordenadaY += coordenadaY;
        
    }
    
    // Metodo que obtiene la coordenada X
    public int getCoordenadaX(){
        
        return coordenadaX;
        
    }
    
    // Metodo que obtiene la coordenada Y
    public int getCoordenadaY(){
        
        return coordenadaY;
        
    }
    
    // Metodo que establece una nueva direccion de movimiento de la nave
    public void setDireccion(int dir){
        
        direccionNave = direccionNave * dir;
        
    }
    
    // Metodo que obtiene la direccion de la nave
    public int getDireccion(){
        
        return direccionNave;
        
    }
    
    // Metodo que dibuja la nave con su nueva posicion en el panel
    public void moverNave(Graphics g, Panel panel){
        
        g.drawImage(naveSprite,coordenadaX,coordenadaY,45,45,panel);
        
    }
    
}


(http://s2.subirimagenes.com/imagen/previo/thump_8350218juego.png) (http://www.subirimagenes.com/imagen-juego-8350218.html)

(http://s2.subirimagenes.com/imagen/previo/thump_8350229espacio.gif) (http://www.subirimagenes.com/imagen-espacio-8350229.html)

(http://s2.subirimagenes.com/imagen/previo/thump_8350233nave.png) (http://www.subirimagenes.com/imagen-nave-8350233.html)


Título: Re: Problema en mi videojuego programado en JAVA, usando librerias Swing/AWT
Publicado por: Chuidiang en 13 Marzo 2013, 20:42 pm
Hola:

No he mirado mucho el código, simplemente un detalle. La clase javax.swing.Timer no es precisa, a veces puede tardar más, a veces menos, dependiendo de la carga de tu código y de los eventos de teclado/ratón/repintado que queden encolados, ya que ese Timer avisa en el mismo hilo de todos esos eventos. Y el código que hagas dentro de ese ActionListener del Timer también afecta a su vez al pintado, ya que puede ralentizar ese hilo. Te pego de la API http://docs.oracle.com/javase/6/docs/api/javax/swing/Timer.html

Citar
the action event handlers for Timers execute on another thread -- the event-dispatching thread. This means that the action handlers for Timers can safely perform operations on Swing components. However, it also means that the handlers must execute quickly to keep the GUI responsive.

Como prueba rápida, usa java.util.Timer, que va totalmente separado del hilo de pintado y de los eventos de teclado y ratón, aparte de usar el reloj del sistema y ser más preciso que javax.swing.timer.

Se bueno.


Título: Re: Problema en mi videojuego programado en JAVA, usando librerias Swing/AWT
Publicado por: Kenkox en 15 Marzo 2013, 05:52 am
Yo lei ya el libro completo de "deitel", es muy bueno, pero tambien deberias de buscar  otras opciones para realizar ese tipo de animaciones... te recomiendo que en lugar de usar el timer, utilices un nuevo Thread que se encargue unicamente de mover a las naves... es decir, crear una clase interna privada en la clase panel, que implemente a runnable o bien a Thread, sobreescribir el metodo "run" y en ese metodo, empezar a modificar las coordenadas de las naves... al ser una clase  una clase interna no tendras problema con el acceso de los objetos de tu clase panel...... en tu clase panel tendras que crear un objeto de tu clase interna privada, y despues ejecutar su metodo run mediante start..... Esto todavia es mas eficiente, ya que vas "separando" el juego en pequeñas partes "independientes" ( notesen las comillas ).... debes de tomar en cuenta tambien, que al momento de que tu estas modificando las coordenadas y al momento de repintarlas... tienes que "dormir" ese hilo ciertos milisegundos ( si no lo haces, todo se movera demasiado rapido y no tendra el efecto deseado )

Ejemplo:
dentro de tu clase panel ---->
Código
  1. private class Movimiento extends Thread{
  2. public void run(){
  3.  
  4. /* Aqui es donde tienes que ir modificando las coordenadas */
  5. /* Haces un Thread.sleep(tiempo); con sus respectivos try y catch */
  6. /* repintas las naves, creo que seria con this.repaint(); */
  7. }
  8. }

en el contructor de tu clase panel ---->
Código
  1. Movimiento mov = new Movimiento();
  2. mov.start();

Solo es como una ayuda, obviamente se tendran que hacer una que otra modificacion a tus clases