I'm currently working on a chess project.
I've set up a working code from console, and im working on setting up a GUI with swing. Debugging my application, I saw that my main and my GUI runs in different threads, so I came to the following question.
Is there a way to put my main thread to sleep while waiting for the user to click on a chess piece, then resume after the click?
To contextualize, I have a 8x8 array of buttons (board[i][j]) and for each button I set up a custom action that saves i and j into 2 static variables I declared into my main. So that after the button is clicked, I send the coordinates of that button to my main code that operates on the "real" matrix of chess pieces calling methods for controls.
Is that the correct way to go about this?
Is there a way to put my main thread to sleep while waiting for the user to click on a chess piece, then resume after the click?
It is the wrong way to think. A GUI should be event driven, rather than working in an infinite loop waiting for input (or for main to get input).
But the problems are (usually) from trying to 'match up' a command line based app and an app. with a GUI.
I say that because it sounds like the command line based app. did not go to the trouble of creating data structures for a ChessGameModel that can be acted on by the players and potentially shared amongst different classes that might need to interact with it. Classes like .. a command line based front end, or the various classes of a GUI, or a server that is running chess games between people over the net or..
Build the ChessGameModel and the rest will be a lot simpler.
What if when you click on a button you set a variable which is checked continually by your "main thread".
//In your GUIClass (GUI Thread)
btnInput1.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
oProcess.setInput("Forward");
}
});
//In your Process Class (Main Thread)
private String input;
public void setInput(String input){
this.input = input;
}
public void checkInput(){
while(true){
if(input.equals("")
{
//Do nothing
Thread.Sleep(1); //Sleep so your loop doesn't use 100% of your processor
} else {
if(input.equals("Forward")
{
//Do the action
}
}
}
}
But you need to share the instance of your process class with the GUI Thread so you can use the same variable.
(Sorry for my spelling)
The answer to this is: Yes, but you shouldn't.
Putting a Thread to "sleep" is wasting CPU cycles. Instead you should strive to make the stuff you do on your main-thread after recieving input in a more "event-driven" way.
First off you should already have some class that contains the board. If you haven't: now's the time ;)
The next thing you want to do is to not make that class your GUI, because the GUI shouldn't be concerned with the gamelogic.
and then it's getting simple, assuming following GUI field:
private Board board = // your actual board;
// assuming Java 8
button.addActionListener((event) -> {
board.recieveAction(i, j);
});
Related
I have recently been developing a game for android. The game is of a similar format to the classic Pokemon games (quite complex). I have got quite far without any problems. However, I am finding it difficult to develop the dialogue (typewriter text) boxes that appear at the bottom of the screen when someone is talking. I am stuck on waiting for any input without blocking the render and update methods (as they all run on the same thread).
This is a simplified version of my game loop, outlining the structure and what I do each frame. The update method shown is called through the View#onDraw method.
public static void update(Canvas canvas, GameView view){
//time operations (calculating delta etc.)
long cTime = System.currentTimeMillis();
delta = cTime - time;
time = cTime;
globals.put("time", time);
globals.put("delta", delta);//set vars for scripts
camera.applyToCanvas(canvas);//apply camera matrix to canvas
if(map != null)map.update();
if(battle != null)map.update();
Effect.updateAll();//update everything (game logic)
render.load(canvas);//load the canvas into my custom render engine
render();//call render method (shown below)
view.invalidate();//reset view for redraw
}
public static void render(){
render.reset();//clears the canvas using canvas.setColor(Color.BLACK)
if(map != null)map.draw();
if(battle != null)battle.draw();
if(dialog != null)dialog.draw();
if(gui != null)gui.draw(); //draw everything using the renderengine
}
As you can see, these operations update all the game components (map, battles, guis etc.) and then renders them to the screen. By looking at the code, it's clear that I'm running these operations on the same thread, so this thread can obviously not be blocked (otherwise the game will just stop).
This is where my problem is. I use an in game gui with a few buttons. These buttons are assigned to 8 integers (0-8) and when the up button is pressed for example, that input data is passed through the game to the existing dialog or battle or whatever needs it. These buttons rely on the main activity's touch events where the MotionEvent which, as a result of running the game loop off of the onDraw method, tuns on the same thread as the game itself. Here is how I handle dialogs:
I use javascript (rhino parser) as follows (passing a dialog object to the script in the variable 'dialog'):
var d = dialog.show("Hello! How are you.");
To get the input, I call the getInput method which takes in the dialog, and up to 4 strings as selection options. This method is supposed to return an integer value. This can be called through the script as follows:
var response = dialog.getInput(d, "I'm fine, thank you!", "Who wants to know.");
The getInput method is as follows in my Dialog class:
public static int getInput(Dialog d, String... args){
d.waitingForInput = true;
d.lastInput = -1;
while(d.waitingForInput || d.lastInput == -1){
//render options
//main thread is obviously blocked here.
}
return d.getLastInput();//returns the d.lastInput and resets waitingForInput and lastInput. The script can then use this value to decide what to do.
}
Now my main question is how to run this method without blocking the render and update thread. More specifically setting the value of d.lastInput and d.waitingForInput when the user touches a certain region of the screen (where the gui select button is).
If there are any doubts about what I am trying to ask in this question, please leave a comment as I am quite tired and have spent some time trying to solve this.
EDIT:
I have thought about running the input on a separate thread but this will still lead to blocking other input methods from being called (such as changing the selected option in the dialog).
If you don't want to stop the threads and you are already half way through
Method1: Use ConcurrentLinkedQueue, ArrayBlockingQueue and its families as static variable and put your values inside it.
Method2: you use can use TCP/UDP sockets using localhost adapter like a message queue system and try to get those values with the same ConcurrentLinkedQueue, ArrayBlockingQueue technique
Try to refer any opensource java game engine source codes and identify how they did or you can use those game engines, like "jMonkeyEngine" "LWJGL" ...etc
I have decided to approach this through a form of event handlers instead. When the required input is down, the specified script is run by the game.
I wrote a simple little maze game for a terminal which repeatedly asks the user to do something (e.g. "In which direction would you like to go? [N/E/S/W]"). I have a navigate() method running in a loop that fires off these questions, stores their answers and does something depending on the answer.
public enum Dir (N, E, S, W);
public void navigate() {
Dir nextDir = utils.askDirection("Which way do you want to go?");
// Do stuff with answer, like changing position of user in maze
}
Now, I've written a simple GUI for my game. I deliberately put all the references to the terminal in a ConsoleUtils class which implements a Utils interface (this has methods like askQuestion()) - the idea being that I could create a GuiUtils class and have my game either as a terminal game or as a GUI game.
The problem is that the navigate method asks the user a question and then "waits" for the response, which the Utils class gives it by using a Scanner to read the newest line of input. However if I use Event Listeners for the new N/E/S/W buttons in my GUI, they fire off events regardless whether the navigate method has asked for one or not.
--> Image of GUI
Is there any way I can combine this or do I need to write a new navigate method for the GUI?
(To be honest, I'm also not entirely sure whether my GUI class should instantiate a game class, in which case the logic for navigate could end up in a GUI method anyway, or whether the game should have a GUI. I haven't written any code for the event listener either yet, since I'm not sure which class should be calling which. This is probably a separate question.)
Your text based game has a loop that repeatedly asks questions to gather user input. Swing provides this loop for you by continually executing Runnable blocks of code that have been posted to the EventQueue. For example, when the user presses a button labeled E, code is posted to the queue that invokes your ActionEvent implementation to handle your game's interpretation of the move east command.
For reference, a complete example of a very simple guessing game is examined here. In pseudocode, the corresponding text based game might look like this:
initialize
loop
prompt "Guess what color!"
get chosenColor
if chosenColor = actualColor
say "You win!"
reset game
else
say "Keep trying."
end loop
A more elaborate game cited there includes the original text-based source.
This question already has an answer here:
How to stop Java from running the entire code with out waiting for Gui input from The user
(1 answer)
Closed 5 years ago.
I'm a rather basic programmer who has been assigned to make a GUI program without any prior experience with creating a GUI. Using NetBeans, I managed to design what I feel the GUI should look like, and what some of the buttons should do when pressed, but the main program doesn't wait for the user's input before continuing. My question is, how do I make this program wait for input?
public class UnoMain {
public static void main(String args[]) {
UnoGUI form = new UnoGUI(); // GUI class instance
// NetBeans allowed me to design some dialog boxes alongside the main JFrame, so
form.gameSetupDialog.setVisible(true); // This is how I'm trying to use a dialog box
/* Right around here is the first part of the problem.
* I don't know how to make the program wait for the dialog to complete.
* It should wait for a submission by a button named playerCountButton.
* After the dialog is complete it's supposed to hide too but it doesn't do that either. */
Uno Game = new Uno(form.Players); // Game instance is started
form.setVisible(true); // Main GUI made visible
boolean beingPlayed = true; // Variable dictating if player still wishes to play.
form.playerCountLabel.setText("Players: " + Game.Players.size()); // A GUI label reflects the number of players input by the user in the dialog box.
while (beingPlayed) {
if (!Game.getCompleted()) // While the game runs, two general functions are repeatedly called.
{
Player activePlayer = Game.Players.get(Game.getWhoseTurn());
// There are CPU players, which do their thing automatically...
Game.Turn(activePlayer);
// And human players which require input before continuing.
/* Second part of the problem:
* if activePlayer's strategy == manual/human
* wait for GUI input from either a button named
* playButton or a button named passButton */
Game.advanceTurn();
// GUI updating code //
}
}
}
}
I've spent about three days trying to figure out how to integrate my code and GUI, so I would be grateful if someone could show me how to make this one thing work. If you need any other information to help me, please ask.
EDIT: Basically, the professor assigned us to make a game of Uno with a GUI. There can be computer and human players, the numbers of which are determined by the user at the beginning of the game. I coded the entire thing console-based at first to get the core of the game to work, and have since tried to design a GUI; currently this GUI only displays information about the game while it's running, but I'm not sure how to allow the code to wait for and receive input from the GUI without the program charging on ahead. I've investigated other StackOverflow questions like this, this, this, or this, but I cannot comprehend how to apply the answers to my own code. If possible, I'd like an answer similar to the answers in the links (an answer with code I can examine and/or use). I apologize if I sound demanding or uneducated and confusing; I've been working diligently on this project for a couple weeks and it's now due tomorrow, and I've been stressing because I can't advance until I figure this out.
TL;DR - How do I get my main program to wait and listen for a button click event? Should I use modal dialog boxes, or is there some other way to do it? In either case, what code needs to be changed to do it?
Unlike console based programming, that typically has a well defined execution path, GUI apps operate within a event driven environment. Events come in from the outside and you react to them. There are many types of events that might occur, but typically, we're interested in those generate by the user, via mouse clicks and keyboard input.
This changes the way an GUI application works.
For example, you will need to get rid of your while loop, as this is a very dangerous thing to do in a GUI environment, as it will typically "freeze" the application, making it look like your application has hung (in essence it has).
Instead, you would provide a serious of listeners on your UI controls that respond to user input and update some kind of model, that may effect other controls on your UI.
So, to try and answer your question, you kind of don't (wait for user input), the application already is, but you capture that input via listeners and act upon them as required.
I'm writing a 2D polygon and physics editor, one functionality is to set a rotation limit for joints.
To use this functionality, the user clicks and drags a line between the joint points which need to receive the limit.
The logic of determining if the pick is valid happens outside of the GUI code.
If a pick is found, I wanted to pop up a JOptionPane.showInputDialog where the user can input the limit.
Thing is, if I do it directly, the program becomes unresponsive, I figure it's because of threading.
I's there a way to define an event listener the GUI can use that doesn't require an actual GUI component?
I want to send an event that also contains a reference to the target object to that component, then telling it that a valid pick has been made and user input is required, and then send the value back via a method of the target object.
I am very inexperienced with Swing.
My hunch is that I might be able to add an ActionListener to the main window, but I don't know how I could address that listener specifically.
As in, how would I need to define an Action that only gets processed by that particular listener?
If that is actually possible, of course.
So far I have only used listeners to let the GUI talk to the logic, not the other way around...
Edit:
The program becomes unresponsive the movement I call
result = JOptionPane.showInputDialog(this,"Enter Limit.");
That just breaks it. Can't even enter anything into the textbox, nor close it, etc.
I figure it's because it spawns a modal dialog that pauses some thread, and calling it from somewhere in the bowels of non GUI code is just not the thing I should do, but I'm too inexperienced to know another way...
Edit2:
I should add that I can use JOptionPane.showInputDialog without any problems if I spawn it, for example, after clicking a button or choosing a popup menu option.
In fact that's how I rename the items I am working with.
But I assume at that point, the dialog is being spawned inside the GUI thread, or this Event Dispatcher queue thing.
The problem with this though is, that this takes visible, interactive GUI components that fire that event.
What I'd like, however, is some sort of component that would spawn JOptionPane.showInputDialog just like a clicked button or context menu would, but without having to be interacted with by the user, but instead by the code.
I guess I could use invisible buttons and emulate mouseclick events, but that's pretty hacky...
Also, I tried spawning Threads and Runnables which spawned the JOptionPane.showInputDialog, but that didn't help either.
Unless I spawn the JOptionPane from a GUI source, everything stalls, and the dialog won't work.
The publisher will have a public add/remove listener, where the subscriber will add itself or be added via another channel to the EventListenerList in the publisher.
You can create your own listener interface that extends EventListener and a function to shoot an event. Below is an example:
import java.util.EventListener;
public interface MyEventListener extends EventListener {
public void myEventOccurred(MyEvent event);
}
You can then create your custom event class, "MyEvent" in the example above like:
import java.util.EventObject;
public class MyEvent extends EventObject {
// customer fields and methods here
public MyEvent(Object source) //more possible args here {
super(source);
//other things here to do what you want
}
}
Now you can have your subscriber implement MyEventListener and override the myEventOccurred(..) method.
Another approach would be to use the SwingWorker class to execute the logic of determining the pick in a dedicated thread without blocking the GUI dispatch thread, and use its callback method to execute the GUI action (open the input dialog).
See : http://docs.oracle.com/javase/6/docs/api/javax/swing/SwingWorker.html
(This page has a better explanation of concept than I could write.)
It should be possible for your background thread to spawn a dialog with invokeAndWait():
final double[] result = new double[1];
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
try {
result[0] = Double.parseDouble(
JOptionPane.showInputDialog("Enter value:"));
} catch(NumberFormatException e) {
result[0] = -1;
}
}
}
// ... do something with result[0]
Here I made the result an array just so that it can be final (accessible to the anonymous class) and also mutable.
I have been working on a Java game for a while that I started back in my college days. After taking considerable breaks due to my professional career, I'm getting back to it and realizing how awful the code is. I basically had a "monolithic main" with both GUI and game logic in the same class file. What I'm attempting to do, is abstract and "componentize" the GUI into smaller chunks. My executed class extends JFrame which I add and remove panels to/from when buttons are clicked. Ex.
public class GameFrame extends JFrame{
private JPanel[] _panels = {new MainPanel(), new OptionsPanel(), new DifficultyPanel()};
private int _currentPanelIndex = 0;
public GameFrame(){
...
add(_panels[_currentPanelIndex]);
...
}
}
Within each panel class, I have private ActionListeners for the buttons. In MainPanel, I'm getting the singleton GameFrame instance and setting the current panel kind of like:
class SinglePlayerButtonListener implements ActionListener{
public void actionPerformed(ActionEvent e){
GameFrame instance = GameFrame.getInstance();
JPanel[] panels = instance.getPanels();
int currentPanelIndex = instance.getCurrentPanelIndex();
instance.remove(panels[currentPanelIndex]);
int newPanelIndex;
for(newPanelIndex = 0; newPanelIndex < panels.length; newPanelIndex++){
if(panels[newPanelIndex] instanceof DifficultyPanel){
break;
}
}
instance.add(panels[newPanelIndex]);
}
}
I do not like this deep of coupling in my classes, but I can live with it. However, the real problem is that when I click the last button that takes me into the game, I can't have:
public void actionPerformed(ActionEvent e){
GameFrame.getInstance().startGame();
}
because this will cause my game to run in the Java Event thread, thereby disallowing any other events from being handled. Previously, I had a busy while loop:
...
while(waiting){
//Do nothing
}
remove(_panels[_currentPanelIndex]);
startGame();
...
...
public void actionPerformed(ActionEvent e){
waiting = false;
}
What is the best way to let my GameFrame class know that I've clicked the play button? Can I send an event or message to it from one of its sub-panels telling it to start, and if so, how do I keep the game from running in the Event thread? Should I handle it in the actionPerformed() method and simply spawn a new thread? I would prefer to keep it in the main thread. Thanks.
Go for Slick 2D (a lightweight OpenGL 2D game development framework with lots of cool stuff) or Nifty-GUI.
Slick has also some examples and tutorials and is easy to learn, for example the StateBasedGame can easily be used to implement multiple in-game menus (such as main menu, settings menu, in-game options, in-game pause/resume etc.)
You should have the game logic executing on it's own thread of execution, possibly when the user clicks a button. I don't understand your prior approach with the while(wait) - that would still create problems if your game logic did some time consuming calculation that prevented the even thread from doing updates because the even thread does not stop executing when you call startGame().
EDIT:
It's not clear from the code you pasted that the GUI updates and the game logic are happening on seperate threads of execution - you might want to demonstrate that in your code.