So I have a painted rectangle that I want to move with the arrow keys that includes diagonal movement, or rather allowance of multiple keys being pressed at the same time (In other words, movement that is similar to player movement in a 2D game). I have attempted to do this with a KeyListener, which was not working. So I decided to move to KeyBindings and I found an example from this website: https://coderanch.com/t/606742/java/key-bindings (Rob Camick's post)
I directly copied the code and it works as intended, except it is moving an icon and not a painted rectangle like I want to do. I have attempted to modify the code so that it would move a painted rectangle, but was only failing. Here is my latest attempt, which is also a minimal reproducible:
import java.awt.event.*;
import java.awt.*;
import javax.swing.*;
public class Test extends JPanel implements ActionListener
{
public JPanel component = this;
public int x = 100;
public int y = 100;
private Timer timer;
private int keysPressed;
private InputMap inputMap;
public void addAction(String name, int keyDeltaX, int keyDeltaY, int keyCode)
{
new NavigationAction(name, keyDeltaX, keyDeltaY, keyCode);
}
// Move the component to its new location
private void handleKeyEvent(boolean pressed, int deltaX, int deltaY)
{
keysPressed += pressed ? 1 : -1;
x += deltaX;
y += deltaY;
// Start the Timer when the first key is pressed
if (keysPressed == 1)
timer.start();
// Stop the Timer when all keys have been released
if (keysPressed == 0)
timer.stop();
}
// Invoked when the Timer fires
public void actionPerformed(ActionEvent e)
{
repaint();
}
class NavigationAction extends AbstractAction implements ActionListener
{
private int keyDeltaX;
private int keyDeltaY;
private KeyStroke pressedKeyStroke;
private boolean listeningForKeyPressed;
public NavigationAction(String name, int keyDeltaX, int keyDeltaY, int keyCode)
{
super(name);
this.keyDeltaX = keyDeltaX;
this.keyDeltaY = keyDeltaY;
pressedKeyStroke = KeyStroke.getKeyStroke(keyCode, 0, false);
KeyStroke releasedKeyStroke = KeyStroke.getKeyStroke(keyCode, 0, true);
inputMap.put(pressedKeyStroke, getValue(Action.NAME));
inputMap.put(releasedKeyStroke, getValue(Action.NAME));
component.getActionMap().put(getValue(Action.NAME), this);
listeningForKeyPressed = true;
}
public void actionPerformed(ActionEvent e)
{
// While the key is held down multiple keyPress events are generated,
// we only care about the first event generated
if (listeningForKeyPressed)
{
handleKeyEvent(true, keyDeltaX, keyDeltaY);
inputMap.remove(pressedKeyStroke);
listeningForKeyPressed = false;
}
else // listening for key released
{
handleKeyEvent(false, -keyDeltaX, -keyDeltaY);
inputMap.put(pressedKeyStroke, getValue(Action.NAME));
listeningForKeyPressed = true;
}
}
}
public void paintComponent(Graphics tool) {
super.paintComponent(tool);
System.out.println(x + ", " + y);
tool.drawRect(x, y, 50, 50);
}
public Test() {}
public static void main(String[] args)
{
new Test().create();
}
public void create() {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
frame.setSize(600, 600);
frame.setLocationRelativeTo( null );
frame.getContentPane().add(component);
inputMap = component.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
timer = new Timer(24, this);
timer.setInitialDelay( 0 );
addAction("Left", -3, 0, KeyEvent.VK_LEFT);
addAction("Right", 3, 0, KeyEvent.VK_RIGHT);
addAction("Up", 0, -3, KeyEvent.VK_UP);
addAction("Down", 0, 3, KeyEvent.VK_DOWN);
frame.setVisible(true);
}
}