I'm new to Java and trying to make a simple Player vs. Computer "Tic-Tac-Toe" game using Swing. In the code I use paintComponent() method to paint certain components and call the repaint() method after the player or computer plays. The problem is that, the game freezes after the third (sometimes the second) time I click the mouse. In GameWindow class I create the instance of Map class.
public class GameWindow extends JFrame{
private final int sizeX = 3;
private final int sizeY = 3;
public GameWindow(){
setLocation(400,150);
setSize(406, 452);
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
setResizable(false);
Map map = new Map(sizeX, sizeY);
add(map, BorderLayout.CENTER);
JPanel bottomPanel = new JPanel();
bottomPanel.setLayout(new GridLayout(1, 2));
add(bottomPanel, BorderLayout.SOUTH);
Button newGame = new Button("Новая игра");
newGame.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("Начинаем новую игру");
}
});
Button exit = new Button("Выход");
exit.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
System.exit(0);
}
});
bottomPanel.add(newGame);
bottomPanel.add(exit);
setVisible(true);
}
}
Here is the listener for the mouse click in the Map class:
public class Map extends JPanel {
private final int sizeX;
private final int sizeY;
private int cellWidth;
private int cellHeight;
private int cellX = -1;
private int cellY = -1;
private String lastPlayer = "nobody";
private String[][] table = new String[3][3];
public Map(int sizeX, int sizeY) {
this.sizeX = sizeX;
this.sizeY = sizeY;
setBackground(Color.WHITE);
for (int i = 0; i < table.length; i++) {
for (int j = 0; j < table.length; j++) {
table[i][j] = "empty";
}
}
addMouseListener(new MouseAdapter() {
#Override
public void mouseReleased(MouseEvent e) {
super.mouseReleased(e);
cellX = e.getX() / cellWidth;
cellY = e.getY() / cellHeight;
if (!winOrDraw()) {
boolean playerProgress = playerProgress();
if(playerProgress) {
botProgress();
}
}
}
});
}
Both in playerProgress() and botProgress() methods I call repaint() method to add new components to the screen. I can't really find out what is the problem in this code and why the program freezes after actually 6th call of repaint() method?
Here are winOrDraw(), playerProgress() and botProgress() methods:
private boolean winOrDraw(){
for (int i = 0; i < table.length; i++) {
if(table[i][0] == table[i][1] && table[i][1] == table[i][2] && !table[i][0].equals("empty")) return true;
else if(table[0][i] == table[1][i] && table[1][i] == table[2][i] && !table[0][i].equals("empty")) return true;
else if(table[0][0] == table[1][1] && table[1][1] == table[2][2] && !table[0][0].equals("empty")) return true;
else if(table[2][0] == table[1][1] && table[1][1] == table[0][2] && !table[2][0].equals("empty")) return true;
}
int i, j = 0;
for (i = 0; i < table.length; i++) {
for (j = 0; j < table.length; j++) {
if(table[i][j].equals("empty")) break;
}
}
if(i == table.length && j == table.length) { lastPlayer = "nobody"; return true; }
else return false;
}
private boolean playerProgress(){
if(!table[cellY][cellX].equals("empty")){
System.out.println("This cell is not empty");
return false;
} else {
lastPlayer = table[cellY][cellX] = "player";
repaint();
return true;
}
}
private void botProgress(){
do{
if(winOrDraw()){
switch (lastPlayer) {
case "player":
System.out.println("You won!");
System.exit(0);
case "bot":
System.out.println("Bot won");
System.exit(0);
default:
System.out.println("Draw");
System.exit(0);
}
}
Random random = new Random();
cellX = random.nextInt(2);
cellY = random.nextInt(2);
if(table[cellY][cellX].equals("empty")) {
lastPlayer = table[cellY][cellX] = "bot";
break;
}
}while (!table[cellY][cellX].equals("empty"));
System.out.println("Bot's turn");
repaint();
}
You are adding your Swing components directly to the JFrame-AWT-container. You should not do that. Instead you should do this:
JPanel panel = new JPanel();
myFrame.setContentPane(panel);
panel.setLayout(...)
panel.add(...);
panel.validate();
This should solve your problem.
Related
I am making a basic platformer game and I need to make it so that every time you jump all the platforms that are below where you jumped disappear and every platform above moves down. It is still in development so just ignore some of the things that are commented out and the messy mode.
Basically, my problem is that when I try to clear all the platforms below the one that you clicked it works fine using this code:
for(int i = 0; i < platforms.length; i++) {
if(platforms[i] == null) {
continue;
}
if(parameters[i][1] > y) {
platforms[i].setVisible(false);
}
}
However later when I try to use .setvisible(true) on the platform that you clicked it doesn't work. Here is the full code:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.math.*;
import java.util.*;
public class Main implements ActionListener {
static JFrame frame;
static JPanel panel;
//static JLabel title;
//static JLabel expl;
static JButton[] platforms;
static Random random;
static boolean playing;
static int[][] parameters;
static int platformsMade;
static int clicked;
static int preClicked;
static int score;
static int lives;
static int standing;
static int speed;
static double gravity;
static int jump;
static String action;
public Main(int seed) throws Exception {
frame = new JFrame("Snakes 'n' Adders");
panel = new JPanel(null);
//title = new JLabel("Snakes 'n' Adders", SwingConstants.CENTER);
//expl = new JLabel("");
platforms = new JButton[100000];
random = new Random();
parameters = new int[100000][5];
lives = 3;
speed = 10;
gravity = 9.81;
jump = 5;
action = "";
//panel.add(title);
//panel.add(expl);
frame.add(panel);
panel.setVisible(true);
frame.setVisible(true);
frame.setSize(500, 500);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
random.setSeed(seed);
panel.setBackground(Color.CYAN);
//title.setFont(new Font("Arial", Font.PLAIN, 50));
}
public void drawPlatform(int x, int y, int w, int h, int colour) {
platforms[platformsMade] = new JButton();
platforms[platformsMade].addActionListener(this);
platforms[platformsMade].setBounds(x, y, w, h);
switch(colour) {
case 0:
platforms[platformsMade].setBackground(Color.BLUE);
break;
case 1:
platforms[platformsMade].setBackground(Color.GREEN);
break;
case 2:
platforms[platformsMade].setBackground(Color.RED);
break;
case 3:
platforms[platformsMade].setBackground(Color.ORANGE);
break;
case 4:
platforms[platformsMade].setBackground(Color.GRAY);
break;
}
parameters[platformsMade][0] = x;
parameters[platformsMade][1] = y;
parameters[platformsMade][2] = w;
parameters[platformsMade][3] = h;
parameters[platformsMade][4] = colour;
panel.add(platforms[platformsMade]);
platforms[platformsMade].setVisible(true);
panel.repaint();
platformsMade++;
}
public void movePlatforms(int distance, int i) {
if(platforms[i] == null) {
NullPointerException end = new NullPointerException();
throw end;
}
//this.drawPlatform(parameters[i][0], parameters[i][1] + distance, parameters[i][2], parameters[i][3], parameters[i][4]);
//platforms[i].setVisible(false);
platforms[i].setBounds(parameters[i][0], parameters[i][1] + distance, parameters[i][2], parameters[i][3]);
parameters[i][1] = parameters[i][1] + distance;
}
#Override
public void actionPerformed(ActionEvent event) {
preClicked = clicked;
for(int i = 0; i < platforms.length; i++) {
if(event.getSource() == platforms[i]) {
clicked = i;
break;
}
}
int y = parameters[clicked][1];
for(int i = 0; i < platforms.length; i++) {
if(platforms[i] == null) {
continue;
}
if(parameters[i][1] > y) {
platforms[i].setVisible(false);
}
else {
this.movePlatforms(150, i);
}
this.movePlatforms(150, clicked);
}
for(int i = 0; i <= random.nextInt(2); i++) {
this.drawPlatform(random.nextInt(500), random.nextInt(500), 50, 50, random.nextInt(4));
}
/*for(int i = 0; i < platforms.length; i++) {
if(platforms[i] == null) {
continue;
}
if(platforms[i].getY() > frame.getY() - platforms[i].getHeight()) {
platforms[i].setVisible(false);
}
}*/
platforms[clicked].addActionListener(this);
platforms[clicked].setVisible(true);
standing = clicked;
for(int i = 0; i < platforms.length; i++) {
if(platforms[i] == null) {
continue;
}
if(clicked == i) {
platforms[i].setText("|");
}
else {
platforms[i].setText("");
}
}
}
public static void main(String[] args) throws Exception {
Main sna = new Main(7845);
//title.setVisible(true);
//expl.setVisible(false);
//Thread.sleep(5000);
//title.setVisible(false);
//expl.setVisible(true);
//Thread.sleep(40000);
for(int i = 0; i < 3; i++) {
sna.drawPlatform(random.nextInt(500), random.nextInt(500), 50, 50, random.nextInt(4));
}
int ticks = 0;
platforms[standing].setText("|");
}
}
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
class Tix extends JFrame {
private static final int WIDTH = 500;
private static final int HEIGHT = 500;
private boolean xTurn = true;
private Font style;
private static JButton[][] btns = new JButton[3][3];
public Tix() {
setTitle("Tix");
setDefaultCloseOperation(EXIT_ON_CLOSE);
setSize(WIDTH, HEIGHT);
createContents();
setVisible(true);
}
public void createContents() {
style = new Font("Comic Sans", 1, 100);
Listener listener = new Listener();
setLayout(new GridLayout(3,3));
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
btns[i][j] = new JButton();
btns[i][j].setFont(style);
btns[i][j].addActionListener(listener);
add(btns[i][j]);
}
}
}
private class Listener implements ActionListener {
public void actionPerformed(ActionEvent e) {
JButton btn = (JButton) e.getSource();
if (xTurn)
btn.setForeground(Color.RED);
else
btn.setForeground(Color.BLUE);
if (btn.getText().isEmpty()) {
btn.setText(xTurn ? "X" : "O");
if (win()) {
JOptionPane.showMessageDialog(null, "Congratulations! Player " + (xTurn ? "X" : "O") + " wins!");
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
btns[i][j].setText(null);
}
}
xTurn = true;
}
else {
xTurn = !xTurn;
}
}
else {
JOptionPane.showMessageDialog(null,"Cell already clicked!");
}
}
}
public static boolean win() {
for (int i = 0; i < 3; i++)
if (btns[i][0].equals("X") && btns[i][1].equals("X") && btns[i][2].equals("X"))
return true;
for (int j = 0; j < 3; j++)
if (btns[0][j].equals("X") && btns[1][j].equals("X") && btns[2][j].equals("X"))
return true;
if (btns[0][0].equals("X") && btns[1][1].equals("X") && btns[2][2].equals("X"))
return true;
if (btns[0][2].equals("X") && btns[1][1].equals("X") && btns[2][0].equals("X"))
return true;
return false;
}
public static void main(String[] args) {
new Tix();
}
}
A for loop to check for the rows.
A for loop to check for the columns.
Two if statements to check for diagonals.
The win method does not return true at all. Is there something wrong with the && operators?
btns[i][j] is a JButton so it will never be equal to a String.
You should replace each method call of the form btns[i][0].equals("X") with something like btns[i][0].getText().equals("X").
Beside that, your win method only checks if the "X" player won. What about the "O" player?
I am working on a game that my friends invented - a little variation on tic tac toe: using a 4x4 board, one player (x) need to get 3 x's in a particular manner while the other can place one 'z' and one 'o' every turn and needs to fill the entire board. My problem is not with the rules and algoritems, but with the graphics: I don't have a lot of experience with graphics, and just can't get my board to work (even without any rules - just show up as needed).
I have a Board class that represents a board. A board has a two dimensional array of Cells. Each Cell (Cell = another class of mine) is also a JButton, and I would like that every time a button is clicked his image will change - so I decided to use ImageIcon. I also have a GameMain class to control the game and a Tools class to add two buttons - 'Exit' and 'Reset'.
If you could please help me by suggesting ways to get my board to load properly, I would appreciate that. Currently the board doesn't show up at all, and if I tweak the code a bit it shows up but the buttons won't show at all.
Here's the code: GameMain.java:
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
public class GameMain extends JPanel {
private Turn _turn;
Board _board;
private Tools _buttons;
private boolean isOver = false;
public enum GameState {PLAYING, xWON, oWON};
private GameState _currentState;
// Name-constants for the various dimensions used for graphics drawing
public static final int CELL_SIZE = 100; // cell width and height (square)
public static final int CANVAS_WIDTH = CELL_SIZE * 4; // the drawing canvas
public static final int CANVAS_HEIGHT = CELL_SIZE * 4;
public static final int GRID_WIDTH = 8; // Grid-line's width
public static final int GRID_WIDTH_HALF = GRID_WIDTH / 2; // Grid-line's half-width
public GameMain() {
this.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
if (_currentState == GameState.PLAYING) {
updateGame();
} else {
initGame(); //game over, restart
}
repaint();
}
});
setLayout(new BorderLayout());
setPreferredSize(new Dimension(CANVAS_WIDTH, CANVAS_HEIGHT + 30));
_board = new Board();
_buttons = new Tools();
initGame();
_buttons.SetObject(_board);
add(_board, BorderLayout.CENTER);
add(_buttons, BorderLayout.SOUTH);
}
public void initGame() {
_turn = Turn.X;
_board.init();
_currentState = GameState.PLAYING;
}
public void updateGame() {
if (_board.hasWonX()) {
_currentState = GameState.xWON;
} else if (_board.hasWonO()) {
_currentState = GameState.oWON;
}
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
setBackground(Color.WHITE);
_board.paint(g);
}
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
JFrame frame = new JFrame("xBlock");
frame.setSize(500, 500);
// Set the content-pane of the JFrame to an instance of main JPanel
frame.setContentPane(new GameMain());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null); // center the application window
frame.setVisible(true); // show it
}
});
}
}
Board:
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
public class Board extends JPanel implements ActionListener {
private Cell[][] _cells;
private Turn _turn;
public Board() {
setLayout(new GridLayout(4, 4));
_cells = new Cell[4][4];
_turn = Turn.X;
for (int i = 0; i < _cells.length; i++) {
for (int j = 0; j < _cells[0].length; j++) {
_cells[i][j] = new Cell(i, j);
_cells[i][j].addActionListener(this);
add(_cells[i][j]);
}
}
}
//initiate board
public void init() {
_turn = Turn.X;
for (int i = 0; i < _cells.length; i++) {
for (int j = 0; j < _cells[0].length; j++) {
_cells[i][j].setState(State.EMPTY);
}
}
}
public void fillCell(Cell c) {
if (c.getState() == State.EMPTY) {
c.setState(_turn.ordinal());
c.setEnabled(false);
c.draw();
_turn = _turn.getNext();
}
}
public void checkCellsAround(Cell c) {
State state = c.getState();
State right, left, up, down;
if (c.getJ() < 3 && c.getJ() > 0) {
right = _cells[c.getI()][c.getJ() + 1].getState();
left = _cells[c.getI()][c.getJ() - 1].getState();
} else if (c.getJ() == 0) {
right = _cells[c.getI()][c.getJ() + 1].getState();
left = State.EMPTY;
} else {
right = State.EMPTY;
left = _cells[c.getI()][c.getJ() - 1].getState();
}
if (c.getI() < 3 && c.getI() > 0) {
up = _cells[c.getI() - 1][c.getJ()].getState();
down = _cells[c.getI() + 1][c.getJ()].getState();
} else if (c.getI() == 0) {
up = State.EMPTY;
down = _cells[c.getI() + 1][c.getJ()].getState();
} else {
up = _cells[c.getI() - 1][c.getJ()].getState();
down = State.EMPTY;
}
switch (state) {
case EMPTY:
break;
case X:
if ((left == State.O && right == State.O) || (up == State.O && down == State.O) || (left == State.Z && right == State.Z) || (up == State.Z && down == State.Z)) {
c.setState(State.HOURGLASS);
}
break;
case O:
if ((left == State.X && right == State.X) || (up == State.X && down == State.X)) {
c.setState(State.EMPTY);
}
break;
case Z:
if ((left == State.X && right == State.X) || (up == State.X && down == State.X)) {
c.setState(State.HOURGLASS);
}
break;
case HOURGLASS:
break;
case SCRIBBLE:
break;
}
}
public void actionPerformed(ActionEvent E) {
Cell c = (Cell) E.getSource();
fillCell(_cells[c.getI()][c.getJ()]);
}
public boolean hasWonO() {
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
if (_cells[i][j].getState() == State.EMPTY) {
return false;
}
}
}
return true;
}
public boolean hasWonX() {
return false;
}
public void paint(Graphics g) {
g.setColor(Color.GRAY);
for (int i = 1; i < 4; i++) {
g.fillRoundRect(0, GameMain.CELL_SIZE * i - GameMain.GRID_WIDTH_HALF,
GameMain.CANVAS_WIDTH - 1, GameMain.GRID_WIDTH,
GameMain.GRID_WIDTH, GameMain.GRID_WIDTH);
}
for (int j = 1; j < 4; j++) {
g.fillRoundRect(GameMain.CELL_SIZE * j - GameMain.GRID_WIDTH_HALF, 0,
GameMain.GRID_WIDTH, GameMain.CANVAS_HEIGHT - 1,
GameMain.GRID_WIDTH, GameMain.GRID_WIDTH);
}
for (int i = 0; i < 5; i++) {
for (int j = 0; j < 5; j++) {
_cells[i][j].draw();
}
}
}
}
Cell.java:
import javax.swing.ImageIcon;
import javax.swing.JButton;
public class Cell extends JButton {
private int _i, _j;
private State _state;
ImageIcon X = new ImageIcon(this.getClass().getResource("x-icon.png"));
ImageIcon O = new ImageIcon(this.getClass().getResource("o-icon.png"));
ImageIcon Z = new ImageIcon(this.getClass().getResource("z-icon.png"));
ImageIcon Hourglass = new ImageIcon(this.getClass().getResource("hourglass-icon.png"));
ImageIcon Scribble = new ImageIcon(this.getClass().getResource("scribble-icon.png"));
public Cell() {
this.setEnabled(true);
_i = 0;
_j = 0;
_state = State.EMPTY;
}
public Cell(int i, int j) {
this.setEnabled(true);
_i = i;
_j = j;
_state = State.EMPTY;
}
public int getI() {
return _i;
}
public int getJ() {
return _j;
}
public void setState(State state) {
_state = state;
if (state == State.EMPTY) {
this.setEnabled(true);
}
}
public void setState(int index) {
_state = State.values()[index];
}
public State getState() {
return _state;
}
public void draw() {
switch (_state) {
case EMPTY:
this.setIcon(null);
break;
case X:
this.setIcon(X);
break;
case O:
this.setIcon(X);
break;
case Z:
this.setIcon(X);
break;
case HOURGLASS:
this.setIcon(X);
break;
case SCRIBBLE:
this.setIcon(X);
break;
}
}
public void highlight() {
}
}
Tools.java:
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
public class Tools extends JPanel {
private JButton _exit, _reset;
private Board _board;
Tools() {
setLayout(new FlowLayout());
_exit = new JButton("Exit");
_reset = new JButton("Reset");
_exit.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
System.exit(0);
}
});
_reset.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
_board.init();
}
});
add(_exit);
add(_reset);
}
public void SetObject(Board b) {
_board = b;
}
}
State.java:
public enum State {
EMPTY, X, O, Z, HOURGLASS, SCRIBBLE;
public State getNext() {
return State.values()[(this.ordinal() + 1) % State.values().length];
}
}
Turn.java:
public enum Turn {
X, O, Z;
public Turn getNext() {
return Turn.values()[(this.ordinal() + 1) % Turn.values().length];
}
}
Thanks in advance!
So after running it, you are getting an ArrayIndexOutOfBoundsException at this line in the paint method of the Board class:
for (int i = 0; i < 5; i++) {
for (int j = 0; j < 5; j++) {
_cells[i][j].draw(); <==========
}
}
Not sure how your game works, but by looking at the loops previous to this one, you are accessing only up to index 3 ( for (int j = 1; j < 4; j++) { ). So if you change the loop max to 4, it gets the game up and running.
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
_cells[i][j].draw();
}
}
Learning to read exceptions and stack traces is very important. It will save you a lot of future headaches. Take some time to read What is a stack trace, and how can I use it to debug my application errors?
And like I said in my comments,
It doesn't look like you're doing anything with the paintComponent in the GameMain. You should just get rid of the paintComponent method altogether in that class. Instead of trying to call board.paint(g);, try to just call board.repaint() in the mouse listener, instead of trying to repaint the main game panel. And just set the background in the constructor of the GameMain instead of in the paintComponent method.
Also in the Board class use paintComponent rather than paint. and don't forget to call super.paintComponent in the paintComponent method
Fixing all the things above, get it work (I guess).
UPDATE
As the MadMan pointed out in the comment below, it would be better to use the _cells.length to avoid having to rely magic numbers. This way you will be sure not to access an inexistant index
for (int i = 0; i < cells.length; i++) {
for (int j = 0; j < cells[i].length; j++) {
_cells[i][j].draw();
}
}
I have a GUI created in my main class file
import java.awt.*;
import javax.swing.*;
public class TicTac extends JFrame {
TicTacEvent tictac = new TicTacEvent(this);
JPanel row1 = new JPanel();
JButton[][] boxes = new JButton[4][4];
JButton play = new JButton("Play");
JButton restart = new JButton("Restart");
JTextField blank1 = new JTextField();
JTextField blank2 = new JTextField();
JOptionPane win = new JOptionPane("Winner");
ImageIcon back = new ImageIcon("cardback.jpg");
public TicTac() {
super ("Tic Tac Toe");
setSize (800,650);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
FlowLayout layout = new FlowLayout();
setLayout(layout);
int name = 0;
String newname;
GridLayout layout1 = new GridLayout(5, 4, 10, 10);
row1.setLayout(layout1);
for (int x=0; x<=3; x++){
for (int y=0; y<=3; y++){
name = name + 1;
newname = Integer.toString(name);
boxes[x][y] = new JButton(newname);
boxes[x][y].setIcon(back);
row1.add(boxes[x][y]);
}
}
row1.add(blank1);
row1.add(play);
row1.add(blank2);
row1.add(restart);
add (row1);
play.addActionListener(tictac);
for (int x=0; x<=3; x++){
for (int y=0; y<=3; y++){
boxes[x][y].addActionListener(tictac);
}
}
setVisible(true);
}
public static void main(String[] arguments){
TicTac frame = new TicTac();
}
}
And I have code using it here
import javax.swing.*;
import java.awt.event.*;
import java.awt.*;
public class TicTacEvent implements ItemListener, ActionListener, Runnable {
TicTac gui;
Thread playing;
Thread restarting;
ImageIcon a = new ImageIcon("x.jpg");
ImageIcon b = new ImageIcon("o.jpg");
int clicks = 0;
int win = 0;
int winx = 0;
int winy = 0;
int cat = 0;
int[][] check = new int[4][4];
public TicTacEvent (TicTac in){
gui = in;
for (int row=0; row<=3; row++){
for (int col=0; col<=3; col++){
check[row][col]=0;
}
}
}
public void actionPerformed(ActionEvent event){
String command = event.getActionCommand();
if (command.equals("Play")) {
startPlaying();
} else if (command.equals("Restart")) {
restart();
}
if (command.equals("1")) {
b1();
}
if (command.equals("2")) {
b2();
}
if (command.equals("3")) {
b3();
}
if (command.equals("4")) {
b4();
}
if (command.equals("5")) {
b5();
}
if (command.equals("6")) {
b6();
}
if (command.equals("7")) {
b7();
}
if (command.equals("8")) {
b8();
}
if (command.equals("9")) {
b9();
}
if (command.equals("10")) {
b10();
}
if (command.equals("11")) {
b11();
}
if (command.equals("12")) {
b12();
}
if (command.equals("13")) {
b13();
}
if (command.equals("14")) {
b14();
}
if (command.equals("15")) {
b15();
}
if (command.equals("16")) {
b16();
}
gui.blank1.setText("X Wins: " + winx + " Y Wins:" + winy);
gui.blank2.setText("Cat Wins(Tie):" + cat);
}
void b1() {
clicks = clicks + 1;
if ((clicks%2)==1){
gui.boxes[0][0].setIcon(a);
check[0][0] = 1;
} else {
gui.boxes[0][0].setIcon(b);
check[0][0] = 2;
}
winner();
}
void b2() {
clicks = clicks + 1;
if ((clicks%2)==1){
gui.boxes[0][1].setIcon(a);
check[0][1] = 1;
} else {
gui.boxes[0][1].setIcon(b);
check[0][1] = 2;
}
winner();
}
void b3() {
clicks = clicks + 1;
if ((clicks%2)==1){
gui.boxes[0][2].setIcon(a);
check[0][2] = 1;
} else {
gui.boxes[0][2].setIcon(b);
check[0][2] = 2;
}
winner();
}
void b4() {
clicks = clicks + 1;
if ((clicks%2)==1){
gui.boxes[0][3].setIcon(a);
check[0][3] = 1;
} else {
gui.boxes[0][3].setIcon(b);
check[0][3] = 2;
}
winner();
}
void b5() {
clicks = clicks + 1;
if ((clicks%2)==1){
gui.boxes[1][0].setIcon(a);
check[1][0] = 1;
} else {
gui.boxes[1][0].setIcon(b);
check[1][0] = 2;
}
winner();
}
void b6() {
clicks = clicks + 1;
if ((clicks%2)==1){
gui.boxes[1][1].setIcon(a);
check[1][1] = 1;
} else {
gui.boxes[1][1].setIcon(b);
check[1][1] = 2;
}
winner();
}
void b7() {
clicks = clicks + 1;
if ((clicks%2)==1){
gui.boxes[1][2].setIcon(a);
check[1][2] = 1;
} else {
gui.boxes[1][2].setIcon(b);
check[1][2] = 2;
}
winner();
}
void b8() {
clicks = clicks + 1;
if ((clicks%2)==1){
gui.boxes[1][3].setIcon(a);
check[1][3] = 1;
} else {
gui.boxes[1][3].setIcon(b);
check[1][3] = 2;
}
winner();
}
void b9() {
clicks = clicks + 1;
if ((clicks%2)==1){
gui.boxes[2][0].setIcon(a);
check[2][0] = 1;
} else {
gui.boxes[2][0].setIcon(b);
check[2][0] = 2;
}
winner();
}
void b10() {
clicks = clicks + 1;
if ((clicks%2)==1){
gui.boxes[2][1].setIcon(a);
check[2][1] = 1;
} else {
gui.boxes[2][1].setIcon(b);
check[2][1] = 2;
}
winner();
}
void b11() {
clicks = clicks + 1;
if ((clicks%2)==1){
gui.boxes[2][2].setIcon(a);
check[2][2] = 1;
} else {
gui.boxes[2][2].setIcon(b);
check[2][2] = 2;
}
winner();
}
void b12() {
clicks = clicks + 1;
if ((clicks%2)==1){
gui.boxes[2][3].setIcon(a);
check[2][3] = 1;
} else {
gui.boxes[2][3].setIcon(b);
check[2][3] = 2;
}
winner();
}
void b13() {
clicks = clicks + 1;
if ((clicks%2)==1){
gui.boxes[3][0].setIcon(a);
check[3][0] = 1;
} else {
gui.boxes[3][0].setIcon(b);
check[3][0] = 2;
}
winner();
}
void b14() {
clicks = clicks + 1;
if ((clicks%2)==1){
gui.boxes[3][1].setIcon(a);
check[3][1] = 1;
} else {
gui.boxes[3][1].setIcon(b);
check[3][1] = 2;
}
winner();
}
void b15() {
clicks = clicks + 1;
if ((clicks%2)==1){
gui.boxes[3][2].setIcon(a);
check[3][2] = 1;
} else {
gui.boxes[3][2].setIcon(b);
check[3][2] = 2;
}
winner();
}
void b16() {
clicks = clicks + 1;
if ((clicks%2)==1){
gui.boxes[3][3].setIcon(a);
check[3][3] = 1;
} else {
gui.boxes[3][3].setIcon(b);
check[3][3] = 2;
}
winner();
}
public void winner() {
/** Check rows for winner */
for (int x=0; x<=3; x++){
if ((check[x][0]==check[x][1])&&(check[x][0]==check[x][2]) && (check[x][0]== check[x][3])) {
if (check[x][0] ==1) {
JOptionPane.showMessageDialog(null, "X is the winner");
win = 1;
winx +=1;
} else if (check[x][0]==2){
JOptionPane.showMessageDialog(null, "Y is the winner");
win = 1;
winy +=1;
}
}
}
/** Check columns for winner */
for (int x=0; x<=3; x++){
if ((check[0][x]==check[1][x])&&(check[0][x]==check[2][x])&& (check[0][x]== check[3][x])) {
if (check[0][x]==1) {
JOptionPane.showMessageDialog(null, "X is the winner");
win = 1;
winx +=1;
} else if (check[0][x]==2) {
JOptionPane.showMessageDialog(null, "Y is the winner");
win = 1;
winy +=1;
}
}
}
if ((check[1][1]== 1) && (check[3][3] == 1) && (check[2][2]==1) && (check[0][0]==1)
|| (check[3][0]==1) &&(check[1][2]==1) &&(check[0][3]==1))
{
JOptionPane.showMessageDialog(null, "X is the winner");
win = 1;
winx +=1;
} else if ((check[1][1]== 2) && (check[3][3] == 2) && (check[2][2]==2) && (check[0][0]==2)
|| (check[3][0]==2) &&(check[1][2]==2) &&(check[0][3]==2)) {
JOptionPane.showMessageDialog(null, "Y is the winner");
win = 1;
winy +=1;
}
//}
/** Checks if the game is a tie */
if ((clicks==16) && (win==0)) {
JOptionPane.showMessageDialog(null, "The game is a tie");
cat =+1;
}
}
public void startPlaying() {
playing = new Thread(this);
playing.start();
gui.play.setEnabled(false);
}
public void restart() {
TicTac restartok = new TicTac();
restartok.row1.add(restartok.blank1);
restartok.row1.add(restartok.play);
restartok.row1.add(restartok.blank2);
restartok.row1.add(restartok.restart);
restartok.add (restartok.row1);
restartok.play.addActionListener(restartok.tictac);
for (int x=0; x<=3; x++){
for (int y=0; y<=3; y++){
restartok.boxes[x][y].addActionListener(restartok.tictac);
}
}
}
public void itemStateChanged(ItemEvent e) {
// throw new UnsupportedOperationException("Not supported yet.");
}
public void run() {
//restart();
//throw new UnsupportedOperationException("Not supported yet.");
}
}
However my question is how I'd reset the GUI, I have some ideas..
The constructor "Public TicTac" creates the gui, however I am not sure how I'd get to happen again through another classfile. My understanding of OOP is that with a constructor I can call to by creating an object
TicTac restartok = new TicTac();
So assumedly, you'd think I'd be creating another JPanel/GUI everytime I called the restart(); method, no?
My OOP expeirence is limited, so I don't have a clue where to start or find out what logic is incorrect. Thanks.
To reset the game, just reset clicks to 0 and the buttons to their original state just as they were created:
boxes[x][y] = new JButton(newname);
boxes[x][y].setIcon(back);
Apart from that, you have many things to fix in your code. Here are some:
Your line boxes[x][y].addActionListener(tictac); is in a loop of its own where it should be in the initial loop. No reason to iterate twice over the same arrays.
Your layout decisions could be better (depending on what exactly you want to get).
Start the GUI with TicTac frame = new TicTac(); from inside an invokeLater method.
Create an ActionListener for each button with a unique functionality. In your case it's 1 for play, 1 for restart, and 1 for all the board buttons.
You're using event.getActionCommand but you did not call setActionCommand on any of the buttons.
Don't use multiple if when you check for the button pressed (action command name), use if else, or better - use a switch statement.
Don't use a separate function for each button. Use 1 function which receives the button as its argument.
Don't create fields when you can create local variables instead.
If you need clarifications leave a comment.
Edit: here is some modified code that resets the buttons (I couldn't stop myself from correcting other parts of the code, though there is still more to do).
public class TicTac extends JFrame {
static JButton[][] boxes = new JButton[4][4];
static int[][] check = new int[4][4];
static JTextField blank1 = new JTextField();
static JTextField blank2 = new JTextField();
static int turns = 1;
static ImageIcon back = new ImageIcon("cardback.jpg");
static ImageIcon x = new ImageIcon("x.jpg");
static ImageIcon o = new ImageIcon("o.jpg");
public TicTac() {
JPanel gamePanel = new JPanel(new GridLayout(5, 4, 10, 10));
for (int x = 0; x<=3; x++) {
for (int y = 0; y<=3; y++) {
boxes[x][y] = new JButton(""+x+y, back);
boxes[x][y].addActionListener(new XOActionListenr(x, y));
gamePanel.add(boxes[x][y]);
}
}
JButton play = new JButton("Play");
JButton restart = new JButton("Restart");
play.addActionListener(new PlayActionListenr());
restart.addActionListener(new RestartActionListenr());
setLayout(new FlowLayout());
gamePanel.add(blank1);
gamePanel.add(play);
gamePanel.add(blank2);
gamePanel.add(restart);
add(gamePanel);
setTitle("Tic Tac Toe");
pack();
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
}
private void winner() {
// Check for winner
}
private class XOActionListenr implements ActionListener {
private int row, col;
private XOActionListenr(int row, int col) {
this.row = row;
this.col = col;
}
public void actionPerformed(ActionEvent e) {
if (turns % 2 == 0) {
boxes[row][col].setText("O");
boxes[row][col].setIcon(o);
check[row][col] = 2;
}
else {
boxes[row][col].setText("X");
boxes[row][col].setIcon(x);
check[row][col] = 1;
}
winner();
turns++;
}
}
private class PlayActionListenr implements ActionListener {
public void actionPerformed(ActionEvent e) {
// Not sure why you would need the "play" button at all,
// but insert here what it's supposed to do
}
}
private class RestartActionListenr implements ActionListener {
public void actionPerformed(ActionEvent e) {
for (int x = 0; x<=3; x++) {
for (int y = 0; y<=3; y++) {
boxes[x][y].setText(""+x+y);
boxes[x][y].setIcon(back);
}
}
}
}
public static void main(String[] arguments) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new TicTac();
}
});
}
}
You do not need to re-create whole GUI again and again. what you need to do is to clear textfields and whatever selection user has made till now. So you need to create a separate method in which you will reset the state of every button/textfields in your GUI.
for example: to clear textfield you will call setText("") method.
Hope this helps.
This is a pong game I made, but the only thing that is not working is the paddles moving. I am not sure how to make the keyboard work with the program. Here is the code for the main game:
//Project: A program where you play the game pong
//This module defines the properties of the user interface
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
public class pongframe extends JFrame
{
private JLabel playerlefttitle;
private JLabel playerrighttitle;
private JLabel speedtitle;
private JTextField speedfield;
private JTextField playerleftscorefield;
private JTextField playerrightscorefield;
private JButton newgame;
private JButton gobutton;
private JButton pausebutton;
private JButton quitgame;
private Timer systemclock;
private Timer paddleclock;
private String speedstring;
private int speed;
private int leng = 10;
private int delayinterval;
private float millisecondpersecond = 1000.0f;
private boolean win = false;
private int playerleftscore=0;
private int playerrightscore=0;
private boolean rightup = false;
private boolean rightdown = false;
private boolean leftup = false;
private boolean leftdown = false;
private boolean barhit = true;
private double direction=0;
private pongoperations graphicalpanel;
private Clockhandlerclass clockhandler;
private PaddleClockHandlerClass paddleclockhandler;
private PaddleHandlerClass paddlehandler;
public pongframe()
{
super("Pong");
JPanel panel1 = new JPanel(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
graphicalpanel = new pongoperations();
graphicalpanel.setBackground(Color.GREEN);
add(graphicalpanel, BorderLayout.CENTER);
add(panel1, BorderLayout.SOUTH);
c.insets = new Insets(0,0,10,10);
newgame = new JButton("New");
c.gridx = 0;
c.gridy = 1;
panel1.add(newgame, c);
speedtitle = new JLabel("Speed");
c.gridx = 1;
c.gridy = 0;
panel1.add(speedtitle, c);
speedfield = new JTextField(3);
c.gridx = 1;
c.gridy = 1;
panel1.add(speedfield, c);
quitgame = new JButton("Quit");
c.gridx = 2;
c.gridy = 1;
panel1.add(quitgame, c);
playerlefttitle = new JLabel("Player Left");
c.gridx = 0;
c.gridy = 3;
panel1.add(playerlefttitle, c);
playerrighttitle = new JLabel("Player Right");
c.gridx = 3;
c.gridy = 3;
panel1.add(playerrighttitle, c);
playerleftscorefield = new JTextField(2);
playerleftscorefield.setEditable(false);
c.gridx = 0;
c.gridy = 4;
panel1.add(playerleftscorefield, c);
gobutton = new JButton("Go");
c.gridx = 1;
c.gridy = 4;
panel1.add(gobutton, c);
pausebutton = new JButton("Pause");
c.gridx = 2;
c.gridy = 4;
panel1.add(pausebutton, c);
playerrightscorefield = new JTextField(2);
playerrightscorefield.setEditable(false);
c.gridx = 3;
c.gridy = 4;
panel1.add(playerrightscorefield, c);
buttonhandler myhandler = new buttonhandler();
newgame.addActionListener(myhandler);
gobutton.addActionListener(myhandler);
pausebutton.addActionListener(myhandler);
quitgame.addActionListener(myhandler);
clockhandler = new Clockhandlerclass();
paddleclockhandler = new PaddleClockHandlerClass();
paddlehandler = new PaddleHandlerClass();
}
private class buttonhandler implements ActionListener
{
public void actionPerformed(ActionEvent event)
{
graphicalpanel.reset();
if(event.getSource() == newgame)
{
speedfield.setText("");
playerleftscore = 0;
playerrightscore = 0;
playerleftscorefield.setText("0");
playerrightscorefield.setText("0");
graphicalpanel.reset();
graphicalpanel.repaint();
gobutton.setEnabled(true);
speedfield.setEditable(true);
newgame.setEnabled(false);
}
else if(event.getSource() == gobutton)
{
speedstring = speedfield.getText();
leng = speedstring.length();
if(leng == 0)
speed = 0;
else
{
speed = Integer.parseInt(speedstring);
gobutton.setEnabled(false);
speedfield.setEditable(false);
}
newgame.setEnabled(false);
delayinterval = (int)Math.floor(millisecondpersecond/speed + 0.5f);
systemclock = new Timer(delayinterval, clockhandler);
systemclock.start();
paddleclock = new Timer(delayinterval, paddleclockhandler);
paddleclock.start();
}
else if(event.getSource() == pausebutton)
{
gobutton.setEnabled(true);
newgame.setEnabled(true);
systemclock.stop();
}
else if(event.getSource() == quitgame)
{
System.exit(0);
}
else
System.out.println("Unkown error");
}
}
private class Clockhandlerclass implements ActionListener
{
public void actionPerformed(ActionEvent event)
{
if(event.getSource() == systemclock)
{
graphicalpanel.grabFocus();
graphicalpanel.moveball(speed,delayinterval, direction, barhit);
direction = graphicalpanel.changedirection(direction);
if(win == false)
{
barhit = graphicalpanel.barhits(barhit);
graphicalpanel.repaint();
win = graphicalpanel.winner();
playerleftscore = graphicalpanel.playerleftwin(playerleftscore);
playerrightscore = graphicalpanel.playerrightwin(playerrightscore);
playerleftscorefield.setText(Integer.toString(playerleftscore));
playerrightscorefield.setText(Integer.toString(playerrightscore));
}
else if(win == true)
{
graphicalpanel.reset();
win = false;
systemclock.restart();
if(playerleftscore == 10)
{
newgame.setEnabled(true);
systemclock.stop();
}
else if(playerrightscore == 10)
{
newgame.setEnabled(true);
systemclock.stop();
}
graphicalpanel.repaint();
}
}
else
System.out.printf("%s\n", "There is a bug in the clock.");
}
}
private class PaddleClockHandlerClass implements ActionListener
{
public void actionPerformed(ActionEvent event)
{
if(event.getSource() == paddleclock)
{
graphicalpanel.moveplayer1(rightup, rightdown);
graphicalpanel.moveplayer2(leftup, leftdown);
graphicalpanel.repaint();
}
}
}
private class PaddleHandlerClass implements KeyListener
{
public void keyTyped(KeyEvent event)
{
}
public void keyPressed(KeyEvent event)
{
if(event.getKeyCode() == KeyEvent.VK_UP)
{
rightup = true;
System.out.println("Up");
}
else if(event.getKeyCode() == KeyEvent.VK_DOWN)
rightdown = true;
if(event.getKeyCode() == KeyEvent.VK_W)
leftup = true;
else if(event.getKeyCode() == KeyEvent.VK_S)
leftdown = true;
}
public void keyReleased(KeyEvent event)
{
if(event.getKeyCode() == KeyEvent.VK_UP)
rightup = false;
else if(event.getKeyCode() == KeyEvent.VK_DOWN)
rightdown = false;
if(event.getKeyCode() == KeyEvent.VK_W)
leftup = false;
else if(event.getKeyCode() == KeyEvent.VK_S)
leftdown = false;
}
}
}
This next bit of code are the functions that I am using for the game:
//Project: A program where you play the game pong
//This module contains the graphics and algorithms used by this project.
import java.awt.Graphics;
import javax.swing.JPanel;
import java.awt.Color;
public class pongoperations extends JPanel
{
int widthofgraphicalarea;
int heightofgraphicalarea;
final int ballradius = 8;
int ballxcoordinate;
double ballycoordinate;
int paddle1xcoordinate;
int paddle1ycoordinate;
int paddle2xcoordinate;
int paddle2ycoordinate;
public void paintComponent(Graphics graphicarea)
{//function to paint the area
super.paintComponent(graphicarea);
this.setBackground(Color.GREEN);
widthofgraphicalarea = getWidth();
heightofgraphicalarea = getHeight();
//create paddle 1
graphicarea.setColor(Color.BLUE);
graphicarea.fillRect(paddle1xcoordinate, paddle1ycoordinate, 10, 50);
//create paddle 2
graphicarea.setColor(Color.RED);
graphicarea.fillRect(paddle2xcoordinate, paddle2ycoordinate, 10, 50);
//Give the ball a white color
graphicarea.setColor(Color.WHITE);
//The 3rd and 4th parameters below represent the diameter of the ball.
graphicarea.fillOval(ballxcoordinate,(int)ballycoordinate,2*ballradius,2*ballradius);
}//End of method paintComponent
public void moveplayer1(boolean rightup, boolean rightdown)
{
if(rightup == true)
paddle1ycoordinate -= 5;
else if(rightdown == true)
paddle1ycoordinate += 5;
positionPlayer1(paddle1xcoordinate, paddle1ycoordinate);
}
public void moveplayer2(boolean leftup, boolean leftdown)
{
if(leftup == true)
paddle2ycoordinate -= 5;
else if(leftdown == true)
paddle2ycoordinate += 5;
positionPlayer2(paddle2xcoordinate, paddle2ycoordinate);
}
public void positionPlayer1(int x, int y)
{
this.paddle1xcoordinate = x;
this.paddle1ycoordinate = y;
repaint();
}
public void positionPlayer2(int x, int y)
{
this.paddle2xcoordinate = x;
this.paddle2ycoordinate = y;
repaint();
}
public void moveball(int speed, int delayinterval, double direction, boolean barhit)
{
if(barhit == true)
ballxcoordinate+=1;
else if(barhit == false)
ballxcoordinate-=1;
if(direction > 0)
ballycoordinate = ballycoordinate + (double)Math.sin(Math.toRadians(direction));
else if(direction < 0)
ballycoordinate = ballycoordinate + (double)Math.sin(Math.toRadians(direction));
}
public boolean barhits(boolean barhit)
{
if(ballxcoordinate == paddle1xcoordinate+10 && (ballycoordinate >= paddle1ycoordinate && ballycoordinate <= paddle1ycoordinate+50))
barhit = true;
else if(ballxcoordinate+2*ballradius == paddle2xcoordinate && (ballycoordinate+2*ballradius >= paddle2ycoordinate && ballycoordinate+2*ballradius <= paddle2ycoordinate+50))
barhit = false;
return barhit;
}
public boolean winner()
{
if(ballxcoordinate+2*ballradius >= widthofgraphicalarea)
return true;
else if(ballxcoordinate+2*ballradius <= 16)
return true;
return false;
}
public int playerleftwin(int playerleftscore)
{
if(ballxcoordinate+2*ballradius >= widthofgraphicalarea)
playerleftscore+=1;
return playerleftscore;
}
public int playerrightwin(int playerrightscore)
{
if(ballxcoordinate+2*ballradius <= 16)
playerrightscore+=1;
return playerrightscore;
}
public double changedirection(double direction)
{//function to change the direction of the ball to bounce of walls
if((int)ballycoordinate+2*ballradius >= heightofgraphicalarea || (int)ballycoordinate+2*ballradius < 16)
direction = -direction;
return direction;
}
public void reset()
{//reset the ball at middle of left side
ballxcoordinate = widthofgraphicalarea/2 - ballradius;
ballycoordinate = heightofgraphicalarea/2 - ballradius;
paddle1xcoordinate = 10;
paddle1ycoordinate = heightofgraphicalarea/2-25;
paddle2xcoordinate = widthofgraphicalarea-20;
paddle2ycoordinate = heightofgraphicalarea/2-25;
}
}
Please someone help. Thanks in advance.
Another question if you can help is once this is finished how do I switch this over to applet form?
Do not use a KeyListener Swing components use KeyBindings.
Dont extend JFrame class unnecessarily
Swing components should be created on Event Dispatch Thread
To set the size of your app (without setSize(..) call on JFrame) use appropiate LayoutManager when adding components buttons etc (which you do) and when drawing in paintComponent override JPanel getPreferredSize() and return an appropriate size which fits all drawings than call pack() on JFrame before setting it visible
Dont forget to call setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); on JFrame so when X is pressed the Event Dispatch Thread and Initial thread are exited, or app will remain running in background.
But to solve your problem after paddlehandler = new PaddleHandlerClass(); add:
graphicalpanel.addKeyListener(paddlehandler);
the problem is you never added the KeyListener to any Component to listen for events.
The proper solution would be KeyBindings which would change your PaddleHandlerClass like this:
private class PaddleHandlerClass {
public PaddleHandlerClass(JComponent jc) {
jc.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("UP"), "up");
jc.getActionMap().put("up", new AbstractAction() {
#Override
public void actionPerformed(ActionEvent ae) {
rightup = true;
System.out.println("Up");
}
});
jc.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("released UP"), "rel up");
jc.getActionMap().put("rel up", new AbstractAction() {
#Override
public void actionPerformed(ActionEvent ae) {
rightup = false;
}
});
}
}
than simply create the paddleHandler and pass instance of JPanel which keys we want to get:
paddlehandler = new PaddleHandlerClass(graphicalpanel);