First, I know that the way I'm trying to read the input is really bad, but I've tried to use Keylistener, and it doesn't work no matter what I try. I don't know what I'm doing wrong, so this is what I'm trying at the moment. I'm trying to call a thread in Controller.java from PreControls.java. If you could help me implement a working keylistener, it would me much appreciated, but I think fixing this thread problem will work too. I have tried debugging it, and the thread doesn't seem to start.
Code in PreControls.java:
Controller C = new Controller();
C.start();
System.out.print("Thread Should be started ");
Code in Controller.java:
package Game;
public class Controller extends Thread {
public void MyShipController(){
System.out.print("Thread Is started ");
String CharIn = "";
while(SpaceInvaders.GameOn = true){
CharIn = PreControls.ReadKeyPressed.getText();
if(CharIn.equalsIgnoreCase("a")){
SpaceInvaders.MyPos[0]--;
System.out.print("Move Left ");
}else if(CharIn.equalsIgnoreCase("d")){
SpaceInvaders.MyPos[0]++;
System.out.print("Move Right");
}else if(CharIn.equalsIgnoreCase(" ")){
//Fire Bullet
}
PreControls.ReadKeyPressed.setText("");
SpaceInvaders.MyShip.setLocation(SpaceInvaders.MyPos[0], SpaceInvaders.MyPos[1]);
jp1.repaint();
}
}
}
Sorry for not providing an SSCCEE. I'd need to send my whole project, and that defeats the point of doing a project.
ReadKeyPressed is the JTextArea that I'm having the letters inputted into.
jp1 is the JFrame
I'm working in the Eclipse IDE.
EDIT: forgot to add: After I start the applet, the Console reads "Thread Should be started" only, so it is a problem with the how I made the thread, or how I'm trying to create it.
Edit 2: My End goal is to detect when a (or left arrow) is pressed and move MyShip (a JLabel) to the left by 1 position and more it to the right by 1 position if d (or right arrow) is pressed.
Alright, I've accepted Williams answer as it made my thread run. And as suggested, I'm going to look into key bindings to detect when the keys are pressed. Thanks for all the help.
This = is an assinment operator.
while(SpaceInvaders.GameOn = true)
I think you wanted this ==
while(SpaceInvaders.GameOn == true)
Or better yet, and much cleaner, just
while(SpaceInvaders.GameOn)
Also, you should use key bindings instead of KeyListener, which my give you focus problems. See this answer for an example of using key bindings. Also see the tutorial
The code you've written in method MyShipController should be placed inside the run method of your thread. The run method is what the thread actually executes within.
As you've written it now, calling start on your Controller class will start your thread, and that thread will end immediately as its run method is empty.
public class Controller extends Thread {
#Override
public void run()
//public void MyShipController(){
System.out.print("Thread Is started ");
String CharIn = "";
while(SpaceInvaders.GameOn = true){
CharIn = PreControls.ReadKeyPressed.getText();
if(CharIn.equalsIgnoreCase("a")){
SpaceInvaders.MyPos[0]--;
System.out.print("Move Left ");
}else if(CharIn.equalsIgnoreCase("d")){
SpaceInvaders.MyPos[0]++;
System.out.print("Move Right");
}else if(CharIn.equalsIgnoreCase(" ")){
//Fire Bullet
}
PreControls.ReadKeyPressed.setText("");
SpaceInvaders.MyShip.setLocation(SpaceInvaders.MyPos[0], SpaceInvaders.MyPos[1]);
jp1.repaint();
}
}
}
However, I suggest your controller class extend Runnable rather than Thread.
Related
I'm coding a game and I'm trying to get the value of a dice roll from a button click in my UI.
I'm not too familiar with the MVC principles but I heard it's the way to go. Any tips on how to get there from this code ?
int move = -1;
while (move == -1) {
this.btnLancerLeD.addMouseListener(new MouseAdapter() {
public int diceRoll;
#Override
public void mouseClicked(MouseEvent arg0) {
diceRoll = jeu.getDe().lancer();
move = diceRoll;
}
});
}
I'm trying to get diceRoll value to move my players on the board.
First, you should only call addMouseListener() once rather than doing it repeatedly in a while loop. Second, you can do the logic of the "move" all inside mouseClicked(). You probably need an if statement.
Note that Swing already contains the logic to wait for the user to do something. This is the whole point of event listeners. They are only fired when that event occurs. In the case of a button, you should use an ActionListener instead of a MouseListener. For more details, I suggest that you check out the official Oracle tutorials for Swing. You can find these with a quick Google search.
I'm trying to break a special case that makes this code recursive.
I have a Javafx game where there are human and computer players each play when it's his turn and there can be many rounds.
A computer is supposed to play automatically and move to the next player immediately and show no direct indication to the UI (but it's possible to review what it did afterwards).
The problem is in the case where there are only computer players, we will come here the moment the currentBoardPane was loaded, enter the condition since all players are computers, set the board of the next player, and then without finishing the call, call this same function again:
currentBoardPane.addListener((e) -> {
if(gameManager.checkIfCurrentPlayerIsComputer()){
gameManager.playAutoMovesForCurrentPlayer();
gameManager.setNextPlayer(); // it does current player property = next player
//update board on scene
currentBoardPaneIndex = ((currentBoardPaneIndex + 1) % gameManager.getPlayers().size());
currentBoardPane.setValue(boardPanes.get((currentBoardPaneIndex))); //this is a recursive call
}
});
Instead of this, if I subscribe a listener to the currentPlayer property in GameManager then I still need to call setNextPlayer() from that listener which is again recursive.
I can make a special case if all players are a computer, then run the game from a while(true){} instead of listeners and binds but there has to be a better way to break this recursion.
Is there a way to not get into recursion while still having listeners and binds?
Notes:
currentBoardPane signifies the current game board on the screen and it's an ObjectProperty.
Making the following assumptions about your code:
Everything is currently running on the FX Application Thread
The currentBoardPane.setValue(...) causes the UI to update (so you update the UI each move)
then a "quick and dirty" way to do this is:
currentBoardPane.addListener((e) -> {
if(gameManager.checkIfCurrentPlayerIsComputer()){
gameManager.playAutoMovesForCurrentPlayer();
//update board on scene
Platform.runLater(() -> {
gameManager.setNextPlayer(); // it does current player property = next player
currentBoardPaneIndex = ((currentBoardPaneIndex + 1) % gameManager.getPlayers().size());
currentBoardPane.setValue(boardPanes.get((currentBoardPaneIndex))); //this is a recursive call
});
}
});
This delegates the updates to a new Runnable, schedules that runnable to execute on the FX Application Thread, and exits the handler immediately. Thus the call to currentBoardPane.setValue(...) is executed later and is no longer recursive.
In fact, if you do just a little more work:
private final Executor aiExecutor = Executors.newSingleThreadExecutor();
// ...
currentBoardPane.addListener((e) -> {
if(gameManager.checkIfCurrentPlayerIsComputer()){
Task<Void> makeMoveTask = new Task<Void>() {
#Override
protected Void call() {
gameManager.playAutoMovesForCurrentPlayer();
return null ;
}
};
makeMoveTask.setOnSucceeded(e -> {
//update board on scene
gameManager.setNextPlayer(); // it does current player property = next player
currentBoardPaneIndex = ((currentBoardPaneIndex + 1) % gameManager.getPlayers().size());
currentBoardPane.setValue(boardPanes.get((currentBoardPaneIndex))); //this is a recursive call
});
aiExecutor.execute(makeMoveTask);
}
});
then this is exactly the code you would use if computing the move took enough time that it would not be acceptable to block the UI while it was happening. (And if computing the move takes very little time, this will still work just fine.) This assumes that playAutoMovesForCurrentPlayer() doesn't update the UI.
Okay, so our assignment is to create a Guessing Game where the user inputs a number and the text foreground is supposed to change to either red if it is too high, blue if it is too low, or green if it is exact.
Our teacher has posted code that does that, and it is quite simple and I can understand it. Problem is, when I try to reformat it for what I need I get the JFrame, I get the text field where I can input it, but when I click submit it just like freezes. I suppose it has to do with how the action listener is written, but I am not sure.
Any help would be appreciate.
Here's my code, edited so just that specific part is shown"
button.addActionListener(
new ActionListener()
{
#Override
public void actionPerformed(ActionEvent arg0)
{
userInput = keyboard.next();
if(Integer.parseInt(userInput) > randomNumber)
{
tf.setForeground(Color.red);;
}
else if(Integer.parseInt(userInput) < randomNumber)
{
tf.setForeground(Color.blue);
}
else if(Integer.parseInt(userInput) == randomNumber)
{
tf.setForeground(Color.green);
}
}
}
);
}
while(true)
That's the problem. Don't block the EDT (Event Dispatch Thread). The GUI will 'freeze' when that happens. See Concurrency in Swing for details and the fix.
I'm making a above mode 2D Zombie Shooter, and I'm having some problems with a thread. here's the deal. I had the character shoot a bullet every time i pressed space. the problem was that if you held space, it would shoot one, then pause, and then shoot a lot of bullets. there were a bunch of ways to fix this, but i want this way because it leaves room for future changes to shoot speed. here is the code for the thread that is causing the problems:
package threads;
import Game.GameCore;
public class Shoot extends GameCore implements Runnable {
/**
* WHEN I START THIS THREAD, THE ENTIRE GAME FREEZES, AND I DO NOT KNOW
* WHY... NEED TO FIX. IT DOES NOT FIX THE PROBLEM TO TAKE OUT THE "SHOOT"
* OR THE "SLEEP"...
*/
public void run() {
while (shooting && gameRunning) { // shooting is made true when space is
// pressed, and set false when space
// is released. gameRunning is true
// if the game is running, which it
// is. removing either of these
// doesnt work either.
player.shoot(); // player comes from the GameCore class, and
// represents the player entity. if i remove this,
// nothing changes.
try {
Thread.sleep(bulletShootSpeedMillis); // bulletShootSpeedMillis
// is equal to 1000, but
// makes no difference
// to change
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
so here is the dang problem. the comments kinda point them out, but ill list them. if i remove the obvious things, such as player.shoot(); or Thread.sleep(bulletShootSpeedMillis); or even one of the things in the while loop, nothing changes. the issue is that when i initiallize the thread, with
else if (key == Integer.parseInt(commands[6])) {
shooting = true;
new Thread(new Shoot()).run();
}
the entire game just freezes. nothing happens at all. the moment i start the thread with space, my game freezes, and i cannot figure out why!!! the previous version with:
else if (key == Integer.parseInt(commands[6])) {
player.shoot();
}
it works just fine. Please help! Thanks in advance! :)
EDIT: thanks for the quick answer. needless to say, major learning experience with simple mistakes XD
Ayyyy!
new Thread(new Shoot()).run(); // ***** !!!!
You don't start a Thread by calling its run() method, since all that does is call the code in the same thread as the calling code. You start a new Thread by calling its start() method.
I am programming a chess game in java, and at the moment I am building a basic interface. It is simply an 8x8 array of buttons that will display in a window. I have coded for these buttons, and have gotten the board to display properly. However, when I connect this with the rest of the game, the game window crashes upon running and I have to force quit the java application. This is my code:
package Chess_Game;
import javax.swing.SwingUtilities;
import Chess_Interface.Iboard;
public class Game_Tester
{
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
Game G = new Game();
Iboard I = new Iboard(G.getBoard().getArray(), G.getSides());
I.setVisible(true);
while(!(G.isGameOver()))
{
boolean redo = true;
while(redo)
{
int row = 0;
int col = 0;
int nRow = 0;
int nCol = 0;
System.out.println("Click the piece you want to move.");
while(!(I.getBool())){}
if(I.getBool())
{
row = I.getRow();
col = I.getCol();
I.setBool(false);
}
System.out.println("Click the place you want to move to.");
while(!(I.getBool())){}
if(I.getBool())
{
nRow = I.getRow();
nCol = I.getCol();
I.setBool(false);
}
if(G.canMove(row, col, nRow, nCol))
{
G.move(row, col, nRow, nCol, I);
redo = false;
}
else
{
System.out.println("You cant move there! Try again!");
}
}
I.updateBoard(G.getBoard().getArray(), G.getSides());
}
}
});
}
}
The board displays properly when I comment out the main while loop (and everything inside of it), and I assume the problem lies somewhere inside there, but I have been unable to find it. I have also looked online for similar game loop problems, but all of those have been for games involving frame rates and movement across a java swing frame, something that is not present in my code.
Any help would be greatly appreciated.
You have several loops such as
while(!(I.getBool())){}
which could potentially run forever if I does not respond as expected. You could start by printing something out within these loops, and within the following blocks if(I.getBool()){...} to see at what point your application gets stuck.
Checking the user interface in a loop like this is not good practice. It is better to use Listeners to respond to the user interface.
Nor is running the main application on the Swing thread using SwingUtilities.invokeLater(new Runnable(), even though it avoids potential problems of updating the GUI from another thread.
In fact, this may be your root problem, as running the main application loop on the Swing thread (the thread used to run the GUI) like this probably prevents the GUI from ever responding properly. You are putting a task (the entire game) onto the GUI's queue, but that task never completes while(!(G.isGameOver())).