I have a problem with my GUI timer. I start my timer when the player clicks on a button in the mine field, and I stop my timer when the game ends.
The first time I test my game, the timer starts and ends normally. However, if I try to play a second round of the game, my timer does not stop.
public class Minesweeper7 extends JFrame implements ActionListener {
static public boolean revealed [][];
public static CountTimer ct;
public Minesweeper7 (int row, int column) {
ct = new CountTimer ();
}
private void setTimerText (String sTime) {
timeLabel.setText (sTime);
}
public void actionPerformed(ActionEvent event){
String coords = event.getActionCommand();
String[] squarePressed = coords.split(",");
x_pressed = Integer.parseInt(squarePressed[0]);
y_pressed = Integer.parseInt(squarePressed[1]);
System.out.println("The button you have pressed is " + x_pressed + ", " + y_pressed);
if (ct.timer.isRunning() == false){
ct.start ();
System.out.println ("timer is running");
}
reveal (row,column,x_pressed,y_pressed,revealed,mines,revealed_number);
gameEnd (row, column, revealed, mines, countMines, counter, end);
System.out.println("There are " + countMines + " .");
System.out.println("");
for (int r = 0;r<row;r++){
for (int c = 0;c<column;c++){
label[r][c].setText(String.valueOf(revealed_number[r][c]));
}
}
}
public void reveal () {
//a recursive method that reveals my buttons
}
public static void main (String args []) {
java.awt.EventQueue.invokeLater (new Runnable () {
public void run () {
new Minesweeper7 (10, 10);
}
});
}
public void gameEnd (int row, int column, boolean revealed [][], boolean mines [][], int countMines, int counter, boolean end) {
for (int r = 0; r < row; r++) {
for (int c = 0; c < column; c++) {
if (mines [r][c] == false && revealed [r][c] == true) {
counter++;
}
else if (mines [r][c] == true && revealed [r][c] == true) {
System.out.println ("Sorry, you lost because you clicked on a mine.");
end = true;
break;
}
}
}
if (counter == (row*column-countMines)) {
System.out.println ("Congratulations! You won the game!");
end = true;
instruction.setText("Congratulations! You won the game!");
}
if (end == true) {
ct.stop ();
}
}
public class CountTimer implements ActionListener {
public static final int ONE_SECOND = 1000;
public int count = 0;
public boolean isTimerActive = false;
public Timer timer = new Timer (ONE_SECOND, this);
public CountTimer () {
count = 0;
setTimerText (TimeFormat (count));
}
public void actionPerformed (ActionEvent e) {
if (isTimerActive) {
count++;
setTimerText (TimeFormat (count));
}
}
public void start () {
count = 0;
isTimerActive = true;
timer.start ();
}
public void stop () {
timer.stop ();
}
public void reset () {
count = 0;
isTimerActive = true;
timer.restart ();
}
}
}
if you start a new game, you could just make a new timer instead of starting and stopping.
if (game end) {
timer = new Timer();
timer.start();
}
Related
I followed some discussion on the website and implemented some suggestions but I was not able to complete the task.
I have this assignment to build Tic Tac Toe game in Java.
There's a lot of tutorials on the web I know, but I wanted to build it using threads for each player so that only one player at a time could enter X/O to the board and I was not able to figure out the implementation for the wait/ notify.
To be honest, I find it a bit confusing! I guess the logic is 90% done, and I am wondering how to finish it.
Basically, I have these classes:
abstract public class Player extends Thread
public class HumanPlayer extends Player
public class MachinePlayer extends Player
public class Board
public class Game
public class Main
I'll paste first the players classes. Notice the run method I tried to Synchronize on top of the gameOver variable:
Player.java
abstract public class Player extends Thread {
abstract int getMyTurn() ;
abstract String getPlayerName() ;
abstract void setPlayerName(String n ) ;
abstract void setSign(int n ) ;
abstract int getSign() ;
}
MachinePlayer.java
import java.util.Random;
public class MachinePlayer extends Player {
private String name ;
private int sign ;
Board board ;
public MachinePlayer(Board board) {
this.board = board;
}
#Override
public void run() {
System.out.println("Player "+name+" turn:" );
while (!board.isGameOver())
{
board.setCurrentPlayerTurn(this.getSign()); // i think it keeps track of which player is holding the lock ?
Move move = generateRandomMove();
board.makeMove(this, move.getX(), move.getY() );
}
}
#Override
int getMyTurn() {
return 0;
}
#Override
public String getPlayerName() {
return name;
}
#Override
public void setPlayerName(String name) {
this.name = name;
}
#Override
void setSign(int sign) {
this.sign = sign ;
}
#Override
int getSign() {
return sign;
}
private Move generateRandomMove(){
while (true)
{
int x = getRandomNumber(0,board.getBoardSize()) ;
int y = getRandomNumber(0,board.getBoardSize()) ;
if (board.isPositionAvalabile(x, y ))
{
return new Move(x,y);
}
}
// todo implement the best move !
}
public int getRandomNumber(int min, int max) {
return (int) ((Math.random() * (max - min)) + min);
}
}
HumanPlayer.java
public class HumanPlayer extends Player {
private String name ;
private int sign ;
private Board board ;
public HumanPlayer(Board board) {
this.board = board;
}
#Override
public void run() {
while (!board.isGameOver())
{
board.setCurrentPlayerTurn(this.getSign()); // I think it keeps track of which player is holding the lock ?
Move move = requestMoveFormHuman(); // request move for human player // will be changed in the GUI?
board.makeMove(this, move.getX() , move.getY()); // check for move logic here >
}
}
#Override
int getSign() {
return sign;
}
#Override
int getMyTurn() {
return 0;
}
#Override
public String getPlayerName() {
return name;
}
#Override
public void setPlayerName(String name) {
this.name = name;
}
#Override
void setSign(int n) {
this.sign = n ;
}
// logic
private Move requestMoveFormHuman(){
int i=0 ;
while (true)
{
System.out.println(i);
Move move = requestMove() ;
int x = move.getX();
int y = move.getY();
if (board.isPositionAvalabile(x,y))
{
return new Move(x,y);
}
}
}
private Move requestMove() {
System.out.println("Player "+name+" turn:" );
System.out.println("Enter Row number: ");
int x = ScanInt();
System.out.println("Enter Coulmn number ");
int y = ScanInt();
return new Move(x ,y ) ;
}
private int ScanInt(){
Scanner scan = new Scanner(System.in);
// This method reads the number provided using keyboard
int num = scan.nextInt();
// Closing Scanner after the use
return num;
}
}
Main.java
public class Main {
public static void main(String[] args) {
Game game = new Game() ;
game.start();
}
}
Board.java
import java.util.HashMap;
import java.util.Scanner;
public class Board {
private int currentPlayerTurn = 0 ;
public int getBoardSize() {
return boardSize;
}
private int boardSize ;
private int[][] board_values ;
private boolean gameOver ;
private HashMap<String , String> result_history;
public Board(int boardSize) {
this.boardSize = boardSize;
board_values = new int[boardSize][boardSize];
for (int i = 0; i < boardSize; i++) {
for (int j = 0 ; j < boardSize; j++)
board_values[i][j] = 0 ;
}
System.out.println("");
}
private String getSign(int n) {
if (n==1)
return "X" ;
if (n==2)
return "0" ;
return " " ; // empty cell
}
public void printBoard(){
// todo change to ui components
for (int i = 0 ; i < boardSize ; i++)
{
for (int j = 0 ; j < boardSize ; j++)
{
System.out.print("|");
System.out.print(" " + getSign(board_values[i][j])+ " ");
System.out.print("|");
}
System.out.println("");
System.out.println("----------------------------------" );
}
}
/** is this the Synchronized one ? */
public boolean makeMove(Player player , int x , int y ) {
/*Update Board Value
insert 1 in the 2d board at x,y for player 1
insert 2 in the 2d board at x,y for player 2
*/
int sign = player.getSign();
updateBoard(x,y , sign ) ;
/*print Board*/
printBoard();
/* check for winner */
doWeHaveAwinner(x,y , sign);
return true ;
}
/*check the whole row (x) for if all signs are equals
, checks the whole column (x) for if all signs are equals
check diagonal if x=y */
private boolean doWeHaveAwinner(int x, int y, int sign) {
// TODO: 16/01/2022
return false ;
}
private void updateBoard(int x, int y , int sign ) {
board_values[x][y] = sign ;
}
public boolean isPositionAvalabile(int x , int y ){
return !(x>this.boardSize || x < 0 || y>this.boardSize || y < 0) ;
}
private void checkMove() {
// todo > ?
}
private void resetBoard(){
// todo set al values to 0
}
private void updateResultHistory(){
// TODO: 16/01/2022 update <Winner Name , Ps+1 >
}
private int ScanInt(){
Scanner scan = new Scanner(System.in);
System.out.print("Enter any number: ");
// This method reads the number provided using keyboard
int num = scan.nextInt();
// Closing Scanner after the use
return num;
}
/*Get Set*/
public synchronized boolean isGameOver() {
return gameOver;
}
public void setGameOver(boolean gameOver) {
this.gameOver = gameOver;
}
public int getCurrentPlayerTurn() {
return currentPlayerTurn;
}
public void setCurrentPlayerTurn(int currentPlayerTurn) {
this.currentPlayerTurn = currentPlayerTurn;
}
}
And here is Game.java, it basically inits 2 players.
Notice that in each player init I passed the board instance as a parameter.
It might a look little bit messy but I think passing the board instance for the players is the important thing here. Also I called the player1().start and player2.start()
Game.java
public class Game {
private Player player1 ;
private Player player2 ;
private Board board ;
private void initBoard(){
/* request board size */
int board_size = requestBoardSize();
board = new Board(board_size); // Synchronized class fields ?
}
private void initGameMode(){
/*
init the players objects as follows
1 - for human-machine game
2 - for machine-human game, and
3 - for human-human game
*/
System.out.println(Utils.str_gameType);
Scanner scanner = new Scanner( System.in);
int game_mode = scanner.nextInt( );
switch (game_mode) {
case 1:
/* init game type1 human-machine Game*/
player1 = new HumanPlayer(board);
player2 = new MachinePlayer(board);
break;
case 2:
player1 = new MachinePlayer(board);
player2 = new HumanPlayer(board);
break;
case 3:
player1 = new HumanPlayer(board);
player2 = new HumanPlayer(board);
break;
default:
throw new IllegalStateException("Unexpected value: " + game_mode);
}
player1.setSign(1);
player2.setSign(2);
System.out.println("");
}
private void initPlayersName(){
/*request name player 1 */
System.out.println(Utils.str_player1Name); /*Scan first name*/
Scanner scan1 = new Scanner(System.in);
String name1 = scan1.next();
player1.setPlayerName(name1);
/*request name player 2 */
System.out.println(Utils.str_player2Name); /*Scan first name*/
Scanner scan2 = new Scanner(System.in);
String name2 = scan2.next();
player2.setPlayerName(name2);
}
public Game() {
System.out.println(Utils.str_start_game);
initBoard();
initGameMode();
initPlayersName();
}
public void start() {
// todo change who starts first
player1.start();
new Thread(new Runnable() {
#Override
public void run() {
try {
Thread.sleep(300);
player2.start();
}catch (Exception e)
{
}
}
}).start();
}
private int requestBoardSize() {
System.out.println(Utils.str_request_board_size);
Scanner scanner = new Scanner(System.in) ;
int i = scanner.nextInt() ;
return i ;
}
}///End of Class
Hello I'm fairly new to programming and this is my first time posting here so any help would be appreciated so:
my problem is that I"m trying to create some kind of 2D shooter game in java but I don't know if my simple game loop is good because when i shoot a missile it shoots a one every 20 ms and it's too fast and shoots a ton of missiles at once so is there any way to adjust it ? Like to keep some delay between every missile and the other??
and please tell me if i have problems or bad programming in my code !!
this is my game panel where most of the game happens and where my loop and adding missiles method in
public class GamePanel extends JPanel implements KeyListener {
Measurments mesure = new Measurments();
int panel_width = mesure.getUniversalWidth();
int panel_height = mesure.getUniversalHeight();
Timer timer;
Random rand = new Random();
ArrayList<Enemy> enemies = new ArrayList<>();
ArrayList<Missile> missiles = new ArrayList<>();
Player player = new Player(0, 0);
boolean up = false;
boolean down = false;
boolean right = false;
boolean left = false;
boolean isShooting = false;
boolean isRunning = true;
public boolean gameRunning() {
return isRunning;
}
int count = 5;
int missilesCount = 6;
public GamePanel() {
timer = new Timer(20, new ActionListener() {
public void actionPerformed(ActionEvent e) {
StartGame();
repaint();
}
});
setSize(panel_width, panel_height);
addKeyListener(this);
timer.start();
for (int i = 0; i < count; i++) {
addEnemy(new Enemy(rand.nextInt(750), rand.nextInt(500)));
}
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
player.paint(g2d);
for (int i = 0; i < enemies.size(); i++) {
Enemy temp = enemies.get(i);
temp.paint(g2d);
}
for (int i = 0; i < missiles.size(); i++) {
Missile mis = missiles.get(i);
mis.paint(g2d);
mis.behave();
}
}
public void StartGame() {
if (isRunning) {
runGame();
setBackground(Color.YELLOW);
} else {
setBackground(Color.BLACK);
}
}
public void runGame() {
update();
};
public void update() {
player.checkBorders();
checkColls();
if (up) {
player.updateUp();
}
if (down) {
player.updateDown();
}
if (right) {
player.updateRight();
}
if (left) {
player.updateLeft();
}
if (isShooting) {
for (int i = 0; i < 5; i++) {
missiles.add(new Missile(player.getX() + 16, player.getY() + 16));
}
}
for (int i = 0; i < missiles.size(); i++) {
Missile temp = missiles.get(i);
if (temp.getX() == panel_width) {
RemoveMissile(temp);
}
}
}
public void addEnemy(Enemy e) {
enemies.add(e);
}
public void removeEnemy(Enemy e) {
enemies.remove(e);
}
public void addMissile(Missile e) {
missiles.add(e);
}
public void RemoveMissile(Missile e) {
missiles.add(e);
}
public void checkColls() {
for (int i = 0; i < enemies.size(); i++) {
Enemy tempEnm = enemies.get(i);
for (int e = 0; e < missiles.size(); e++) {
Missile tempMis = missiles.get(e);
if (tempMis.missileRect().intersects(tempEnm.enemyRect())) {
enemies.remove(tempEnm);
missiles.remove(tempMis);
}
}
}
}
public void keyPressed(KeyEvent e) {
int key = e.getKeyCode();
if (key == e.VK_UP) {
up = true;
}
if (key == e.VK_DOWN) {
down = true;
}
if (key == e.VK_RIGHT) {
right = true;
}
if (key == e.VK_LEFT) {
left = true;
}
if (key == e.VK_ENTER) {
isRunning = true;
}
if (key == e.VK_SPACE) {
isShooting = true;
}
}
public void keyReleased(KeyEvent e) {
int key = e.getKeyCode();
if (key == e.VK_UP) {
up = false;
}
if (key == e.VK_DOWN) {
down = false;
}
if (key == e.VK_RIGHT) {
right = false;
}
if (key == e.VK_LEFT) {
left = false;
}
if (key == e.VK_SPACE) {
isShooting = false;
}
}
public void keyTyped(KeyEvent e) {
}
}
Thanks in advance !!
private long fired = 0L;
public void update() {
...
// firing missiles: only if the missile count is less than the max., and the elapsed
// time is more than a limit (100 ms)
if ( isShooting && missiles.size() < missilesCount &&
( System.currentTimeMilis() - this.fired ) > 100 ) {
missiles.add( new Missile( player.getX() + 16, player.getY() + 16 ) );
// time of last firing
this.fired = System.currentTimeMilis();
}
...
}
public void RemoveMissile(Missile e) {
// as Guest is asked in another answer, this method should remove, not add...
missiles.remove(e);
}
To make my code more efficient, I have tried to separate the GUI and Gameplay. The code complies but when I make a new Game(); the Gui displays correctly but when I try to interact with it (i.e. change a name on the board or click a button the methods do not work.
The GUI Class Constructor:
public GUI()
{
makeFrame();
assignmines();
}
note: Assign mines and make frame are the only methods in this class.
The Game Class: (From the constructor)
public Game()
{
new GUI();
//UPDATES THE LABELS
updateGamesPlayed() ;
UpdateName();
}
// *********************************GAME CONTROLS************
private void quit()
{
System.exit(0);
}
//RESETS THE BOARD
public void reset()
{
frame.setVisible(false);
String tempName = Game.this.namelabel.getText();
frame.dispose();
Game gb= new Game();
gb.namelabel.setText(tempName);
score = 0;
}
// iNITIATES NEW GAME
public void newGame(){
frame.setVisible(false);
frame.dispose();
new Game();
}
// INCREASE THE ARRAY OF BUTTONS
public void biggerBoard(){
boardsize = 10;
reset();
}
// INCREASES NUMBER OF MINES ASSIGNED TO THE BOARD
public void changeDifficulty(){
numberOfMines = 15;
mine = 15;
minesLeft = 15;
reset();
}
}
// LOSING THE GAME ALERT
public void lose() {
status.setText("You're finished");
gamegoing = false;
JFrame parent = new JFrame();
JOptionPane.showMessageDialog(parent, "Sorry, you lost");
reset();
}
// WINNING THE GAME ALERT
public void win() {
status.setText("You won!");
gamegoing = false;
JFrame parent = new JFrame();
JOptionPane.showMessageDialog(parent, "Congratualations, you won!");
updateGamesWon();
Game.this.setVisible(false);
Game.this.dispose();
reset();
}
// UPDATING THE SCORE
public void updatescore() {
scorelabel.setText("" + score + " points");
if (100 - score <= 10) win();
}
public void gamesPlayed() {
gamesPlayed.setText("" + noGamesPlayed + " Games Played");
}
//UPDATES THE NAME BASED ON BUTTON CLICK
public void UpdateName() {
saveName.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent ae){
playername = nameEnter.getText();
namelabel.setText(playername);
}
});
}
//INCREMENTS THE NUMBER OF GAMES THAT HAVE BEEN PLAYED
public void updateGamesPlayed() {
noGamesPlayed ++;
}
//uPDATES HOW MANY GAMES HAVE BEEN WON
public void updateGamesWon() {
noGamesWon ++;
}
//WHAT VALUES THE CHARACTER HAVE
static char getUserChar(int cellValue) {
if(cellValue == Mine) {
return 'X';
} else if( cellValue == Empty) {
return '+';
} else if (cellValue == Flag || cellValue == FlaggedMine) {
return 'F';
} else if (cellValue == UncoveredMine) {
return 'X';
} else { String adjMines = Integer.toString(cellValue);
return adjMines.charAt(0);
}
}
//METHOD TO DISPLAY HOW MANY MINES AROUND THE BUTTON CLICKED
static int numAdjMines(int[][] mineBoard, int row, int col) {
int numMines = 0;
for(int dr = -1; dr <= 1; dr ++) {
for(int dc = -1; dc <= 1; dc++) {
if(row + dr >= 0 && row + dr < mineBoard.length &&
col+ dc >= 0 && col + dc < mineBoard[0].length) {
if(mineBoard[row+dr][col+dc] == Mine ||
mineBoard[row+dr][col+dc] == FlaggedMine) {
numMines++;
}
}
}
}
return numMines;
}
// TAKES X AND Y VALUE DESCRIBES WHAT HAPPENS ON CLICK
public void click(int row, int col) {
if(mineBoard[row][col] == Mine) {
buttons[row][col].setIcon( new ImageIcon( "images/bomb.gif" ) );
lose();
} else {
score += 1;
updatescore();
buttons[row][col].setText("" + numAdjMines(mineBoard, row, col));
buttons[row][col].setForeground(Color.GREEN);
mineBoard[row][col] = UncoveredEmpty;
//buttons[row][col].setText(Character.toString(getUserChar(mineBoard[row][col])));
if(numAdjMines(mineBoard, row, col) == Empty) {
for(int dr = -1; dr <= 1; dr ++) {
for(int dc = -1; dc <= 1; dc++) {
if(row+dr >= 1 && row+dr < 10 &&
col+dc >= 1 && col+dc < 10) {
if(mineBoard[row+dr][col+dc] == Empty) {
click(row+dr,col+dc);
}
}
}
}
}
}
}
//ACTION WHEN USER CLICKS ON A BUTTON
private class MouseListener extends MouseAdapter {
private int x = 0;
private int y = 0;
public MouseListener(int row, int col) {
this.x = row;
int i = 0;
this.y = col;
}
public void mouseClicked(MouseEvent e) {
if(e.getButton() == MouseEvent.BUTTON1) {
if((mineBoard[x][y] == Empty) && (Game.this.gamegoing == true)) {
Game.this.click(x, y);
} else if(mineBoard[x][y] == Mine) {
buttons[x][y].setIcon( new ImageIcon( "images/bomb.gif" ) );
Game.this.lose();
}} else if(e.getButton() == MouseEvent.BUTTON3) {
Game.this.buttons[x][y].setText("F");
}
}
}
}
How can I link the GUI and the functionality? I think I have got the wrong logic in the constructors but i'm not sure. (I hope all the relevant code is there, I have omitted some fields and methods due to length).
I have two classes (Sampling and Stacker). The Sampling class (my Main class) is extends JFrame and has a JButton with an ActionListener to open the Stacker class.
The problem is when the button is clicked, the Stacker class will open but only a frame without any components. When I switch the main method into the Stacker class, the program works fine. What is the problem?
Here is the code:
The Sampling class:
public class Sampling extends JFrame implements ActionListener
{
private JButton openStacker;
Stacker st;
public Sampling()
{
setSize(300,300);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setLayout(new FlowLayout());
setLocationRelativeTo(null);
openStacker = new JButton("Start Stacker!");
add(openStacker);
openStacker.addActionListener(this);
setVisible(true);
}
public void actionPerformed(ActionEvent e)
{
dispose();
st = new Stacker();
}
public static void main (String args[])
{
new Sampling();
}
}
The Stacker game class:
public class Stacker extends JFrame implements KeyListener
{
int iteration = 1;
double time = 200;
int last = 0;
int m = 10;
int n = 20;
JButton b[][];
int length[] = {5,5};
int layer = 19;
int deltax[] = {0,0};
boolean press = false;
boolean forward = true;
boolean start = true;
public Stacker()
{
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setSize(400,580);
this.setUndecorated(false);
this.setLocationRelativeTo(null);
b = new JButton [m][n];
setLayout(new GridLayout(n,m));
for (int y = 0;y<n;y++)
{
for (int x = 0;x<m;x++)
{
b[x][y] = new JButton(" ");
b[x][y].setBackground(Color.DARK_GRAY);
add(b[x][y]);
b[x][y].setEnabled(false);
}//end inner for
}
this.setFocusable(true);
this.pack();
this.addKeyListener(this);
this.setVisible(true);
go();
}
public void go()
{
int tmp = 0;
Component temporaryLostComponent = null;
do{
if (forward == true)
{
forward();
} else {
back();
}
if (deltax[1] == 10-length[1])
{
forward = false;
} else if (deltax[1] == 0)
{
forward = true;
}
draw();
try
{
Thread.sleep((long) time);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}while(press == false);
if (layer>12)
{
time= 150-(iteration*iteration*2-iteration);
} else
{
time = time - 2.2;
}
iteration++;
layer--;
press = false;
tmp = check();
length[0] = length[1];
length[1] = tmp;
if (layer == -1)
{
JOptionPane.showMessageDialog(temporaryLostComponent, "Congratulations! You beat the game!");
repeat();
}
if (length[1] <= 0)
{
JOptionPane.showMessageDialog(temporaryLostComponent, "Game over! You reached line "+(18-layer)+"!");
repeat();
}
last = deltax[1];
start = false;
go();
}
public int check()
{
if (start == true)
{
return length[1];
}
else if (last<deltax[1])
{
if (deltax[1]+length[1]-1 <= last+length[0]-1)
{
return length[1];
}
else
{
return length[1]-Math.abs((deltax[1]+length[1])-(last+length[0]));
}
}
else if (last>deltax[1])
{
return length[1]-Math.abs(deltax[1]-last);
}
else
{
return length[1];
}
}
public void forward()
{
deltax[0] = deltax[1];
deltax[1]++;
}
public void back()
{
deltax[0] = deltax[1];
deltax[1]--;
}
public void draw()
{
for (int x = 0;x<length[1];x++)
{
b[x+deltax[0]][layer].setBackground(Color.DARK_GRAY);
}
for (int x = 0;x<length[1];x++)
{
b[x+deltax[1]][layer].setBackground(Color.CYAN);
}
}
public void repeat()
{
if(JOptionPane.showConfirmDialog(null, "PLAY AGAIN?","WARNING",JOptionPane.YES_NO_OPTION)== JOptionPane.YES_OPTION)
{
dispose();
new Stacker();
}else{
System.exit(0);
}
}
public void keyPressed(KeyEvent e)
{
if (e.getKeyCode() == KeyEvent.VK_SPACE)
{
press = true;
}
}
public void keyReleased(KeyEvent arg0)
{
}
public void keyTyped(KeyEvent arg0)
{
}
}
Just to put all my comments into an answer, and give you somewhere to start with:
Comment 1:
Take out go(); see that happens. I tested it and it will work. If you leave it there, even the frame's close button is jammed. You're blocking the edt with the while->Thread.sleep junk. You'll want to do some refactoring. You're code it hard to follow and I have no idea what you're trying to do, so I didn't even attempt it
Comment 2:
If you're wondering why it works when you just run the main from the Stacker class, it's probably because you are running it outside the EDT,
public static void main(String[] args) { new Stacker(); }. What happens when you click the button, that action is performed within the EDT, and hence your new Stacker() will be run on the EDT. In which case the EDT gets blocked by your while loop. If you try run the program from the Stacker class, but wrap it in a SwingUtilities.invokeLater, you will also notice the program fails to work. Swing programs should be run on the EDT though.
Comment 2: Read the first few sections on Concurrency with Swing
So what you can do is use a Swing Timer (which operates on the EDT) for the game loop. What I did was refactor your code a bit. It doesn't operate the way you want it to yet, only because I didn't really understand the logic of your code. So I couldn't get it to work. What I did though, is put some of the logic into the Timer.
Timer timer = new Timer((int)time, new ActionListener(){
public void actionPerformed(ActionEvent event) {
if (forward == true) {
forward();
} else {
back();
}
if (deltax[1] == 10 - length[1]) {
forward = false;
} else if (deltax[1] == 0) {
forward = true;
}
draw();
}
});
And when the go() method is called, it just starts the timer by calling timer.start(). Basically what you need to know about the timer, is that every tick (the milliseconds you pass it), the actionPerformed will be called. So you can update the game state in that method, just like you did in the while loop each iteration.
Take some time to go over How to Use Swing Timers
To get the game working properly, you still need to make some adjustments, but this should give you a head start.
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class Sampling extends JFrame implements ActionListener {
private JButton openStacker;
Stacker st;
public Sampling() {
setSize(300, 300);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setLayout(new FlowLayout());
setLocationRelativeTo(null);
openStacker = new JButton("Start Stacker!");
add(openStacker);
openStacker.addActionListener(this);
setVisible(true);
}
public void actionPerformed(ActionEvent e) {
dispose();
st = new Stacker();
}
public static void main(String args[]) {
SwingUtilities.invokeLater(new Runnable(){
public void run() {
new Sampling();
}
});
}
}
class Stacker extends JFrame implements KeyListener {
int iteration = 1;
double time = 200;
int last = 0;
int m = 10;
int n = 20;
JButton b[][];
int length[] = {5, 5};
int layer = 19;
int deltax[] = {0, 0};
boolean press = false;
boolean forward = true;
boolean start = true;
Timer timer = new Timer((int)time, new ActionListener(){
public void actionPerformed(ActionEvent event) {
if (forward == true) {
forward();
} else {
back();
}
if (deltax[1] == 10 - length[1]) {
forward = false;
} else if (deltax[1] == 0) {
forward = true;
}
draw();
}
});
public Stacker() {
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setSize(400, 580);
this.setUndecorated(false);
this.setLocationRelativeTo(null);
b = new JButton[m][n];
setLayout(new GridLayout(n, m));
for (int y = 0; y < n; y++) {
for (int x = 0; x < m; x++) {
b[x][y] = new JButton(" ");
b[x][y].setBackground(Color.DARK_GRAY);
add(b[x][y]);
b[x][y].setEnabled(false);
}//end inner for
}
this.setFocusable(true);
this.pack();
JPanel panel = (JPanel)getContentPane();
panel.addKeyListener(this);
this.setVisible(true);
panel.requestFocusInWindow();
go();
}
public void go() {
int tmp = 0;
Component temporaryLostComponent = null;
timer.start();
if (layer > 12) {
time = 150 - (iteration * iteration * 2 - iteration);
} else {
time = time - 2.2;
}
iteration++;
layer--;
press = false;
tmp = check();
length[0] = length[1];
length[1] = tmp;
if (layer == -1) {
JOptionPane.showMessageDialog(temporaryLostComponent, "Congratulations! You beat the game!");
repeat();
}
if (length[1] <= 0) {
JOptionPane.showMessageDialog(temporaryLostComponent, "Game over! You reached line " + (18 - layer) + "!");
repeat();
}
last = deltax[1];
start = false;
//go();
}
public int check() {
if (start == true) {
return length[1];
} else if (last < deltax[1]) {
if (deltax[1] + length[1] - 1 <= last + length[0] - 1) {
return length[1];
} else {
return length[1] - Math.abs((deltax[1] + length[1]) - (last + length[0]));
}
} else if (last > deltax[1]) {
return length[1] - Math.abs(deltax[1] - last);
} else {
return length[1];
}
}
public void forward() {
deltax[0] = deltax[1];
deltax[1]++;
}
public void back() {
deltax[0] = deltax[1];
deltax[1]--;
}
public void draw() {
for (int x = 0; x < length[1]; x++) {
b[x + deltax[0]][layer].setBackground(Color.DARK_GRAY);
}
for (int x = 0; x < length[1]; x++) {
b[x + deltax[1]][layer].setBackground(Color.CYAN);
}
}
public void repeat() {
if (JOptionPane.showConfirmDialog(null, "PLAY AGAIN?", "WARNING", JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) {
dispose();
new Stacker();
} else {
System.exit(0);
}
}
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_SPACE) {
System.out.println("Pressed");
press = true;
}
}
public void keyReleased(KeyEvent arg0) {
}
public void keyTyped(KeyEvent arg0) {
}
}
Notice the SwingUtilities.invokeLater in the main. That's how you can start up the program on the EDT. The link on Concurrency In Swing will give you more information.
I was wondering if someone coule help me on how to implement a thread which runs infinitely in the background until the user presses p at which point it pauses the other threads and upon pressing r resumes other threads. This is some of the code
Some of the main object
public class CardGame
{
static Player[] players;
static int handSize;
static Queue<Card>[] playingDeckArray;
public static void main(String[] args){
Scanner reader = new Scanner(System.in);
System.out.println( "\nHello, how many players would you like" );
int playersNum = Integer.parseInt(Checks.userInputCheck( "\\d" ));
System.out.println( "\nHow many cards should each player begin with" );
int handSize = Integer.parseInt(Checks.userInputCheck( "\\d" ));
System.out.println( "\nWhich strategy would you like to use 1 or 2" );
int strategy = Integer.parseInt(Checks.userInputCheck( "[12]$" ));
Logger.createDeck( playersNum, handSize );
makePlayers( playersNum, handSize, strategy );
makePlayingDecks( playersNum );
dealInitialHand( playersNum, players, handSize );
makePlayerOutputs();
for ( int i = 0; i < players.length; i++){
logInitialHand(players[i]);
}
CardGame cG = new CardGame();
cG.startPauseThread();
for ( int i = 0; i < players.length; i++){
new Thread(players[i]).start();
}
}
public void startPauseThread(){
Thread add = new Thread( pauseInputThread );
add.start();
}
Thread pauseInputThread = new Thread(){
public void run(){
int i = 0;
for(;;){
System.out.println("i'm still here" );
Scanner reader = new Scanner(System.in);
String result = Checks.userInputCheck( "[pPrR]$" );
i++;
System.out.println(i);
}
}
};
}
The player object which are the threads to be paused
public class Player implements Runnable
{
Card[] hand;
String playerName;
int strategyChosen;
public void run(){
System.out.println( "les do dis" );
}
private Player(){
}
public Player( int strategy, int cardsInHand, int playerNumber ){
hand = new Card[cardsInHand];
strategyChosen = strategy;
playerName = "Player " + playerNumber;
}
public String getPlayerName(){
return playerName;
}
public void fillHand(){
for ( int i = 0; i < hand.length; i++){
hand[i] = new Card(0);
}
}
public void setHand( int value, int index ){
hand[index].setCardValue( value );
}
public void seeHand(){
for ( int i = 0; i < hand.length; i++){
System.out.println( hand[i].getCardValue() );
}
}
public String getHand(){
String result = "";
for ( int i = 0; i < hand.length; i++ ){
result = result + hand[i].getCardValue() + " \n" ;
}
return result;
}
public int getHandValue( Card card ){
return card.getCardValue();
}
}
The players will be 'playing a game' where they draw and discard objects from arrays, but the user should be able to pause and resume the programm at any point during the game. i just dont quite understand how to go about that, using events and listners.
Help would be appreciated. Thank you.
Thread has no mechanism for this on its own. You can, however, easily add this functionality in to your own process. You'll have some flag to set and check and then probably the best is to have a wait/notify scheme. Here's a simple demonstration:
abstract class PausableTask implements Runnable {
private volatile boolean paused;
private final Object lock = new Object();
void setPaused(boolean shouldPause) {
synchronized (lock) {
paused = shouldPause;
if (!paused) {
lock.notify();
}
}
}
boolean isPaused() { return paused; }
#Override
public void run() {
for (;;) {
synchronized (lock) {
while (paused) {
try {
lock.wait();
} catch (InterruptedException e) {}
}
}
doTask();
}
}
abstract void doTask();
}
class Counter {
volatile long count;
public static void main(String[] args) {
final Counter counter = new Counter();
PausableTask increment = new PausableTask() {
#Override
void doTask() {
counter.count++;
}
};
PausableTask decrement = new PausableTask() {
#Override
void doTask() {
counter.count--;
}
};
decrement.setPaused(true);
PausableTask next = increment;
Scanner in = new Scanner(System.in);
long count = counter.count;
new Thread(increment).start();
new Thread(decrement).start();
for (;;) {
System.out.print(
(next == increment ? "Counting up from " : "Counting down from ")
+ count + ". Enter 'exit' to abort or anything else to toggle: "
);
if (in.nextLine().equals("exit")) {
System.exit(0);
}
if (increment.isPaused()) {
next = increment;
decrement.setPaused(true);
} else {
next = decrement;
increment.setPaused(true);
}
count = counter.count;
next.setPaused(false);
}
}
}
For taking user input from the keyboard, there's not really a convenient way to do that in Java. If you want to take straight keystrokes you need a GUI component for them to happen in. If you do plan on implementing a GUI take a look at the key bindings tutorial.
It's not possible to pause a thread simply by calling some predefined method, nor it's possible to kill a thread. The only thing you can do is to implement this behavior by yourself. It means that you will do something like this:
public class MyThread extends Thread {
private volatile boolean running = true;
private volatile boolean paused = false;
public void kill() {
this.running = false;
}
public void setPaused(boolean paused) {
this.paused = paused;
}
#Override
public void run() {
while (running) {
if (!paused) {
// do another step
}
}
}
}
However, it's possible that I didn't understand your question correctly. Leave me a feedback so I can update my answer eventually.