A look at the KIAVC internals

As a first “deep dive” post, I thought I’d share some details about how KIAVC works internally, in terms of its main cycle, how it loads and keep track of resources, how it deals with scripting, rendering, etc. Again, I won’t focus too much on any specific feature (the scripting part will definitely have its own post, for instance), but it should give a good understanding on how I structured the code and some of the choices I made.

I’ll start by giving a quick intro on how the engine is structured internally, mostly in how it deals with resources, to then describe the main loop that actually implements the engine behaviour.

Dependencies

Before starting, though, let’s have a quick look at dependencies.

The main one is SDL2, which to me was a no-brainer for a few reasons: first of all, it’s used by a ton of projects out there; then, I had played with the 1.0 version of the library already, many years ago, so I had a bit of familiarity wth it; and finally, as a library conceived for cross-platform development, it made a lot of sense to use it to abstract as many differences between Linux, Windows and MacOS away.

Another library I chose to rely on was GLib. It’s a library I rely on a lot in other projects, since it provides amazing helper functionality like hashtables, queues, and stuff like that, but for KIAVC I initially tried to avoid it, as I wanted to first check if SDL2 provided some replacements and shims already (as it does for memory allocation and strings management already, for instance), and I wasn’t sure whether it could be an issue when targeting platforms like Windows (due to the additional DLL dependency). Eventually, I figured out GLib was actually already implicitly part of the set of dependencies due to SDL_ttf (for HarfBuzz), so I decided to simply start using it and making my life easier. In KIAVC, I currently only use it to implement hashtables (which I use a lot for addressing registered resources) and linked lists (because I’m lazy 😀 ).

Finally, another important core dependency is of course the Lua embedded engine, which is required for scripting the game. The way I implemented scripting management in the core, it’s supposed to try and shim most of the Lua engine functionality through functions: I did it this way to keep the doors open to other scripting languages in the future, but in practice it’s currently quite heavily tailored on how the Lua engine works.

Generic structure

As anticipated in the introduction post, I wrote KIAVC in C, while using Lua for the scripting part. This means there’s an engine core written in C that implements the “hard” stuff, like getting user input, rendering, audio management, handling resources, and stuff like that, which then interacts with a set of Lua scripts that implement logic on top of that. Borrowing an image from the excellent Groebelshoot blog, it looks quite similar to this:

As I’ll explain in a future post on scripting, there’s a few things I do a bit differently (the game state is partly shared between the engine itself and scripts, for instance), but apart from that, this is a good representation of how responsibilities are shared.

The whole engine is single threaded, which is a choice I made on purpose to ensure we’d keep things simple, and to minimize the risk on nasty race conditions. This allowed me to work on an event-based pattern as part of a main loop, as I’ll explain better further below. Of course, using a single thread also means using a single core on the machine, which may be suboptimal: I’m not sure if this will be a problem further along the road, e.g., if/when I’ll start tinkering with higher resolutions or smoother animations, but for now this seems to be working nicely and with a very low use of resources. I’ll worry about performance when I need to worry about it :mrgreen: .

Focusing on the engine itself (the “game framework” in the picture above), each resource type has its own struct, which helped me organized the code in pseudo-classes: there’s one for images/animations, for instance, one for rooms, one for actors, one for fonts and so on, each with their own helper code for things I needed to be able to do from the engine loop.

More specifically, the engine revolves around the idea of “registering” resources. This simply means that, whenever you want to for instance use an image in your game, you first need to “register” it with a unique ID: this results in the engine creating a dedicated instance of the related image struct, and saving it into a map, so that we can quickly reference it any time that we need it. This also allows us to re-use the same resource in different contexts: if you want the same background to be used in two different rooms, you just configure both rooms to refer to the same image ID. The simple sequence diagram below, for instance, shows how we can register a “tree” image, and then use it for multiple objects we’ll put in a room:

Registering a resource doesn’t mean it will be loaded right away: the engine loads resources automatically when it needs them, which means that in the context of the background or object image we were using as an example, we’ll only load the image when we know we’re about to render it. KIAVC is not as “efficient” at unloading resources at the moment, though: once a resource has been loaded, it stays in memory until it’s needed again, wh. In the future I’ll probably add some kind of reference counting mechanism, where we can unload resources that aren’t needed anymore (until they are), but so far this hasn’t been much of an issue, and with the small demo I wrote memory never was an issue.

