Ilann Ilann - 9 months ago 29
Java Question

How can I simultaneity run blocks of code with key bindings?

I am currently learning how to use key bindings. I was toying with the code I wrote, and I noticed when I press two keys (arrow keys), only the last one would run. Should I simply use KeyListener or is there a way to make this work? Since its a game, it would have to be able to run over 4 keys at the same time.

package game;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.awt.image.BufferStrategy;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferInt;

import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.KeyStroke;

import game.sfx.Screen;
import game.sfx.SpriteSheet;

public class Game implements Runnable{

private static final long serialVersionUID = 1L;

public static final int WIDTH = 160;
public static final int HEIGHT = WIDTH / 12 * 9;
public static final int SCALE = 3;
public static final String NAME = "Game";

private JFrame frame;
private JPanel panel;

public boolean running = false;
public int tickCount = 0;

private BufferedImage image = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
private int[] pixels = ((DataBufferInt) image.getRaster().getDataBuffer()).getData();

Screen screen;

public Game(){
panel = new JPanel();

panel.setMinimumSize(new Dimension(WIDTH*SCALE, HEIGHT*SCALE));
panel.setMaximumSize(new Dimension(WIDTH*SCALE, HEIGHT*SCALE));
panel.setPreferredSize(new Dimension(WIDTH*SCALE, HEIGHT*SCALE));

frame = new JFrame(NAME);

frame.setLayout(new BorderLayout());

frame.add(panel, BorderLayout.CENTER);


InputMap im = panel.getInputMap(JPanel.WHEN_IN_FOCUSED_WINDOW); // key binding here
ActionMap am = panel.getActionMap();

im.put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0), "r");
am.put("r", new InputHandler("right", this));
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0), "l");
am.put("l", new InputHandler("left", this));
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0), "u");
am.put("u", new InputHandler("up", this));
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0), "d");
am.put("d", new InputHandler("down", this));


public void init(){
screen = new Screen(WIDTH, HEIGHT, new SpriteSheet("res/Untitled.png"));

public synchronized void start() {
running = true;
new Thread(this).start();

public synchronized void stop() {
running = false;

public void run() {
long lastTime = System.nanoTime();
double nsPerTick = 1000000000D/60D;

int frames = 0;
int ticks = 0;

long lastTimer = System.currentTimeMillis();
double delta = 0;


while (running){
long now = System.nanoTime();
delta += (now - lastTime) / nsPerTick;
lastTime = now;
boolean shouldRender = true;
while(delta >= 1)
delta -= 1;
shouldRender = true;

try {
} catch (InterruptedException e) {

if (shouldRender)

if(System.currentTimeMillis() - lastTimer >= 1000){
lastTimer += 1000;
System.out.println(ticks + " ticks, " + frames + " frames");
frames = 0;
ticks = 0;

public void tick(){


public void render(){

screen.render(pixels, 0, WIDTH);

Graphics g = panel.getGraphics();

g.drawImage(image, 0, 0, panel.getWidth(), panel.getHeight(), null);



public static void main(String[] args){
new Game().start();


class InputHandler extends AbstractAction {

private static final long serialVersionUID = 1L;
private String key;
private Game game;

public InputHandler(String key, Game game) {
this.key = key; = game;

public void actionPerformed(ActionEvent e) {
case "right":
case "left":
case "up":
case "down":



This is the code


Do what I recommend in my linked to answer:

  • Create a game loop using a Swing Timer
  • Create an enum called Direction that has UP, DOWN, LEFT, and RIGHT items
  • And that also has int vector fields that indicate actual direction
  • Create a HashMap<Direction, Boolean> that is changed when an arrow key is pressed
  • Have the game loop pole this map, and alter direction depending on which direction is mapped to Boolean.TRUE.
  • Set up your Key Bindings to simply change the state of the HashMap, and that's it.