Threads with Key Bindings
Multi-threading is not necessary unless you want your game to be multi-threaded.
The issue is, can two players press different keys? If so, you can use booleans to indicate whether a key is down and reset the flag when the key is released.
In your game logic, check the states of the booleans and act appropriately. See the following example where both paddles can move independently:
[Image of paddles moving independently]
Here's an example code:
import java.awt.*; import java.awt.event.*; import javax.swing.*; public class GameLogic extends JFrame { public GameLogic() { initComponents(); } private void initComponents() { JFrame frame = new JFrame("Game Test"); //create the gamepanel final GamePanel gp = new GamePanel(600, 500); //create panel to hold buttons to start, pause JPanel buttonPanel = new JPanel(); final JButton startButton = new JButton("Start"); final JButton pauseButton = new JButton("Pause"); final JButton resetButton = new JButton("Reset"); pauseButton.setEnabled(false); resetButton.setEnabled(false); //add listeners to buttons startButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent ae) { gp.clearEntities(); addEntityToPanel(gp); startButton.setEnabled(false); pauseButton.setEnabled(true); resetButton.setEnabled(true); //start the game loop which will repaint the screen runGameLoop(gp); } }); //create and add keybindings for game panel GameKeyBindings gameKeyBindings = new GameKeyBindings(gp, player1Entity, player2Entity); pauseButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent ae) { boolean b = GamePanel.paused.get(); GamePanel.paused.set(!b);//set it to the opposite of what it was i.e paused to unpaused and vice versa if (pauseButton.getText().equals("Pause")) { pauseButton.setText("Un-pause"); } else { pauseButton.setText("Pause"); } } }); resetButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent ae) { resetGame(gp); } }); buttonPanel.add(startButton); buttonPanel.add(pauseButton); buttonPanel.add(resetButton); frame.add(gp); frame.add(buttonPanel, BorderLayout.SOUTH); frame.pack(); frame.setLocationRelativeTo(null); frame.setVisible(true); } //Simply used for testing (to simulate sprites) can create different colored images public static BufferedImage createColouredImage(String color, int w, int h, boolean circular) { BufferedImage img = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB); Graphics2D g2 = img.createGraphics(); switch (color.toLowerCase()) { case "green": g2.setColor(Color.GREEN); break; case "magenta": g2.setColor(Color.MAGENTA); break; case "red": g2.setColor(Color.RED); break; case "yellow": g2.setColor(Color.YELLOW); break; case "blue": g2.setColor(Color.BLUE); break; case "orange": g2.setColor(Color.ORANGE); break; case "cyan": g2.setColor(Color.CYAN); break; case "gray": g2.setColor(Color.GRAY); break; default: g2.setColor(Color.WHITE); break; } if (!circular) { g2.fillRect(0, 0, img.getWidth(), img.getHeight()); } else { g2.fillOval(0, 0, img.getWidth(), img.getHeight()); } g2.dispose(); return img; } private void runGameLoop(final GamePanel gp) { Thread loop = new Thread(new Runnable() { @Override public void run() { gp.gameLoop(); } }); loop.start(); } private void resetGame(GamePanel gp) { gp.reset(); gp.clearEntities(); addEntityToPanel(gp); gp.repaint(); } void addEntityToPanel(GamePanel gp){ ArrayList<BufferedImage> ballEntityImages = new ArrayList<>(); ArrayList<Long> ballEntityTimings = new ArrayList<>(); ballEntityImages.add(createColouredImage("white", 50, 50, true)); ballEntityTimings.add(500l); Entity ballEntity = new Entity(gp.getWidth() / 2, gp.getHeight() / 2, ballEntityImages, ballEntityTimings); ballEntity.RIGHT = true; //create images for entities ArrayList<BufferedImage> advEntityImages = new ArrayList<>(); ArrayList<Long> advEntityTimings = new ArrayList<>(); advEntityImages.add(createColouredImage("orange", 10, 100, false)); advEntityTimings.add(500l); advEntityImages.add(createColouredImage("blue", 10, 100, false)); advEntityTimings.add(500l); //create entities AdvancedSpritesEntity player1Entity = new AdvancedSpritesEntity(0, 100, advEntityImages, advEntityTimings); ArrayList<BufferedImage> entityImages = new ArrayList<>(); ArrayList<Long> entityTimings = new ArrayList<>(); entityImages.add(createColouredImage("red", 10, 100, false)); entityTimings.add(500l);//as its the only image it doesnt really matter what time we put we could use 0l //entityImages.add(createColouredImage("magenta", 100, 100)); //entityTimings.add(500l); Entity player2Entity = new Entity(gp.getWidth() - 10, 200, entityImages, entityTimings); gp.addEntity(player1Entity); gp.addEntity(player2Entity);//just a standing still Entity for testing gp.addEntity(ballEntity);//just a standing still Entity for testing } //Code starts here public static void main(String[] args) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { try {//attempt to set look and feel to nimbus Java 7 and up for (UIManager.LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) { if ("Nimbus".equals(info.getName())) { UIManager.setLookAndFeel(info.getClassName()); break; } } } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { } GameLogic gameLogic = new GameLogic(); } }); } } class GameKeyBindings { public GameKeyBindings(JComponent gp, final Entity entity, final Entity entity2) { gp.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_W, 0, false), "W pressed"); gp.getActionMap().put("W pressed", new AbstractAction() { @Override public void actionPerformed(ActionEvent ae) { entity.UP=true; } }); gp.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_S, 0, false), "S pressed"); gp.getActionMap().put("S pressed", new AbstractAction() { @Override public void actionPerformed(ActionEvent ae) { entity.DOWN=true; } }); gp.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0, false), "up pressed"); gp.getActionMap().put("up pressed", new AbstractAction() { @Override
The above is the detailed content of How Can I Handle Multiple Key Presses Simultaneously in a Java Game Using Key Bindings?. For more information, please follow other related articles on the PHP Chinese website!