Of course, not all struct instances are related to actual resources: some of them are associated with functionality that the engine needs to provide, like BAG archiving support (the ability to package asset files in an archive, and loading from it rather than from disk), interaction with Lua scripts and pathfinding. I’ll focus on those in future posts.

Main loop

As anticipated, the engine is single threaded, and basically works in a loop that starts when you fire up the engine, and is only interrupted when you quit. To design this loop, I basically did what every game seems to be doing out there, so it’s nothing new:

  1. you get user input (mouse, keyboard)
  2. you update your “world”, making it progress using specific units of time (e.g., ticks)
  3. you actually render something on screen on a regular basis

All of those three steps are repeated over and over again, even if of course you don’t always do something when dealing with any of those steps. You only capture input if you got events about something happening, for instance, otherwise you move on: if you always wait for a mouse click before you leave step 1., for instance, this means that in a single threaded application the image will freeze until you click, since step 3. (rendering) only comes later. In a nutshell, the flow is depicted in the ugliest diagram you’ll see today:

At the same time, “updating the world” means changing the state of the resources as time goes by: deciding which is the current frame in a walking animation for an actor, for instance, depends on how much time passed; if you move to the next frame any time you get to step 2., you’ll get a super fast animation depending on how fast your CPU is. As such, this is the step where you decide how resources are updated in general, which includes if/how animations should proceed, updating the current position of actors, rooms or objects depending on user input (e.g., using previously calculated pathfinding to move the actor a step further), and so on. However this is handled, it’s important that this is kept completely separated from rendering, as otherwise you risk having a game that moves at different speeds depending on how fast the machine can draw things. KIAVC does take this into account, by updating everything in step 2. (which includes poking the Lua engine, so that pending coroutines can be resumed and the “world” can be updated there too), and only taking care of that to draw in step 3.

In fact, the rendering step actually needs to only worry about a single thing: rendering stuff. In KIAVC, this means iterating on all things we need to draw, in order of spatial placement (the engine keeps an ordered list where the ordering is dictated by the z-plane of each resource to draw), and just draw according to the last updates that were performed in step 2. Again, the rendering part will NOT be performed any time we iterate in the loop, quire the opposite: in fact, we should only draw as often as dictated by the framerate we want the game to have. This means that, if we configured the engine to draw at 60fps (frames-per-second), then we’ll only do something if 1/60 of a second has passed since the last time we drew something on screen. Considering updating the state of the animations is performed independently of rendering, the end result is that the “speed” of the game will be exactly the same when you play at 60fps as when you play at 5fps: the only difference will be that at lower framerates you may see things a bit more choppy, and lose some animation frames, but the game will always work at the intended speed. Again, this is something KIAVC does automatically.

File resources

Let’s have a look, now, at some of the resources that KIAVC can register, with a few words on how they were implemented and why, and the current limitations I plan to take care of next. These are all resources that the loop introduced above uses automatically, when they’re configured to be part of a current scene.

Images and animations

As you can see, I’ve put images and animations together, and for a simple reason: they share a lot in common. Initially I had two separate structs for them, but since they differed only in the number of frames, I eventually confluted them together, meaning the engine now consider an image an animation with a single frame, and treats it that way. Notice that, in Lua scripts, you actually refer to images and animations using different classes, which then transparently interact with the code to register the same kind of resource: I chose to do that for semantic reasons, and try to avoid some confusion for developers. Implementation-wise, I used the SDL2_image library to deal with both images and animations, obviously, since I’m using SDL2 as a foundation.

Most of the times you just have to provide a path to the image to register it, but considering not all images may have a transparent background, I took advantage of the SDL2 SDL_SetColorKey function to also expose a way to provide a color to treat as transparency. In the demo, this is used for instance for the blinking cursor, which has a yellowish background instead of being transparent.

