Author Topic: Input system and the "-More-" prompt.  (Read 27643 times)

mike3

  • Rogueliker
  • ***
  • Posts: 125
  • Karma: +0/-0
    • View Profile
    • Email
Input system and the "-More-" prompt.
« on: May 14, 2013, 05:46:06 AM »
Hi.

I'm wondering: what's the best way to structure the input system in a roguelike game? That is, the part of the program that gets the input from the keyboard (or mouse, or both) and handles it. Namely, what I'm wondering about is, it is possible to somehow centralize the getting of input and then pass it on to the parts of the program that need it? The difficulty arises with stuff like inventory menus and the infamous "-More-" prompt. Suppose we have a "display" object which has a method in it to display messages in the message area. If we tell it to display a message, but the message isn't big enough to fit, then the "-More-" prompt has to be used, which requires waiting for keyboard input. But this would seem to require the display system to be able to fetch input from the keyboard itself. What's the best way to handle this?

Krice

  • (Banned)
  • Rogueliker
  • ***
  • Posts: 2316
  • Karma: +0/-2
    • View Profile
    • Email
Re: Input system and the "-More-" prompt.
« Reply #1 on: May 14, 2013, 11:56:26 AM »
But this would seem to require the display system to be able to fetch input from the keyboard itself.

Yes, it's called "user interface". You know, for displaying stuff on a computer monitor (form of interface that humans use) and waiting for keyboard commands.

Quendus

  • Rogueliker
  • ***
  • Posts: 447
  • Karma: +0/-0
  • $@ \in \{1,W\} \times \{1,H\}$
    • View Profile
    • Klein Roguelikes
