I am creating my first game in Java. The game is Monopoly. I am struggling with how I should design the game to model its turn-based structure (managing player turns). I want to allow for both a single human-controlled and one or multiple AI-controlled players to play the game.
My specific issue is that I do not know whether to implement a game loop or not, meaning a loop which can manage the players and the variables directly related to the game of Monopoly, (think of things such as prompting each player for their turn, incrementing the turn to the next player, or getting dice rolls from each player—in turn). I am not referring to the more low-level meaning of the term “game loop” which relates more to drawing frames on the screen, updating physics, or updating AI at a specific rate of time.
My understanding is that my options for trying to implement what I need are either to:
Implement a completely event-driven program which has no such game loop, or
Implement a game loop—something that is long-running in the background and basically never-ending as long as the game is running. This would be the more procedural approach.
When I first started trying to solve this issue, I ran into problems of my UI freezing because my game loop was never-ending and was completely consuming the thread on which it was running (I just made a very simple while loop to illustrate this). So I went to the effort of creating a SwingWorker to encapsulate my game loop. That solved the issue of UI freezes, but still left me wondering if I was going down the wrong path.
As a general rule, I found that most advice on the web generally seems to favor any approach which is event-driven, and thus my current implementation utilizing a SwingWorker could be a step in the wrong direction. But I cannot fully grasp how I would implement a completely event-driven system for this specific task (meaning no game loop present). It seems to me that a loop has to exist somewhere for managing the player turns.
Here are my specific questions:
Are game loops (as I am describing them) appropriate for turn-based games such as Monopoly—specifically for queuing the player turns and prompting the appropriate player for their turn, one player at a time (and queuing the entire procedure of/sequence of steps that comprise a turn)?
If a purely event-driven system were to be created for managing player turns, how do you iterate through each player to prompt them for their turn and keep iterating until the game ends?
If a game loop were to be used to solve the specific problem described above, does it have to be run within its own thread (possibly using SwingWorker) in order to avoid freezing the UI? My situation is Java-specific, but I suppose I would be interested in answers for non-Java-specific situations as well.
Currently, I have my code organized using the MVC pattern. My controller is where my game loop (the actual SwingWorker thread) resides. It is far from complete, but it helps illustrate how I am managing player turns in what I am calling a "game loop".
SwingWorker code from controller:
swingWorker = new SwingWorker<Void, Model>() {
#Override
protected Void doInBackground() throws InterruptedException {
gameLoopRunning = true;
while (gameLoopRunning) {
//to do: use a timer instead of thread.sleep
Thread.sleep(1000);
//user turn prompt
if (model.getActivePlayer().isUserControlled()) {
boolean userRolled = false;
while(!userRolled) {
System.out.println("Roll the dice please...");
Thread.sleep(3000);
}
}
//bot turn prompt
else {
//insert code for bot rolling dice here
model.rollDice();
}
publish(model);
Thread.sleep(1000);
model.incrementPlayerTurn();
publish(model);
}
return null;
}
#Override
protected void process(List<Model> chunks) {
Model gameModel = chunks.get(chunks.size() - 1);
//hard-coded for 6 players
for (int i = 0; i < 6; i++) {
view.getPlayerPanel(i).setTurn(gameModel.getPlayers().get(i).isTurn());
}
view.getGamePanel().getDice().setDie1(model.getDie1());
view.getGamePanel().getDice().setDie2(model.getDie2());
}
};
swingWorker.execute();
The comment from SirDarius is spot on.
Though, for something as simple as advancing player turns, you don't really need to bother implementing a full fledged finite state machine.
In terms of MVC, this is what you should do for human players:
The Model: Provide methods for advancing the active player to the next player and for running through the "turn process" (i.e. rolling the dice, moving the active player's token, etc.). Because much of the turn process is event driven, these method calls will be made from event listeners in the controller.
The View: Raise an event when the active player finishes their turn, as well as raising events on various other input.
The Controller: Whenever a player finishes their turn, tell the model to advance to the next player, and start the "turn process" again. Whenever a player provides input, an event will be fired that tells the model to advance to the next stage of the turn.
For AI players, the majority of the same code can be used, but it does not make sense to have the turn progression be driven by the view. Instead, the model would need to have another "turn process" method which would be specifically for AI players. The only difference being that the code would execute in succession without waiting for input from the view, instead of being a series of event listeners.
Related
I am only a beginner in Java and until now I just put the functionality into the addActionListener() method of the buttons, it was enough for little games and stuff.
But now I am trying to make it seriously and I am wondering how to connect those 2.
As an example I am making a Fuchimi game, so I have my classes for the actual game and then a class that builds the frame with everything needed.
But my actual problem right now is, that after the frame is created, it doesn't do the following code since the code pauses at the window, like here:
FuchimiUI ui = new FuchimiUI();
//The following is not executed
Hand playerHand = null;
while (playerHand == null) {
playerHand = ui.getPlayerHand();
}
Hand enemyHand = generateHand();
ui.changeEnemyText("Enemy picked " + enemyHand.toString());
if (enemyHand.beats(playerHand)) {
ui.changeGenText("Computer wins!");
} else
ui.changeGenText("You win!");
The buttons I have just change the hand of the player.
So how can I do that properly, having the game code being compiled while the frame is already open?
I thought about threads, but I have too little knowledge about them, thus I don't know if that would be a good way.
Edit:
The ui.getPlayerHand() method returns the chosen hand(rock, paper or scissors) that the player has chosen through the buttons.
Of course I could have written the whole code in each of the button's addActionListener()methods, but I doubt that's the proper way of doing that.
So in general, all I wanted to do is let the player choose his hand and then let the game generate a random hand, then compare those two and change the text of one of the labels, depending on wether the player won or not.
The problem you are having results from the fact that your while loop is blocking the UI thread. You need to offload it to a different thread and then enqueue the UI updates back on the UI thread. The same situation is encountered here, please have a look.
There are several ways to fix this. One of them is the SwingWorker.
The steps are:
Override doInBackground for your while loop.
In it, call publish to store intermediate results (like the messages you want to display).
Override process to display the intermediate results in your UI.
The third page of above mentioned tutorial covers this.
As much as I agree with Domi's answer, that long-running code should go into a background thread, I strongly suspect that this is not what you need in this situation, that instead you should re-think the structure of your program. Likely what you need instead of that while loop is a modal dialog.
For more and better advice, consider telling us more details of the game logic and your program set up. For instance, tell us exactly what ui.getPlayerHand() does, as a start.
What you want to do is to change the structure of your program so that it is event-driven and state based where its behavior changes depending on its state. For instance if your program is in "choose hand" mode, then those buttons or other user interfaces are all that respond to the user.
I'm making a Java multi-player turn-based game and I want to limit the time that each player have to make their move, the game is composed of game sessions or rooms and each room have 4 players.
The game have around 40 game sessions and each sessions have a minimum of 160 turns.
First I looked into the java.util.Timer, then I found out about the ScheduledExecutorService which seems much better, I could have a SingleThreadScheduledExecutor for each game session, create a new runnable each turn and if the player make is move before the runnable is executed I could call the ScheduledFuture.cancel() method.
In theory it seems fine but I have some concerns, so I want to know if:
Is this the right approach? or there are better alternatives?
Could I just have a ScheduledThreadPool for all game sessions instead
one SingleThreadScheduledExecutor for each game session?
I noticed that canceling a ScheduledFuture will keep it in the
memory until his execution time, could this be a problem for the
memory usage?
And last, is it possible to reuse the same runnable (1 for each game
session) instead of creating a new one each turn.
A ScheduledExecutorService is a fine place to start. Just remember to properly synchronize your access to game state.
It is generally legal to recycle a runnable, but that is probably not the best option here.
Unless the number of turns were going to be huge, the overhead for cancelling tasks is not worth it. Instead, include in your runnable information on what turn in what game is being timed. When the task executes, check the game state to see if that is still the current turn, and do nothing if the turn count has already moved on.
This avoids race conditions between cancel() completing and the task executing, as would happen when a move is submitted close to the deadline.
I'm writing my first ever Android game.
It's a simple card game where player will have 3 BOT players.
Right now i'm writing a core logic for it in pure java. (Not thinking much about AndEngine and graphics yet)
The game has two phase:
Initially all players would draw a match of card asynchronously
After a first phase control moves serially (Synchronously) from one player to next one to draw a card.
So, i'm confused about how many threads would i need?
shall i put each player into a separate thread? (as phase 1 may need it)
OR
Or should i carry out this in one single thread? (as in Phase 2 synchronous behavior is needed)
If i put each player into different thread how can i serialize those threads to do sequential tasks (Phase 2- control move to player one after other)????
ALso
Right now the logic I'm writing is in pure java. Will it give me any trouble while configuring it with AndEngine?? I mean is there any specific format of handling inputs and using this logic in ANdEngine?? Its all about just calling methods of those classes to start game and to perform any operation on game.
I think Synchronous. If you think of a card game, you can't do anything until the previous player has made their move anyway.
If you start using separate threads you are just over-complicating things for yourself.
I'm creating a simple game turn based game in NetBeans. After the initialization of the GUI it calls the function herosTurn() to which waits for the users choice and and creates the outcome of that choice from a separate class Hero. When I step through the code in Debug mode, I get correct outcomes, but if I just run the code nothing is ever appended to the Text Area unless I have the wait function constantly appending text while it waits for input. I've seen other questions similar to this but they all involved multi-threading, and I don't believe that is what I am doing. Any help would be greatly appreciated.
This is the main class:
package Flow;
import Forms.Battleinterface;
/**
*
* #author Steemo
*/
public class battle {
public static int hAct;
public static int gLife = 200;
public static void herosTurn() {
hAct = 0;
Forms.Battleinterface.biText.append("What will you do?");
while (hAct == 0){
// adding the line below makes code work but is ugly.
//Forms.Battleinterface.biText.append(".");
continue;
}
if (hAct == 1){
Entities.Hero.attack();
}
}
public static void main(String args[]) {
Battleinterface battleinterface = new Forms.Battleinterface();
Battleinterface.Start();
while (gLife > 0) {
herosTurn();
}
}
}
And this is the Hero() class that is in a separate package:
package Entities;
import java.util.Random;
/**
*
* #author Steemo
*/
public class Hero {
static Random hGen = new Random(54154454);
public static void attack() {
int hAtt = 0;
hAtt = hGen.nextInt(6) + 15;
Forms.Battleinterface.biText.append("\nYou swing your axe and do " + hAtt
+ " Damage!!!");
}
}
I am not attaching the class I use to generate the GUI (Battleinterface) because the GUI generates fine and the only other thing happening there is the passing of the input hAct.
If it is needed I can attach it.
Replace this code...
while (hAct == 0){
continue;
}
...with this instead:
while (hAct == 0){
try {
Thread.yield();
} catch (InterruptedException interruptedEx) {
// Log the interruption somewhere.
}
}
Assuming you're using AWT/Swing on some level? This is an infinite loop, preventing other threads from ever running. By doing this you never let the UI thread actually do any updating, which means it appears to hang. You may not be doing any threading on your own, but AWT/Swing comes with Threads built in to do various functions, and they need to periodically get CPU time to do their work.
The reason this works in debugging is because the debugger is pausing the herosTurn method as you're stepping through it, allowing the UI thread to do its updates (including getting input from the user), but when simply running your game, the herosTurn method never pauses, and that method is occupying 100% of the available CPU time for your app.
Finally, as Mike Clark mentions, you typically shouldn't write UI with infinite loops. Instead you define components, which trigger events. Your code is notified of those events and reacts appropriately. This is what is known as the UI's event model. If you're using Swing, the introductory info on working within the event model is covered here.
I also wouldn't typically use AWT/Swing for games, because of the complications of UI coding, rendering performance, and several other reasons relating to the reality that AWT/Swing were not built to be good tools for games. That being said, a turn-based game can work fine this way (because the rendering performance requirements are often much lower) if you're willing to delve into the UI code to get it done, in addition to a few other reasons which I've outlined in a previous answer.
Hmm, there might be an issue with flushing your text buffer to the text area. Try explicitly flushing your text buffer after every print to see if that makes a difference.
It seems to me that your program is stuck in a while loop in the method herosTurn() As long as that function has not returned, nothing is going to update if you program this game as a single thread application.
It works when you uncomment the Forms.Battleinterface.biText.append("."); line cos then you send a signal to the GUI every iteration which causes it to update.
Games usually have a main game loop from which all elements of the program are controlled. Maybe a change of your implementation strategy will help?
I'm not a games programmer, so this might not be the best approach, but why don't you try setting up a javax.swing.Timer that runs every, say, 100 milliseconds. In inside the timer action, you can write all the code which checks and advances the game state and generates output to the user.
I'd suggest collecting the user's input in a JTextField that is separate from the place where the game output is printed. If you want to know when the user presses enter to send what they've typed, you can register an ActionListener on the JTextField.
textField.addActionListener(yourListener);
Edit: This makes alot more sense to me now that i've taken a step away from the code, thanks for the help.
Just found stack overflow the other day through Coding Horror and it looks awesome. Figure that i'd ask the community about a problem i'm currently trying to work out.
I'm developing a roguelike sortof game using j2me for midp 2.0 phones. The project is still in the basic stages of development as I figure out how it's going to work. The part i'm currently stuck on has to do with threading.
The game has a custom HaxCanvas class which extends GameCanvas and Implements runnable. It's run method calls repaint() and then sleeps for 50 ms, resulting in a frame rate of 20 FPS. This allows me to write the rest of the game without having to put repaint everywhere and should make animations and effects easier to do later on. (at least in theory).
The flow of the game is controlled by a GameManager class, which loops through all the NPC's on the map, taking their turns, until it's the player's turn. At this point I need to get input to allow the player to move around and/or attack things. I originally was calling gameManager.runUntilHeroTurn() in the keyPressed method of my HaxCanvas. However after reading up on j2me system threads I realized that putting a method with the potential to run for a while in a callback is a bad idea. However I must used keyPressed to do input handeling, since i need access to the number keys, and getKeyStates() does not support this.
Sofar my attempts to put my gameloop in it's own thread have resulted in disaster. A strange "uncaught ArrayIndexOutOfBoundsException" with no stack trace shows up after the game has run for several turns .
So i suppose my question is this:
For a "turn based" game in j2me, what's the best way to implement the game loop, allowing for input handeling only when it's the player's turn?
Although not j2me specifically you should capture user input, the general strategy is to queue the input it until its time to process the input.
input ---> queue <---> Manager(loop)
This way you can even script input for debug purposes.
So you don't need a new thread. Each time the user presses key you store them in a buffer, and then process the contents of the buffer when necessary. If the player buffer has no input, the manager should skip all gameplay, do animations and then start over (since the game is not an action game).
I would avoid threading for the game logic as J2ME threading, depending on manufacturer of course, does not do a great job of sharing the limited resources. You will often see pauses while a thread does heavy processing. I would only recommend threads for loading or network connectivity features as in this case you will just be giving the user basic "Loading..." feedback.
To handle this, I would not have sub-loops to update each of the AI in one frame. I would do something like following in the run function:
public void run() {
while(true) {
// Update the Game
if(gameManager.isUsersTurn()) {
// Collect User Input
// Process User Input
// Update User's State
}
else {
// Update the active NPC based on their current state
gameManager.updateCurrentNPC();
}
// Do your drawing
}
}
You want to avoid having everything updated in one frame as 1) the updating might be slow, resulting in no immediate visual feedback for the user 2) you can't animate each individual NPC as they make their action. With this setup you could have NPC states, NPC_DECIDE_MOVE and NPC_ANIMATING, that would allow you further control of what the NPC is doing. NPC_ANIMATING would basically put the game in a waiting state for the animation to take place, avoiding any further processing until the animation is complete. Then it could move on to the next NPC's turn.
Also, I would just have a gameManager.update() and gameManager.paint(g) (paint would be called from paint) that would handle everything and keep the run method thin.
Finally, did you look into flushGraphics()? With the GameCanvas you usually create a Graphics object, draw everything to that and then call flushGraphics(), then wait. The method you mention is the way of tackling it for the Canvas class. Just thought I would mention this and post a link:
Game Canvas Basics