I'm asking because I want the addShot()
method in my GamePanel
class to be called when the user hits enter," this initializes a shot object representing a missile fired from a ship, but it doesn't do anything. Is there a visibility issue here, or did I just structure the key event and listener relationship wrong? I'm only posting relevant code, but I can post the rest if necessary.
Here's the code:
public static class GameTest extends JFrame {
private static final int WINDOW_WIDTH = 800;
private static final int WINDOW_HEIGHT = 500;
public GamePanel gamePanel;
public GameTest() throws IOException {
super("Deep Fried Freedom");
setResizable(false);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(WINDOW_WIDTH, WINDOW_HEIGHT);
setLayout(new BorderLayout());
gamePanel = new GamePanel();
add(gamePanel);
center(this);
setVisible(true);
this.addKeyListener(new aKeyListener());
this.setFocusable(true);
} // end constructor
public void center(JFrame frame) {
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
Point center = ge.getCenterPoint();
int w = frame.getWidth();
int h = frame.getHeight();
int x = center.x - w / 2, y = center.y - h / 2;
frame.setBounds(x, y, w, h);
frame.validate();
}//end of center method
public class aKeyListener implements KeyListener {
@Override
public void keyTyped(KeyEvent e) {
}//end empty keyTyped method
@Override
public void keyPressed(KeyEvent e) {
switch (e.getKeyCode()) {
case KeyEvent.VK_A:
Launcher.lRun = -20;
gamePanel.move(gamePanel);
break;
case KeyEvent.VK_D:
Launcher.lRun = 20;
gamePanel.move(gamePanel);
break;
case KeyEvent.VK_ENTER:
gamePanel.addShot();
break;
default:
Launcher.lRun = 0;
}
}//end keyPressed method
@Override
public void keyReleased(KeyEvent e) {
}//end empty keyReleased method
}//end aKeyListener class
}//end GameTest class
- Yours is likely a focus issue -- something in the GamePanel stealing focus perhaps, a very common problem with KeyListeners.
- General advice: favor using Key Bindings, not a KeyListener for this type of need.
Useful links:
- Swing Resources
- Please check my second example program in my answer to a StackOverflow question here.
- Overall Swing Tutorials
- Key Bindings
- Swing Timer
- Concurrency in Swing
Edit
For example:
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import javax.swing.*;
public class GameTest extends JFrame {
private static final int WINDOW_WIDTH = 800;
private static final int WINDOW_HEIGHT = 500;
public GamePanel gamePanel;
public GameTest() {
super("Deep Fried Freedom");
setResizable(false);
// setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
// setSize(WINDOW_WIDTH, WINDOW_HEIGHT); // never do this
gamePanel = new GamePanel();
setUpKeyBinding(gamePanel);
add(gamePanel);
pack();
setLocationRelativeTo(null); // to center!
setVisible(true);
}
@Override
public Dimension getPreferredSize() {
return new Dimension(WINDOW_WIDTH, WINDOW_HEIGHT);
}
private void setUpKeyBinding(GamePanel gamePanel2) {
// only need window to have focus
int condition = JComponent.WHEN_IN_FOCUSED_WINDOW;
// get the GamePanel's InputMap and ActionMap as these will be used to set
// up our Key Bindings
InputMap inputMap = gamePanel2.getInputMap(condition);
ActionMap actionMap = gamePanel2.getActionMap();
// bind the A key to move back 20 pixels
KeyStroke keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_A, 0);
inputMap.put(keyStroke, keyStroke.toString());
actionMap.put(keyStroke.toString(), new MoveAction(gamePanel2, -20));
// bind the D key to move forward 20 pixels
keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_D, 0);
inputMap.put(keyStroke, keyStroke.toString());
actionMap.put(keyStroke.toString(), new MoveAction(gamePanel2, 20));
// bind the ENTER key
keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0);
inputMap.put(keyStroke, keyStroke.toString());
actionMap.put(keyStroke.toString(), new EnterAction(gamePanel2));
}
public static void main(String[] args) {
new GameTest();
}
// our Action classes that will bound to key strokes
private class MoveAction extends AbstractAction {
private GamePanel gamePanel2;
private int distance;
public MoveAction(GamePanel gamePanel2, int distance) {
this.gamePanel2 = gamePanel2;
this.distance = distance;
}
@Override
public void actionPerformed(ActionEvent e) {
gamePanel2.moveItem(distance);
}
}
private class EnterAction extends AbstractAction {
private GamePanel gamePanel2;
public EnterAction(GamePanel gamePanel2) {
this.gamePanel2 = gamePanel2;
}
@Override
public void actionPerformed(ActionEvent e) {
gamePanel2.addShot();
}
}
}
// a trivial GamePanel class to just show that everything is working as expected
class GamePanel extends JPanel {
public void moveItem(int i) {
// your moveItem method will instead actually move something, a distance of i
System.out.println("Move Item Method distance: " + i);
}
public void addShot() {
// your addShot method will actually shoot
System.out.println("Add Shot Method");
}
}