Re: Input system and the "-More-" prompt.
« Reply #2 on: May 14, 2013, 12:42:04 PM »
There are several factors affecting the way that the input/display/logic loop should be handled in a game:
  • What it needs to accomplish
    • How often does it need to render? Every time the monitor refreshes (graphical/mouse input) or every time a key is pressed (terminal, keyboard only, no animations)?
    • How many different input states are there? (game modes, menus, -more- prompts, etc.)
    • How rigid is the relationship between a key being pressed and the game logic advancing a turn? (If every keypess advances the game by one tick, then there's need to separate logic from input)
  • How much time you want to spend on it
    • Does the game have a deadline like 2 days or 7 days, or is it a long-term project?
    • Are you practising game design, good coding patterns, or just trying to get a game out of the door?
  • How flexible you want it to be in case of future changes
    • Are you writing for a terminal library (redrawing every keypress) and considering adding animations or switching to a graphical library (redrawing at 60FPS)?
    • Do you have a simple time system that you might in future replace with a more intricate one?
    • Do you have a bug whereby trying to walk into a wall consumes a turn?
    • Will the menu structure change or be made scriptable?

A half-sensible loop would be something like this:
  • The game window renders the game and/or menu system.
  • The game window receives keyboard/mouse input, checks if it needs to respond to them (for instance, resize/close events), and passes them on to the menu system if it doesn't consume them. Otherwise, go back to the render step.
  • The menu system checks if it's active, and reacts to input if it is (then goes back to the render step). Otherwise, pass it to the message area.
  • The message area checks if it's waiting for input (-more-, yes/no, or text input prompt), and processes this input if it is (then goes back to the render step). Otherwise, pass it to the game logic.
  • The game processes input as normal and goes back to the render step.

mike3

  • Rogueliker
  • ***
  • Posts: 125
  • Karma: +0/-0
    • View Profile
    • Email
Re: Input system and the "-More-" prompt.
« Reply #3 on: May 14, 2013, 11:12:01 PM »
However, what if something in the game logic wants to send a message to the message display, and a "more" is triggered there? In the way that loop is structured, input can't be had until the game logic finishes and the next cycle begins.

Quendus

  • Rogueliker
  • ***
  • Posts: 447
  • Karma: +0/-0
  • $@ \in \{1,W\} \times \{1,H\}$
    • View Profile
    • Klein Roguelikes
Re: Input system and the "-More-" prompt.
« Reply #4 on: May 15, 2013, 02:48:43 AM »
The point of that loop is to allow rendering with vertical sync (which in some rendering libraries limits the framerate by sleeping before refreshing the screen) to continue as normal while waiting for input, without having to resort to multithreading. So if there's a big delay (like waiting for a keyboard input) then the game logic needs to stop and let the render/input loop run until it has something to process.

If there's a large range of events that can stop the game in the middle of the AI turn (anything that generates a message), making it impractical for the game logic function to be pausable/resumable without multithreading, then there are a few options.

If the user response has no effect on the result of the AI action, then there's no reason not to simply let the game logic complete processing, and record all the animations and message emissions to a list which is then replayed (in a much simpler function which can be paused/resumed without great complication).

It's worth considering whether you really need -more- prompts. They break immersion by dragging my eyes from the map to the message log and making me keep track of whether the game is expecting a command or a spacebar next.

Personally, I much prefer having a message display area that's large enough to contain the average turn's worth of messages (with a command to view the backlog), and relying on animations and peripheral vision of the message log to alert me to any unusual happenings. This aids immersion and makes the game's response to a given keypress more predictable, reducing mistakes.

The other option is to have the logic loop call the render loop. This is similar to using the standard curses getch() function, but wrapping it in a function which does continuous rendering and allows escaping into the menu system.

mike3

  • Rogueliker
  • ***
  • Posts: 125
  • Karma: +0/-0
    • View Profile
    • Email
Re: Input system and the "-More-" prompt.
« Reply #5 on: May 15, 2013, 02:56:30 AM »
The point of that loop is to allow rendering with vertical sync (which in some rendering libraries limits the framerate by sleeping before refreshing the screen) to continue as normal while waiting for input, without having to resort to multithreading. So if there's a big delay (like waiting for a keyboard input) then the game logic needs to stop and let the render/input loop run until it has something to process.

If there's a large range of events that can stop the game in the middle of the AI turn (anything that generates a message), making it impractical for the game logic function to be pausable/resumable without multithreading, then there are a few options.

If the user response has no effect on the result of the AI action, then there's no reason not to simply let the game logic complete processing, and record all the animations and message emissions to a list which is then replayed (in a much simpler function which can be paused/resumed without great complication).

It's worth considering whether you really need -more- prompts. They break immersion by dragging my eyes from the map to the message log and making me keep track of whether the game is expecting a command or a spacebar next.

Personally, I much prefer having a message display area that's large enough to contain the average turn's worth of messages (with a command to view the backlog), and relying on animations and peripheral vision of the message log to alert me to any unusual happenings. This aids immersion and makes the game's response to a given keypress more predictable, reducing mistakes.

The other option is to have the logic loop call the render loop. This is similar to using the standard curses getch() function, but wrapping it in a function which does continuous rendering and allows escaping into the menu system.

It sounds like what you're mentioning here is a game with continuous rendering (realtime animations?), whereas I'm just doing a simple ASCII system here.

Quendus

  • Rogueliker
  • ***
  • Posts: 447
  • Karma: +0/-0
  • $@ \in \{1,W\} \times \{1,H\}$
    • View Profile
    • Klein Roguelikes
Re: Input system and the "-More-" prompt.
« Reply #6 on: May 15, 2013, 04:37:44 AM »
See my first post in this thread. The system you should program depends on the game's design objectives. I can't make any specific recommendations without knowing what it needs to accomplish, how much time you want to spend on it, and how flexible you want it to be to future changes.

Even an ASCII game might need continuous rendering. DoomRL and Angband's explosions, highlighting the tile that the mouse points to in a libtcod game, etc.


mike3

  • Rogueliker
  • ***
  • Posts: 125
  • Karma: +0/-0
    • View Profile
    • Email
Re: Input system and the "-More-" prompt.
« Reply #7 on: May 15, 2013, 05:26:29 AM »
Well, then, here goes:

1. How often does it need to render? I'd think after every keypress would be it, although what do we do then about, say, an explosion or a magic spell or something else like that going off during the process of a turn after a keypress?
2. Input states: there's the main game, menus, and "more" prompt
3. Advancing turn: Well, merely opening a menu shouldn't advance the logic through the turn, but an actual action of the player in the world (pick up an item, attack, move, whatever) should (though trying to move into a wall shouldn't).

4. Time spent: There is no deadline
5. Code practice: Well, I'd like to finish the game, but having a reasonably good code would be nice as well.

6. Terminal or graphics? Right now I'm just interested in a terminal, but in the future (probably well into the future) I'd like to maybe move to a graphical system.
7.  The time system right now is based on "events", set to happen at a given time in the future, on a priority queue, sorted by the time remaining. Each entity gets an event upon which it would decide what kind of action to perform, and the time between these events is determined by the entity's speed.
8. Yes, walking on a wall would consume a turn the way it is now. I'd like it not to.
9. The menu system is hardcoded/not based on scripting languages.

Krice

  • (Banned)
  • Rogueliker
  • ***
  • Posts: 2316
  • Karma: +0/-2
    • View Profile
    • Email
Re: Input system and the "-More-" prompt.
« Reply #8 on: May 15, 2013, 06:55:27 AM »
In the way that loop is structured, input can't be had until the game logic finishes and the next cycle begins.

