I'm new to Java graphics and threads, and I'm trying to make a game (specifically, Pong). The idea is that two people can play on the same keyboard (i.e. there are two paddles that are controlled through different keys). Currently, both players can't move their paddle at the same time.
Is there a solution to this? Are separate threads the answer?
If possible, I'd like the paddles to be able to move (at least seemingly) at the same time.
Update: It seems like using a Set<Integer>
to store pressed keys is the best option. I've done that (and it works), but I'm wondering if any of this code is not on the Event Dispatching Thread (EDT) and if I need to use SwingUtilities.invokeLater();
. Here's the necessary code:
private Set<Integer> keysDown = Collections.synchronizedSet(new HashSet<Integer>());
public void keyPressed(KeyEvent e)
{
keysDown.add(e.getKeyCode());
}
public void keyReleased(KeyEvent e)
{
keysDown.remove(e.getKeyCode());
}
public void updatePaddlePositions()
{
if (keysDown.contains(KeyEvent.VK_W))
paddleOne.move(-PADDLE_MOVE_INCREMENT);
if (keysDown.contains(KeyEvent.VK_S))
paddleOne.move(PADDLE_MOVE_INCREMENT);
if (keysDown.contains(KeyEvent.VK_UP))
paddleTwo.move(-PADDLE_MOVE_INCREMENT);
if (keysDown.contains(KeyEvent.VK_DOWN))
paddleTwo.move(PADDLE_MOVE_INCREMENT);
try {
Thread.sleep(DELAY);
} catch (InterruptedException e) {
System.out.println("You Interrupted the game!");
}
canvas.repaint();
}
Here's the paintComponent
method of the canvas
object:
public void paintComponent(Graphics g)
{
super.paintComponent(g);
paddleOne.paint(g);
paddleTwo.paint(g);
updatePaddlePositions(); // Does this need to be SwingUtilities.invokeLater(this)?
// And should updatePaddlePositions() be run() as a result?
}
And here's the paint
method of the paddleOne
and paddleTwo
objects:
public void paint(Graphics g)
{
g.setColor(Color.BLACK);
g.fillRect(x, y, PADDLE_WIDTH, PADDLE_HEIGHT);
}
Feel free to comment on my design if anything pops out as "bad" to you. Lastly, what does Collections.synchronizedSet(new HashSet<Integer>())
mean/do?
Update #2: It seems like key bindings are the way to go (even though they take more code, in this case). What make key bindings better? Is it that they work separately from everything else (and don't need window focus like key listeners)?
Also, I understand that HashSet<Integer>
is just a subclass of Set<Integer>
, but what is the purpose of Collections.synchronizedSet(...)
? I'm assuming it has to do with threads, but I don't know why it's needed in this program (if it is at all).
This may be a legitimate use case for the low-level access afforded to a
KeyListener
. See How to Write a Key Listener andKeyEventDemo
; don't forget torequestFocusInWindow()
. Also consider offering keyboard control for one player and mouse control for the other.Addendum: @David Kroukamp has adduced an appealing counter-example using key bindings. For reference, the example cited here illustrates one approach to managing key preferences.
First off, use Swing
KeyBinding
s Also I see no real need for multi-threadung unless you want your game multi-threaded.To clarify the problem is you need to be able for 2 players to press different keys?
If so:
Solution:
Simply use
boolean
s to flag whether or not a key is pressed down, you would than of course have to reset the flag when the key is released.In your game logic you would check the states if the booleans and act appropriately.
See my below example (both paddles can move independently using W and S and UP and DOWN keys):