Huh boy. Location implementation is taking much longer than I was expecting it to – every time I implement something I realize I need to implement something else too before I’ll be satisfied enough to record another demo video. Already I’ve got locations themselves implemented along with transitions between them, initiation of conversations with characters in locations, cutscenes, and environment examination, but I’ve still got more to do. On the plus side, this is going to be a pretty huge update when it finally goes live. Hopefully you folks can wait a little while longer.
While we wait, though, since the last blog entry was pretty well-received, I thought I’d write another one, this time dealing with game structure and cutscenes. …But first, more screenshots! Just for fun.
Much more after the break!
So, cutscenes. These were certainly an interesting beast in terms of planning. Before I start specifically talking about cutscenes though, it’d probably be helpful to talk more broadly a little bit on the topic of design structure.
Software design tends to be a very misunderstood art among those who’ve never done it before. I constantly have people who have this picture in their heads that software design is basically just sitting in front of a computer writing line after line after line of code and then you’re done. That’s… not exactly an accurate picture, to say the least. In fact, the actual programming is only a small minority of the process, and that comes at the very end. Computer languages are just tools like anything else – you wouldn’t start building a house with no plans and just hope it all works out in the end, and similarly you wouldn’t start programming a sizable project and just hope it works out in the end either.
In fact, the vast majority of time spent on a large software project is in the planning stage – the stage at which everything is laid out conceptually without actually implementing it. The main reason for this is two concerns known as scalability and maintainability. That’s roughly tech jargon for, “Its design needs to be easily conceptually understandable, and needs to remain understandable and manageable even as the project’s size grows.” It’s very easy to start coding something quick and dirty that works on a small scale, but which quickly begins to fall apart as the size and scope of the project grows. Any successful large project requires a great deal of logical and hierarchical structure that acts as the glue holding everything together.
In My Little Investigations, for example, the root object is a case, which holds several areas, each of which holds several locations, which in turn hold characters, foreground elements and transitions, and then characters hold encounters, which finally hold conversations and interrogations. This ups the initial complexity, but ultimately is a big win in terms of the above two qualities – this makes it so that, rather than worrying about the case as a gigantic whole, we can instead encapsulate a lot of the functionality in smaller pieces that can then be easily swapped out in a manner consistent with the user experience. For example, the area that the player is currently in holds a reference to the current location that the player is in, and then when it goes to update and draw, it just tells that location to update and draw rather than directly doing anything itself. When the player then moves to a new location, we just swap out that reference to the current location with a reference to the new location the player moved to, and everything just keeps trucking along happily.
As another example, within locations, there’s a check to see whether there’s an encounter ongoing; if so, the location just updates and draws that encounter, whereas otherwise it accepts keyboard input to move the player character (Twilight) around the scene. We want to make it so that the player can click on one of those and have Twilight either comment on the foreground element or start a conversation with a character. In order to accomplish this, given this design, all we need to do is load the encounter associated with the foreground element or the character, and the location will then just automatically do the right thing since encounters are also self-contained objects that run themselves. If we didn’t do this, then we’d have to specifically worry about all the details every time, which is not something you want to do in a software project – that very quickly becomes unmaintainable.
Which brings us to cutscenes. As stated above, cutscenes (that is to say, sequences of character motion and dialog that involves no actual gameplay) are a pretty interesting case in video games. For starters, there’s no obvious level in the design hierarchy in which cutscenes fit – intuitively they should exist at the location level, considering that cutscenes obviously take place at a location; however, at second glance the area level might be more appropriate, since a single cutscene can theoretically span multiple locations. Furthermore, one thing that computers are really good at doing is repeating things – same input, same output. Cutscenes really do not fit into this paradigm well at all – they are one-shot deals, things that are triggered and which run once and only once, even if the players go through the same motions a second time that triggered a cutscene the first time.
So I initially was going to either have areas own cutscenes, or have cutscenes exist independent of this hierarchy. But then came the practical considerations that began to outweigh the conceptual considerations: if areas owned cutscenes, or if they weren’t in the hierarchy at all, then what would trigger their display? Would we have to check every single cutscene in every single location to see if the player is in that location and whether the cutscene should be displayed? The more I thought about it, the more it began to make much more sense to associate cutscenes with locations rather than with areas, which was what I was initially going to do.
And eventually that’s exactly what I did: locations own cutscenes, and when you’re in a location, it checks to see whether any cutscenes are enabled but have not yet run, and if there are, then it runs them. This also makes it possible to simulate cutscenes that span multiple locations, as well: you can just enable two cutscenes in two different locations and then have the first cutscene move you to the second location when it’s done, at which point in time the second cutscene will seamlessly begin, making it seem like one long cutscene.
And that’s all for today’s behind the scenes look at stuff in video games!