I'm trying to build a text based D&D type game, and I'm stuck on how to let the user call a method at any time during the game.
The game will run its course, and if the user decides at any time they want to take a peak at his/her stats, the user will type "character sheet" and all his stats etc. will show.
My only idea to go about my problem is to to use:
if( variable.equals("character sheet"))
callMethod();
but this only works once.
Now even if I put it in a loop, yes, it would let me do it as many times as I want, but it won't execute the rest of the program...
Without the loop it will let me do it once, and execute the rest of the program but will never let the user type Character Sheet and open the method ever again.
/////////////////
import java.util.Scanner;
public class MainGame
{
public static void main(String[] args)
{
Scanner input = new Scanner(System.in);
String characterSheet;
CharacterCreation create = new CharacterCreation();
System.out.println("Choose a race:");
System.out.println("Race List:\nDwarf\nDark Elf\nHalfling\nHuman");
create.stats();
System.out.println("If you want to see your character sheet in the future type 'character sheet'");
characterSheet = input.nextLine();
characterSheet.toLowerCase();
if(characterSheet.equals("Character Sheet"))
create.getStats();
}
}
Well, the big question is: is your game running whatever the user does, or does it run in step with each user action? In the second case, you need a simple loop:
while (isRunning){
getUserInput();
updateGameWorld();
}
If the game runs independently of the user's action, you'll need 2 threads: one that will update the world regularly, and one that will listen to the user inputs and adapt the world to them.
I'd suggest you read about "game loops", but be warned that they usually about drawing graphics in frame, which may dilute their general purpose. But basically you have one game loop that renders the world, and another thread that handles user actions.
Related
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);
});
I´ve been working on a GUI and I´ve run into some problems with a JMenu. The GUI is in a separate class that takes all the actions of the program from the rest of the classes. My problem with using the menu is that I want it to do 2 things: first, to show the correct panels based upon a user choice and second, wait for user input to complete the chosen task.
I´ve arranged it into 13 different if.. else clauses depending on the user choice, this part works correctly with the nescessary input options (panels) shown that the user need to input data.
Part two when the user sees the right panels and wants to input information (int and Strings) is where things don´t go as intended. Instead of waiting for user input and then take actions based on those data the program rushes forward and continues. Since no data is entered, needless to say, the output is not the intended one.
I´ll provide part of the class as it´s quite large.
class Employee implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
if(e.getActionCommand().equals("1"))
{
panelB.setVisible(false);
panelC.setVisible(false);
panelD.setVisible(false);
display.setText(bank.infoBank()); }
else if(e.getActionCommand().equals("2"))
{
panelB.setVisible(true); //Show all panels
panelC.setVisible(true);
panelD.setVisible(true);
label2.setText("Accountnumber: ");
text2.setText("");
display.setText("");
}
...
else if(e.getActionCommand().equals("5"))
{
panelB.setVisible(true);
panelC.setVisible(false);
panelD.setVisible(true);
display.setText("");
if(e.getActionCommand().equals("Ok") && !pNrText.getText().isEmpty()) //This is a JButton that when pressed should send the data to the method
{
if(checkInput(pNrText) == true) //Method to validate input
{
pNr = Long.parseLong(pNrText.getText()); //pNr is an input field
bank.addSavingsAccount(pNr); //this is a method from another class
}
else
{
JOptionPane.showMessageDialog(null, "Only digits permitted!");
}
}
This last part (actioncommand equals 5) is one of the places where the program doesn´t wait for the user to input anything before it continues and thus receives no input at all to process.
This is part of an ATM-program built around different JMenus, in another place where an JRadioButton is used it works as intended but I can´t get it to work using the JMenu and I don´t want to use a JRadioButton with so many choices(13).
Any input greatly appreciated!
/Johan
"This last part (actioncommand equals 5) is one of the places where the program doesn´t wait for the user to input anything before it continues and thus receives no input at all to process."
else if(e.getActionCommand().equals("5")) {
panelB.setVisible(true);
panelC.setVisible(false);
panelD.setVisible(true);
display.setText("");
if(e.getActionCommand().equals("Ok") {
I don't know why you would expect this behavior. This is not a console program where a scanner waits for input. Event driven programming doesn't work like that. One event get's one response. There's no waiting. Everything in the actionPerformed happens exactly once. That means when you press 5, the corresponding if will perform. The OK-if will never be performed because no event will ever reach it because it's trapped in the 5-if. Quickes fix, would be to give the OK-block it's own else-if on the same level as the 5-if
Like I said in my comment. Avoid all these if statement. Add an anonymous listener to each menu item.
okItem.addActionListener(new ActionListener(){
public void actionPerforemd(ActionEvent e) {
}
});
But you can even excel beyond this and use Action. Personally I prefer to go this route for menu items, for a number of reasons.
Also as an aside, you should be using a CardLayout to switch between panels.
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.
I have developed virtual keyboard module, it contains 2 classes
KBM (the module itself) (on enter press it sets value of String data to the text i typed in KBMListener, and Boolean changed to true in KBMListener)
KBMListener
MainFrame
What is doing mainFrame:
When I run the program MainFrame loads the GUI and starts "while(true)" loop in "public void run()". This loop look like :
while(true){
if(status_changed){
jTextArea.setText(getKbml().getData());
getKbml.setStatus_changed(false);
}
sleep(500);
}
The boolean status_changed is changed in a keyboard Listener.
KBM is the virtual keyboard. When the user type text and press enter, it set the String data to text typed and boolean status_changed to true in KBMListener.
KBML just connects the MainFrame with KBM and loads the keyboard from KBM everytime the user clicks into textarea in mainframe.
What I want is every 0.5 sec or instantly get value to mainframe when enter is pressed.
While loop is working good, but cpu usage is around 12% on 1.6GHz dualcore processor.
I heard about callback but I can not understand how it works. I hope somebody can help me... Try to avoid document listener please.
What you'll want to look into is the Observer design pattern. It uses an interface to notify 'listeners' of changes, and is often the answer to infinite loops. You can find a simple implementation example + more information here : http://java.dzone.com/articles/design-patterns-uncovered
Or simply search the web for "observer pattern java".
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.