Animations are handled a bit differently. At the moment, the engine assumes the animation will be provided as a single image, presenting a row of the frames that make the animation itself, rather than separate images with the different frames. Besides, to keep things simple in this first iteration, I also made a few assumption that I’ll definitely need to address sooner or later, namely:

  1. the code assumes all frames of the animation will have the same size, that is computed automatically from the size of the full image and the number of frames (which needs to be provided by who’s registering the image); this makes sense in most cases, but there are times where this might be considered limiting;
  2. the code at the time of writing also doesn’t provide any way to specify how long each animation frame should last, and simply uses a hardcoded timer (100ms) to advance frames; this is of course quite silly and stupid, but again, it’s how I started writing the code to get something working sooner, and I haven’t fixed that yet.

An example of an animation used in the demo (which was adapted from this excellent free asset) can be seen below, where we have a single image with 8 different frames. Since the whole image has a 320×69 resolution, and we tell the engine there are 8 frames, the engine will automatically assume it can clip it in 8 chunks of 40×69: when rendering, this clipping is performed at runtime, passing an SDL_Rect for the source to SDL_RenderCopy when drawing the current frame.

That said, once you register an image/animation, and configure a game resource to use it, there’s nothing else you need to do: the engine will take care of the rendering for you automatically.

Music tracks and sound effects

Just as images and animations are implemented in the same struct, I did the same for music tracks and sound effects, since they share the same implementation; once again, they’re exposed as different classes in Lua scripts, instead, to make a distinction between the two clearer (e.g., music tracks loop, while sound effects don’t).

The main reason why I chose to keep them together is related to how SDL2_mixer, the library I use for audio management, works internally. SDL_mixer does have different functions for dealing with music tracks and generic sounds (which they call chunks), each with their own optimizations: as explained in the documentation, chunks are decoded right away and stored in memory, while music is decoded on demand (as they may be larger). The main problem, though, is that the music related functions, while neat, don’t allow you to play multiple tracks at the same time: I considered that quite limiting, especially considering I wanted to be able to emulate iMuse kind of functionality (e.g., by smoothly fade out one track while I fade another one in), and that didn’t seem to be possible with music channels. As such, I decided to simply use chunks for both, and then expose different functionality on top of that, e.g., in terms of fading channels, looping vs. not looping, and so on. So far this seems to be working nicely!

Whether it’s music or sounds, our chunks don’t have a pre-assigned channel, but we let the library pick one when starting to play a chunk, and we then keep track of it. Considering we can fade out channels too, this also means we need to be able to know when a channel has finished playing: for this, I chose to rely on Mix_ChannelFinished so that a callback would be invoked where I could update the mapping between chunks and channels. That said, this is one of the places where the single threaded nature of the engine, and the assumptions I had made, caused a problem: in fact, SDL_mixer uses separate threads for audio playback, and the callback was invoked from one of those threads. This forced me to add some limited locking functionality just to the audio “class” in KIAVC, so that I could use them in a thread-safe way transparently to the core.

One important feature that is still missing, though, is volume management. I’d like to be able to expose a way to set a global volume, but that isn’t as simple as it sounds. In fact, while SDL2_mixer does provide a function called Mix_MasterVolume that would be perfect for that, it’s unfortunately only available from version 2.6.0, which is very recent and not available to many (it definitely isn’t to me on my Fedora 35!) . This means that any attempt to set a master volume on older versions would typically need setting the volume for the different channels separately and independently. That’s all good and doable, but there’s a different issue with this: since we support fading audio channels in an out, setting the volume channel actually interferes with that 😦 As such, for now I’ve kept this feature on hold, until I can figure out a better way to deal with this.

Fonts and text rendering

In an adventure game, text is quite important of course, so I did spend some time trying to figure out how to render text properly. I once more relied on the help of an SDL2 library for that, specifically SDL2_ttf. In fact, while I briefly considered using image based fonts (which are apparently quite common in the gaming world), they seemed to require more effort than I wanted to spend in this initial stage, and so I went for the “easy way out” of TrueType fonts, at least for now.

In the KIAVC core, fonts are one of the resources you can register, specifically by providing a path to the TTF file you want to use, and the size of the text: this does mean that if you want to support the same font in different sizes you need to register multiple instances, but that’s probably not a big deal (as I don’t expect that to happen very often anyway). Once such a font is registered, it can then be referenced to create as much rendered text as you want, e.g., for dialogs, cursor text, random text that needs to appear in the game and so on.

