Author Topic: Window managers and "printing messages"  (Read 20810 times)

mike3

  • Rogueliker
  • ***
  • Posts: 125
  • Karma: +0/-0
    • View Profile
    • Email
Window managers and "printing messages"
« on: July 29, 2013, 10:59:01 AM »
Hi.

This thread is a follow-up to some issues mentioned here, where "requerent" brought up the concept of "window managers":

http://forums.roguetemple.com/index.php?topic=3497.30

I'm wondering now about that old problem of "printing messages" -- i.e. all the "you hit the <foo> and kill it" stuff. Suppose your game loop looks like this (this is just a text mode game, no fancy realtime animations or anything like that yet):

Code: [Select]
loop:
   receive input
   pass input to window manager
   tell the window manager to redraw

Now when the window manager receives the input, it then goes on to the focused pane. The game area may have several panes in use -- in my program, it'd be messages, world, and stats. The messages area shows all the "you kill the <foo>" messages, and the world area shows the game word, and the stats are shows the attributes and what not of the player character and indicates what level you're on. When input is passed to the world pane, it then may be processed in some high-level way, e.g. keys are mapped through to commands (since keys could be reconfigured, we don't pass keys on to the logic). Then the command goes into logic. In logic (remember, our call stack at this point now looks something like this: logic_routine | pane_input_handler | wm_input_handler | main_loop, where the first element is the function we're in and the rest are higher up), it gets handled in whatever way is appropriate, e.g. a movement command goes on to the movement system, or something. But during that logic processing, messages may be generated. E.g. there's a collision with a wall, or we attack a monster. Consider the case of monster attacking, since that's where multiple messages separated by logic are likely to occur. The player attacks the monster. A message is sent. Logic continues. The monster fights back (assume it wasn't killed). More messages are sent.

The problem? For one, the render phase comes only after wm_input_handler returns. Though, in the thread I link to, it's mentioned it's OK to tell the WM to update from the logic (the "separation of logic and render" refers to avoiding mixing low-level rendering operations in with game logic). But, the main loop is where input also is acquired as well. What if we have a "more" prompt, necessitating input to go to the message pane now, while there's still unfinished logic? It seems like we'd need to break out of the logic and go all the way back up the stack to the main loop, or spawn another input/logic/render loop down inside the one we're already in! And what if we want to support "more-less" as well as mored (e.g. if we were using a non-textmode interface where scrollbars and so on are available?) messages?

This is similar to something I mentioned here in earlier threads, only now I'm curious about it in the context of this new window-manager paradigm.

Anvilfolk

  • Rogueliker
  • ***
  • Posts: 374
  • Karma: +0/-0
    • View Profile
Re: Window managers and "printing messages"
« Reply #1 on: July 29, 2013, 07:12:53 PM »
Well, when you attack, everything should happen, the messages for everything that happens since your attack all the way to your next turn (e.g. monsters attack, etc) are going back to the message pane, and then it gets drawn. Once that's one, you can scroll up and down. I don't see any essential logic separation that needs to happen here.

However, let's try another example. Suppose than when you are attacked, you get the choice of parrying with your sword, or using your shield. Perhaps the shield is safer, but doesn't allow you to counter-attack, while parrying using your sword is harder but might allow a counter-attack. Thus, somehow, you should get a prompt between one of your turns and your next turn.

I guess in general, we're just talking about "interrupts". Some action is executing, but we determine that there's some input that can happen before this. That's a very interesting problem that I can't think of a solution to off-hand. I'll try to use events as little as possible, but I feel they are needed.

I assume that whenever your player does an action, it takes a number of ticks. The world stores how many are left to execute.

  • Suppose you, the hero H, attack the monster M. You slash it but don't kill it. It takes 50 units util your next action.
  • After 25 units, it's M's turn. He attacks you. The logic calls player.startAttack(M).
  • player.startAttack(M) checks that there's a possible interrupt. It pushes a ShieldInterruptEvent.
  • The GUI catches the ShieldInterruptEvent and creates an ShieldInterruptPane in the GUI, which contains the ShieldInterruptEvent .
  • The game is now in the usual loop, but the ShieldInterruptPane is capturing all the input events and not letting them proceed anywhere else.
  • Once the player provides adequate input, it uses the ShieldInterruptEvent to make a callback to player.finaliseAttack() with appropriate attack modifications.

You can probably have an Attack class that's being passed around the events and modified as it goes through these things?

The advantage of this is that the same way that the ShieldInterruptEvent is caught by the is caught by the GUI, it may also be caught by the AI enemy, and thus this method can also work for non-player Shield interrupts.

How does this sound?
"Get it hot! Hit it harder!!!"
 - The tutor warcry

One of They Who Are Too Busy

mike3

  • Rogueliker
  • ***
  • Posts: 125
  • Karma: +0/-0
    • View Profile
    • Email
Re: Window managers and "printing messages"
« Reply #2 on: July 30, 2013, 10:42:11 AM »
Well, when you attack, everything should happen, the messages for everything that happens since your attack all the way to your next turn (e.g. monsters attack, etc) are going back to the message pane, and then it gets drawn. Once that's one, you can scroll up and down. I don't see any essential logic separation that needs to happen here.

However, let's try another example. Suppose than when you are attacked, you get the choice of parrying with your sword, or using your shield. Perhaps the shield is safer, but doesn't allow you to counter-attack, while parrying using your sword is harder but might allow a counter-attack. Thus, somehow, you should get a prompt between one of your turns and your next turn.

I guess in general, we're just talking about "interrupts". Some action is executing, but we determine that there's some input that can happen before this. That's a very interesting problem that I can't think of a solution to off-hand. I'll try to use events as little as possible, but I feel they are needed.

I assume that whenever your player does an action, it takes a number of ticks. The world stores how many are left to execute.

  • Suppose you, the hero H, attack the monster M. You slash it but don't kill it. It takes 50 units util your next action.
  • After 25 units, it's M's turn. He attacks you. The logic calls player.startAttack(M).
  • player.startAttack(M) checks that there's a possible interrupt. It pushes a ShieldInterruptEvent.
  • The GUI catches the ShieldInterruptEvent and creates an ShieldInterruptPane in the GUI, which contains the ShieldInterruptEvent .
  • The game is now in the usual loop, but the ShieldInterruptPane is capturing all the input events and not letting them proceed anywhere else.
  • Once the player provides adequate input, it uses the ShieldInterruptEvent to make a callback to player.finaliseAttack() with appropriate attack modifications.

You can probably have an Attack class that's being passed around the events and modified as it goes through these things?

The advantage of this is that the same way that the ShieldInterruptEvent is caught by the is caught by the GUI, it may also be caught by the AI enemy, and thus this method can also work for non-player Shield interrupts.

How does this sound?

So where do these events go -- does the UI object contain an event queue? What does the main loop look like in this case, compared to what I showed in my original post?

Anvilfolk

  • Rogueliker
  • ***
  • Posts: 374
  • Karma: +0/-0
    • View Profile
Re: Window managers and "printing messages"
« Reply #3 on: July 30, 2013, 11:54:09 AM »
I have an EventManager class, which has a singleton instance, but other things can also be/have EventManagers. For instance, any entity in a game can be an EM, the game world itself can also be an EM for purely game related events (nothing that requires UI, etc), and so forth.

The Event Manager interface is simply "notify(event)", and "registerListener(eventType)". Every time you send a notify, it will check whether there are any listeners for that event type, and send them a notification that that event happened.

I've seen some people queue events and handle them explicitly in the loop, but that might not be necessary.
"Get it hot! Hit it harder!!!"
 - The tutor warcry

One of They Who Are Too Busy

mike3

  • Rogueliker
  • ***
  • Posts: 125
  • Karma: +0/-0
    • View Profile
    • Email
Re: Window managers and "printing messages"
« Reply #4 on: July 30, 2013, 10:13:11 PM »
I have an EventManager class, which has a singleton instance, but other things can also be/have EventManagers. For instance, any entity in a game can be an EM, the game world itself can also be an EM for purely game related events (nothing that requires UI, etc), and so forth.

The Event Manager interface is simply "notify(event)", and "registerListener(eventType)". Every time you send a notify, it will check whether there are any listeners for that event type, and send them a notification that that event happened.

I've seen some people queue events and handle them explicitly in the loop, but that might not be necessary.

So then the event gets sent directly to the manager, and not queued? But then how do we get back up into the main loop to get the input to the prompt pane?

Also, for messages, there isn't a scroll bar in this text mode game, but rather a "more" prompt, requiring input. Am I right in interpreting your solution to be to queue up all the messages and then at the end of the turn logic have the message pane display the messages, switching focus to it so as to be able to handle the "more" prompts?

Anvilfolk

  • Rogueliker
  • ***
  • Posts: 374
  • Karma: +0/-0
    • View Profile
Re: Window managers and "printing messages"
« Reply #5 on: July 31, 2013, 10:02:58 PM »
I'm not sure about your game's specifics. I would say you can NOT queue events, and just handle them as they happen. Then as soon as you notify the EventManager of an Event, it gets handled by all listeners, and the code just continues executing past the .notify(event) call.

What I was saying is that you could have a EventManager.queueEvent(event) and then EventManager.handleQueuedEvents(), but I don't currently see any use for this.

What I would do in that situation is have the message box be the first pane to get access to input. Then, you'd do the turn logic, and shoot off all game events. The message box pane receives all of that, and updates what it needs to show, but doesn't scroll down.

Then, because the message box pane is getting the input first, and it's in a state in which it hasn't shown everything (there's a "more" prompt), it will consume all input. If it's the ENTER key (for example), it scrolls down. If it's not, it does nothing, but it still consumes the input.


Would this work?
"Get it hot! Hit it harder!!!"
 - The tutor warcry

One of They Who Are Too Busy

mike3

  • Rogueliker
  • ***
  • Posts: 125
  • Karma: +0/-0
    • View Profile
    • Email
Re: Window managers and "printing messages"
« Reply #6 on: July 31, 2013, 11:34:09 PM »
I'm not sure about your game's specifics. I would say you can NOT queue events, and just handle them as they happen. Then as soon as you notify the EventManager of an Event, it gets handled by all listeners, and the code just continues executing past the .notify(event) call.

What I was saying is that you could have a EventManager.queueEvent(event) and then EventManager.handleQueuedEvents(), but I don't currently see any use for this.

What I would do in that situation is have the message box be the first pane to get access to input. Then, you'd do the turn logic, and shoot off all game events. The message box pane receives all of that, and updates what it needs to show, but doesn't scroll down.

Then, because the message box pane is getting the input first, and it's in a state in which it hasn't shown everything (there's a "more" prompt), it will consume all input. If it's the ENTER key (for example), it scrolls down. If it's not, it does nothing, but it still consumes the input.


Would this work?

So then while the logic is going, the message pane would sit and collect messages (displaying whatever can fit), and when the logic is over, the game switches focus to the pane and that's where you can handle the input to the "more"? Seems like a good idea.

Anvilfolk

  • Rogueliker
  • ***
  • Posts: 374
  • Karma: +0/-0
    • View Profile
Re: Window managers and "printing messages"
« Reply #7 on: July 31, 2013, 11:41:22 PM »
I'd even go as far as to say that you don't need to update any of the screen while the logic is going, though that depends on how you organise your main loop. I think you were talking about redrawing only parts of the screen in some other thread... but I think you could still only do graphics related stuff when you handle graphics, later in the main loop. I tend to do:

  • Game update
  • Draw
  • Player Input

In this situation, when the events are sent, nothing is redrawn. The message box just collects information, and can mark itself as "dirty" or "needs update" when it receives a new message. Then, when you come to the Draw part of the main loop, the message box display is updated if it's dirty.

Let us know how it goes! :)
"Get it hot! Hit it harder!!!"
 - The tutor warcry

One of They Who Are Too Busy

mike3

  • Rogueliker
  • ***
  • Posts: 125
  • Karma: +0/-0
    • View Profile
    • Email
Re: Window managers and "printing messages"
« Reply #8 on: August 03, 2013, 10:05:38 PM »
Well, when you attack, everything should happen, the messages for everything that happens since your attack all the way to your next turn (e.g. monsters attack, etc) are going back to the message pane, and then it gets drawn. Once that's one, you can scroll up and down. I don't see any essential logic separation that needs to happen here.

However, let's try another example. Suppose than when you are attacked, you get the choice of parrying with your sword, or using your shield. Perhaps the shield is safer, but doesn't allow you to counter-attack, while parrying using your sword is harder but might allow a counter-attack. Thus, somehow, you should get a prompt between one of your turns and your next turn.

I guess in general, we're just talking about "interrupts". Some action is executing, but we determine that there's some input that can happen before this. That's a very interesting problem that I can't think of a solution to off-hand. I'll try to use events as little as possible, but I feel they are needed.

I assume that whenever your player does an action, it takes a number of ticks. The world stores how many are left to execute.

  • Suppose you, the hero H, attack the monster M. You slash it but don't kill it. It takes 50 units util your next action.
  • After 25 units, it's M's turn. He attacks you. The logic calls player.startAttack(M).
  • player.startAttack(M) checks that there's a possible interrupt. It pushes a ShieldInterruptEvent.
  • The GUI catches the ShieldInterruptEvent and creates an ShieldInterruptPane in the GUI, which contains the ShieldInterruptEvent .
  • The game is now in the usual loop, but the ShieldInterruptPane is capturing all the input events and not letting them proceed anywhere else.
  • Once the player provides adequate input, it uses the ShieldInterruptEvent to make a callback to player.finaliseAttack() with appropriate attack modifications.

You can probably have an Attack class that's being passed around the events and modified as it goes through these things?

The advantage of this is that the same way that the ShieldInterruptEvent is caught by the is caught by the GUI, it may also be caught by the AI enemy, and thus this method can also work for non-player Shield interrupts.

How does this sound?

I just realized something here which I'm not clear on: step 3. Given what you've said in the posts after this, I suppose you imagine sending the GUI the event, e.g. gui.catchEvent(shieldInterruptEvent) or something like that. But we still have to get out of the loop now so as to be able to get back into the main loop getting input and passing it to the window manager. And does finalizeAttack() also resume the rest of the turn logic (e.g. to run through the remaining monsters in the level, for example)?

Anvilfolk

  • Rogueliker
  • ***
  • Posts: 374
  • Karma: +0/-0
    • View Profile
Re: Window managers and "printing messages"
« Reply #9 on: August 04, 2013, 10:06:42 AM »
You are indeed splitting the game logic. You essentially have a pre-attack piece of logic that checks for possible interrupts, which is handled in 3. The interrupts are sent out as events somehow, and the GUI state is updated to deal with player input for the interrupt.

After that, like I say back in step 5, you are in the usual game loop, which looks at the game and the GUI and draws it. The rest of the game attack logic is executed after the player has dealt with the interrupt GUI stuff. Once the game attack logic FINISHES executing, you do the rest of the game turn logic, which has other monsters execute and so forth :)
"Get it hot! Hit it harder!!!"
 - The tutor warcry

One of They Who Are Too Busy

mike3

  • Rogueliker
  • ***
  • Posts: 125
  • Karma: +0/-0
    • View Profile
    • Email
Re: Window managers and "printing messages"
« Reply #10 on: August 04, 2013, 11:33:44 AM »
You are indeed splitting the game logic. You essentially have a pre-attack piece of logic that checks for possible interrupts, which is handled in 3. The interrupts are sent out as events somehow, and the GUI state is updated to deal with player input for the interrupt.

After that, like I say back in step 5, you are in the usual game loop, which looks at the game and the GUI and draws it. The rest of the game attack logic is executed after the player has dealt with the interrupt GUI stuff. Once the game attack logic FINISHES executing, you do the rest of the game turn logic, which has other monsters execute and so forth :)