Are you serious? Of course you can pause (+continue with key press) in any point you want. It doesn't break the "cycle".

mike3

  • Rogueliker
  • ***
  • Posts: 125
  • Karma: +0/-0
    • View Profile
    • Email
Re: Input system and the "-More-" prompt.
« Reply #9 on: May 15, 2013, 09:08:21 AM »
In the way that loop is structured, input can't be had until the game logic finishes and the next cycle begins.

Are you serious? Of course you can pause (+continue with key press) in any point you want. It doesn't break the "cycle".

But then whatever has the message routine needs to know about the keyboard/input manager/etc. . Is that kind of dependency bad?

Krice

  • (Banned)
  • Rogueliker
  • ***
  • Posts: 2316
  • Karma: +0/-2
    • View Profile
    • Email
Re: Input system and the "-More-" prompt.
« Reply #10 on: May 15, 2013, 05:05:07 PM »
But then whatever has the message routine needs to know about the keyboard/input manager/etc. . Is that kind of dependency bad?

If you feel really bad about that, you can write a dedicated input routine for the message class.

I'm using C++ and global handles for stuff like GUI and keyboard routines. Sometimes keyboard is a part of GUI class.
« Last Edit: May 15, 2013, 05:06:56 PM by Krice »

AgingMinotaur

  • Rogueliker
  • ***
  • Posts: 805
  • Karma: +2/-0
  • Original Discriminating Buffalo Man
    • View Profile
    • Land of Strangers
Re: Input system and the "-More-" prompt.
« Reply #11 on: May 15, 2013, 06:08:35 PM »
I also mostly use one class for the interface/terminal, with functions such as get_keypress(), print_message(), players_turn(), and so forth. If I need a more prompt to split up a message or a turn, I basically just ask the class instance to execute get_keypress(), ignoring the result (or waiting for Spacebar to be pressed). Never experienced any problems with doing it that way. Some basic utilities like get_keypress() could probably even be had as global functions.

As always,
Minotauros
This matir, as laborintus, Dedalus hous, hath many halkes and hurnes ... wyndynges and wrynkelynges.

kraflab

  • Rogueliker
  • ***
  • Posts: 454
  • Karma: +0/-0
    • View Profile
    • kraflab.com
Re: Input system and the "-More-" prompt.
« Reply #12 on: May 16, 2013, 11:31:51 AM »
My loop is

1) Read input - this involves an event manager, which will depend on your particular library to get keyboard/other data.  there is a global array that can be accessed like "if (keyHit[key_left]) {do something}"
2) Game logic - for instance, during the player turn I may check for key input and act on it.  If no input has been given then there is no logic to perform.
3) Draw logic - this includes animation
4) Render

If you only want to draw the screen and render when something changes, you can just have a trigger for the draw/render section instead of having it be automatic.  You can even be really lazy and have a global bool draw_update that you set to false at the beginning of the loop and toggle in the logic as needed.  Basically, all you need to do is keep sections separate.  You shouldn't have drawing muddled with logic for instance (you certainly can but you'll probably hate yourself later on).  Once you have that all your questions should answer themselves.  It isn't particularly complicated.

mike3

  • Rogueliker
  • ***
  • Posts: 125
  • Karma: +0/-0
    • View Profile
    • Email
Re: Input system and the "-More-" prompt.
« Reply #13 on: May 16, 2013, 03:38:10 PM »
My loop is

1) Read input - this involves an event manager, which will depend on your particular library to get keyboard/other data.  there is a global array that can be accessed like "if (keyHit[key_left]) {do something}"
2) Game logic - for instance, during the player turn I may check for key input and act on it.  If no input has been given then there is no logic to perform.
3) Draw logic - this includes animation
4) Render

If you only want to draw the screen and render when something changes, you can just have a trigger for the draw/render section instead of having it be automatic.  You can even be really lazy and have a global bool draw_update that you set to false at the beginning of the loop and toggle in the logic as needed.  Basically, all you need to do is keep sections separate.  You shouldn't have drawing muddled with logic for instance (you certainly can but you'll probably hate yourself later on).  Once you have that all your questions should answer themselves.  It isn't particularly complicated.

So what do you do to handle the whole "message" thing (messages depend on what happens in the game logic, but render to the display and may require input (the "more" prompt, for example))?

Quendus

  • Rogueliker
  • ***
  • Posts: 447
  • Karma: +0/-0
  • $@ \in \{1,W\} \times \{1,H\}$
    • View Profile
    • Klein Roguelikes
Re: Input system and the "-More-" prompt.
« Reply #14 on: May 16, 2013, 05:04:27 PM »
Is there so little screen space that messages have to fit into one line and the game flow needs to be interrupted with a "more" prompt?