4

I'm writing a text-based game, in C. I want the game to handle NPCs movement and actions in the background, while the user is making his moves. I'd also use time-based events to tell the user when midnight is (in game-time), or to activate certain things at certain times.

I know that Dwarf Fortress is all single thread stuff, but I can't understand how that's done. I don't know how he handles events. Surely he's not polling.

I've never done any thread programming, or anything with sockets. I've been programming for a while, but I know nothing about those things.

I googled options, but there seems to be a lot of stuff that comes under the heading of event-handling. I have no idea where to start. The first idea that comes to mind, is have two separate programs communicating through a text file, but that seems like a very ugly solution.

What's the simplest solution to handle events such as I described?

I'm currently working in Windows but I would switch over to linux if it's easier. I just happened to be using a Windows machine when I started, so it doesn't matter which.

  • 3
    On which operating system? Please edit your quesiton to improve it. – Basile Starynkevitch Jun 27 '15 at 5:26
6

It is operating system specific (or hardware specific if you are coding some kernel-like software on the bare metal like an OS kernel -see osdev.org-, in freestanding C). Stricto sensu you probably cannot write a game in purely standard hosted C99 (without using any external library, except the C standard library using only the few functions standardized in C99): you need to use some operating system service.

I'm focusing on Linux in my answer below.

If you are coding on Linux (in hosted C, as all user programs are), you'll code your event loop around a multiplexing syscall like poll(2) (or perhaps the older select(2), which I usually don't recommend; see also epoll(7)). Read about the C10K problem. You might use some event loop library like libev or libevent.

If you are unfamiliar with most Linux syscalls (listed in syscalls(2)...), read Advanced Linux Programming.

Reading and polling the terminal is tricky on Linux (because tty-s are quite complex). You probably want to use some library, like ncurses, to make a terminal application.

If you want to code a GUI application, you'll practically use some toolkit framework like Qt or Gtk (or libsdl). They provide an event loop, and you'll need to register callbacks (read also about continuations, it is a relevant concept).

If you want to have two programs (written by you) communicating, you'll need to use some IPC machinery, notably pipe(7)-s. You'll probably need some event loop in some (or both) of them.

For time-related issues, poll(2) (so all event loop libraries built above it) is given a delay. See also time(7).

I don't recommend using signal(7)-s in your case (signals are an interrupt like abstraction provided by the OS, notably POSIX ones). If you do, be very careful, it is tricky. A signal handler is only allowed to call very few async-signal-safe functions, and the usual way is often to simply set some volatile sig_atomic_t flag in it, to be tested and reset inside your event loop. See also POSIX signal concepts chapter.


If you are coding on a non-POSIX operating system like Windows, you need to learn how to write event loops on it, and what is the low-level system API. You'll probably find some library for that. There exist a few libraries (e.g. Qt & POCO - both for and in C++) which are cross-platform. Windows programming is very different from POSIX programming, I know nothing about it.

  • 2
    ​​​​​​​​​​​​​​​Please stop bumping the question with minor edits. Almost every link in your answer is unnecessary. This is a software development site, people are expected to know or be able to find out on their own what an operating system is, for example. – yannis Jun 27 '15 at 13:31
1

The simplest solution is to use interrupts and timers.

The interrupts indicate:

  1. User I/O inputs
  2. Timer expiration

Two separate programs could communicate via two pipes or msgsnd() or semaphores or mutexes or signals.

(I think there is no need for multiple programs.)

If you write the program so that everything is interrupt driven, along with a 'background' activity that is running when no interrupt is being serviced. Then the program should be 'relatively' easy to implement.

Some experience with real-time embedded program would greatly assist you in the design, coding, debugging and documenting of the program.

  • 2
    This is mostly true for a kernel-like freestanding system. You don't have direct access to IO or interrupts or hardware timer when coding user code to be run under some operating system. – Basile Starynkevitch Jun 27 '15 at 5:25
  • 2
    I'm tempted to downvote that answer, because it does not answer the question; it looks like the OP want to code under some operating system (not on the bare metal), and then the above answer is off-topic. – Basile Starynkevitch Jun 27 '15 at 5:44

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.