Autor
|
Tema: Ayuda, eventos de Teclado no es escuchado en JPANEL (Leído 8,323 veces)
|
DarkSorcerer
Desconectado
Mensajes: 69
|
Voy a crear un videojuego similar al Space Invaders, para eso, quiero que el jugador controle la nave por medio del teclado, la cosa es que el juego consiste en una Ventana (JFrame) y varios niveles que tengo pensado en hacerlo dentro de un JPanel donde es el lugar que se dibuja los enemigos, la nave del heroe, y otros obstaculos como meteoritos, agujeros negros, tormentas solares, etc, intente implementar la interfaz KeyListener en JPanel pero no los escucha, hice lo correcto y registre el evento, pero lo mas curioso es que si me escucha los eventos del Mouse, pero no del Teclado. Una solucion que encontre fue implementarlo en JFrame y de ahi usar los metodos para mover la nave accediendo a Jpanel y me funciono, pero no es lo que quiero, yo quiero mover la nave implementando KeyListener en JPanel, en otros foros me decian que intente usando el metodo "setFocusable(true)", pero igual no me funciono. Por ahora, no les mostrare el codigo del juego, pero si de un programa que hice especialmente para mostrar mi duda, es similar a mi problema. Use el compilador Netbeans 7.3 Clase Principal package ejercicio47;
import javax.swing.JFrame;
public class Ejercicio47 {
public static void main(String[] args) { JFrame ventana = new JFrame(); Panel panel = new Panel(); ventana.add(panel); ventana.setDefaultCloseOperation(Ventana.EXIT_ON_CLOSE); ventana.setSize(500,500); ventana.setTitle("Testeo de eventos"); ventana.setFocusable(true); ventana.setResizable(false); ventana.setVisible(true);
} }
Clase Panel package ejercicio47;
import javax.swing.JPanel; import java.awt.event.MouseListener; import java.awt.event.MouseEvent; import java.awt.event.KeyListener; import java.awt.event.KeyEvent; import java.awt.Graphics; import java.awt.Color;
public class Panel extends JPanel implements KeyListener, MouseListener { public Panel(){ setBackground(Color.WHITE); addMouseListener(this); addKeyListener(this); } public void mouseClicked(MouseEvent e){ System.out.println("Hola mundo"); } public void mouseEntered(MouseEvent e){ System.out.println("Hola mundo"); } public void mousePressed(MouseEvent e){ System.out.println("Hola mundo"); } public void mouseExited(MouseEvent e){ System.out.println("Adios mundo"); } public void mouseReleased(MouseEvent e){ System.out.println("Adios mundo"); } public void keyTyped(KeyEvent e){ System.out.println("Hola mundo"); } public void keyPressed(KeyEvent e){ System.out.println("Hola mundo"); } public void keyReleased(KeyEvent e){ System.out.println("Adios mundo"); } public void paintComponent(Graphics g){ super.paintComponent(g); } }
|
|
|
En línea
|
|
|
|
RyogiShiki
Desconectado
Mensajes: 745
げんしけん - Hikkikomori FTW!!!
|
Hola que tal. Antes que nada revisando la documentación sobre KeyListeners encuentras la información que necestas. Sin embargo paso a explicar lo que sucede. Cuando escuchas un evento de teclado sobre un componente, es necesario saber sobre que componente el evento va ser escuchado, por ejemplo, si tengo dos JPanel, y cada uno tiene su propio KeyListener, al abrir la aplicación y oprimir una tecla, el programa no sabrá a cual de los dos Listeners estoy haciendo referencia, por esta razón es necesario tener un mecanismo que permita identificar que componente debe procesar el evento, para esto se hace uso del Foco, si el primer panelpanel tiene el Foco, entences este responderá al evento, si el segundo lo tiene, el segundo lo hará. Lo que falta en tu código es un mecanismo efetivo para asignar el foco al componente determinado. En primer lugar, el método: setFocusable(boolean b) no debería estar en el JFrame, sino más bien en el JPanel: setBackground (Color. WHITE); addMouseListener(this); addKeyListener(this); setFocusable(true); }
Ahora que nuestro Panel tiene la habilidad de obtener foco, debemos definir como debe hacerlo, en este caso lo haremos al hacer click sobre este, para esto simplemente agregamos una linea de código más al método sobreescrito mouseClicked(Event e): System. out. println("Hola mundo"); requestFocusInWindow(); }
En este momento al hacer click sobre el Panel este obtendrá el foco dentro de la ventana, ahora si oprimes alguna tecla, verás como los eventos son correctamente procesados. PD: Usar requestFocusInWindow() envés de requestFocus(). El primero otorgará el foco al componente dentro de la ventana que se encuentre, el segundo robará el foco de otras ventanas que estén abiertas (como las de otros programas) Espero sea de ayuda. Saludos
|
|
|
En línea
|
|
|
|
DarkSorcerer
Desconectado
Mensajes: 69
|
Hola, primero que nada, muchas gracias por la ayuda y por tomarte tu tiempo en ayudarme, en parte me sirvio (para el caso del codigo que puse), pero no me pudo solucionar el problema de mi juego, y creo que descubri la causa pero no encuentro la solucion. Estoy ocupando Herencia, de todas maneras, ¿Alguien de aca estaria dispuesto a revisar mi codigo y ayudarme a encontrar el error? Mi codigo esta documentado para que no tengan problemas de lo que quiero comunicar.
|
|
« Última modificación: 6 Mayo 2013, 09:42 am por DarkSorcerer »
|
En línea
|
|
|
|
DarkSorcerer
Desconectado
Mensajes: 69
|
Bueno, les dejo mi codigo, soy novato en esto y quizas hayan partes que se ven newbies, acepto criticas constructivas si hay que mejorar algo, las destructivas no las tomo en cuenta. Al final del codigo hay enlaces a las imagenes que use. Descubri el origen del problema, y sucede cuando paso al siguiente nivel, el primer nivel es la Portada que se inicializa en el constructor de Ventana, pero si en vez de inicializar Portada e inicializo Nivel1, logro que los eventos de teclado sean escuchados, pero busco que el primer nivel sea la portada. Clase principal (Main) package videojuego3; public class Videojuego3 { public static void main (String[] args ) { //Crea la ventana contenedora de Niveles Ventana ventana = new Ventana(); //Ciclo infinito while(true){ ventana.setVisible(true); //Instruccion que pasa al siguiente nivel si se completo el nivel anterior if(ventana.getNivel().estaCompleto()){ ventana.setNivel(new Nivel1()); } } } }
Clase Ventana package videojuego3; import javax.swing.JFrame; /** * Clase que representa la Ventana contenedora de los niveles * @author RPZ */ public class Ventana extends JFrame { //El primer nivel es el menu de inicio private Nivel nivel = new Portada(); public Ventana(){ super("Space Troubles"); setSize(500,500); setResizable(false); setDefaultCloseOperation (JFrame. EXIT_ON_CLOSE); add(nivel); } /** * Metodo que permite remplazar el nivel que esta en la ventana por otro, una * vez completado. * @param nivel El nuevo nivel. */ public void setNivel(Nivel nivel){ this.nivel = nivel; //Tuve que poner este metodo, mira lo que suce si no lo pongo, para que //no se "mezclara" con el nivel anterior. getContentPane().removeAll(); add(nivel); } /** * Devuelve el nivel actual del juego * @return Retorna el nivel actual en juego */ public Nivel getNivel(){ return nivel; } }
Clase Nivel package videojuego3; import javax.swing.JPanel; import java.awt.Image; import java.awt.Graphics; /** * Clase que representa al un Nivel del juego, incluye la portada * @author RPZ */ public class Nivel extends JPanel { protected boolean estaCompleto; public Nivel (Image fondo ){ this.fondo = fondo; this.estaCompleto = false; setFocusable(true); } /** * Metodo que permite marcar el nivel cuando esta completo. * @param estaCompleto El marcador booleano que representa el nivel completo. */ public void setCompleto(boolean estaCompleto){ this.estaCompleto = estaCompleto; } /** * Metodo que devuelve el estado del nivel, True si esta completo y False si * esta incompleto * @return True si esta completo, False si esta incompleto. */ public boolean estaCompleto(){ return estaCompleto; } /** * Metodo que permite dibujar en el panel, lo cual tiene diferente implementa * cion en las clases hijas. * @param g Paremtro Graphics. */ } }
Clase Enemigo package videojuego3; import java.awt.Graphics; import java.awt.Image; /** * Clase que representa al enemigo extraterrestre. * @author RPZ */ public class Enemigo { /** * Coordenada X. */ protected int x; /** * Coordenada Y. */ protected int y; /** * La direccion que se mueve el enemigo, positivo a la derecha, negativo a * la izquierda. */ protected int dirHor; /** * La anchura del enemigo en pixeles. */ protected int ancho; /** * La altura del enemigo en pixeles. */ protected int alto; /** * Los puntos de vida del enemigo. */ protected int hP; /** * Los puntos de ataque del enemigo. */ protected int aP; /** * El Sprite que muestra la apariencia del enemigo. */ public Enemigo (int x, int y, int dirHor, int ancho, int alto, int hP, int aP, Image sprite ){ this.x = x; this.y = y; this.dirHor = dirHor; this.ancho = ancho; this.alto = alto; this.hP = hP; this.aP = aP; this.sprite = sprite; } /** * Establece la posicion horizontal. * @param x La coordenada X. */ public void setX(int x){ this.x = x; } /** * Establece la posicion vertical. * @param y La coordenada Y. */ public void setY(int y){ this.y = y; } /** * Establece la salud del enemigo. * @param hP Puntos de salud. */ public void setHP(int hP){ this.hP = hP; } /** * Establece el ataque del enemigo. * @param aP */ public void setAP(int aP){ this.aP = aP; } /** * Devuelve la posicion horizontal. * @return La coordenada X. */ public int getX(){ return x; } /** * Devuelve la posicion vertical. * @return La coordenada Y. */ public int getY(){ return y; } /** * Devuelve la salud. * @return La salud del extraterrestre. */ public int getHP(){ return hP; } /** * Devuelve el ataque. * @return Los puntos de ataque del extraterrestre. */ public int getAP(){ return aP; } /** * Mueve "dirHor" unidades horizontalmente. */ public void moverHor(){ verificarChoque(); x += dirHor; } /** * Verifica que el enemigo no salga de la vista de la pantalla y rebota en * las paredes del escenario. */ private void verificarChoque(){ if(x > 465 || x < 0){ dirHor *= -1; } } /** * Dibuja el enemigo en el Nivel. * @param g Graphics. */ g.drawImage(sprite,x,y,ancho,alto,null); } }
Clase Assault package videojuego3; import javax.swing.ImageIcon; /** * Clase hija que representa al tipo de enemigo "Assault", unidad de asalto, * el enemigo mas comun y simple. * @author RPZ. */ public class Assault extends Enemigo { public Assault(int x, int y, int dirHor){ super(x,y,dirHor, 32, 32, 25, 5, new ImageIcon("assault.png"). getImage()); } }
Clase Heroe package videojuego3; import java.awt.Graphics; import java.awt.Image; import javax.swing.ImageIcon; /** * Clase que representa al protagonista del juego. * @author RPZ. */ public class Heroe { /** * Coordenada X. */ private int x; /** * Coordenada Y. */ private int y; /** * Puntos de vida. */ private int hP; /** * Puntos de ataque. */ private int aP; /** * Puntos de armadura. */ private int armor; /** * El Sprite que representa su apariencia. */ public Heroe(int x, int y){ this.x = x; this.y = y; this.hP = 100; this.aP = 5; this.armor = 0; this. sprite = new ImageIcon("naveHeroe.png"). getImage(); } /** * Permite mover la nave horizontalmente. * @param mov La "mov" posiciones que se mueve la nave, puede ser izquierda o * derecha. */ public void moverNave(int mov){ this.x += mov; } /** * Metodo que dibuja la nave Heroe en el nivel. * @param g Graphics. */ g.drawImage(sprite,x,y,32,32,null); } }
Clase Portada package videojuego3; import java.awt.Color; import javax.swing.ImageIcon; import java.awt.Graphics; import java.awt.event.MouseAdapter; import java.awt.event.MouseMotionListener; import java.awt.event.MouseEvent; import java.awt.Font; /** * Clase que representa a un nivel especial, la Portada del juego. * @author RPZ. */ public class Portada extends Nivel { /** * Color del subtitulo "Jugar". */ /** * Color del subtitulo "Instrucciones". */ /** * Color del subtitulo "Creditos". */ /** * Fuente de letra del titulo. */ private Font fuenteTitulo ; /** * Fuente de letra de los subtitulos. */ private Font fuenteSubtitulo ; /** * Fuente de letra de la informacion del autor. */ private Font fuenteAutor ; public Portada(){ super(new ImageIcon("portada.jpg"). getImage()); this. color1 = Color. YELLOW; this. color2 = Color. YELLOW; this. color3 = Color. YELLOW; this. fuenteTitulo = new Font("Serif", Font. BOLD, 40); this. fuenteSubtitulo = new Font("Serif", Font. PLAIN, 20); this. fuenteAutor = new Font("Serif", Font. PLAIN, 12); EventoMouse evento = new EventoMouse(); addMouseListener(evento); addMouseMotionListener(evento); setFocusable(true); } /** * Metodo sobreescrito que permite dibujar el menu principal o la portada * en el nivel. * @param g Graphics. */ super.paintComponent(g); g.drawImage(fondo,0,0,500,500,this); g.setFont(fuenteTitulo); g. setColor(Color. YELLOW); g.drawString("SPACE TROUBLES",75,65); g.setFont(fuenteSubtitulo); g.setColor(color1); g.drawString("Jugar",220,340); g.setFont(fuenteSubtitulo); g.setColor(color2); g.drawString("Instrucciones",190,370); g.setFont(fuenteSubtitulo); g.setColor(color3); g.drawString("Créditos",210,400); g.setFont(fuenteAutor); g.drawString("© 2013 RPZoft",205,440); } /** * Clase interna que representa al administrador de eventos del Mouse. */ /** * Metodo que permite cambiar de color los subtitulos al pasar el puntero * sobre ellos. * @param evento */ if(evento.getX() >=220 && evento.getX() <=270 && evento.getY() >= 330 && evento.getY() <= 350){ repaint(); }else{ if(evento.getX() >=200 && evento.getX() <=290 && evento.getY() >= 360 && evento.getY() <=380){ repaint(); }else{ if(evento.getX() >=200 && evento.getX() <=270 && evento.getY() >= 390 && evento.getY() <=410){ repaint(); }else{ repaint(); } } } } } /** * Metodo que permite pasar al siguiente nivel, un nivel jugable. * @param evento */ if(evento.getX() >=220 && evento.getX() <=270 && evento.getY() >= 330 && evento.getY() <= 350){ setCompleto(true); } } } }
Clase Nivel1 package videojuego3; import javax.swing.ImageIcon; import java.awt.Graphics; import java.awt.event.ActionListener; import java.awt.event.ActionEvent; import java.awt.event.KeyListener; import java.awt.event.KeyEvent; import javax.swing.Timer; /** * Arreglo que contiene a los enemigos. */ private Enemigo enemigos[]; /** * El heroe dentro del nivel. */ private Heroe heroe; public Nivel1(){ super(new ImageIcon("fondo1.jpg"). getImage()); enemigos = new Enemigo[3]; enemigos[0] = new Assault(20,20,1); enemigos[1] = new Assault(330,60,-1); enemigos[2] = new Assault(190,100,1); heroe = new Heroe(200,400); //Temporalizador, permite que haya tiempo en el juego. temporizador.start(); Teclado evento1 = new Teclado(); addKeyListener(evento1); setFocusable(true); } /** * Metodo que se llama atraves del tiempo. Permite que las naves enemigas * se este moviendo con respecto al tiempo. * @param evento */ for(int i=0; i<3; i++){ enemigos[i].moverHor(); } repaint(); } /** * Metodo sobreescrito que permite dibujar los enemigos y el heroe en el nivel. * @param g Graphics. */ super.paintComponent(g); g.drawImage(fondo,0,0,500,500,this); for(int i=0; i<3; i++){ enemigos[i].dibujar(g); } heroe.dibujar(g); } public Heroe getHeroe(){ return heroe; } } if(e. getKeyCode() == KeyEvent. VK_RIGHT){ heroe.moverNave(3); requestFocusInWindow(); repaint(); } heroe.moverNave(-3); requestFocusInWindow(); repaint(); } } } } }
Fondo de la portada: http://www.subirimagenes.com/imagen-portada-8421349.htmlFondo nivel 1: http://www.subirimagenes.com/fondosycapturas-fondo1-8421353.htmlSprite nave heroe: http://www.subirimagenes.com/imagen-naveheroe-8421354.htmlSprite nave assault: http://www.subirimagenes.com/imagen-assault-8421356.html
|
|
« Última modificación: 6 Mayo 2013, 11:24 am por DarkSorcerer »
|
En línea
|
|
|
|
RyogiShiki
Desconectado
Mensajes: 745
げんしけん - Hikkikomori FTW!!!
|
Revisando el código por encima, noto que cuando haces que el panel tome foco (en la clase Nivel1) es precisamente cuando estás procesando un evento del teclado, Pero para procesar este evento debes tener el foco del panel antes. Basicamente el problema está en la linea 109 de la clase anidada Teclado dentro de Nivel1. El foco no debería pedirse al procesar un evento de teclado, debes usar otra manera para asignar el foco al panel. Por ejemplo implementando un MouseListener y llamando al método requestFocusInWindow() dentro de la implementación del método mouseEntered() es una forma de hacerlo.
|
|
|
En línea
|
|
|
|
sapito169
Desconectado
Mensajes: 629
|
Muchas felicitaciones y gracias por el aporte lo estoy revisando Lo que está mal es que pongas comentarios tontos y obvios /** * Metodo que permite remplazar el nivel que esta en la ventana por otro, una * vez completado. * @param nivel El nuevo nivel. */ public void setNivel(Nivel nivel){ this.nivel=nivel } /** * Devuelve el nivel actual del juego * @return Retorna el nivel actual en juego */ public Nivel getNivel(){ return nivel; }
no entiendo por que comentar getters y setters /** * Metodo que devuelve el estado del nivel, True si esta completo y False si * esta incompleto * @return True si esta completo, False si esta incompleto. */ public boolean estaCompleto(){ return estaCompleto; }
ho de verdad creo que si veo un método se llama estaCompleto talves se me ocurra que sirva para saber si está completo
|
|
« Última modificación: 6 Mayo 2013, 17:10 pm por sapito169 »
|
En línea
|
|
|
|
|
Mensajes similares |
|
Asunto |
Iniciado por |
Respuestas |
Vistas |
Último mensaje |
|
|
Diferenciar eventos según teclado C#
.NET (C#, VB.NET, ASP)
|
kondrag_X1
|
3
|
3,459
|
22 Abril 2015, 15:50 pm
por kondrag_X1
|
|
|
ayuda a ajustar vídeo a jpanel
Java
|
SoyBolita
|
0
|
2,449
|
22 Febrero 2016, 05:23 am
por SoyBolita
|
|
|
Ayuda con eventos del teclado
Java
|
sebast345
|
3
|
2,569
|
18 Noviembre 2016, 13:22 pm
por Orubatosu
|
|
|
Duda manejando eventos de teclado en Java
Java
|
niano
|
2
|
2,340
|
11 Julio 2019, 19:04 pm
por niano
|
|
|
Comparar eventos de teclado con strings (C#)
.NET (C#, VB.NET, ASP)
|
Alejovsq
|
3
|
2,965
|
9 Agosto 2019, 01:34 am
por Alejovsq
|
|