I have a jFrame that is implementing a poker game. I have a thread so that the computer opponents take time with their moves. I've tried to implement it so that the Thread waits when a human turn comes up. Before I even put a human player in, though, the frame doesn't call repaint(). I've used the debugger in Netbeans to check this: it does get to the line where the frame calls repaint(), but for some reason it doesn't actually do it. Here's the code:
public void run() {
for (int i = 0; i < 2; i++) {
for (int j = 0; j < players.size(); j++) {
Card card = deck.draw();
players.get(i).addToHand(card);
output.append("Player " + players.get(i).getName() + " got a " + card + ".\n");
System.out.println("Player " + players.get(i).getName() + " got a " + card + ".\n");
}
}
while (true) {
if (!players.isEmpty() && players.get(0) instanceof HumanPlayer)
humansTurn = true;
if (humansTurn) {
synchronized (this) {
try {
this.wait();
} catch (InterruptedException e) {
}
}
} else if (humanMoveMade) {
playMove(humanMove, players.remove(0));
humanMoveMade = false;
}else {
//unrelated code, then:
debug.update();
repaint();
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
}
}
}
}
Basically it's supposed to get to that else whenever the human player isn't making his or her move, and it does get to that repaint, but it never goes through for some reason. The window appears, but none of the components.
EDIT: I should also mention that the debug.update() method call before the repaint() is supposed to update information on another frame, but nothing is showing up in that window either...
I need to have this ready soon, so I really need some help with this. What is going on?
Ugh...sorry, false alarm. I had forgotten to check when this frame gets created. Turns out I had accidentally called the run() method instead of running the thread the way it normally is (I had tried to implement something different beforehand). After going back to making a new thread and calling start(), it works now.
Related
I'm developing an application in Java to help me land my first job as a junior developer. It's a chess game with a GUI that both human players click on from the same machine.
When it's, say, white's turn to move, the application calls white's getMove(Interface interaction) method until a valid MoveAttempt is returned. Here's the getMove(Interface interaction) method of HumanPlayer:
public MoveAttempt getMove(Interface interaction) {
while(!interaction.selectionMade()) {
}
byte pieceFile = interaction.getPenultimateFile();
byte pieceRank = interaction.getPenultimateRank();
byte toFile = interaction.getUltimateFile();
byte toRank = interaction.getUltimateRank();
return new MoveAttempt(pieceFile, pieceRank, toFile, toRank, getIsWhite());
}
penultimateFile, penultimateRank, ultimateFile and ultimateRank are supposed to store the file (column) and rank (row) of the last two chess tiles clicked. This is achieved through this actionPerformed(ActionEvent event) which Interface has because it implements ActionListener
public void actionPerformed(ActionEvent event) {
LocalizedButton button = (LocalizedButton) event.getSource();
if(penultimateFile == -1) {
penultimateFile = button.getFile();
penultimateRank = button.getRank();
}
else {
ultimateFile = button.getFile();
ultimateRank = button.getRank();
}
}
and by calling this method before each call to getMove(Interface interaction)
public void resetClicks() {
penultimateFile = -1;
penultimateRank = -1;
ultimateFile = -1;
ultimateRank = -1;
}
So the idea is that a move attempt is not made until someone has clicked on two chess squares which is why I have a while loop indefinitely calling selectionMade():
public boolean selectionMade() {
return penultimateFile != -1 && penultimateRank != -1 && ultimateFile != -1 && ultimateRank != -1;
}
This didn't work---pieces didn't move---so in an attempt to see what was happening I put this print statement
System.out.println(interaction.getPenultimateFile() + ", " +
interaction.getPenultimateRank() + ", " +
interaction.getUltimateFile() + ", " +
interaction.getUltimateRank());
into the while loop to see what was going on and now it works---pieces move---except I may have encountered times in which it didn't work but I last I tried I couldn't get it to fail.
I don't want to print anything to the console; what should I do in lieu of having this while loop?
Edit: Putting boolean lol = 0 just above the loop and lol = !lol in the loop doesn't allow the code to work. Neither does calling doNothing().
Edit: Here's the source code: https://github.com/JosephBGriffith/Chess
Right now only the pawns work because I have other bugs that I need to fix. En passant works except the opponent piece doesn't get eliminated.
I would invert the control, so that the UI pushes moves to the game, rather than the game trying to pull moves from the UI.
So your game class might have:
class Game {
boolean move(int fromFile, int fromRank, int toFile, int toRank) { ... }
...
}
If the move wasn't legal (e.g. if it was the other player's turn) then move returns false and the move doesn't occur. That is, the internal state of the Game is unchanged.
And your actionPerformed method becomes:
public void actionPerformed(ActionEvent event) {
LocalizedButton button = (LocalizedButton) event.getSource();
if(penultimateFile == -1) {
penultimateFile = button.getFile();
penultimateRank = button.getRank();
}
else {
game.move(penultimateFile, penultimateRank, button.getFile(), button.getRank());
penultimateFile = -1;
}
}
You could use the return value of move to provide some feedback to the user if the move is illegal.
Something to note about this suggestion is that move is executed on the Swing event thread. In theory this is bad practice, although unless your move method is very slow it won't matter.
Read https://docs.oracle.com/javase/tutorial/uiswing/concurrency/index.html and consider whether you want to use invokeLater.
Hi everyone i would like to ask if is it possible not to use timer in Java netbeans to display on my JLabel all value of my variable "counter" using while loop. Here is my sample code.
int counter = 0;
while (counter < 10) {
lblDisplay.setText("Completed " + Integer.toString(counter));
try {
Thread.sleep(1000);
lblDisplay.setText("Completed " + Integer.toString(counter));
} catch (InterruptedException ex) {
Logger.getLogger(Increment.class.getName()).log(Level.SEVERE, null, ex);
}
counter++;
}
in using of system.out.println it was displayed but in my Label was not.
Yes it's possible to avoid using a Swing Timer to achieve this, but if you did this then:
You'd have to make sure that the loop and the Thread.sleep(...) were run in a background thread off of the Swing event thread. If you don't do this, you will freeze the event thread and thus freeze your GUI and render it useless.
And then you'd have to make sure that when you only make Swing calls from the background thread, you take pains to queue those calls onto the Swing event dispatch thread. If you don't do this, you will run the risk of causing occasional very hard to debug threading errors.
Because of the extra work involved and the risk of getting it wrong, you'll find that it is much simpler and safer to just use a Swing Timer. For instance your posted code looks like it's at grave risk of putting the entire GUI/application to sleep since it has both a while loop and a Thread.sleep(...) called without concern for threading.
For example, without a Timer, your code could look something like (caveat: code not compiled nor tested):
new Thread(new Runnable() {
public void run() {
int counter = 0;
while (counter < 10) {
lblDisplay.setText("Completed " + Integer.toString(counter));
try {
Thread.sleep(1000);
final int finalCounter = counter;
SwingUtilities.invokeLater(new Runnable() {
public void run() {
lblDisplay.setText("Completed " + finalCounter);
}
});
} catch (InterruptedException ex) {
Logger.getLogger(Increment.class.getName()).log(Level.SEVERE, null, ex);
}
counter++;
}
}
}).start();
That's a bit more complicated than I like, while the Swing Timer could look like:
int delay = 1000;
new Timer(delay, new ActionListener() {
private int count = 0;
#Override
public void actionPerformed(ActionEvent e) {
if (count < 10) {
lblDisplay.setText("Completed " + counter);
} else {
((Timer) e.getSource()).stop(); // stop the Timer
}
counter++;
}
}).start();
Which is simpler and safer than the previous.
I have a slot machine program with some graphics, and the graphic is supposed to change when you pull the lever and for some reason it changes the graphic after it goes through all of the other code first. Have a look:
Declare images:
static ImageIcon jImage = new ImageIcon("C:\\Users\\Harry\\Desktop\\jackpotLeverNotPulled.png");
static ImageIcon jackpot1 = new ImageIcon("C:\\Users\\Harry\\Desktop\\jackpotimage1.png");
static ImageIcon jackpotPulled = new ImageIcon("C:\\Users\\Harry\\Desktop\\jackpotLeverPulled.png");
Now I add to panel:
static JLabel jlb = new JLabel(jImage);
Now I want the image to change when a certain area is clicked on my panel but the main jackpot code runs first and then the image changes:
public void mousePressed(MouseEvent e) {
// Returns the X coordinate of where the mouse was click on the panel
System.out.println("X Coordinate: " + e.getX() );
// Returns the Y coordinate of where the mouse was click on the panel
System.out.println("Y Coordinate: " + e.getY() );
System.out.println();
Scanner ansr = new Scanner(System.in);
String yesno;
int random = (int)(Math.random() * 21 );
int percentCheck = (int)(Math.random() * 10 );
if (e.getX ()>975 && e.getX ()<1159 && e.getY ()>82 && e.getY ()<218){
jlb.setIcon(jackpotPulled);
if (cashMoneyz<1) {
System.out.println("Insufficient funds");
image1.setIcon(jackpot1);
} else {
System.out.println("One dollar has been removed from you slot machine balance");
cashMoneyz--;
try {
System.out.println("Spinning...");
Thread.sleep(1000);
System.out.println("Spinning...");
Thread.sleep(1000);
System.out.println("SPINNINGGGGG...OMG SOOO INTENSE");
Thread.sleep(1000);
} catch (InterruptedException ie)
{
}
}
System.out.println("You have this much money (in dollars) left in your slot machine balance: " + cashMoneyz);
System.out.println("");
System.out.println("----------------------------------------------------------------------------------");
}
It does the if statements and try catches and only changes the graphic to jackpotPulled at the end of everything.
Thanks in advance :)
There are basically 2 problems in your code:
1)
A call to label.setImage() won't update immediately, as this is true for everything in AWT and Swing. Any time a repaint request is fired, it is simply added to a repaint queue, that will wait patiently for all other tasks done in the EDT (Event Dispatching Thread) to finish. But since you do other things in the mousePressed(), they will run first. A simple solution for this would be to do the computing in mouseReleased(). But a bigger problem exists.
2)
What you are currently doing is "starving" the EDT - a bad programming practice - as all screen related invocations must be executed immediately. Sleeping the EDT won't allow any repaints to take place while running. This is true for any long running tasks as well.
Its solution is to run the non-painting calls in a different thread:
private volatile boolean isComputing = false;
public void mousePressed(MouseEvent evt) {
if(isComputing)
return;
isComputing = true;
// .
// .
// .
// change icon here, or any
// other swing related change.
// .
// .
// run game
new Thread(){
public void run(){
// all non-swing computations
SwingUtilities.invokeLater(new Runnable() {
public void run() {
// change back icons,
// and some other swing updates
}
}
isComputing = false;
}
}.start();
}
An event handler (mousePressed) souldn't take a long time to complete, there should be no sleeps in it. As long as it runs (or sleeps), nothing else can happen. The runtime is waiting for the handler to return and displays the image after that. I would move most of the code to a function called by a timer, and use a state variable to keep track of how intensely the wheels are spinning.
I am working on Deal or No Deal with a user interface. The first problem I ran into was how to wait for a button action to continue, and I used Count Down Latches and it worked perfectly. But whenever, I click a button, everything in my JFrame disappears and comes back when you mouse over, it all of a sudden reappears when I press another buttton (This never happened before I used Count Down Latches, and this also happens with Semaphores, etc.) I'll try to keep my code as relevant as possible.
public CountDownLatch cdl = new CountDownLatch(1);
pickFirst();
try {
cdl.await();
} catch (Exception E) {
}
while (banker.findCasesLeft() > 2) {
banker = new Banker(Main.f.values);
for (i = casesToPick; i >= 1; i--) {
cdl = new CountDownLatch(1);
pickCase();
picked = false;
try {
cdl.await();
} catch (Exception E) {
}
}
^^^ That was my class that deals with picking cases Below is class with actionlisteners
public void actionPerformed(ActionEvent ae) {
if (!Main.me.pickedFirst) {
Main.me.pickedCase = caseNo;
Main.f.log += "You picked to keep case " + caseNo + ".\n";
setText(caseNo + "\np");
Main.f.changeLog();
Main.me.pickedFirst = true;
Main.me.cdl.countDown();
} else {
int value = Main.me.values[caseNo-1];
Main.me.values[caseNo] = 0;
Main.f.values[getIndex(value)].setSelected(true);
Main.f.log += "You picked to get rid of case " + caseNo + ". It contained $" + value + ".\n";
Main.f.changeLog();
Main.me.picked = true;
Main.me.cdl.countDown();
}
setEnabled(false);
}
Note that the await() method of CountDownLatch "Causes the current thread to wait until the latch has counted down to zero." If that thread is the event dispatch thread, GUI updates will be blocked until the wait condition changes. In general, CountDownLatch is meant to allow separate threads to rendezvous; it should't be used to within the event dispatch thread. This complete example, which coordinates multiple SwingWorker instances, may help clarify the usage.
so for the game I'm creating I realized I mist have done something wrong with my gameLoop because the first time I play through my game it runs great, but the second time or anything after that, it slows down by about half. Even if I minimize the game (Because that stops the gameLoop, and then bringing it up again starts it back up) here is the gameLoop code:
public void gameLoop(){
new Thread(){
public void run() {
while(gameRunning){
try {
Thread.sleep(1000/60);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (tutorial){
updateBullet();
updatePlayer();
repaint();
} else {
updateEnemies();
updateBullet();
createEnemies();
updateParticles();
updatePlayer();
repaint();
}
}
repaint();
}
}.start();
}
I start it for the first time in the init() just with
gameLoop();
And then I also have:
public void stop(){
bg.stop();
gameRunning = false;
}
public void start(){
bg.start();
gameRunning = true;
gameLoop();
}
And finally the playerUpdate also stops the loop with (The Thread inside of player is to allow for some effects to finish after the player dies):
public void updatePlayer(){
if (player.isMovingLeft){
player.x-=3;
}
if (player.isMovingRight){
player.x+=3;
}
for (int j=0; j < enemies.size(); j++){
if (player.isAlive){
if (enemies.get(j).x+19 > player.x && enemies.get(j).x < player.x+40 && enemies.get(j).y > player.y && enemies.get(j).y < player.y+40) {
enemies.remove(j);
j--;
explode.setFramePosition(0);
explode.start();
for (int k = 0; k <21; k++){
addParticle(player.x+20,player.y+20,2);
}
new Thread(){
public void run() {
try {
Thread.sleep(2000);
gameRunning = false;
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}.start();
player.isAlive = false;
break;
}
}
}
}
And then it is restarted with in the keyPressed event:
if (!gameRunning){
if (arg0.getKeyCode() == KeyEvent.VK_ENTER){
enemies.clear();
bullets.clear();
particles.clear();
score = 0;
player.x = 200;
player.isMovingLeft = false;
player.isMovingRight = false;
player.isAlive = (true);
gameRunning = true;
gameLoop();
}
}
So why is it that whenever the loop is stopped and started again, it runs at half the speed? Thanks!
It looks like you're starting a new thread for each gameloop; this means each time the gameloop runs, you've got another thread for the Java VM to handle. This is extremely inefficient, as eventually you'll have 1000 threads running, causing HUGE lag. Is there any way you could rewrite your code without threading there?
Also, what is this supposed to do?
try {
Thread.sleep(1000/60);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Why would you do 1000/60? A: Why not just use 16? B: It seems like you meant something else here, not sure what though
Also, what is the bg variable your reference in your start() and stop() methods?
It looks like you are trying to stop the thread by using the gameRunning boolean. If this is not volatile, then the game loop may not notice changes from the GUI thread that sets it to false and will run forever. Even if it is volatile, you have a race condition if start is called again before the game thread notices the stop command.
You should instead store a reference the the created thread and interrupt it in your stop method.
Also are all your update methods thread safe with respect to the paint method. updatePlayer doesn't look thread safe, and you don't know when paint will be called so it could happen at the same time as your update method. Even if the paint method doesn't write to the shared data, it could still see inconsistent data due to lack of a memory barrier.
I'd suggest doing all the updates in the GUI thread unless it is very slow and you need the multithreading. Look at using a Timer from Swing to to initiate your update logic.