Hey thanks for looking at my post. I've been working on a passion project over the summer and this issue has risen. First off this may count as a duplicate question but I've been looking around this site and Oracle for a fix and couldn't find one, or more likely I just do not understand the code I am working with. A major help is one Hovercraft Full Of Eels on questions like this one.
I want to get a box, JPanel
, to move around a JFrame
, well another JPanel
, with the w
, a
, s
, d
keys. First I created my own panel by extending JPanel
. From there I have managed to get movement working but there is stuttering because of how key bindings work and I read adding a swing timer would improve stuttering. My initial guess is I'm not implementing something correctly or do not know enough about what I'm doing to see my mistake. I also tried my hand at setting a flag to help continual movement. There are no error messages and there are still things I need to implement, like preventing going out of bounds. Here is what I have:
public class PlayerPanel extends JPanel {
private static final int width = 100;
private static final int height = 200;
private int xPos, yPos;
private boolean movingUp, movingDown, movingLeft, movingRight;
private static final int SPIN_TIMER_PERIOD = 20;
private Timer timer;
public PlayerPanel() {
xPos = this.getX();
yPos = this.getY();
movingUp = movingDown = movingLeft = movingRight = false;
timer = new Timer(SPIN_TIMER_PERIOD, new SpinTimerListener());
timer.setInitialDelay(0);
timer.start();
setPreferredSize(new Dimension(width, height));
setBackground(Color.cyan);
setUpKeyBindings();
}
private void setUpKeyBindings() {
int condition = JComponent.WHEN_IN_FOCUSED_WINDOW;
InputMap inMap = this.getInputMap(condition);
ActionMap actMap = this.getActionMap();
inMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_W, 0), "moveUp");
actMap.put("moveUp", new KeyAction("up"));
inMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_S, 0), "moveDown");
actMap.put("moveDown", new KeyAction("down"));
inMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_A, 0), "moveLeft");
actMap.put("moveLeft", new KeyAction("left"));
inMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_D, 0), "moveRight");
actMap.put("moveRight", new KeyAction("right"));
}
public class KeyAction extends AbstractAction {
private String direction;
private int delta = 2;
public KeyAction(String direction) {
this.direction = direction;
}
@Override
public void actionPerformed(ActionEvent e) {
switch(direction) {
case "up":
movingUp = true;
yPos -= delta;
break;
case "down":
movingDown = true;
yPos += delta;
break;
case "right":
movingRight = true;
xPos += delta;
break;
case "left":
movingLeft = true;
xPos -= delta;
break;
default:
break;
}
}
}
private class SpinTimerListener implements ActionListener{
@Override
public void actionPerformed(ActionEvent e) {
int delta = 5;
if(movingUp) {
yPos -= delta;
movingUp = false;
}
else if(movingDown) {
yPos += delta;
movingDown = false;
}
else if(movingLeft) {
xPos -= delta;
movingLeft = false;
}
else if(movingRight) {
xPos += delta;
movingRight = false;
}
setLocation(xPos, yPos);
}
}
}
I tried to keep my code minimal and this is what I've built up to.
Yes there are more efficient ways to code this, like using enum to help set up my key binds, but my coding philosophy is:
- figure out what I want to do, get it working (usually with what I call brute force code)
- understand why it works
- make it better and make it pretty.
I'm in the understanding phase. Another very valid point is why am I not using Graphics, as in Graphics g.draw(blah). TBH I have no idea. I could not get it to work and I need to spend more time with it before I ask a question involving it since asking someone to teach me how to use Graphics does not seem appropriate here.
So aside from using Graphics like I should be, how can I better implement my key binds and swing timer. I was thinking me using setLocation
might be an issue instead of using graphics.repaint or something but setLocation
calls repaint so I don't think that is the primary issue, but probably still one none the less. I apologize for the wall of text but I want to try and be thorough so...
TL:DR; I am making a custom JPanel
move around with key binds and a swing timer. The movement stutters and I would prefer it not too. After posting and some rest I'll combine the four moving booleans into one as that also might not be helping and add a state variable for direction and try to declutter my code. Thank for looking at my code if you did and any help is welcome. I like learning how to code and read any number of references you tell me I was too lazy to search for.
Also here is my main if you want to run exactly what I'm running, PlayerPanel
and a Driver
class with a main method are my only two files I'm working with.
public class Driver {
public static void main(String args[]) {
JFrame frame = new JFrame();
frame.setSize(1000, 500);
JPanel background = new JPanel();
background.setBackground(Color.BLACK);
PlayerPanel player = new PlayerPanel();
background.add(player);
frame.add(background);
frame.setVisible(true);
}
}