So then the event is sent to the GUI to tell it to change state, and then we quit the logic routine, allowing control to bubble back on up to the main loop (that is, the call to send the event is near or actually the last thing we do at that point in that part of the code), where the new pane takes over, gets the confirmation, and then the callback is invoked and the logic resumes?

Anvilfolk

  • Rogueliker
  • ***
  • Posts: 374
  • Karma: +0/-0
    • View Profile
Re: Window managers and "printing messages"
« Reply #11 on: August 04, 2013, 02:46:26 PM »
Yes, that's how I'd do it - but I'm definitely not sure it's the best way :)
"Get it hot! Hit it harder!!!"
 - The tutor warcry

One of They Who Are Too Busy

mike3

  • Rogueliker
  • ***
  • Posts: 125
  • Karma: +0/-0
    • View Profile
    • Email
Re: Window managers and "printing messages"
« Reply #12 on: August 05, 2013, 09:14:55 PM »
Thanks. But I noticed, however, that this seems almost like it'd be the kind of problem that's been done before, especially since something similar would crop up in GUI-app programming for a program for any regular GUI-based system: put up a window, and you have to select options in it to continue with some process. The windows may be "modal" or not -- e.g. they block usage of other windows or not when open.

In MS Windows (I'm programming this under Linux, actually, but I'll use MS Windows as an example since it's a GUI system with which I'm familiar), a program using the windowing functionality of the OS has what is called a "message loop", which gets "messages" from the system (which can indicate anything, including keypresses or mouse clicks), and passes them on to the window. This is sort of analogous to the main loop in the program under discussion here, which has it's own internal windowing system and the loop gets input and then passes it on to the window manager and that "makes the windows go".