Text rendering requires a reference to the font you want to use, and then has a few settings you can specify, like the color of the text and, optionally, an outline to draw around the text itself. This allows you, for instance, to create white text with a black border for the lines your main character is speaking. Outlines did provide an interesting challenge: initially I thought I simply had to draw the same text more than once in slightly different positions (e.g., multiple instances of black text, and then white text on top of that), but while that is indeed how you do it with image-based fonts, it turned out there was an easier way of doing that with SDL2_ttf, by using some of its Blended functions. I tinkered with that until I got something I was happy with, and it seems to be working fine now. The two screenshots below, for instance (which come from the engine demo), show the outline at work for an actor speaking and for some cursor text when hovering on object, using different fonts:

Of course, as anticipated an outline is entirely optional, and you can choose to render text without it as well if that’s what you want. The screenshot below, for instance, show how I chose to use no outline when displaying dialog puzzles instead:

That said, there’s one key feature that, at the time of writing, is still incomplete, and is related to automatic wrapping of the code when you don’t want to exceed a set width for the rendered text. SDL2_ttf does have some _Wrapped versions of its rendering functions for text, but once more not all are available if not in recent versions, and they seem to have some quirks too: first of all, it seemed to cause some issues when using outlined text (sometimes the text and outline wouldn’t wrap at the same point), and besides there were issues with text justification as well, since text would not be centered (the ability to control that is provided by TTF_SetFontWrappedAlign, but only in too recent versions of the library). To keep things simple, for now, I added some code to manually split text to render in multiple lines when detecting a “new line” character, and that works quite nicely: it also requires the game developer to manually worry about multiple lines, though, which is definitely suboptimal, so as a next step I plan to figure out a way to arbitrarily split the text in multiple lines in an automated way depending on the maximum target width (e.g., using TTF_SizeUTF8 to estimate the resulting width of the lines before actually performing any text rendering).

Game resources

Actual files are obviously not the only resources you can register in the engine. There are actually other resources that play a much more important role, and it’s the ones related to key concepts in the engine from a gaming perspective. There are resources, for instance, to represent the concept of rooms, actors, costumes, objects and cursors, besides resources that are more closely related to some engine functionality like dialog puzzles and pathfinding (both of which I’ll talk about in different posts to come) .

Rooms

Borrowing this concept from SCUMM, a room in KIAVC is where a scene is taking place, and may not be a room at all: it may be a forest, or a close-up of a character, or end credits rolling. Historically, they were called rooms since SCUMM was created for Maniac Mansion, which being a mansion did have a lot of them 😀

Within the engine, you typically first register a room with a unique ID (that you can use to reference it any time you need it later), and then set some of its key properties, which includes the background image you want to use, plus optionally some foreground and background layers (depending on their z-plane). The engine also keeps track of the room “position” (what’s currently displayed on the screen), which is particularly important in large rooms where you may need to follow an actor around and perform some scrolling. Besides, a room in KIAVC also needs information on the walkboxes to use for pathfinding, that is which parts of the room an actor can actually walk on and how to go from where you are to where you click (which is too long to explain here, and I’ll address in a dedicated post), and a list of actors and objects that it contains.

We mentioned before how we can register images and sounds in the engine, so the fact that a room needs to have a specific background or a specific background music is something that’s decided when scripting a room, so from Lua in this case. We’ll focus more on this aspect when we’ll talk about the relation between Lua scripts and the KIAVC engine, as there’s a lot to say there. What’s important to point out here is that, once you set some properties from the script and let the engine know what you want a room to have, the engine, will take care of rendering things automatically for you, which includes scrolling when it needs to, rendering things in the right order (e.g., if you add a layer with a silhouette of a tree that needs to be in front, an actor will always be behind it), and things like that.

As many resources in the engine, there are some things that are incomplete for rooms as well. A key thing that’s currently missing is vertical scrolling: I started tinkering with the engine using assets from existing games from the past (like Monkey Island and Flight of the Amazon Queen), and many of them only had horizontal scrolling (when I think about it, the first time I saw vertical scrolling in a LucasArts game was probably in a scene from The Dig, although I may be wrong!). As such, it was easy to start that way. That said, this is definitely a limitation I’ll have to address: if you think about Thimbleweed Park, for instance, vertical scrolling was very much an option there (remember the shop library with all those books? 😀 ), and more in general modern games do need that option at times.

