I am trying to shoot a missile at a certain rate but currently you can simple hold down the fire button (Space) and it will make a continuous line of missiles.
I believe this is because the KeyEvent is being triggered when you hold it down when what I need it to do is only trigger once when you hold it down.
How would I make it detect the holding down of a button as only pressing it once?
public void keyPressed(KeyEvent e) {
int key = e.getKeyCode();
if (key == KeyEvent.VK_SPACE) {
fire();
}
if (key == KeyEvent.VK_A) {
dx = -1;
}
if (key == KeyEvent.VK_D) {
dx = 1;
}
}
public void keyReleased(KeyEvent e) {
int key = e.getKeyCode();
if (key == KeyEvent.VK_SPACE) {
}
if (key == KeyEvent.VK_A) {
dx = 0;
}
if (key == KeyEvent.VK_D) {
dx = 0;
}
}
Just add a check to make sure you've released the key before allowing yourself to fire again. I use AtomicBoolean to ensure there are no multithreading issues by the different events getting fired.
private final AtomicBoolean canShoot = new AtomicBoolean(true);
public void keyPressed(KeyEvent e) {
int key = e.getKeyCode();
if (key == KeyEvent.VK_SPACE) {
if (canShoot.compareAndSet(true, false)) {
fire();
}
}
// snip
}
public void keyReleased(KeyEvent e) {
int key = e.getKeyCode();
if (key == KeyEvent.VK_SPACE) {
canShoot.set(true);
}
// snip
}
Related
public void setUpButtonListeners() {
ActionListener buttonListener = new ActionListener() {
#Override
public void actionPerformed(ActionEvent ae) {
Object o = ae.getSource();
if ((o == slots[3][1]) || (o == slots[3][2])) {
slideDown(slots);
} else if ((o == slots[0][1]) || (o == slots[0][2])) {
slideUp(slots);
} else if ((o == slots[1][3]) || (o == slots[2][3])) {
slideRight(slots);
} else if ((o == slots[1][0]) || (o == slots[2][0])) {
slideLeft(slots);
}
}
};
slots[3][1].addActionListener(buttonListener);
slots[3][2].addActionListener(buttonListener);
slots[0][1].addActionListener(buttonListener);
slots[0][2].addActionListener(buttonListener);
slots[1][3].addActionListener(buttonListener);
slots[2][3].addActionListener(buttonListener);
slots[1][0].addActionListener(buttonListener);
slots[2][0].addActionListener(buttonListener);
}
This the relevant code. I can find a ton of information on how to add keylisteners to specific JComponents but all I want to do is make it so that if(up arrow pressed) then slideUp(slots), instead of having to press JButtons on the screen to call these functions.
Edit:
Fixed, and it was really simple.
Added
frame.setFocusable(true);
frame.addKeyListener(new KeyListener() {
#Override
public void keyTyped(KeyEvent e) {
// TODO Auto-generated method stub
}
#Override
public void keyPressed(KeyEvent e) {
keyCode = e.getKeyCode();
switch (keyCode) {
case KeyEvent.VK_UP:
slideUp(slots);
}
}
#Override
public void keyReleased(KeyEvent e) {
// TODO Auto-generated method stub
}
});
to constructor.
Maybe you should use a custom KeyEventDispatcher to handle the arrow key events, otherwise you will have issues with the components focus.
KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager();
manager.addKeyEventDispatcher( new ArrowsKeyDispatcher() );
...
class ArrowsKeyDispatcher implements KeyEventDispatcher {
public boolean dispatchKeyEvent(KeyEvent e) {
if(e.getID() == KeyEvent.VK_UP) {
//Do something here when pressing UP ARROWKEY
}
// Do the same for all keys you need to handle globally
...
return false;
}
}
I will only supply the relevant parts of the code as it is quite large. Help me figure out why I never get keyboard events to the GameBoard JPanel. The game code runs just fine until I added the new feature where I wanted it to have a welcome screen.
Edit: If you would like to view the entire project (it's an eclipse project), here is the link to download it Eclipse project, I honestly can't format almost 1000 lines of code here on StackOverflow, that'll be painful even for you.
Main.java
private void initUI() throws IOException {
cardLayout = new CardLayout();
mainPanel = new JPanel(cardLayout);
welcomeMenu = new Welcome(cardLayout, mainPanel);
mainPanel.add(welcomeMenu, "welcome");
game = new GameBoard();
mainPanel.add(game, "game");
add(mainPanel);
setTitle("Pacman");
setDefaultCloseOperation(EXIT_ON_CLOSE);
setSize(380, 420);
setLocationRelativeTo(null);
}
This is the welcome/menu panel (some section of it).
Welcome.java (servers as a menu)
#Override
public void actionPerformed(ActionEvent evt) {
if (evt.getActionCommand() == Actions.EXIT.name()) {
System.exit(0);
} else if (evt.getActionCommand() == Actions.CONFIG.name()) {
JOptionPane.showMessageDialog(null, "Not yet implemented");
} else if (evt.getActionCommand() == Actions.PLAY.name()) {
// The part that switches to game, works as expected.
cl.show(mp, "game");
}
}
GameBoard class has a KeyAdapter class within it that is used to listen to key events, however, in the addition of the new feature using CardLayout, I could not get the key events to the panel so my PacMan is just stuck in one place opening and closing its mouth like a fish.
GameBoard.java
private void initBoard() {
addKeyListener(new TAdapter());
setFocusable(true);
setBackground(Color.black);
initGame();
}
...
class TAdapter extends KeyAdapter {
#Override
public void keyPressed(KeyEvent e) {
int key = e.getKeyCode();
if (inGame) {
if (key == KeyEvent.VK_LEFT) {
req_dx = -1;
req_dy = 0;
} else if (key == KeyEvent.VK_RIGHT) {
req_dx = 1;
req_dy = 0;
} else if (key == KeyEvent.VK_UP) {
req_dx = 0;
req_dy = -1;
} else if (key == KeyEvent.VK_DOWN) {
req_dx = 0;
req_dy = 1;
} else if (key == KeyEvent.VK_ESCAPE && timer.isRunning()) {
inGame = false;
} else if (key == KeyEvent.VK_PAUSE) {
if (timer.isRunning()) {
timer.stop();
} else {
timer.start();
}
}
} /*
* else { if (key == 's' || key == 'S') { inGame = true; initGame(); } }
*/
}
#Override
public void keyReleased(KeyEvent e) {
int key = e.getKeyCode();
if (key == Event.LEFT || key == Event.RIGHT || key == Event.UP || key == Event.DOWN) {
req_dx = 0;
req_dy = 0;
}
}
}
The issue was using Key Listener when I should have been using Key Binding in the GameBoard JPanel. So instead of this,
class TAdapter extends KeyAdapter {
#Override
public void keyPressed(KeyEvent e) {
int key = e.getKeyCode();
if (inGame) {
...
} else if (key == KeyEvent.VK_UP) {
req_dx = 0;
req_dy = -1;
} else if (key == KeyEvent.VK_DOWN) {
...
}
}
}
I replaced it with this approach (I will only demonstrate Arrow Up scenario),
private class UpAction extends AbstractAction {
private static final long serialVersionUID = 1L;
#Override
public void actionPerformed(ActionEvent e) {
if (!inGame)
return;
req_dx = 0;
req_dy = -1;
}
}
...
private void setupKeyListeners() {
getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0), "doUp");
...
getActionMap().put("doUp", new UpAction());
...
}
And later on,
private void initBoard() {
setupListeners();
setFocusable(true);
setBackground(Color.black);
initGame();
}
I'm trying to make a game in java, just a simple platformer, but I'm having difficulty when running the code. I can't seem to get any response from key presses. The only thing I can think hasn't been working properly is the keyPressed and keyReleased functions. Below is the relevant code.
public ReflexPanel() {
initBoard();
setFocusable(true);
addKeyListener(this);
Timer timer = new Timer(1000/120, this);
timer.start();
}
private void initBoard() {
loadMenu();
int w = menu.getWidth(this);
int h = menu.getHeight(this);
setPreferredSize(new Dimension(w, h));
}
private void step() {
if(mainMenu){
if(ePressed) {
System.exit(0);
}
if(hPressed) {
loadScores();
repaint();
}
}
}
public void keyTyped(KeyEvent e) {}
#Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == 'e') {
ePressed = true;
}
if (e.getKeyCode() == 'h') {
hPressed = true;
}
}
#Override
public void keyReleased(KeyEvent e) {
if (e.getKeyCode() == 'e') {
ePressed = false;
}
if (e.getKeyCode() == 'h') {
hPressed = false;
}
}
#Override
public void actionPerformed(ActionEvent e) {
step();
}
The ePressed and hPressed variables are just booleans set to false by default, and loadScores calls a png file.
You can't do this:
if(e.getKeyCode() == 'e'){
// code logic
}
KeyEvent::getKeyCode doesn't return the char you press on the keyboard. It "returns the integer keyCode associated with the key in this event". When using KeyEvent::getKeyCode you have to use the KeyEvent key constants values predefined in the class. So for example:
if(e.getKeyCode() == KeyEvent.VK_E){
// code logic
}
Or you can use KeyEvent::getKeyChar which "returns the character associated with the key in this event".
You're using getKeyCode() which returns an int value with constants given in KeyEvent class, such as KeyEvent.VK_E.
You're looking to use getKeyChar() which returns 'e' directly.
if (e.getKeyChar() == 'e') { // Now it has an actual chance of working
If I move my player1 and player2 up, and let's say I push the down key for player1, my player stops moving up. I can't find the problem. Can someone please help me and explain what I did wrong?
package game;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
public class KeyInput extends KeyAdapter{
private Handler handler;
private boolean [] keyPressed = new boolean [4];
public KeyInput(Handler handler){
this.handler = handler;
}
public void keyPressed(KeyEvent e){
int key = e.getKeyCode();
keyPressed[0]= false;
keyPressed[1]= false;
keyPressed[2]= false;
keyPressed[3]= false;
for(int i = 0; i <handler.object.size(); i++){
GameObject tempobject= handler.object.get(i);
if (tempobject.getId()== ID.Player1){
if (key == KeyEvent.VK_UP){tempobject.setSpeedy(-7); keyPressed[0] = true;}
if (key == KeyEvent.VK_DOWN){tempobject.setSpeedy(7); keyPressed[1] = true;}
}
if(tempobject.getId()== ID.player2)
if (key == KeyEvent.VK_W){tempobject.setSpeedy2(-7); keyPressed[2] = true;}
if (key == KeyEvent.VK_S){tempobject.setSpeedy2(7); keyPressed[3] = true;}
}
if(key == KeyEvent.VK_ESCAPE)System.exit(1);
}
public void keyReleased(KeyEvent e){
int key = e.getKeyCode();
for(int i = 0; i <handler.object.size(); i++){
GameObject tempobject= handler.object.get(i);
if (tempobject.getId()== ID.Player1){
if (key == KeyEvent.VK_UP) keyPressed[0] = false;
if (key == KeyEvent.VK_DOWN) keyPressed[1] = false;
if(!keyPressed[0] && !keyPressed[1])tempobject.setSpeedy(0);
}
if (tempobject.getId()== ID.player2){
if (key == KeyEvent.VK_W) keyPressed[2] = false;
if (key == KeyEvent.VK_S) keyPressed[3] = false;
if(!keyPressed[2] && !keyPressed[3])tempobject.setSpeedy2(0);
}
}
}
}
It probably has to do with this:
keyPressed[0]= false;
keyPressed[1]= false;
keyPressed[2]= false;
keyPressed[3]= false;
This would make it so that whenever any key is pressed, the other keys are set to false, even if they may still be being held down.
I have managed to pause the game using *running = !running
But it's unable to unpause if this is used
And thread.resume() or thread.wait() doesn't work either to unpause it when 'P' is pressed
private volatile boolean running;
private Thread thread;
public static enum STATE {
MENU,
GAME,
};
public static STATE State = STATE.MENU;
public void init(){
requestFocus();
}
private synchronized void start(){
if(running)
return;
running = true;
thread = new Thread(this);
thread.start();
}
private synchronized void stop(){
if(!running)
return;
running = false;
try{
thread.join();
}catch(InterruptedException e){
e.printStackTrace();
}
}
public void run() {
init();
while(running){
/some codes
}
stop();
}
private void render(){
if(State == STATE.GAME){
p.render(g);
c.render(g);
}else if(State == STATE.MENU){
menu.render(g);
}
g.dispose();
bs.show();
}
public void keyPressed(KeyEvent e){
int key = e.getKeyCode();
if(State == STATE.GAME){
if(key == KeyEvent.VK_RIGHT){
p.setVelX(5);
}else if(key == KeyEvent.VK_LEFT){
p.setVelX(-5);
}else if(key == KeyEvent.VK_DOWN){
p.setVelY(5);
}else if(key == KeyEvent.VK_UP){
p.setVelY(-5);
}else if(key == KeyEvent.VK_SPACE && !is_shooting){
c.addEntity(new Bullet(p.getX(), p.getY(), tex, this));
is_shooting = true;
}else if(key == KeyEvent.VK_P){
This line is to pause.
running = !running;
}
}
}
public void keyReleased(KeyEvent e){
int key = e.getKeyCode();
if(key == KeyEvent.VK_RIGHT){
p.setVelX(0);
}else if(key == KeyEvent.VK_LEFT){
p.setVelX(0);
}else if(key == KeyEvent.VK_DOWN){
p.setVelY(0);
}else if(key == KeyEvent.VK_UP){
p.setVelY(0);
}else if(key == KeyEvent.VK_SPACE){
is_shooting = false;
}else if(key == KeyEvent.VK_P){
// This line doesn't work.
running = true;
}
}
At the moment, as soon as running is set to false, your game thread exits (run() method returns).
public void run() {
init();
while(running){
/some codes
}
stop();
}
Should be changed to something more like this:
public void run() {
init();
while(true){
if(!running) {
Thread.sleep(1000); //1 second or something else
continue;
}
//Game logic here
}
stop();
}
You will of course need to differentiate between running and paused, to be able to break out of this loop.
Setting running = !runnning will just change the variable, you're not actually stopping anything unless you're using the variable in the game loop.
To pause the method, use Thread.sleep()or simply stop the thread, then start it again if you don't know how long you want to pause it for.