Now, in MS Windows, when a modeless window ("non-modal") is created, one uses the main message loop. This would then run into the same problems as are involved here, namely, how to resume a command after it has put up a modeless window. Such a call does not block and return, say, what button was clicked, since its processing is handled by the main message loop. So one has the same problem of having to split the command logic across the window. However, I've always (though I never did an extremely huge, sophisticated program on MS Windows) used, and it seems a lot of programs use, modal windows when the currently-running command needs input from a new window (as opposed to, say, a paint program where you often set options for a tool on a toolbar instead -- I'm not sure that idea could be adepted here or not). So I myself never had to tackle this problem. As mentioned, a modal window blocks usage of the program's main window (and other windows). You have to fill it out to proceed. When a modal window is invoked, a new message loop is started for that window, and this provides a blocking effect, and when the window closes, the new message loop stops and the command's code is able to resume as normal.

In the case of this program, such a thing would be equivalent to starting up a subsidiary input/logic/render loop in the command's code, e.g. by calling a routine that runs such a loop, for example. However, isn't the idea here to keep everything to one main loop? Otherwise, aren't you then mixing too much with other stuff? If I could find some Windows programs that use a modeless window in the manner indicated, whose source code is available, perhaps maybe that would indicate a solution to the problem. Or, just ask on a Windows programming forum :)

