label start:

scene bg uni

show sylvie smile



s "Oh, hi, do we walk home together?"

m "Yes..."

"I said and my voice was already shaking."



scene bg meadow

with fade



"We reached the meadows just outside our hometown."

"Autumn was so beautiful here."

"When we were children, we often played here."

m "Hey... ummm..."



show sylvie smile

with dissolve



"She turned to me and smiled."

"I'll ask her..."

m "Ummm... will you..."

m "Will you be my artist for a visual novel?"

while(ActionButton.NotPressed)

{

DoNothing();

}

AdvanceToNextLineOfDialog();

function Update()

{

if(WaitingForDialogToAdvance and ActionButton.Pressed)

{

AdvanceToNextLineOfDialog();

}

UpdateRestOfGame();

}

function Update()

{

if(WaitingForDialogToAdvance and ActionButton.Pressed)

{

AdvanceToNextLineOfDialog();

}

if(CurrentSong.IsFinished)

{

PlayNextSong();

}

UpdateRestOfGame();

}

function ShowDialog()

{

ShowDialogContents();

WaitingForDialogToAdvance = true;

}

def show_dialog

show_dialog_contents

wait_fiber = Fiber.new do

wait_for_input

end

wait_fiber.resume

show_next_dialog

end



def wait_for_input

until action_button.pressed

do_nothing

end

Fiber.yield

end

async void ShowDialog()

{

ShowDialogContents();

await WaitForInput();

ShowNextDialog();

}

And now for the much more exciting part 2 on my blog series about the development of Metis, the game engine behind Vacant Sky: Awakening. You can read the first part here The topic this time is on cutscenes, what goes into writing them, and why supporting them is a nightmare.When developing a piece of software, a good way to start is by imagining you’re an end user of the software (in this case, the person making a game using your game engine) and writing out how you would like to interface with it. In this case, I’m going to imagine I’m writing a cutscene with this engine and come up with a convenient format.To begin with, I’m going to indicate one engine which, in my opinion, makes the authoring of cutscenes as easy as conceivably possible. That engine is Ren’py, a particularly well-designed domain-specific engine for making visual novels. Since most of visual novel authoring is writing dialog, it was made to be the simplest possible task.Taken from the Ren’py tutorial:A line of dialog is represented by a line of code consisting of two strings: the name of the speaker and what they said. It’s easy to read and easy to write. Virtually no overhead (except for the quotes). I think that, in a perfect world, it could be simplified to something like Me: Yes… but we’ll cross that bridge when we come to it.What makes this so good is that Ren’py was designed for a highly specific genre and its developer identified what the most common tasks would be, then made them as easy as possible. Since Awakening is such a story-based game, much of the content creation will be in writing dialog, so I want something as easy to use (if not easier) as this.Let’s break down exactly what’s happening here:1) Show a background image2) Show Sylvie’s smiling portrait3) Have Sylvie say a line of dialog4) Wait for the user to advance to the next line of dialog)5) Have the protagonist say a line of dialog6) (Wait for input)7) Fade out the current background image8) (Wait for fade out to complete)9) Fade in new background image10) (Wait for fade in to complete)11) Show a line of narrationSeems fairly straightforward and easy to implement. What’s so tough about this? If you’re a programmer, you probably saw the problem right off the bat.What exactly do we mean by “waiting?”Let’s say we’re on step 4. A line of dialog has just been displayed and we’re waiting on the user to push a key to advance. How exactly do you implement that?A first attempt might look something like this:This while loop will keep on spinning, doing nothing, until it detects that the action button has been pressed, after which point the loop will break and it’ll go on.The problem with this approach is that while you’re waiting, your entire game is blocked, waiting on the loop to finish. You can’t do anything else. Background processes such as music aren’t updating. The UI isn’t updating properly. Depending on your graphics framework, it might stop drawing properly. This is called busy waiting.So, let’s try another approach. Instead, let’s go into the game’s main update loop and put the wait there:This approach requires you to keep track of when you’re waiting for the dialog to advance (probably with a true/false flag) and to put a check against it at the start of your update loop.Good news: It works!For a lot of games, this approach works fine. The problem arises when there turn out there are multiple things you’re waiting on. Let’s say, in addition to waiting for the action button to be pressed to advance dialog, you also wanted to play a different song when the current one ends:Now let’s say you wanted to have animations, or some other gradual visual effect. For each one of these, you need a variable and a new condition in your update loop. This is annoying but manageable. The real problem is that, while you weren’t looking, your code has become a monster:This is pretty much what your function to show dialog looks like now. What’s the problem here? It makes sense, right?The problem is that you’ve broken your function up into two functions (pre-waiting and post-waiting) and it’s not clear from reading one of them how they’re supposed to behave together. You’ve entered callback hell, a dark place where all your functions are split into two, threaded together by a nightmarish web of conditional checks and function forwarding. Here, nothing is as it seems and following the logic of your game is nigh impossible.If you can’t wait inside your functions and you can’t wait outside of them, what are you supposed to do? How do you avoid busy waiting without falling into callback hell?The answer: It depends.The solution to this problem depends on what programming language you’re using. “But wait!” you say. “You haven’t said what programming language you’re using yet!” And indeed I haven’t. At this point, we’re still in the design phase of the engine. This is all part of the exploration of the design requirements. Now, we’re finally at the stage where our design requirements are going to start making some decisions for us.Let’s look at some possible solutions to the waiting paradox.Fibers are a form of lightweight threads which are useful for asynchronous tasks. In this case, it would look like:It’s a bit of a simplified example, but the idea is sound. There’s a little bit of a learning curve, but this solves the problem neatly. The whole of the show dialog functionality is contained within the show dialog function, which keeps the code easy to follow and maintain.Very similar to Ruby’s fibers in terms of usage, just in Lua instead of Ruby.A relatively recent development, the async/await feature of C# 5.0 takes the cake for one of my favorite new language features.Simple and elegant. All you do is mark a function as async and then await it (aside: The actual implementation of WaitForInput() here is a little hairy, but I won’t sweat the details for now).So, we’ve got three possible ways to handle the problem of how to implement asynchronous commands in cutscenes. The choice depends on what language we’re using. So, now we have to choose what programming language we’re going to use. To narrow it down further, let’s revisit our list of design requirements.The other bottleneck requirement is cross-platform deployment. Let’s look at how Ruby, Lua, and C# shape up in these regards:-Ruby: Limited or no support for games on mobile-Lua: Available on most platforms but none (yet) support Windows 8 apps-C#: Available on everythingLua has always been an agile language and quick to appear on other platforms. The lack of current Windows 8 app support doesn’t concern me as much as the fact that most of the cross-platform game frameworks using it are either too new or just flat-out suck. I tried out Moai several times, but the documentation is abysmal.Although by default only available on Microsoft platforms, C# is also available on Android and iOS via Mono and has a very powerful framework for it called Monogame. And this is purely subjective, but I would much prefer to build a game engine in a statically typed language for the ease of debugging and architecting.For that reason, C# was chosen as the language of choice for Metis, which will sit atop the Monogame framework.The next part will dive deeper into the logistics of cutscene implementation with regards to scripting, and how I both had my cake and ate it, too.