简体   繁体   中英

JButton ActionListener two player game

I am trying to create a two player game with Java Swing.

I have one JButton .

My idea is to switch to another player when the JButton is clicked. When player one clicks the JButton , it becomes player two's turn; when player two clicks, it becomes player one's turn.

However my codes so far does not allow the program to wait for player two's click. When player one click, player two is considered to have also already clicked.

How do I go about solving this by making the program wait for player two's click?

boolean game = true;
final boolean p1 = false;
final boolean p2 = false;
...
while (game) {
    p1 = true;
    while (p1) {
        enterMoveButton.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent arg0) {
                doSomething();
                p1 = false;
                p2 = true;
            }
        });
    }
    while (p2) {
        enterMoveButton.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent arg0) {
                doSomething();
                p2 = false;
                p1 = true;
            }
        });
    }
}

我建议改用JToggleButton 。有关使用它们的信息,请参见《 Java教程》中的 如何使用按钮,复选框和单选按钮 ”。

Why don't you disable JButton of the player who doesn't have their turn and later enable when the player gets his turn and disable opponent's button.

button.setEnabled(false);

Assuming you have two different button

Good luck!

Since you're coding Swing, don't do while (true) loops as you'll block the event thread, the EDT. Instead you should either use a Swing Timer, or more likely in your case, since I'm guessing you're playing a turn-based game (please correct me if wrong), make actions dependent upon events. With the latter, rather than swapping ActionListeners, you would simply change the program state via a single field and have the ActionListener's behavior be altered depending on this state.

For an example of the latter please see the code below. The program's state is held by the playerIndex int variable:

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;

public class ToggleGame extends JPanel {
   public static final String[] PLAYERS = {"Player 1", "Player 2"};

   // turnIndex is either 0 or 1, depending on whose turn it is.
   private int turnIndex = 0; 
   private JButton turnButton = new JButton(PLAYERS[turnIndex]);

   public ToggleGame() {
      add(new JLabel("Turn:"));
      add(turnButton);
      setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));

      turnButton.addActionListener(new ActionListener() {
         public void actionPerformed(ActionEvent evt) {
            turnBtnAction(evt);
         }
      });
   }

   private void turnBtnAction(ActionEvent evt) {
      turnIndex++; // next player
      turnIndex %= PLAYERS.length; // mod 2
      turnButton.setText(PLAYERS[turnIndex]);

      doSomething(turnIndex);
   }

   private void doSomething(int index) {
      String msg = "It is now " + PLAYERS[index] + "'s turn!";
      String title = "Whose Turn Is It?";
      JOptionPane.showMessageDialog(this, msg , title, JOptionPane.INFORMATION_MESSAGE);
   }

   private static void createAndShowGui() {
      ToggleGame mainPanel = new ToggleGame();

      JFrame frame = new JFrame("ToggleGame");
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.getContentPane().add(mainPanel);
      frame.pack();
      frame.setLocationByPlatform(true);
      frame.setVisible(true);
   }

   public static void main(String[] args) {
      SwingUtilities.invokeLater(new Runnable() {
         public void run() {
            createAndShowGui();
         }
      });
   }
}

When player one click, player two is considered to have also already clicked

This is because you use addActionListener. When you call this method, it doesn't replace the previous one. It just add another listener to the button click. When it is clicked, it executes all the listeners that are added to the button.

You can solve this problem by defining two actionListeners:

ActionListener a1 = new ActionListener(){

    @Override
    public void actionPerformed(ActionEvent arg0) {
        doSomething();
        p1 = false;
        p2 = true;

    }   
};

ActionListener a2 = new ActionListener(){

    @Override
    public void actionPerformed(ActionEvent arg0) {
        doSomething();
        p2 = false;
        p1 = true;
   }
};


while(game){
    p1 = true;
    while(p1){
        enterMoveButton.removeActionListener(a2);
        enterMoveButton.addActionListener(a1);
    }
    while(p2){
        enterMoveButton.removeActionListener(a1);
        enterMoveButton.addActionListener(a2);
    }

Why not instead of using two boolean variables you use only one like say :

boolean myturn = true; // at the start for Player 1 it's true.

@Override
public void actionPerformed(ActionEvent arg0) 
{
   if (myturn == true)
   {
      doSomething();  // Do whatever Player1 is suppose to do at his turn.
                      // Now since myturn will be false after this, so Player1
                      // won't be able to move till Player 2 takes his turn.
      myturn = false;
   }
   else if (myturn == false)
   {
      doThisInstead(); // Do whatever Player2 is suppose to do at his turn.
                       // Here again myturn will will change to true, now Player2
                       // won't be able to move till Player1 makes his next move.
      myturn = true;
   }
}

Here is code that explains what i just said :

import javax.swing.*;
import java.awt.event.*;

public class ButtonTest extends JFrame implements ActionListener
{
  private JPanel panel;
  private JButton button;
  private JLabel label;
  private String player1 = "I am player one.";
  private String player2 = "I am player two.";
  private boolean myturn = true;

  public ButtonTest()
  {
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    panel = new JPanel();
    button = new JButton(player1);
    label = new JLabel(player1);
    button.addActionListener(this);

    panel.add(label);
    panel.add(button);

    setContentPane(panel);
    pack();
  }

  public void actionPerformed(ActionEvent ae)
  {
     if (myturn == true)
    {
      button.setText(player2);
      label.setText(player2);
      myturn = false;
    }
    else if (myturn == false)
    {
      button.setText(player1);
      label.setText(player1);
      myturn = true;
    }
  }

  public static void main(String... args)
  {
    SwingUtilities.invokeLater(new Runnable()
    {
      public void run()
      {
        new ButtonTest().setVisible(true);
      }
    });
  }
}

A single variable can do the trick for you, instead of using two different.

Hope that might help in some way. Regards

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM