Note: This thread is not about launching a compiled program from within another program. But rather about running another program logic in parallel to the main program.
In libGDX, a game is handled with screen. A screen has a specific kind of display and input. For example: Menu Screen, Game Screen and option screen.
In most basic game switching game screen is not really a problem. You know that from menu you can go to game or option and you know that when you finish option and game, you get back to menu. So you can actually hard code the destination screen in those class, it's like a "Goto Menu Screen".
One of my screen will be composed of sub-screen which is the same logic as screen except that it stacks multiple sub-screen displayed when that screen is active. Now I am trying to make some sort of hybrid video/board game engine. One of the sub screen could be "Chose a card from your hand", now in that case, there could be multiple situations where a card could be played from your hand. Which mean that when the card is chosen you actually don't know where to go next. For example, let's take that turn order sequence:
Draw a card
Play a card from your hand
Place that card into play
Play a card from your hand
Place that card in the discard pile
Now, you want to reuse the code of "play a card from your hand" to make sure you do not code the same thing twice. But here, "Play a card from your hand" don't know if it should next play the selected card into play or place the selected card into the discard pile. So it cannot use the "GoTo" method.
In fact I will need to have some sort of "Program" to change screen that would map the procedure of the game play. The game would first draw a card, then as the player to chose a card, then use the return value and place that card into play, etc. That works well in a regular program, but that seems harder to do in Libgdx, because the framework is real time. So after each executed command, I need to return the handle of the program to libgdx so that he can do proper animations and rendering. Else the program will simply freeze and wait for user input which will never work. So I need to run a program in parallel of the libgdx program that will tell libgdx which sub-screen to display according to the logic of the game.
So far, I found 2 solutions, but I was wondering if there was something else that I could use.
The first un-elegant solution is an instruction pointer. Like the processor is doing in assembly, remember the ID of the next instruction to run, have a huge switch case that will list all possible instruction. Each time render is called, it will check if the subscreen is finished, if yes, it will execute the next instruction. It could look to something like this:
Note: the code is not perfect, it's just for the illustration.
static int IP = 1; // instruction pointer
if ( subscreen_finished == true )
switch ( IP )
{
case 1:
hand.draw_card();
IP = 2;
break;
case 2:
hand.chose_card();
IP = 3;
break;
case 3:
play_card ( hand.getcard());
IP = 4;
break;
case 4:
hand.chose_card();
IP=5;
break;
case 5:
hand.discard ( hand.getcard() );
IP=6
break;
case 6:
end_of_turn();
break;
}
Each function call would set subscreen_finished to false. It basically wait for the user input, or wait for the animation to be completed before setting it to true.
As you can see, it's really not elegant and it could be very hard to follow the program especially if you want loops like " do 3 actions".
The second method consist in running a parallel thread that could work like this
hand.draw_card();
hand.chose_card();
hand.play_card ( hand.getcard );
hand.chose_card();
hand.discard ( hand.getcard );
end_of_turn();
Each function call would setup the right subscreen and enter a waiting loop until an answer is chosen by the player or the animations are completed. Looks much more elegant, but I must use multi-threading.
On another thread somebody suggested using state machine and messaging.
But the state machine does not quite work for me. Because in my example above, if the game is at the "chose a card from hand" state, in order to know which state to do next, it needs to know all the previous steps that were accomplished. Or know that we are at step 4 and that the next step is 5 because "chose card" could be called at step 2 or 4.
Is there any other solution available? It's really hard to find documentation or other implementation of something similar, because most application are not real time like it's the case of video games.
Related
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 trying to develop a version of rock, paper, scissors, lizard, spock using Java's Swing UI. I've successfully been able to create frames to select player 1 and player 2 and which rules the game is won by (best 2 out of 3, play till quit, single round), and that run the actual game. But I'm having trouble looping the game screen if the user want's to play, say best 2 out of 3. I had originally coded the program just using the console output(Scanner), but now that I am trying to implement the Java Swing UI. And I can't seem to figure out how to loop round after round without producing all of the game screens at once.
For example, here I have a method I call playRound(). After adding 1 to the round counter, this method constructs class GameWindow extends JFrame implements ActionListener
public static void playRound() {
++round; //Simple int counter to keep track of round
GameWindow oneRound = new GameWindow();
oneRound.setSize(400, 150);
oneRound.setLocationRelativeTo(null);
oneRound.setVisible(true);
Inside the GameWindow class, I have 5 ActionListeners on the 5 buttons the user can decide to play(rock, paper, scissors, lizard, or spock). The ActionListeners identify which button was pressed, then triggers the rest of the game logic, as seen below.
#Override
public void actionPerformed(ActionEvent e) {
String move1 = "";
Object source = e.getSource();
if (source == rockBtn) {
move1 = "rock";
} else if (source == paperBtn) {
move1 = "paper";
} else if (source == scissorsBtn) {
move1 = "scissors";
} else if (source == lizardBtn) {
move1 = "lizard";
} else {
move1 = "spock";
}
String move2 = Game.p2.move();
Game.p1.learn(move1, move2);
Game.p2.learn(move2, move1);
this.dispose();
Game.score(move1, move2);
}
I'm fully aware that if I use a while loop along the lines of
while (round < 3)
playRound();
I'm going to get three GameWindows to pop up all at once. Am I stupid, or is there a way to close the window other then this.dispose() and get a new one to trigger/open so the user can play again?
Sorry if this is very sophomoric, but I've been scouring JavaDocs trying to learn the answer. The closest thing I can figure out is that I'm looking for a WindowEvent, but I'm not sure where to place the listener for it, or what action I would need it to trigger. If you just tell me I'm an idiot, I'll go bury my head in the sand and be done with it, but any advice would be greatly appreciated!
If I understood your problem, you want to have three rounds, each time redoing the same logic but keeping the score as a "global variable" for the three rounds, giving user the opportunity to restart again or close entire application after the three rounds are completed.
I'll give you a pratical idea of how I'd make this implemented:
I suggest you to move main coordination logic in a main method, and keep the rest as you posted, with a little modifications.
You can just make your playRound() method returning a ResultDTO object instead of void; this DTO can be a simple POJO object containing all the variables representing the data you want to globally maintain (for example in a ResultDTO[] array with 3 elements, filling one position for each round), filling it in the playMethod()'s logic and managing the return in an external caller main method. After the three rounds you can just check for result in the main method, print out a dialog showing the results you want to show, and then ask user a yes or no option with JOptionChooser. If user wants to play again, just repeat this whole logic, in the other case you can call System.exit(0) to close application or do whatever you want first (save a file with memory data, print a goodbye message, and so on, it depends on your imagination and how you want to implement this, just be creative).
To ensure your application will not close at the end of a round, you can use oneRound.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE) to avoid application exiting when calling dispose() on your frame.
Im creating an uno game and it is almost fully functional and i'm using javaFX to create it. It is Computer vs User and the problem is that when a user clicks on a card button, the middle card is supposed to be replaced with that card and then the computer goes, however what ends up happening is that the computer goes right away and so you only see the computer's card played in the middle. I am sure this has something to do with how i structured my code specifically the action event pertaining to the button clicked. However, since this is my first ever java GUI and i am fairly new to java i am struggling to understand how to structure it so that i am able to show the user's move. Also due to this, i am unable to implement a skip card even though i have tried using a boolean and creating another method i think the main problem lies within how the main gameloop and the actionevent inside is set up.
This method is called and it checks for a button click and then gets the index of the button in the player's arraylist/hand/ The boolean was my attempt at implementing a skip card but what kept happening is the computer would always play right after the user's move when a skip card was played.
public void gameLoop(){
for(int i =0; i<buttonList.size();i++){
buttonList.get(i).setOnAction((ActionEvent)->{
indexOfHandButton = buttonList.indexOf((Button)ActionEvent.getSource());
humanMakeMove();
if(!isReverseTurn()) {
computerMakeMove();
}
});
}
}
This method used the index given from the gameloop actionevent and makes the actual move in the backend. It then clears the hbox containing the users hands and calls showhumanHand which fills it up with the updated cards and similarily with the middle card. The if statements to try and implement the skip cards have not worked, i have also tried creating a new action even inside the if statement and creating a method or recursively calling humanMakeMove but of course the index will be the same and will cause an error.
public void humanMakeMove() {
String result = human.makeMove(game, theDeck, indexOfHandButton, computer);
if(result.equals("skip")){
setReverseTurn(true);
}
hbHumanHandBtn.getChildren().clear();
hbMiddleCard.getChildren().remove(middle);
middle = generateMiddleCard();
hbMiddleCard.getChildren().add(middle);
showHumanHand();
System.out.println(">>>>>>>>>>>>>>>>>>>>>>>" + buttonList);
System.out.println(result);
if (middleCard.getType() != null) {
if (middleCard.getType().equals("skip") && isReverseTurn()) {
System.out.println(isReverseTurn());
gameLoop();
setReverseTurn(false);
}
}
}
So my main question is how can i restructure this or add something that allows for the user's card to show in the middle before the computer goes right away, i have tried a timer/sleep method too. And my skip card doesnt work but i think that has to do with how i set up my action listener which is messing up two problems. Thank you for reading this and let me know if you have any input!
I am creating a game where the user must tap the screen faster to allow them to go faster in game, however I have encountered some problems. I have made the game so it calculates the amount of taps per minute from the users last tap and their current tap, however this method seems to be jerky and does not work too well. I also cannot work out another way to do it, so that the when they don't tap at all, it slows down.
How would I go about creating this mechanism for the game where the faster the user taps, the faster the game goes, and if they don't tap at all it slows to a stop.
Thanks
Here is a snippet of what I have so far, calculating the Taps Per Minute (TPM) of the user. (This is in the on touch method). I am currently passing the TPM into an update method which moves the background by TPM/100 each time it updates (it's running at 30FPS)
if (thisTouch == 0 || lastTouch == 0) {
Log.d("info","First Touch");
thisTouch = lastTouch = System.currentTimeMillis();
} else {
Log.d("d","touch");
thisTouch = System.currentTimeMillis();
long difference = thisTouch - lastTouch;
TPM = (int)((1000*60)/difference);
lastTouch = thisTouch;
}
I would like to know how I can change this so that the game speeds up when they click faster, and then slows when they do not touch the screen.
Maybe you could do something like this:
Create a PriorityQueue< Long>
Whenever the user taps the screen, add (currentTime + someTimeOut) to the queue
Whenever you are going to check the current speed (eg size of queue), first remove all elements > currentTime.
Don't forget to add appropriate thread safety measures if you do something like this of course.
Not to be "that guy" but it sounds like your current plan of taps per minute is pretty good but just implemented badly. However, I would strongly recommend a smaller time quantity such as taps per three seconds since games are usually fast paced and having to wait a whole minute to see your character speed up or slow down may produce a sense of delayed lag.
Alternatively, you could could use some form of acceleration that is increased up to a maximum limit every time the screen is tapped and decreases over the time as the screen is not tapped.
Now that I see you updated your question with some code, I'd like to point out that a tap is a touch and release from the screen not necessarily a touch. I honestly don't know from your code whether or not you're compensating for this so this may be the source of some of your problems.
Lastly, for game development algorithms and theory you may want to see this StackExchange site: https://gamedev.stackexchange.com/
It sounds like you're very close to getting your game to feel the way you want it to, good luck!
Your general approach is pretty much the only way to do it, it just needs some fine tuning.
Keep a general TapsPerTime variable. With each new tap you register, do not replace the TapsPerTime, but calculate a new, weighted value:
TapsPerTime = (TapsPerTime * X) + (MeasureTapsPerTime * (1-X))
The factor X you need to find empirically (by trying out what works best for you). The general idea here is that each measurement will only nudge the used value a bit into the right direction.
Also, if you do not detect a tap for a set amount of time, simply update the TapsPerTime with the same formula, but use 0 (zero) for MeasureTapsPerTime. So if the user does not do anything the value goes down.
In a simple card game (human vs. CPU) the logic works, but I want to delay the computer's turn.
I have tried using Thread.sleep(int milliseconds) which works, but it messes up the order images are displayed. I'm not using a game loop, I am just dynamically updating ImageViews whenever cards are changed. The problem with Thread.sleep is all the images only update after Thread.sleep, there is no displaying only the human card before Thread.sleep. The human's card and computer's card display after Thread.sleep.
I've used Thread.sleep like so:
playPlayerCard(player); // Human first
displayPile(); // Display card pile (ImageView's)
player = nextPlayer(player); // Get's next player in Player mPlayers List<Player>
// Wait for computer to 'Think'
Thread.sleep(500);
playPlayerCard(player); //Computer's turn
displayPile(); // Display card pile (ImageView's)
Am I using Thread.sleep() wrong? Is there a better/correct way? I've searched online and tried using new Thread(), using handler.postDelayed(Runnable r, long milliseconds) and also CountDownTimer but none work since my variables: playPlayerCard(player); aren't final variables.
I've always had problems delaying actions and the images appearing at the correct times. Any suggestions? Thanks in advance.
Couldn't you just implement the Computer Playing logic in a AsyncTask and fire it when the human turn is done ?
I think it would make much more sense, that way, as soon as the computer is done "playing" you can determine the actions to take in the onPostExecute() method, in your case I think that would be dealing cards.
It would also be really simple to block user inputs while the computer is playing, either with a progress dialog (which isn't all that pleasent for a game I understand) or simply by disabling buttons :)
Here's the documentation for it.
Hope this helps!
I used the solution from #Jakar and changed my variables to class-scope in order to use the Handler and Runnable correctly. This worked, the delay works correctly using
Runnable r = new Runnable() {
public void run() {
playPlayerCard();
}
};
mHandler.postDelayed(r, 500);
To clarify the solution, I had to take out the arguments from playPlayerCard(Player player) and use a class-scope Player mPlayer; variable in playPlayerCard() instead.