Another partial limitation is in scrolling itself, which can be a bit choppy at times. At the moment, I have some hardcoded values on how much you should scroll when following actors around, which is most definitely not the best way to handle that: at the very least, for instance, we should take into account the actor speed. Besides, there could be nicer effects to apply when scrolling as well: I mean, look at how glorious this tech demo from TP was!

Actors and costumes

An actor in the engine is basially anything that can potentially talk, walk around, be talked to, etc. As such, actors are used not only for the main character (or characters, if you want to do something à-la Maniac Mansion, Thimbleweed Park or Resonance with multiple characters you can control), but also NPCs you’ll engage with. Notice that an actor doesn’t need to represent a person: it could be an object, or an animal, or whatever else, as long as you need it to do more things than a more static object can do.

Anything related to how an actor should look like (still or animated) is not a property of the actor itself, but a so-called “costume”. In a nutshell, in the engine registering a costume means associating a set of previously registered images and/or animations to different activities: in the demo, for instance, we register four different static images for the detective standing still (one for each direction), four animations for talking, and four animations for walking. This set constitutes a “costume”, that can then be assigned to an actor, so that when an actor, for instance, walks around, the engine knows it needs to use the related animations from the associated costume. Separating actors from costumes is important since it allows us to re-use the same costume for different actors, without having to duplicate registrations: this is again something I did in the demo as a necessity, since I only had a single animated character to play around with, and so I ended up assigning the same detective costume to both the player actor and the NPC you talk to. In actual games, this may be useful in different scenarios: in SCUMM, for instance, they used this trick for the Nazi soldiers in the Indiana Jones 3 game (with some more advanced tricks that are not part of KIAVC yet). Besides, it allows for more flexibility for a single actor as well: if you need different animations for an actor depending on whether he’s wearing jeans or a tuxedo, you simply define different costumes, and then set one or another for the actor depending on the state.

The engine supports a few additional properties that can be dynamically applied to actors in a scene, like their position (relative to the room), their walking speed, their z-plane index, the scale factor (e.g., to make them smaller when going towards a mountain), and so on. Actors are also the only resources that the engine can apply pathfinding to, since they’re the only resources that can be talked to walk to a specific point in the room. Rendered text for an actor is also automatically placed on top of them by the engine, and their duration roughly timed to how long the string is.

That said, there are a few things that we still need to implement as far as actors are concerned, which are mainly limitations in the set of images and animations you can provide in a costume (and so for rendering an actor). At the moment, you can only specify three different things: images to use for standing still, animations to use when talking, and animations to use when walking, and all of them only for 4 directions (up, down, left, right). When you look at how SCUMM works, it’s less static than that, as you can also define “custom animations for the so-called “special animations”, that is those animations you’ll only use for specific cases (e.g., Guybrush grinning, or raising the bone to the sky and his pants falling down). As such, in the future there will need to be more flexibility in KIAVC as well, so that game developers are given more freedom should they need it.

Objects

Objects are a special kind of resource in the engine, as they have many different purposes. On one end, they can indeed represent actual objects, meaning objects you can possibly pick up and interact with, all with their own images or animations to be represented in the game world. On the other end, they could be nothing more than props, or even abstract UI elements you may want to be displayed on the screen (e.g., an inventory, a settings button, a knob of some kind, etc.). At such, the engine is configured to act differently depending on how scripts register and configure/update objects.

As far as the engine is concerned, an object is basically a structure identified by a unique ID plus a few optional properties, like the room the object is in, if it’s owned by an actor, and so on; you can also specify whether the object is an interactable object, a prop (something you only put on the background to give some color, like an animated lantern), or an UI item, which also dictates whether the object position will be relative to the screen or the room; in case the object is configured to be interactable, coordinates for how to detect when the mouse is hovering on the object can be provided too, so that the engine can work on that and notify the script when hovering on an object starts/stops.

It’s important to point out that an object may or may not have an image/animation associated with it: to make a simple example, in the demo there are several objects you can interact with, that are actually part of the background, though. When you look at the restaurant, hovering over it does display its information, even though there’s no actual restaurant object: simply speaking, we registered an object and told the engine those coordinates had to be associated with it, specifying what needed to happen when we interacted with it.

