Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Top level game loop design

403 views
Skip to first unread message

Michał Brzozowski

unread,
Apr 18, 2013, 8:26:51 AM4/18/13
to
Hello r.g.r.d,

I started another roguelike project a few weeks ago, and I'm about to make the first code refactoring, so I want to make sure to get it right. This topic has probably been discussed already, but I couldn't find any references. Feel free to point to articles or posts on this group.

I've already designed a lot of the classes and managed to keep things simple, but I can't find an easy solution to the problem of passing and interpreting key strokes into actions, and simultaneously presenting the game on the screen. I started with a Model, View, Presenter scheme. Here's some pseudocode.

top level game loop {
presenter.present(model, view);
}

prenter.present(model, view) {
for every object in model { // objects meaning creatures, items, tiles, etc.
view.render(object.graphical_represenation());
}

// things like "you get hit", etc
view.update_message_window(model.new_messages());

action = view.get_player_action();

model.interpret(action);
model.move_all_monsters();
}

Pretty nice and simple, but doesn't work. The reason is there may be many things happening in between player's actions, and the screen needs to updated more often. Also, many messages might appear, and the message window needs to block if it's filled, and the view must be displaying the situation that generated the last message (much like in Nethack, maybe other games solve it in a different way). This is typical during combat with many monsters. Another thing is displaying animations, for example of fired projectiles.

I thought about putting the model in control of its rendering, but it would require calling an update() method every time the state changes, and I'm not sure how I'd synchronize it with the message box.

I could probably do it with a few hacks and some spaghetti, but maybe there is a simple design that every one uses and I've overlooked.

Thanks for the help,
Michal

Gerry Quinn

unread,
Apr 18, 2013, 1:56:49 PM4/18/13
to
In article <ef79c023-cb94-4132...@googlegroups.com>,
mi...@extremic.com says...
>
> I started another roguelike project a few weeks ago, and I'm about
> to make the first code refactoring, so I want to make sure to get it right.

What I've done is have the game model output 'animation' objects that go
into a list. An animation can be a floating damage number above a
creatures head, a text message, or an arrow in flight.

When the time comes to draw the game, the game state and the animations
list are checked. The current state of the game is drawn, and any
relevant animations are overlaid.

Animations come in two classes, blocking and non-blocking. Nothing else
happens in the game until all blocking animations are complete (for
example an arrow flying to its destination may be rendered over several
frames, during which no in-game actions occur). A non-blocking
animation like a floating damage number just moves up and fades - it has
no influence on the game so the window just draws it over the correct
monster until its time expires.

One monster or player character may be thw subject of a blocking
animation; he is not drawn as part of the game state but as an
animation.

Text output could optionally block when the text window is full.

Works well for roguelikes since every action is atomic and sequential -
things that aren't (like damage number animation) are for information
only and have no side effects. It's not the most flexible system, but
it is simple and may meet your needs.

- Gerry Quinn

Radomir Dopieralski

unread,
Apr 18, 2013, 2:32:19 PM4/18/13
to
On 2013-04-18, Michał Brzozowski <mi...@extremic.com> wrote:

[...]

> Pretty nice and simple, but doesn't work. The reason is there may be
> many things happening in between player's actions, and the screen needs
> to updated more often. Also, many messages might appear, and the message
> window needs to block if it's filled, and the view must be displaying
> the situation that generated the last message (much like in Nethack,
> maybe other games solve it in a different way). This is typical during
> combat with many monsters. Another thing is displaying animations, for
> example of fired projectiles.

This is actually one of the reasons why turn-based games are so much
simpler to code -- you just process everything for the given turn and then
pause waiting for the player input, and repeat. Part of what makes
roguelikes so appealing to developers too!

So you start with something like this:

while not game over {
update display ($updates)
$input = wait for player input
$happenings = process game logic ($input)
$updates = process game graphics ($happenings)
}

There are several ways you can go from there, for example, you can add
some crude unskippable animations:

while not game over {
while there are unfinished animations {
$updates = update to next frame ($animations)
update display ($updates)
wait to keep constant fps
}
$input = wait for player input
$happenings = process game logic ($input)
$animations = process game graphics ($happenings)
}

Of course this is quite annoying for the players -- they hate unskippable
animations, and for a reason. So we can try and make them skippable, and
add some idle animations for our monsters, water, etc.

