Skip to main content Link Search Menu Expand Document (external link)

Theme: auto

Voice Over Triggers

First, change the level that you load initially to "Assets/Level01.json".

EnergyLauncher Cooldown

It turns out that the "cooldown" property for EnergyLauncher is not actually set for every EnergyLauncher. If it’s not set, you want the cooldown for the EnergyLauncher to be a default of 1.5f. You can easily do this just in LevelLoader. When you read in the "cooldown" property, initialize the float you’re using to 1.5f instead of 0.0f.

VO Trigger Basics

The basic idea of a VOTrigger is that it becomes activated the first time the player collides with it. It then starts playing a sequence of voice over lines while having the HUD show corresponding subtitles. When the sequence of lines finishes, the VOTrigger can optionally open a door or load a different level.

For example, here’s one of the triggers in Level01.json:

{
   "type":"VOTrigger",
   "pos":[0.0, 0.0, -50.0],
   "door":"1",
   "sounds":[
      "Glados-01-01.ogg",
      "Glados-01-03.ogg",
      "Glados-01-04.ogg"
   ],
   "subtitles":[
      "Hello and, again, welcome to the Aperture Science computer-aided enrichment center.",
      "Your specimen has been processed and we are now ready to begin the test proper.",
      "Before we start, however, keep in mind that although fun and learning are the primary goals of all enrichment center activities, serious injuries may occur."
   ]
}

In this case, there are three voice over sounds that will play, one after another. When the last sound finishes, the "1" door should open.

For simplicity, you may assume that the "sounds" and "subtitles" arrays will always be the same size.

Create an Actor subclass called VOTrigger. It needs:

  • A CollisionComponent with size (1, 1, 1) but it is NOT a collider so don’t do Add/RemoveCollider for it
  • An override of OnUpdate
  • An override of OnProcessInput

In LevelLoader add code that creates a VOTrigger on type "VOTrigger". Don’t worry about the additional properties of VOTrigger yet.

Make sure your code compiles and runs, and you load into Level01: Level01 loaded

Adding Additional Properties

Add the following private member variables to VOTrigger:

  • A std::string for the door name
  • A std::string for the next level
  • A std::vector<std::string> for the sounds
  • A std::vector<std::string> for the subtitles

Then in LevelLoader, add code to parse the properties from the JSON and set the corresponding members in VOTrigger (either with the constructor or with setter functions):

  • Door name - "door" - Use GetStringFromJSON
  • Next level - "level" - Use GetStringFromJSON
  • "sounds" - Use GetStringArrayFromJSON
  • "subtitles" - Use GetStringArrayFromJSON

Use breakpoints to confirm that you’re parsing the properties properly. The first and second VOTriggers in the level have a "door" property while the third one has a "level" property. Both should have "sounds" and "subtitles".

Basic Playback

The first time the VOTrigger intersects with the player, the VOTrigger should activate and play the first sound.

Once a VOTrigger is activated, on every frame it should check if the sound it’s playing is SoundState::Stopped, in which case it should start playing the next sound (if there is one). If there are no sounds left to play:

  • If the door name member variable is set to something, open that door
  • If the next level member variable is set to something, set the next level in Game to it, which will force the level to change to the specified level
  • Set the VOTrigger itself to ActorState::Destroy, so it gets removed

Hint: We recommend you make a function to “play next sound” and you can use that both for the initial sound and any subsequent ones, as well as checking in there if there are sounds left.

Once your VOTrigger is implemented correctly, it should work something like in this video. Notice that when the first set of lines finish, the door opens. And after the “You’re doing very well” line, the game loads into Level02. (Note that I started the video recording during the first VO line, you only hear the second half of the very first introductory line. You should hear the entire line in your game.)

Fast Forward

Particularly for testing purposes, we want to be able to quickly advance through voice over lines. Add code in VOTrigger::OnProcessInput that, on a leading edge of the F key, stops the current sound (if the VOTrigger is playing one).

Confirm that you can press the F key to skip the current line, and if there are other sounds left in the trigger, those also continue to still play.

Subtitles

To add subtitles, we first need to add a new HUD component to the player. Create a subclass of UIComponent called HUD that has a constructor, destructor, and an override of the Draw function (from UIComponent).

In Player, create a HUD instance and save it in a member variable, and add a getter for it.

Make sure your HUD compiles.

Loading the Font

For fonts, we use the SDL_TTF library. In Game.cpp:

  • Add an #include <SDL2/SDL_ttf.h>
  • In Game::Initialize, right before the call to LoadData, call TTF_Init();
  • In Game::Shutdown, right before the call to SDL_Quit, call TTF_Quit();

In HUD, add a class Font* member variable. In the constructor, dynamically allocate the Font and call the Load function, passing in "Assets/Inconsolata-Regular.ttf" as the file name.

In the destructor, call Unload on the font and delete it.

Creating Subtitle Textures

The way the Font class works is you call RenderText on it, passing in the string and a color, and it will return a pointer to a texture that contains the text.

Add two class Texture* pointers to HUD – one for the subtitle and one for the subtitle shadow, and initialize them to nullptr.

Add a new function to HUD called ShowSubtitle that takes in a string for the text to show. It should do the following:

  1. At the start of the function, if the subtitle texture pointer is not null, call Unload on both the subtitle and subtitle shadow textures, delete both, and set both pointers to null.
  2. If the text to show isn’t empty:
    1. Concatenate "GLaDOS: " to the start of the text to show
    2. Call RenderText on the font once with the text from (a), passing in Color::LightGreen and saving the texture in the subtitle texture
    3. Call RenderText a second time with the same text from (a), this time passing in Color::Black and saving it in the subtitle shadow texture

Then back in VOTrigger, every time you play the next sound, you should also call ShowSubtitle on the player’s HUD with the correct text from "subtitles". Make sure that when there are no sounds left, you call ShowSubtitle("") to clear out the texture.

Make sure your code doesn’t crash when playing VO. You won’t see the subtitles yet.

Drawing the Subtitles

You do the drawing in HUD::Draw. If mSubtitle is set, you first need to calculate the Vector2 screen position for the subtitles:

  • The x-component is 0
  • The y-component is -325.0f + height / 2.0f, where height is the value you get when you call GetHeight() on the subtitle texture

To draw the texture, call DrawTexture which is inherited from the parent, passing in shader, the texture to draw, and the position to draw at. For now, just draw the subtitle, not worrying about the shadow.

You should now see the subtitles, though they may be difficult to read without the shadow. Confirm that the subtitles change with each VO line, and when the VO ends, the subtitle goes away. The subtitle will look like this: Subtitles

Adding the Shadow

The trick to add the shadow is just that right before you draw the subtitle texture, first draw the subtitle shadow texture but at the calculated position plus an offset of (2.0f, -2.0f).

You should now see a shadow behind the subtitle, which makes it much easier to read: Subtitles with shadows

Once you’ve pushed this code, you’re ready to move on to part 2.