Objects as part of the UI rather than the room are particularly interesting for different reasons, as they’re what allows you to provide a custom user interface depending on how you want your game to work and look like. In the demo, for instance, I wanted to add a simplified inventory permanently on top: to do that, I first of all created a non-interactable object called “inventory”, marked it as a UI element, and then told the engine to display it on top of the screen (x=0, y=0); then, for objects that can be picked up, I added some more code to the script so that when an object (i.e., the skull, in my demo) was picked up, it would also be changed to have a UI status (while before it was part of the room), and its position changed so that it would fit one of the slots on the inventory, as shown in the screenshot below.

Future enhancements to the demo may include additional UI objects for, e.g,, arrows to use when the inventory starts to fill up, so that when you click one the index of the inventory changes. You may even want to implement the inventory in a completely different way, e.g., with a button that makes a bag appear with the objects in it: that could be implemented with a UI object acting as the inventory on/off trigger, and a different UI object that only appears when you click the inventory button to show the inventory content. The idea is that this could be used for implementing a ton of different things (possibly even a SCUMM-like verb menu!), but of course whether the code is indeed that flexible or not already is very much to be verified.

One thing I’d like to implement soon, for objects, is the ability to group them, so that we can enforce group actions: to make a simple example, if you have multiple UI objects all part of an “inventory” group (the group background, the objects themselves, other buttons), a showObjectGroup(“inventory”) or hideObjectGroup(“inventory”) could tell the engine to start or stop rendering multiple objects at the same time, rather than independently trigger the visibility of each object we want to impact (that would force the script to keep possibly more state than needed).

Cursors

It may seem weird to include cursors as part of the resources you can register in KIAVC, but there’s a reason for that. In fact, while in most cases the pointer may always remain the same, there may be cases where you may want it to change in the game: e.g., a blinking cursor when you move the mouse around, a different cursor when you’re hovering over something, or an object icon as the cursor when you want to try and use the object with something. Considering that each cursor resource you create can be associated with a specific image/animation, it’s quite easy to then script cursor changes to tell the engine which cursor to switch to dynamically. The animation below, which again comes from the demo, shows a practical example of this, where we start with the “regular” blinking mouse, which then changes when we’re hovering on the skull, and finally “becomes” the skull when we click it to select it, just to become the “main” cursor again when we right click to deselect the object:

As far as the engine is concerned, once a specific cursor resource is dynamically configured to be the active one, it will instruct the engine to render the right thing as you move the mouse around. At the time of writing, you can configure two different types of cursor: the “main” one (the default cursor that will be displayed), and a “hotspot” one (the cursor that should be automatically used when hovering over something). The reason for having two sets of cursors configurable in the engine is mostly avoiding too much back and forth: in fact, while scripts are notified when hovering over something happens, and so tey could automate a cursor change accordingly, since that may happen a lot it felt like too much guidance needed from scripts, and so an additional burden on developers. That said, engine can also be configured to add some text to a pointer, which gave me the opportunity to still use those hovering events in the scripts to react somehow: specifically, in the demo I chose to use those events to tell the engine to use the related object name as the cursor text, which is one more thine the image above displays.

In theory, these dynamically configured cursors could also be used for using contextual cursors: e.g., you may want right clicking to change the action you want to perform, so that the cursor icon can change accordingly (e.g., a mouth to talk, or a fist to pick up or use things). In practice, I haven’t really checked, but that could be some nice homework for interested developers :mrgreen:

That’s all!

I hope this wasn’t too boring, but I felt I needed to cover some of the foundation first, before addressing more interesting and “appealing” topics like scripting, pathfinding, dialog puzzles and so on. As explained in this post, a lot of the “meat” is there already, but there’s also quite some work to do in order to finalize the implementation of what’s available (e.g., more control on animations, automated splitting of text on multiple lines, vertical scrolling, etc.).

In case you noticed anything that smelled weird to you when reading the post, please do let me know! I implemented things in ways that made sense to me, but that may be quite differently from how games are usually developed. As such, feedback from people actually working on things like this for more than fun would be great to have.

See you soon again for another post!

Advertisement

One thought on “A look at the KIAVC internals

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s