Let’s Make: Traffic Department 2192 – Part 22

Prototyping - Mission Briefing Programming

This is out longest unbroken programming segment thanks to the sheer number of objects and interactions. We're looking at roughly 500 lines a code - a solid day's work for the hobbyist programming.

Let's take a look at the object's we'll be building.

Objects

Our design called for these five objects:

Concept Object Notes
Briefing Controller obj_briefing Loads and holds data for the scene. Spawns child objects as necessary
Banner obj_banner Displays a text-only line in large font centered on the screen
Setting Splash obj_scrloader Displays a full-screen setting for the dialogue sequence including 3 lines of text
Interstitial Screen obj_picloader A partial screen graphic used to show action during dialogue. We're just going to copy the SCR object for now
Dialogue obj_dialogue Manages the speaking between characters. Displays faces, names, and draws dialogue once character at a time.

 

GML Code

We'll go through the above objects and a couple of scripts.

obj_briefing: Create 1

Seen this one before? [insert 10th comment about lack of GM multiple inheretence, but hedge away from the dangerous/lazy designs that use it]

 

obj_briefing: Create 2

We'll use these states in our briefing controller to manage the object creation

 

obj_briefing: Create 3

Let's load the mission titles from the text file that we created by extracting them from the binary (see video)

 

obj_briefing: Create 4

We'll manage the dialogue data with two lists that act as the data holder and the index.

 

obj_briefing: Create 5

This is where we load the storyboards for all the missions. For now, we'll set up mission on and add a few more by the end of this series

 

obj_briefing: Create 6

Other variables we'll need that track where we are in the storyboard. We'll call a script that we'll define next

 

Script: briefing_next

Moves the briefing controller to the next important event in the scene. We isolate this activity in a script because it's frequently called by external objects and we want to avoid 'off-by-one' or other such errors as we add objects. Use this safe interface.

 

obj_briefing: Destroy 1

Byebye keyboard and adios data structures.

 

obj_briefing: Destroy 2

Clean up any lingering children. This shouldn't be required, but you never know...

 

obj_briefing: Destroy 3

Go to the mission

 

obj_briefing: Step 1

This is where we handle the briefing state to create the child objects and assign their variables from the storyboard.

 

obj_briefing: Step 2

Process user input here.

 

obj_banner: Create 1

Keyboard and object references

 

obj_banner: Create 2

Variables for the banner. These are just placeholders since we set the actual values after the object's constructor runs. We do set a 'just_created' variable to trigger the object to calulate text widths on the first step of it's life.

 

obj_banner: Destroy 1

Remove the keyboard...yet...again...

 

obj_banner: Destroy 2

Whenver a child object like this banner is destroyed, we must tell the parent to proceed through the storyboard.

 

obj_banner: Step 1

Perform the first-step calculations for the banner. In this case, we need to calculate the text width to properly center it. Recall that the text is set remotely by the parent after creation and so we couldn't do this in the constructor. This is the first opportunity. You'll see the pattern several more times, as well as a polymorphic approach using custom events. Not necessary, but this goes with my project theme of solving the same problem in several different ways.

 

obj_banner: Step 2

Banners fade in and out like most other things in the game. Fade outs trigger destroy

 

obj_banner: Step 3

The banner needs to handle keyboard input

 

obj_banner: Draw 1

The text is draw in red using our larger mission font and centered based on our previous text size calculations

 

obj_scrloader: Create 1

Surprise! The SCR loader also needs to receive commands from the keyboard object

 

obj_scrloader: Create 2

We have a few variables such as the screen, the line text, and position calculations.

 

obj_scrloader: Destroy 1

Deregister the keyboard

 

obj_scrloader: Destroy 2

Push the briefing to the next step

 

obj_scrloader: Step 1

Fade the SCR object display.

 

obj_scrloader: Step 2

Handle commands pushed on to the stack from the keyboard

 

obj_scrloader: Draw 1

Draw the screen and the three text lines. Right now the color and the lines are always the same, but there's actually a few differences from scene to scene in the original game. Also there is more of a shadow outline, while we're going to keep the same shadow concept that we'ved use throughout the project.

 

obj_dialogue: Create 1

Keyboard and references

 

obj_dialogue: Create 2

Create the enum for our states.

 

obj_dialogue: Create 3

All the variables we'll need to make the dialogue happen.

 

obj_dialogue: Destroy 1

Goodbye keyboard

 

obj_dialogue: Destroy 2

Move the briefing to the next step

 

obj_dialogue: Step 1

Dialogue fading

 

obj_dialogue: Step 2

Handle commands from the keyboard. We'll be looking for any key to move to the line and escape to skip the scene.

 

obj_dialogue: Step 3

Handle all the dialogue states. If we're reading, we check the dialogue file for special control characters or text. This involves matching the first byte and handling each case. If we're writing, we add a character to the drawn line unless it's time to change lines or we reach the end of the line according to the algorithm we discussed in the last part. Finally, if we're waiting, then any user input moves us forward.

 

obj_dialogue: Draw 1

Draw the whole scene including faces, names, and the dialogue buffer.

 

Script: face_escape

We can't directly take the byte value from the file because it's off by one. So we have an interpretation function. We'll see others later on that will be a bit more involved than this.

 

Script: scroll_screen_text_buffer

This is our inefficient solution for moving through the text buffer. See the last part for more ranting about the virtues of ring buffers versus this linear time solution.