I've developed a working chess engine with minimax and alpha-beta, however I want to test my algorithm by playing itself, computer vs computer. I have tried everything to no avail. Just wondering how I would go about this?
public class Main {
static JTextArea textField;
public static void main(String[] args) {
while ( 'K' != ABChess.board[ABChess.kingLocationUU/8][ABChess.kingLocationUU%8]) {ABChess.kingLocationUU++;}
while ( 'k' != ABChess.board[ABChess.kingLocationLL/8][ABChess.kingLocationLL%8]) {ABChess.kingLocationLL++;}
Asset.init("/images/ChessPiecess.png");
ABChess.updateKingLocations();
//print();
JPanel depthPanel = depthPanel();
JPanel optionPanel = optionPanel();
JPanel logPanel = logPanel();
JPanel menuPanel = new JPanel();
menuPanel.setPreferredSize(new Dimension(140, 100));
menuPanel.setLayout(new BoxLayout(menuPanel, BoxLayout.Y_AXIS));
menuPanel.add(depthPanel);
menuPanel.add(optionPanel);
menuPanel.add(logPanel);
GUInterface gui = new GUInterface();
JPanel panel = new JPanel(new BorderLayout());
panel.add(gui);
panel.add(menuPanel, BorderLayout.EAST);
JFrame frame = new JFrame(ABChess.title);
frame.setSize(ABChess.width, ABChess.height);
frame.add(panel);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setResizable(true);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
System.out.println(ABChess.possibleMoves());
ABChess.playerChoice = JOptionPane.showOptionDialog(null, "Who wants to make the first move?", "Who moves first?", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, ABChess.options, ABChess.options[0]);
if (ABChess.playerChoice == 0){
ABChess.flipBoard();
long startTime=System.currentTimeMillis();
Move autoMove = AlphaBeta.alphaBeta(ABChess.gameDepth, 1000000, -1000000, new Move(), 0);
long endTime=System.currentTimeMillis();
ABChess.makeMove(autoMove);
ABChess.flipBoard();
System.out.println("COMPUTER'S MOVE TOOK "+((endTime-startTime)/1000.0)+" SECONDS");
ABChess.printBoard();
frame.repaint();
displayMessage("Took "+((endTime-startTime)/1000.0)+" seconds");
}
}
This is the initial call to the algorithm when the file is ran.
public void mousePressed(MouseEvent event) {
if ( event.getX() < 8*sizeOfSquare && event.getY() < 8*sizeOfSquare) {
mouseX = event.getX();
mouseY = event.getY();
repaint();
}
}
public void mouseReleased(MouseEvent event) {
if (event.getX() < 8*sizeOfSquare && event.getY() < 8*sizeOfSquare) {
newMouseX = event.getX();
newMouseY = event.getY();
if (event.getButton() == MouseEvent.BUTTON1) {
// Regular move
Move legalMovesMove = new Move(mouseY/sizeOfSquare, mouseX/sizeOfSquare, newMouseY/sizeOfSquare, newMouseX/sizeOfSquare, Test6.board[newMouseY/sizeOfSquare][newMouseX/sizeOfSquare]);
java.util.List<Move> legalMoves = ABChess.possibleMoves();
for(Move m : legalMoves) {
if (m.equals(legalMovesMove)) {
ABChess.makeMove(legalMovesMove);
ABChess.flipBoard();
long startTime=System.currentTimeMillis();
Move autoMove = AlphaBeta.alphaBeta(ABChess.gameDepth, 1000000, -1000000, new Move(), 0);
long endTime=System.currentTimeMillis();
ABChess.makeMove(autoMove);
ABChess.flipBoard();
System.out.println("COMPUTER'S MOVE TOOK "+((endTime-startTime)/1000.0)+" SECONDS");
ABChess.printBoard();
repaint();
}
}
checkMate = ABChess.kingSafe();
if(checkMate == false){
int yes = JOptionPane.showOptionDialog(null, "Do you want to make the first move?", "Who moves first?", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, null, JOptionPane.YES_OPTION);
if (yes == JOptionPane.YES_OPTION){
ABChess.resetGame();
repaint();
} else if (yes == JOptionPane.NO_OPTION){
System.exit(0);
}
}
legalMoves = ABChess.possibleMoves();
if (legalMoves.size() == 0) {
ABChess.playAgain = JOptionPane.showOptionDialog(null, "Stalemate! Wanna play again?", "Draw!", JOptionPane.YES_NO_OPTION,
JOptionPane.QUESTION_MESSAGE, null, ABChess.choice, ABChess.choice[1]);
if (ABChess.playAgain == 0) {
System.out.println("Yes I will");
ABChess.resetGame();
repaint();
} else {
System.exit(0);
}
}
}
}
}
This is where the algorithm is called every time the mouse is released. Not sure how to code to where it plays itself with the white pieces instead of me.
I would normally seperate the Player from the Game, and the Game would request the interaction from the Player object. The Player object would either be a Human (so the needed input is delegated to some UI) or an AI so it would be delegated to some implementation which decides which move is best.
I would recommend using an object for the ABChess Game instead of static methods.
So with a bit of refactoring and seperating the UI from the logic as well, it could look like this:
interface Player {
Move decide(List<Move> legalMoves);
}
class ChessGame {
ABChess game;
Player player1;
Player player2;
UIInterface ui;
ChessGame(Player player1, Player player2, UIInterface ui) {
this.player1 = player1;
this.player2 = player2;
this.ui = ui;
game = ...
}
public void simulate() {
// ... initial ui ...
boolean player1Turn = true;
do {
Move move = null;
if (player1Turn) {
move = player1.decide(game.possibleMoves());
} else {
move = player2.decide(game.possibleMoves());
}
game.makeMove(move);
// ... update ui ...
player1Turn = !player1Turn;
// check if somebody has won ...
} while (game.isRunning());
// ... update ui with the game result ...
}
}
Once that is done simulating games becomes easy. You just need to initiate the ChessGame with the proper players and call the simulate method. At that point you could also decide to skip the UI presentation completly (so the learning will be much faster).
Related
I have built a snake game where a JPanel that implements a card layout manager is placed onto the JFrame. Three other JPanels are added to the card layout.
public void init () {
JOptionPane.showMessageDialog (this, "Don't let the snake hit the borders or you lose!", "Introduction to the Snake Game", JOptionPane.INFORMATION_MESSAGE);
appleCounter.label.setBorder (new LineBorder (Color.yellow, 1));
mainPanel.setLayout (card);//CHANGING THE LAYOUT MANAGER FOR THE JPANEL TO CARDLAYOUT
Screens [0] = new Screen ();//CREATING AN INSTANCE OF A JPANEL
mainPanel.add (Screens [0], "one");//ADDING THE JPANEL TO THE CARD LAYOUT
add (mainPanel, BorderLayout.CENTER);//ADDING THE JPANEL TO THE JFRAME
add (appleCounter.label, BorderLayout.SOUTH);
pack ();
setLocationRelativeTo (null);
setVisible (true);
}
This is so that after the snake collides with the border of the frame, a JDialog appears asking if they'd like to try again. If the player clicks 'yes' the next JPanel from the card layout will appear.
if (xCoor < 0 || xCoor > 80 || yCoor < 0 || yCoor > 60) {//IF THE SNAKE COLLIDES WITH THE BORDER OF THE FRAME
number = 1;
collide = true;
createApples ();
stop ();//CALLING THE METHOD THAT I AM HAVING PROBLEMS WITH
}
However, I am having issues with the stop method because when the snake collides with the border & the player clicks "yes" the next JPanel from the card layout appears. But the JPanel doesn't listen for any key inputs from the player, as a result, the snake cannot change directions.
public void stop () {
running = false;
try {
int response = JOptionPane.showConfirmDialog (this, "Do you want to play again?", "Opps looks like you lost", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE);
if (response == JOptionPane.YES_OPTION) {
if (digit < 3) {
Frame.card.removeLayoutComponent (Frame.Screens [digit]);
Frame.Screens [digit] = null;
digit++;
Frame.Screens [digit] = new Screen ();
if (digit == 1) {
Frame.card.removeLayoutComponent (Frame.Screens [digit]);
Frame.Screens [digit] = null;
Frame.mainPanel.add (Frame.Screens [digit], "two");
Frame.card.removeLayoutComponent (Frame.Screens [digit]);
} else if (digit == 2) {
Frame.mainPanel.add (Frame.Screens [digit], "three");
}
} else if (response == JOptionPane.NO_OPTION) {
System.exit (0);
} else if (response == JOptionPane.CLOSED_OPTION) {
System.exit (0);
}
thread.join ();
} catch (InterruptedException e) {
e.printStackTrace ();
}//CLOSE CATCH
}
The JPanel instances are created using the Screen class which extends from JPanel class, even though the two JPanels in the card layout setFocusable to true so it should throw keyEvents.
public Screen () {
setFocusable (true);//THE JPANEL COMPONENT WILL BE AN EVENT SOURCE, THROWING KEY EVENTS TO THE KEY INSTANCE
addKeyListener (new Key ());//REGISTER THE KEY INSTANCE TO LISTEN TO KEY EVENTS
setPreferredSize (new Dimension (WIDTH, HEIGHT));
r = new Random ();
apples = new ArrayList <Apple> ();
start ();
}
Here is the inner class which has the keyPressed () that is called when the player clicks a directional key:
public class Key implements KeyListener {
public void keyPressed (KeyEvent e) {
int key = e.getKeyCode ();
if (key == KeyEvent.VK_RIGHT && !left) {
up = false;
down = false;
right = true;
}
if (key == KeyEvent.VK_LEFT && !right) {
up = false;
down = false;
left = true;
}
if (key == KeyEvent.VK_UP && !down) {
left = false;
right = false;
up = true;
}
if (key == KeyEvent.VK_DOWN && !up) {
left = false;
right = false;
down = true;
}
}
public void keyReleased (KeyEvent e) {}
public void keyTyped (KeyEvent e) {}
I am a beginner at Java so I would appreciate it if when answering this question there is a minimal amount of technical language or that the answer is explained in a way a beginner can understand. To clarify only the first Screen instance created in the init () listens for key inputs, the other two Screen instances cannot.
I have a tic tac toe game I made with java GUI and was trying to implement a way to restart the game by having users click on a menu bar item.
Please let me know what other ways I could try to get a working restart feature.
What I tried so far is to invoke the playGame() method when I click on the menu bar item but that doesn't work as the while loop in the playGame method makes it stuck.
public TicTacToe()
{
/* Create JFrame and set up the size and visibility */
frame = new JFrame("Tic Tac Toe");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
/* Create menu bar*/
JMenuBar menubar = new JMenuBar();
JMenu game = new JMenu("Game");
newGame = new JMenuItem("New Game");
quit = new JMenuItem("Quit");
newGame.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent evt) {
newGameActionPerformed(evt);
}
});
quit.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent evt) {
quitActionPerformed(evt);
}
});
game.add(newGame);
game.add(quit);
menubar.add(game);
frame.setJMenuBar(menubar);
/* Add text area to frame. */
frame.add(scrollableTextArea);
frame.setLocationRelativeTo(null);
frame.setSize(400,400);
frame.setVisible(false);
}
private void quitActionPerformed(ActionEvent evt){
System.exit(0);
}
private void newGameActionPerformed(ActionEvent evt) {
clearBoard();
}
public void playGame()
{
frame.setVisible(true);
clearBoard(); // clear the board
// loop until the game ends
while (winner==EMPTY) { // game still in progress
while (playerWent == false){
if (topRight.getModel().isPressed()){
topRight.setText(player);
topRight.setEnabled(false);
playerWent = true;
}
else if (topMid.getModel().isPressed()){
topMid.setText(player);
topMid.setEnabled(false);
playerWent = true;
}
else if (topLeft.getModel().isPressed()){
topLeft.setText(player);
topLeft.setEnabled(false);
playerWent = true;
}
else if (midRight.getModel().isPressed()){
midRight.setText(player);
midRight.setEnabled(false);
playerWent = true;
}
else if (center.getModel().isPressed()){
center.setText(player);
center.setEnabled(false);
playerWent = true;
}
else if (midLeft.getModel().isPressed()){
midLeft.setText(player);
midLeft.setEnabled(false);
playerWent = true;
}
else if (botRight.getModel().isPressed()){
botRight.setText(player);
botRight.setEnabled(false);
playerWent = true;
}
else if (botMid.getModel().isPressed()){
botMid.setText(player);
botMid.setEnabled(false);
playerWent = true;
}
else if (botLeft.getModel().isPressed()){
botLeft.setText(player);
botLeft.setEnabled(false);
playerWent = true;
}
}
numFreeSquares--; // decrement number of free squares
// see if the game is over
if (haveWinner()) {
winner = player; // must be the player who just went
if (winner.equals(PLAYER_X)){
gameState.setText("Player X wins");
return;
} else {
gameState.setText("Player O wins");
return;
}
}
else if (numFreeSquares==0) {
winner = TIE; // board is full so it's a tie
gameState.setText("Tie game");
return;
}
// change to other player (this won't do anything if game has ended)
if (player==PLAYER_X) {
player=PLAYER_O;
gameState.setText("Game in progress, Player O's turn");
playerWent = false;
}
else {
player=PLAYER_X;
gameState.setText("Game in progress, Player X's turn");
playerWent = false;
}
}
}
The loop will override the restart function you're trying to implement. My suggestion is that you try to refactor your code to work event-driven. To keep it short and simple: event-driven programming is the User Interface responding to(and acknowledging) the user's input. You can do this by a class that manages the game's turns.
Here is some sample code for reference, I've used this for my own tic-tac-toe project(JavaFX framework):
private void playersGameProcess() {
//Looping through the button field to add mouseclick events, if there is pressed on a button the game's state switches between CROSS and NOUGHT.
for (int i = 0; i < buttons2D.length; i++) {
for (int j = 0; j < buttons2D[i].length; j++) {
Button button = buttons2D[i][j];
buttons2D[i][j].setOnMouseClicked(event -> {
if (game.getGameState() == "X" && button.getId() == null) {
game.incrementTurnCount();
System.out.println("Turn: " + game.getTurnCount());
notification.setText("It's nought's turn!");
game.setGameState("O");
button.setId("buttonClickX");
checkWinningConditions("X");
} else if (game.getGameState() == "O" && button.getId() == null) {
game.incrementTurnCount();
System.out.println("Turn: " + game.getTurnCount());
notification.setText("It's cross's turn!");
button.setId("buttonClickO");
game.setGameState("X");
checkWinningConditions("O");
}
});
}
}
}
So I am making a space invaders clone. Originally I had no problem getting my game to work with a simple main class that created the frame, created the gameplay and started the thread.
But then I tried to implement a start menu and it all went to crap. The menu appears with success but the gameplay does not appear when I press start.
I am running out of ideas and I am completely stumped. I am somewhat new as well to SO, so if there is anything I left out, I appreciate any help.
Here is the original with no menu that worked fine:
public static void main(String[] args) {
JFrame frame = new JFrame("SpaceRaiders");
frame.setSize(600, 600);
frame.setLocationRelativeTo(null);
frame.setResizable(false);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Gameplay gameplay = new Gameplay();
frame.add(gameplay);
frame.setVisible(true);
Thread t1 = new Thread(gameplay);
t1.start();
}
However, the moment I tried to implement a menu to then play the game, I am running into all sorts of trouble. I created a UI class as well as an actual "game" class like so:
public class UI {
JFrame frame, f2;
JPanel titrePanel, startButtonPanel, loadButtonPanel, p2;
JLabel nomJeu;
JButton startButton, loadButton;
Font fontTitre, fontStart;
Gameplay gameplay;
public void createUI(ChoixJeu cj) {
frame = new JFrame("SpaceRaiders");
frame.setSize(600, 600);
frame.setLocationRelativeTo(null);
frame.setResizable(false);
frame.setLayout(null);
frame.getContentPane().setBackground(Color.black);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//------------------ECRAN MENU---------------------
//Titre
titrePanel = new JPanel();
titrePanel.setBounds(100, 100, 400, 100);
titrePanel.setBackground(Color.BLUE);
Font fontTitre = new Font("Times New Roman", Font.BOLD, 50);
Font fontStart = new Font("Times New Roman", Font.PLAIN, 20);
nomJeu = new JLabel("SpaceRaiders");
nomJeu.setForeground(Color.white);
nomJeu.setFont(fontTitre);
titrePanel.add(nomJeu);
//Start button
startButtonPanel = new JPanel();
startButtonPanel.setBounds(200, 400, 200, 40);
startButtonPanel.setBackground(Color.BLACK);
startButton = new JButton("START");
startButton.setBackground(Color.BLACK);
startButton.setForeground(Color.WHITE);
startButton.setFont(fontStart);
startButton.setFocusPainted(false);
startButton.addActionListener(cj);
startButton.setActionCommand("start");
startButtonPanel.add(startButton);
//Load Button
loadButtonPanel = new JPanel();
loadButtonPanel.setBounds(200, 440, 200, 100);
loadButtonPanel.setBackground(Color.BLACK);
loadButton = new JButton("LOAD");
loadButton.setBackground(Color.BLACK);
loadButton.setForeground(Color.WHITE);
loadButton.setFont(fontStart);
loadButton.setFocusPainted(false);
titrePanel.add(nomJeu);
loadButtonPanel.add(loadButton);
frame.add(startButtonPanel);
frame.add(titrePanel);
//------------------ECRAN MENU FIN---------------------
frame.setVisible(true);
}
And the game class...
public class Jeu {
ChoixJeu cj = new ChoixJeu();
UI ui = new UI();
Ecrans e = new Ecrans(ui);
Gameplay gp;
public static void main(String[] args) {
new Jeu();
}
public Jeu() {
ui.createUI(cj);
Gameplay gameplay = new Gameplay();
this.gp = gameplay;
}
public class ChoixJeu implements ActionListener {
#Override
public void actionPerformed(ActionEvent ae) {
String yourChoice = ae.getActionCommand();
switch (yourChoice) {
case "start":
e.montrerEcranJeu();
new Thread(gp).start();
ui.frame.add(gp);
break;
default:
break;
}
}
}
}
I also tried to make a class/method that hides the menu panels
public void montrerEcranJeu() {
//Cache Menu
ui.titrePanel.setVisible(false);
ui.startButtonPanel.setVisible(false);
//Montre Jeu
// ui.frame.add(gameplay);
}
And just in case the Gameplay class. The run() method is at the bottom
public class Gameplay extends JPanel implements KeyListener, ActionListener, Runnable {
private Ship player = new Ship(new Point(200, 555));
Timer t = new Timer(5, this);
private ArrayList<Laser> lasers = new ArrayList<Laser>();
private int laserNb;
private boolean readytofire;
private boolean shot = false;
private ArrayList<Invader> invaders = new ArrayList<Invader>();
private boolean pause;
public Gameplay() {
super();
t.start();
addKeyListener(this);
setFocusable(true);
setFocusTraversalKeysEnabled(false);
for (int j = 0; j < 80; j += 20) {
for (int i = 0; i < 20; i++) {
invaders.add(new Invader(5 + i * 30, j));
}
}
}
public boolean addLaser(Laser a) {
lasers.add(a);
return true;
}
public boolean addPlayer(Ship p) {
this.player = p;
return true;
}
#Override
public void keyTyped(KeyEvent ke) {
}
public void keyPressed(KeyEvent e) {
if (KeyEvent.VK_RIGHT == e.getKeyCode()) {
moveRight();
}
if (KeyEvent.VK_LEFT == e.getKeyCode()) {
moveLeft();
}
if (KeyEvent.VK_SPACE == e.getKeyCode()) {
shoot();
System.out.println("Space Action from Gameplay is working");
}
}
#Override
public void keyReleased(KeyEvent e) {
}
#Override
public void actionPerformed(ActionEvent ae) {
repaint();
}
public void moveRight() {
if (player.getCentre().getX() >= 580) {
player.setX(580);
} else {
double movement = player.getCentre().getX();
movement += 10;
player.setX(movement);
}
this.repaint();
}
public void moveLeft() {
if (player.getCentre().getX() <= 20) {
player.setX(20);
} else {
double movement = player.getCentre().getX();
movement -= 10;
player.setX(movement);
}
this.repaint();
}
public void shoot() {
shot = true;
if (readytofire) {
Point top = new Point(player.getTopX(), player.getTopY());
Laser laser = new Laser(top);
addLaser(laser);
}
}
public void moveShot() {
if (shot) {
for (Laser l : lasers) {
l.setY(l.getTopLeft().getY() - 1);
}
}
}
#Override
public void paint(Graphics g) {
setBackground(Color.black);
super.paint(g);
player.draw(g);
for (Laser l : lasers) {
l.draw(g);
}
for (Invader i : invaders) {
i.draw(g);
}
}
// public void paintComponent (Graphics g){
// Controle Thread
public void run() {
while (true) {
moveShot();
for (Invader i : invaders) {
i.moveAndUpdate();
}
// for (Invader i : invaders) {
// if (){
// System.out.println("YOU ARE DEAD!");
// }
// }
try {
Thread.sleep(10);
readytofire = true;
} catch (InterruptedException ex) {
Logger.getLogger(Gameplay.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}
So, using null layouts is the beginning of your problems. I might recommend using CardLayout which is designed to help you dynamically switch between views. See How to Use CardLayout for more details. I'd also suggest taking the time to read through Laying Out Components Within a Container and finding one or more appropriate layouts to support your menu.
You're also making a lot of fundamental mistakes. Swing is not thread safe, so you should avoid updating the UI (or something the UI depends on) from outside the context of the EDT - see Concurrency in Swing for more information and How to Use Swing Timers for a possible solution.
As a general recommendation, you should avoid overriding paint and, in the case of classes which extend from JComponent, prefer paintComponent instead. You should also avoid call methods which might change the state of the component during a paint cycle, this can increase the number of repaint requests and degrade the performance of your program (ie, don't call setBackground inside paint).
Have a look at Performing Custom Painting and Painting in AWT and Swing for more details about how the paint system works and how best you can work with it.
You should also avoid KeyListener, this is likely to cause you issues when you introduce other, focusable, components into the picture. Instead, you should favour the Key bindings API instead
I've read through [insert link or tutorial], but it still doesn't help...
And forgive me if this doesn't happen all the time.
The point of providing you the tutorial links is to encourage you to learn something;
Learn where to find answers to your questions
Learn how the APIs work
Expand your knowledge and understanding of how the APIs work
Having said that, they're not always "obvious" as to the solution. What I do when I'm in this situation is start with one or more new projects, dedicated to just working on that aspect of the API I'm trying to understand. For here I can explore the concepts in isolation and when I "think" I understand them, try and implement them into the project I'm working on. This might take a number of iterations, but once it works, I have gained a much deeper understanding and appreciation of the API then I would have gained from a simple "copy-n-paste" solution
public class SocialNetwork extends Program
implements Constants {
Canvas canvas = new Canvas();
public void init() {
breakoutButton = new JButton("Play Breakout Game");
breakoutButton.setForeground(Color.WHITE);
breakoutButton.setBackground(Color.BLACK);
add(breakoutButton, WEST);
breakoutButton.addActionListener(this);
getContentPane().setBackground(Color.BLACK);
addActionListeners();
add(canvas);
}
}
public void actionPerformed(ActionEvent e) {
if (e.getActionCommand().equals("Play Breakout Game") || e.getSource() == breakoutButton) {
canvas.displayMessage("game started"); //displayMessage method displays the parameter string on the canvas.
Breakout bo = new Breakout();
bo.setVisible(true);
}
}
This is the main code which creates the button which is supposed to launch the breakout game. The code for breakout is :
public class Breakout extends GraphicsProgram {
public void run() {
setBackground(Color.BLACK);
setUpBricks();
points = new GLabel("Points: " + pointsCounter);
add(points, getWidth()/2 - points.getWidth()/2, getHeight() - points.getAscent());
points.setColor(Color.WHITE);
for(int i=0; i < NTURNS; i++) {
addMouseListeners();
setUpGame();
playGame();
if (brickCounter == 0) {
GLabel winner = new GLabel("You Win! You got " + pointsCounter + " points.");
winner.setFont("Times New Roman-25");
winner.setColor(Color.WHITE);
add(winner, getWidth()/2 - winner.getWidth()/2, getHeight()/2 - winner.getAscent()/2);
break;
}
}
if (ball.getY() > getHeight()) {
GLabel message = new GLabel("Game Over! You got " + pointsCounter + " points.");
message.setFont("Times New Roman-25");
message.setColor(Color.WHITE);
add(message, getWidth()/2 - message.getWidth()/2, getHeight()/2 - message.getAscent()/2);
}
}
The problem is that when I click on the button, it registers the click, opens a JFrame, but does not run the program. There is just a blank JFrame. What am I doing wrong?
Note: I have only posted the basic code for the breakout game part.
Your code creates the Breakout object and sets its visibility:
Breakout bo = new Breakout();
bo.setVisible(true);
However, you never invoke any other methods. For example you may want to invoke a run method or a main method. You have to call those methods somehow in order to execute the code.
Another option would be to add a listener to the Breakout class so that it executes your code when the window opens, something like this:
addWindowListener(new java.awt.event.WindowAdapter() {
public void windowOpened(java.awt.event.WindowEvent evt) {
//call a method that runs the program here!
}
});
I have been having some problems with using the Timer function of Java swing. I am fairly new to programming with Java, so any help is greatly appreciated. I have looked over many other Timer questions on this site but none of them have answered my question. I have made a GUI that allows you to play rock paper scissors, where you can choose from clicking three buttons. I want my program to sleep for around 1 second after you click the button, and again after it displays a message. After I realized Thread.sleep() wouldn't work for my GUI, I tried to implement a timer.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.Border;
import java.io.*;
public class rps {
//ROCK PAPER SCISSORS
static JLabel middle = new JLabel();
static JLabel them = new JLabel();
static JLabel yourWins = new JLabel();
static JLabel theirWins = new JLabel();
static JPanel yourPanel = new JPanel();
static JPanel middlePanel = new JPanel();
static JLabel blank1 = new JLabel();
static JLabel blank2 = new JLabel();
static JButton rock = new JButton("Rock");
static JButton paper = new JButton("Paper");
static JButton scissors = new JButton("Scissors");
static int yw = 0;
static int tw = 0;
static ButtonHandler listener = new ButtonHandler();
public static void main(String[] args) {
//Create the frame
JFrame frame = new JFrame("Rock Paper Scissors");
frame.setSize(500, 500); //Setting the size of the frame
middle.setFont(new Font("Serif", Font.PLAIN, 30));
middle.setHorizontalAlignment(SwingConstants.CENTER);
them.setFont(new Font("Serif", Font.PLAIN, 15));
them.setHorizontalAlignment(SwingConstants.CENTER);
yourWins.setHorizontalAlignment(SwingConstants.CENTER);
theirWins.setHorizontalAlignment(SwingConstants.CENTER);
//Creating panels
JPanel bigPanel = new JPanel();
Border border = BorderFactory.createLineBorder(Color.BLACK, 1);
Border wlb = BorderFactory.createLineBorder(Color.RED, 1);
them.setBorder(border);
yourPanel.setBorder(border);
bigPanel.setBorder(border);
yourWins.setBorder(wlb);
theirWins.setBorder(wlb);
middlePanel.setBorder(border);
//Creating grid layouts
GridLayout yourGrid = new GridLayout(1,3,10,10);
GridLayout theirGrid = new GridLayout(1,1); //One row, one column
GridLayout middleGrid = new GridLayout(5,1);
GridLayout bigGrid = new GridLayout(3,1);//Two rows, one column
//Setting the layouts of each panel to the grid layouts created above
yourPanel.setLayout(yourGrid); //Adding layout to buttons panel
them.setLayout(theirGrid); //Adding layout to label panel
middlePanel.setLayout(middleGrid);
bigPanel.setLayout(bigGrid);
//Adding r/p/s to your grid.
yourPanel.add(rock);
yourPanel.add(paper);
yourPanel.add(scissors);
//Adding w/l rations to middlegrid.
middlePanel.add(theirWins);
middlePanel.add(blank1);
middlePanel.add(middle);
middlePanel.add(blank2);
middlePanel.add(yourWins);
//Attaching the listener to all the buttons
rock.addActionListener(listener);
paper.addActionListener(listener);
scissors.addActionListener(listener);
bigPanel.add(them);
bigPanel.add(middlePanel);
bigPanel.add(yourPanel);
//Shows the score at 0-0.
yourWins.setText("Your wins: " + yw);
theirWins.setText("Their wins: " + tw);
frame.getContentPane().add(bigPanel); //panel to frame
frame.setVisible(true); // Shows frame on screen
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
//Class represents what do when a button is pressed
private static class ButtonHandler implements ActionListener {
public void actionPerformed (ActionEvent e) {
Timer timer = new Timer(1000, this);
String tc = random();
them.setText("They chose: " + tc + "!");
if (e.getSource() == rock) {
whoWins("rock", tc);
} else if (e.getSource() == paper) {
whoWins("paper", tc);
} else if (e.getSource() == scissors) {
whoWins("scissors", tc);
}
yourWins.setText("Your wins: " + yw);
theirWins.setText("Their wins: " + tw);
timer.setRepeats(false);
timer.start();
}
}
public static String random() {
int random = (int) (Math.random() * 3);
if (random == 0) {
return "Rock";
} else if (random == 1) {
return "Paper";
} else if (random == 2) {
return "Scissors";
}
return "";
}
public static void whoWins(String yc, String tc) {
if (yc.equals("rock")) {
if (tc.equals("Rock")) {
middle.setText("It's a tie!");
} else if (tc.equals("Paper")) {
middle.setText("You lose!");
tw++;
} else if (tc.equals("Scissors")) {
middle.setText("You win!");
yw++;
}
} else if (yc.equals("paper")) {
if (tc.equals("Rock")) {
middle.setText("You win!");
yw++;
} else if (tc.equals("Paper")) {
middle.setText("It's a tie!");
} else if (tc.equals("Scissors")) {
middle.setText("You lose!");
tw++;
}
} else if (yc.equals("scissors")) {
if (tc.equals("Rock")) {
middle.setText("You lose!");
tw++;
} else if (tc.equals("Paper")) {
middle.setText("You win!");
yw++;
} else if (tc.equals("Scissors")) {
middle.setText("It's a tie!");
}
}
}
}
What is actually happening is there is no delay from when I press the button to a message displaying, because clearly I am not using the timer correctly. I would like the timer to just run once, and after it runs the code will execute. However, when I click a button the timer will run on repeat although setRepeats is false. Therefore, the message I want to display, instead of being delayed, is displayed instantaneously but then goes on a loop and keeps displaying a message (the message is random) until I shut off the program. If I click the button again, it will double the tempo of the timer it seems, and the messages display twice as fast and so on and so forth.
them.setText("They chose: " + tc + "!");
This is the message that is displayed on repeat, with the variable tc changing every time. The timer seems to just be displaying this message every timer interval (1s).
Any help would be greatly appreciated.
EDIT:
So I added this section :
private static class ButtonHandler implements ActionListener {
public void actionPerformed (ActionEvent e) {
// I'd be disabling the buttons here to prevent
// the user from trying to trigger another
// update...
// This is an instance field which is used by your
// listener
Timer timer = new Timer(1000, listenert);
timer.setRepeats(false);
timer.start();
}
}
private static class timer implements ActionListener {
public void actionPerformed (ActionEvent e) {
String tc = random(); //A method that chooses a random word.
them.setText("They chose: " + tc + "!");
if (e.getSource() == rock) {
whoWins("rock", tc); //whoWins is a method that will display a message.
} else if (e.getSource() == paper) {
whoWins("paper", tc);
} else if (e.getSource() == scissors) {
whoWins("scissors", tc);
}
yourWins.setText("Your wins: " + yw);
theirWins.setText("Their wins: " + tw);
// Start another Timer here that waits 1 second
// and re-enables the other buttons...
}
}
so what I believe happens now is when I click a button, the buttonhandler listener starts the timer which is attached to the timer listener (named listenert) which will run the code in the actionPerformed of the timer class. however the sleep function still is not working
EDIT 2.5:
private static class ButtonHandler implements ActionListener {
public void actionPerformed (ActionEvent e) {
final JButton button = (JButton)e.getSource();
Timer timer = new Timer(1000, new ActionListener() {
public void actionPerformed(ActionEvent e) {
String tc = random();
them.setText("They chose: " + tc + "!");
if (button == rock) {
whoWins("rock", tc);
} else if (button == paper) {
whoWins("paper", tc);
} else if (button == scissors) {
whoWins("scissors", tc);
}
yourWins.setText("Your wins: " + yw);
theirWins.setText("Their wins: " + tw);
}
});
timer.setRepeats(false);
timer.start();
}
}
that is what I have so far, I just need to add antoher sleep after
them.setText("They chose: " + tc + "!");
where would I put a timer.restart() if any? the timer.start() is at the end of the method which I don't quite understand.
So, the ActionListener you supply to the Timer is notified when the timer "ticks", so you ButtonHandler actionPerformed should look more like...
public void actionPerformed (ActionEvent e) {
// I'd be disabling the buttons here to prevent
// the user from trying to trigger another
// update...
// This is an instance field which is used by your
// listener
choice = e.getSource();
Timer timer = new Timer(1000, listener);
timer.setRepeats(false);
timer.start();
}
And your listener should look more like
public void actionPerformed (ActionEvent e) {
String tc = random(); //A method that chooses a random word.
them.setText("They chose: " + tc + "!");
if (choice == rock) {
whoWins("rock", tc); //whoWins is a method that will display a message.
} else if (choice == paper) {
whoWins("paper", tc);
} else if (choice == scissors) {
whoWins("scissors", tc);
}
yourWins.setText("Your wins: " + yw);
theirWins.setText("Their wins: " + tw);
// Start another Timer here that waits 1 second
// and re-enables the other buttons...
}
For example...
You may consider taking a look at How to use Swing Timers for more details
Updated
Start with a simple example...
public class TestPane extends JPanel {
private JLabel label;
private SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
public TestPane() {
setLayout(new GridBagLayout());
label = new JLabel();
add(label);
tick();
Timer timer = new Timer(500, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
tick();
}
});
timer.start();
}
protected void tick() {
label.setText(sdf.format(new Date()));
}
}
This just calls the tick method every half second to update the time on the JLabel...
firstly import the following ;
import java.awt.event.ActionEvent ;
import java.awt.event.ActionListener ;
import javax.swing.Timer ;
then initialize the timer at the end of the form like this ;
public static void main(String args[]) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new mainprogramme().setVisible(true);
}
});
}
private Timer timer ;
then after initializing the timer add a public class like following;
public class progress implements ActionListener {
public void actionPerformed(ActionEvent evt){
int n = 0 ;
if (n<100){
n++ ;
System.out.println(n) ;
}else{
timer.stop() ;
}
}
}
after you do this go to the j Frame>right click and select>Events>window>window Opened and type the following ;
private void formWindowOpened(java.awt.event.WindowEvent evt) {
timer = new Timer(100,new progress()) ;
and after you do all this take a button name it as anything and type the following in its void like following ;
timer.start();
AND THAT'S IT CODE IT AND THEN REPLY ME...