6

I'm trying to work up a basic text-based game as I'm learning Java. I'd like to be able to count rounds in the game as a means of managing the pacing of certain events. For instance, changing rooms could be limited to once per round (a second, in the test code.) A small creature might attack or change rooms at a higher rate, whereas a larger one might be more cumbersome. Good so far? Great.

So, I cooked this up and immediately realized that I'd be hitting a block each time the while loop waited for the player to input a command. Code:

private void startPlaying() {
    //declare clock/round variables.
    int lastRound = 0;
    int currentRound = 0;
    long lastTime = System.currentTimeMillis();
    long currentTime;

    while (player.getIsPlaying()){
        //Clocking
        currentTime = System.currentTimeMillis();
        if ((lastTime + 1000) < currentTime) {
            lastTime = currentTime;
            lastRound = currentRound;
            currentRound++;
            System.out.println("Current round:\t" + currentRound + "\tCurrent time:\t" + currentTime); //EDIT:NOTE: This is just a test line to observe the loop.
        }//end if (Clocking)

        Command command = new Command();
        String[] commandString = command.setAll(); //Array gets parsed elsewhere.
        player.doCommand(commandString);  
        //Class Player extends Pawn extends Actor; Pawn has most command methods.
    }
    finishPlaying();
}//END STARTPLAYING()

So, here is my question:

Is there a way I could use a separate method to log time/rounds concurrent to the while loop presenting the player with a command prompt?

If not, is there a different way to make this a non-issue that I'm just not seeing/practiced in yet?

millimoose
  • 36,982
  • 8
  • 75
  • 128
eenblam
  • 438
  • 1
  • 6
  • 19

4 Answers4

4

Take a look at Concurrency tutorial. With threads you can wait user input without stopping other processes (and make these other processes execute at the same time - not in parallel, but time-sharing).

Jean Waghetti
  • 4,571
  • 1
  • 16
  • 28
  • I suppose Oracle's tutorial would have been a more sensible place to start. Up-voting once I have the reputation. – eenblam Mar 20 '13 at 18:57
1

It is called "game loop" which allows the game to run smoothly regardless of the input of the user.

The most straightforward solution - create 2 threads, frist will wait for user input and puts it into ConcurrentLinkedQueue with capacity 1. The second thread will run your game loop and takes user input from queue to process it if queue is not empty.

You can use any data structure you want to exchange data between 2 threads, it can be even volatile string variable. The only requirements read write access to this variable should be synchronized somehow.

Anton
  • 5,365
  • 3
  • 28
  • 43
  • Awesome, thanks for the concise explanation. I'll probably need to spend a little time in the docs, but that sounds quite doable. – eenblam Mar 20 '13 at 18:58
1

A real-time text adventure? Sounds interesting. I wouldn't suggest trying to do concurrency for this particular problem, there are easier ways.

Normally you wouldn't mix blocking on input with time in seconds. Unless you have your heart set on this design, I'd suggest either.

1) Don't block on user input. Write your own input handling code by checking for key-presses each frame. Then you can just calculate the time difference between iterations. E.g. a monster moves 1 block second, so if the current loop iteration took 100ms then it moves 0.1 blocks. (store these values as floats internally, even if you draw on a text grid.

2) Increment game time in 'ticks' based on user input. This would be NetHack/Roguelike-style. Monsters can move so many blocks per tick, rather than per second.

Zutty
  • 5,113
  • 24
  • 31
  • Thought about the tick method, but I can't see that transferring to a multiplayer implementation, which would be a nice project for the future. I also appreciate the alternative approach in option 1, since that would be an enlightening project in itself. I'll probably use threads anyway just to learn them (the original goal) and then implement this input handling within that thread. – eenblam Mar 20 '13 at 19:03
1

Yes there is a way. You would need to put the "Round Counting" code in its own Thread, so it in not blocked by the user waiting to input data. The java.util.concurrency package can help with this.

Look at Java Doc the scheduleAtFixedRate() method will execute a runnable at fixed intervals. The "round counting" code would be moved to a class that implements the runnable interface. And this would be executed at the set time interval. This is reasonably advanced though.