But then again, MS Windows may not be the best design there is out there -- in which case, perhaps looking at other GUI systems might be useful? As this kind of problem has surely come up before, I'd think.

What do you think?

I have another question, though: In the program as I have it now, the main game object deals with the window manager and the panes making up the game's "GUI" (actually, right now it's just a text mode program, so not really "graphical" :) ) directly, that is, it actually has separate window-manager and pane objects it works with. Would it make more sense to hide those in some kind of container or something? What do you do in this regard? What kind of methods does your container, if any, have? Also, there is a phase of the game that comes before the main loop, namely the main menu, which requires different panes. And in addition to the 3 main panes of the game (messages, world, and stats), we could have additional panes that appear during the game (like the inventory menu, or "chatting with NPCs" menus). It seems then that if we are using a container, then we either have to expose some panes to the game, thereby seeming to defeat the purpose of the container, or we have to let the container become bloated with methods to handle all the different panes, which then doesn't seem "tidy". What do you think?

mike3

  • Rogueliker
  • ***
  • Posts: 125
  • Karma: +0/-0
    • View Profile
    • Email
Re: Window managers and "printing messages"
« Reply #13 on: August 08, 2013, 03:42:19 AM »
I saw this:

http://stackoverflow.com/questions/8567594/how-to-create-a-non-modal-form-but-blocking

which dealt with a sort-of similar problem in Windows programming. One answer was to pass information or a delegate to the modeless window. While I'm not familiar with C#, which is what they're using, I looked it up and it seems like the option of "passing a delegate" here is like a callback.

Trystan

  • Rogueliker
  • ***
  • Posts: 164
  • Karma: +0/-0
    • View Profile
    • my blog
Re: Window managers and "printing messages"
« Reply #14 on: August 08, 2013, 06:10:17 AM »
Something that I've tired, and advocated in my java rougelike tutorial at http://trystans.blogspot.com/2011/09/roguelike-tutorial-06-hitpoints-combat.html, is that actions in the game notify any creatures who see them. The notices are handled according to the creature. If the creature is the player then it's added to the "-- more --" style list of mesagesg. Otherwise, it is ignored. Or the creature can learn from it.