while not game over {
while not $input {
$updates = update to next frame ($animations)
update display ($updates)
wait to keep constant fps
$input = check for player input
}
$updates = update to last frame ($animations)
update display ($updates)
$happenings = process game logic ($input)
$animations = process game graphics ($happenings)
}

This is almost what we want, except for this pesky problem with the *more*
prompt, inventory, yes/no prompts and menus in general. But for those,
I have a separate concept: scenes. You can code a nicely working menu (or
more prompt, or yes/no prompt, or inventory screen, whatever) with code
similar to the one above, with its own animations, display updates and
input handling. Then you put all those screens into objects, and make
a stack of them. The main game loop will always loop through the code of
the scene that is at the top of the stack. But when things happen, your
animations can push new scenes on the stack, or pop themselves from it (or
do a combined pop and push, by replacing themselves with a different
scene). As a bonus, you can use this also for the start screen, character
creation, game over screen, high scores, etc.

A little more about those magical "animation" objects, because they do the
bulk of the work there. They are created from the "happenings" (I didn't
want to use the word "events", because it's too common in programming),
and are supposed to represent them. For example, if the player attacked
a monster, that would generate an appropriate happening, which records
that very fact, together with the positions of the player character and
the monster and whether the attack hit or missed, etc. Now, you take the
list of happenings and generate a list of animations from them. In this
case, you have the animation of the player character swinging her sword
at the monster, the (delayed) animation of the monster getting hit, and
the (further delayed) animation of blood splattering the walls. Oh, and
the animations for displaying the right messages in the console, and
perhaps an animation for displaying the *more* prompt, which would, upon
updating it, push a scene onto the scene stack, instead of updating the
display.

Anyways, there are many more ways for organizing your game loops. This is
one that works pretty well for me (by the way, I use iterator generators
in python to represent the animations), but I would be very curious about
other approaches too!

--
Radomir Dopieralski, sheep.art.pl

alex23

unread,
Apr 19, 2013, 1:37:26 AM4/19/13
to
On Apr 18, 10:26 pm, Michał Brzozowski <m...@extremic.com> wrote:
> I could probably do it with a few hacks and some spaghetti, but maybe there is a
> simple design that every one uses and I've overlooked.

I've found this article discussing various game loops to be
invaluable:

http://www.koonsolo.com/news/dewitters-gameloop/



Michał Brzozowski

unread,
Apr 19, 2013, 3:18:50 AM4/19/13
to
W dniu czwartek, 18 kwietnia 2013 20:32:19 UTC+2 użytkownik Radomir
Dopieralski napisał:
> Anyways, there are many more ways for organizing your game loops. This is
>
> one that works pretty well for me (by the way, I use iterator generators
>
> in python to represent the animations), but I would be very curious about
>
> other approaches too!
>

Thanks guys, that helped a lot.

Radomir, so let's take a situation that a monster hit the player and
caused some damage. So your "happening" object contains info on the
monster, the player and the damage. And you put it in a queue, and
before updating the screen you read all the elements of the queue, is
that right? Do you ever read the whole game state for rendering or do
you always update the screen using the additive changes that the
happenings or animations represent?

Also, your happening objects represent all possible monster actions
and things that can happen in the game, right? It must take a lot of
code and classes to do that, doesn't it? I thought that if the model
directly called the rendering logic, I could avoid that extra step.

Radomir Dopieralski

unread,
Apr 19, 2013, 5:10:01 AM4/19/13
to
On 2013-04-19, Michał Brzozowski <mi...@extremic.com> wrote:
> W dniu czwartek, 18 kwietnia 2013 20:32:19 UTC+2 użytkownik Radomir
> Dopieralski napisał:
>> Anyways, there are many more ways for organizing your game loops. This
>> is one that works pretty well for me (by the way, I use iterator
>> generators in python to represent the animations), but I would be very
>> curious about other approaches too!
>>
>
> Thanks guys, that helped a lot.
>
> Radomir, so let's take a situation that a monster hit the player and
> caused some damage. So your "happening" object contains info on the
> monster, the player and the damage. And you put it in a queue, and
> before updating the screen you read all the elements of the queue, is
> that right? Do you ever read the whole game state for rendering or do
> you always update the screen using the additive changes that the
> happenings or animations represent?

The latter, except for the initial rendering of the level at the
beginning. Although I do have animations for monsters and items appearing.

> Also, your happening objects represent all possible monster actions and
> things that can happen in the game, right? It must take a lot of code
> and classes to do that, doesn't it?

Not really, because I program in a dynamic programming language and
construct most of the needed objects at hoc when needed.

> I thought that if the model directly
> called the rendering logic, I could avoid that extra step.

Yes, you can do that, but at a cost of coupling your model with the
rendering code. It should be fine for a single-player game.

--
Radomir Dopieralski, sheep.art.pl

Gerry Quinn

unread,
Apr 19, 2013, 11:03:29 AM4/19/13
to
In article <slrnkn22k...@shell.sheep.art.pl>, ne...@sheep.art.pl
says...

> > Also, your happening objects represent all possible monster actions and
> > things that can happen in the game, right? It must take a lot of code
> > and classes to do that, doesn't it?
>
> Not really, because I program in a dynamic programming language and
> construct most of the needed objects at hoc when needed.

Even in C++ or similar it is not that hard, as the objects just need to
be big enough to hold all the data you need to transfer, and they can
have a code representing the subtype of 'happening' (I think it is
similar to my 'animation' concept).

Basically the objects are just messages.

- Gerry Quinn

paul-d...@sbcglobal.net

unread,
Apr 19, 2013, 8:10:29 PM4/19/13
to
Michał Brzozowski <mi...@extremic.com> writes:

> Hello r.g.r.d,
>
> I started another roguelike project a few weeks ago, and I'm about to
> make the first code refactoring, so I want to make sure to get it
> right. This topic has probably been discussed already, but I couldn't
> find any references. Feel free to point to articles or posts on this
> group.
>
> I've already designed a lot of the classes and managed to keep things
> simple, but I can't find an easy solution to the problem of passing
> and interpreting key strokes into actions, and simultaneously
> presenting the game on the screen.

I'm using something like this:

for (ever) {
when (key-pressed) ui.current-mode.process-key()
ui.current-mode.draw()
}

and a process-key() method does something like:

## process-key for movement mode
case(key) {
t: ui.enter-mode(targeting-mode) # throwing
h: ui.dmap.advance-world(move-left)
## other move keys here....
}

and advance-world takes a description of the move the player wants to
make, then progresses the game until it's time for player input again.

I'm not doing animations, but I am doing graphical "messages" that
diagram events of the past turn. I just have a spot in my dmap struct
where I store description objects like "(throw point-a point-b)".

Essentially I've got a "world" object that holds the whole world state,
and a UI object that interprets input and draws everything. The world
can be asked to do one unit of work (simulate one turn), and its
contents can be interrogated by the UI. And actually, all the work in
the UI is done by the mode objects. The UI object just tidies up some
variables that would otherwise be loose.

Sharp

unread,
Apr 20, 2013, 4:31:30 AM4/20/13
to

Gerry Quinn

unread,
Apr 20, 2013, 7:25:56 AM4/20/13
to
In article <8a9d6c76-2f57-4a79...@googlegroups.com>,
artur...@gmail.com says...
Actually I'm not sure the issues targeted by this article are key for
most roguelikes. They are more for action games IMO.

That said, I have always advocated that unless you really want to be
able to run as a terminal emulation, you should build your roguelike
with some basic animation capability, so in that sense it can be
relevant.

- Gerry Quinn

Krice

unread,
Apr 21, 2013, 4:37:31 AM4/21/13
to
On 19 huhti, 10:18, Michał Brzozowski <m...@extremic.com> wrote:
> Also, your happening objects represent all possible monster actions
> and things that can happen in the game, right? It must take a lot of
> code and classes to do that, doesn't it?

The action model doesn't have to be complex. The idea in
"actions in queue" -model is simple. It's simply gathering actions
and placing them in the right order. It's possible to create
a game where actions happen in the right order without placing them
into queue at all, in other words executing the actions as they
happen. But it's much easier to let queue handle the actions,
and you can then also process actions to check out things like
multiple messages/actions or even deciding if a message should
be displayed if it's not important.

Michał Brzozowski

unread,
Apr 22, 2013, 6:43:25 AM4/22/13
to
On 21 Kwi, 10:37, Krice <pau...@mbnet.fi> wrote:
There is also a side effect of the queue approach, the rendering class
needs to keep a state so it can be updated by the action objects.
Unless these hold a current snapshot of the (visible) world. Executing
the actions as they happen lets the rendering class be stateless, a
much cleaner design IMO. I still haven't decided which design to
choose though.

Radomir Dopieralski

unread,
Apr 22, 2013, 7:28:32 AM4/22/13
to
No, it doesn't need to be stateful if you just put enough information in
the queued objects -- for example, instead of "A moves to x, y" you need to
record "A moves from x1, y1 to x2, y2".

--
Radomir Dopieralski, sheep.art.pl

Michał Brzozowski

unread,
Apr 22, 2013, 9:38:35 AM4/22/13
to
On 22 Kwi, 13:28, Radomir Dopieralski <n...@sheep.art.pl> wrote:
Ok, but you need to redraw the whole screen upon each action. Do you
just apply the updates to a bitmap buffer? How do you redraw the now
empty tile that A has left, do you also keep that data in the bitmap
object?

paul-d...@sbcglobal.net

unread,
Apr 22, 2013, 7:09:00 PM4/22/13
to
Isn't that information in the world map?

Radomir Dopieralski

unread,
Apr 23, 2013, 6:01:28 AM4/23/13
to
On 2013-04-22, Michał Brzozowski <mi...@extremic.com> wrote:
No, of course I don't redraw the whole screen on every frame. Nobody does
that, except for beginner flash programmers. I have several layers of
background, a number of sprite groups and some GUI elements -- all of them
have their own image buffers. I update their positions/frames/whatever and
keep track of what has changed, so that I only have to update the dirty
rectangles on the screen. That's the normal way of doing it, unless you
intend to display 5 FPS on a 2GHz CPU, making the laptop hover 5cm over
your desk by the sheer power of its fans trying to prevent the CPU from
bursting in flames. Even if you rely on the GPU (which I do not) to do all
the work, you will get a much better battery life if you update your
screen reasonably.

So yes, the display class does have state, quite a lot of state about what
is being displayed, how it is animated, what part is visible due to
scrolling, etc. But all that information really doesn't belong in the game
state -- it's specific to this particular display. If you were to make
a split-screen multiplayer game, then you would just have two display
classes, each with its own state, and a single game state class.

The whole point about the queue and the data objects on it is to separate
your display from your game.

--
Radomir Dopieralski, sheep.art.pl

Michał Brzozowski

unread,
Apr 23, 2013, 11:10:07 AM4/23/13
to
On 23 Kwi, 12:01, Radomir Dopieralski <n...@sheep.art.pl> wrote:
Ok, thanks, I guess I'm a terrible programmer then :)

Michal

Radomir Dopieralski

unread,
Apr 24, 2013, 5:20:31 AM4/24/13
to
> Ok, thanks, I guess I'm a terrible programmer then :)
>

Argh, I did it again, didn't I? Sorry, I didn't want to demean the other
possible techniques, what I describe is of course only suitable for graphics-
and animation-heavy applications. If the display is simple and
straightforward, it's OK to keep it coupled with your game state. You only
want to separate it when it starts to get complicated. Personally, I'm
kind of fascinated with the topic, so I try to keep it separate and use
stuff like dirty updates etc. even when it's a simple turn-based game, but
that's just me, and it probably doesn't make me more likely to actually
finish the game.

--
Radomir Dopieralski, sheep.art.pl

Gerry Quinn

unread,
Apr 24, 2013, 10:55:05 AM4/24/13
to
In article <slrnkncn5...@shell.sheep.art.pl>, ne...@sheep.art.pl
says...

> No, of course I don't redraw the whole screen on every frame. Nobody does
> that, except for beginner flash programmers. I have several layers of
> background, a number of sprite groups and some GUI elements -- all of them
> have their own image buffers. I update their positions/frames/whatever and
> keep track of what has changed, so that I only have to update the dirty
> rectangles on the screen. That's the normal way of doing it, unless you
> intend to display 5 FPS on a 2GHz CPU, making the laptop hover 5cm over
> your desk by the sheer power of its fans trying to prevent the CPU from
> bursting in flames. Even if you rely on the GPU (which I do not) to do all
> the work, you will get a much better battery life if you update your
> screen reasonably.

I stopped using dirty rectangles a decade ago, when computers got fast.

- Gerry Quinn

Ray Dillinger

unread,
Apr 24, 2013, 10:46:02 PM4/24/13
to
On 04/18/2013 05:26 AM, Michał Brzozowski wrote:

> Pretty nice and simple, but doesn't work. The reason is there may be many things happening in between player's actions, and the screen needs to updated more often. Also, many messages might appear, and the message window needs to block if it's filled, and the view must be displaying the situation that generated the last message (much like in Nethack, maybe other games solve it in a different way). This is typical during combat with many monsters. Another thing is displaying animations, for example of fired projectiles.
>
> I thought about putting the model in control of its rendering, but it would require calling an update() method every time the state changes, and I'm not sure how I'd synchronize it with the message box.
>
> I could probably do it with a few hacks and some spaghetti, but maybe there is a simple design that every one uses and I've overlooked.
>

I recommend having a schedule that keeps track of all the actions that
are going to happen. Each action may have some effects on the map, on
mobs, or on the player -- and may (or may not) insert further actions
into the schedule.


Then the game loop becomes:

Repeat
Get the next Action
Execute that Action
Until the last action executed was GAME_OVER.

The action PLAYERS_TURN, when executed, schedules DRAW_THE_MAP,
DISPLAY_TEXT_OUTPUT, and FIND_PLAYER_TURN_ACTION.

FIND_PLAYER_OFFTURN_ACTION and DISPLAY_TEXT_OUTPUT get scheduled
by DISPLAY_TEXT_OUTPUT iff it runs out of room; The "rescheduling"
of DISPLAY_TEXT_ACTION allows the "rest of the text output" to be
displayed. FIND_PLAYER_OFFTURN_ACTION uses an alternate menu restricted
to "meta" and "out-of-game" actions (which take no game time) as opposed
to "in-game" actions. Most creatures when they do something will
schedule an ADD_TEXT_OUTPUT which of course just accumulates text until
DISPLAY_TEXT_OUTPUT belches it all out just
before the player's turn.

The main objects involved are the game, the display, the map, the
actors, (which includes all mobs) and the menus.

Hope that helps.



paul-d...@sbcglobal.net

unread,
Apr 25, 2013, 6:20:50 PM4/25/13
to
A lot better to find a display method that won't run out of room though,
isn't it? A --more-- prompt is awful UI design. An alternative might be
to flood over the game screen as much as necessary, and print a message
to "press such and such key to shrink messages". Same worst case work
required from the player, but if an insignificant part of the map is
covered, no action is required. And most of all, the player's actions
never get eaten or ignored by a prompt they didn't realize was sitting
there. Or of course you could remove the message queue in favor of
another depiction for events (which I'm heartily in favor of).

> FIND_PLAYER_OFFTURN_ACTION uses an alternate menu restricted to "meta"
> and "out-of-game" actions (which take no game time) as opposed to
> "in-game" actions. Most creatures when they do something will
> schedule an ADD_TEXT_OUTPUT which of course just accumulates text
> until DISPLAY_TEXT_OUTPUT belches it all out just before the player's
> turn.

This seems like an interesting system, your input processing code is
called from the same action queue that controls other game events, like
monster motions. Is that right? And if you had animations, you could
alter it a little bit so that instead of a screen-drawing action, you'd
have an action to prepare everything the presentation system needed to
draw the screen and animations.

Ray Dillinger

unread,
May 3, 2013, 4:02:59 AM5/3/13
to
On 04/25/2013 03:20 PM, paul-d...@sbcglobal.net wrote:

> This seems like an interesting system, your input processing code is
> called from the same action queue that controls other game events, like
> monster motions. Is that right?

'Zactly.

> And if you had animations, you could
> alter it a little bit so that instead of a screen-drawing action, you'd
> have an action to prepare everything the presentation system needed to
> draw the screen and animations.

Yes. The paradigm is very very general. You can take that
action loop and do essentially anything with it,

There's no point in having a separate system and different
scheduling rules for input and screen drawing and monster
movement and message display. They're all actions that need
to get done, they need to get done at particular moments in
the schedule, and if you're doing a general event scheduling
system you already have a system to schedule actions that
need to get done and do them when they come up on the schedule.

Bear



0 new messages