Home

Awesome

textboxy (legacy version)

<p align="center"> <img width="507" height="90" src="https://i.imgur.com/uFojZyT.gif"><br/> <a href="https://twitter.com/glitchroy">Twitter</a> | <a href="https://marketplace.yoyogames.com/assets/6934/textboxy-engine">Marketplace</a> </p> This is the legacy version of textboxy. For the new version, please take a look at the master branch. textboxy aims to be a simple to use textbox engine for GameMaker Studio 2.

Features

<p align="center"> <img width="350" height="60" src="https://i.imgur.com/wjl8gsK.png"> </p>

Some more features I'd like to add are

Explanation

At its core, textboxy utilizes an action queue. You queue up different actions like showing strings, changing the position or speed and then execute them all in order.
The strings themselves can be modified using control codes to adjust color, pauses and other effects.

A really basic queue would look like this:

tbyAddAction(TbyAction.SetPosition, 100, 100);
tbyAddAction(TbyAction.ShowString, "Hello world!");
tbyStart();

This would show a message box with the words "Hello world" at position 100, 100 (top-left corner of the message box).
You can see all available actions below.

Usage

Actions

<table> <tr> <th>Definition</th> <th>Description</th> <th>Example</th> </tr> <tr> <td><pre lang="gml">SetMaxWidth(maxWidth:Number)</pre></td> <td>Sets the maximum width before a line break is automatically inserted.</td> <td> <pre lang="gml"> // Sets the maximum width // before a line break to 150 pixels tbyAddAction(TbyAction.SetMaxWidth, 150);</pre> </td> </tr> <tr> <td><pre lang="gml">SetMaxLines(maxLines:Number)</pre></td> <td>Sets the maximum number of lines in a given message box.<br />(In a future version, this should split the message in two single messages, but for now, it just cuts the message off).</td> <td> <pre lang="gml"> // Message boxes are now // at most two lines long tbyAddAction(TbyAction.SetMaxLines, 2);</pre> </td> </tr> <tr> <td><pre lang="gml">SetFont(fontResource:Number)</pre></td> <td>Sets the font for following messages.</td> <td> <pre lang="gml"> // Changes the font to fontBig tbyAddAction(TbyAction.SetFont, fontBig);</pre> </td> </tr> <tr> <td><pre lang="gml">SetSpeed(speed:Number)</pre></td> <td>Sets the speed for following messages.</td> <td> <pre lang="gml"> // Sets the speed to 5, meaning 5 steps // pausing between drawing each character tbyAddAction(TbyAction.SetSpeed, 5);</pre> </td> </tr> <tr> <td> <pre lang="gml"> SetOrigin(x:Number, y:Number)</pre> </td> <td>Sets the message box origin (bottom middle of the message box, where the "bubble" sprite is located).</td> <td> <pre lang="gml"> // The following messages will be drawn // with their origin at 100, 100 tbyAddAction(TbyAction.SetOrigin, 100, 100);</pre> </td> </tr> <tr> <td> <pre lang="gml"> SetPosition(x:Number, y:Number)</pre> </td> <td>Sets the message box top-left corner manually.</td> <td> <pre lang="gml"> // The following messages will be drawn // with their top-left corner at 10, 10 tbyAddAction(TbyAction.SetPosition, 10, 10);</pre> </td> </tr> <tr> <td><pre lang="gml">SetPause(frames:Number)</pre></td> <td>Inserts a pause of x frames in the action queue. Most useful between messages.</td> <td> <pre lang="gml"> // Pauses for one second before executing // the next action in the queue tbyAddAction(TbyAction.SetPause, room_speed);</pre> </td> </tr> <tr> <td><pre lang="gml">SetSpeaker(instId:Number)</pre></td> <td>Binds the following messages to a speaker. The message will then follow the speaker instance. To reset, set to <tt>noone</tt> or overwrite with <tt>tbyActionSetOrigin()</tt> or <tt>tbyActionSetPosition()</tt>.</td> <td> <pre lang="gml"> // Sets the instance referenced // in global.player as the speaker tbyAddAction(TbyAction.SetSpeaker, global.player);</pre> </td> </tr> <tr> <td><pre lang="gml">SetSound(soundResource:Number)</pre></td> <td>Sets the message sound for the following messages.</td> <td> <pre lang="gml"> // Changes the sound to sndHighPitch tbyAddAction(TbyAction.SetSound, sndHighPitch);</pre> </td> </tr> <tr> <td> <pre lang="gml">ShowString(message:String)</pre> </td> <td>Adds a message box.</td> <td> <pre lang="gml"> // Display the message box tbyAddAction(TbyAction.ShowString, "[j]Crazy!!!");</pre> </td> </tr> <tr> <th><b>Shorthand</b></th> <th></th> <th></th> </tr> <tr> <td> <pre lang="gml"> tby(&lt;optional&gt;instId:Number, &lt;optional&gt;speed:Number, message:String)</pre> </td> <td>Shortcut to set a common message.</td> <td> <pre lang="gml"> // Sets speaker, speed and string tby(id, 4, "First"); // Speaker and string carry over tby("Second"); // Removes the speaker, speed is still 4 tby(noone, "Third"); // To adjust speed, // speaker must be specified tby(noone, 1, "Fourth");</pre> </td> </tr> <tr> <td><pre lang="gml">tbyPause(frames:Number)</pre></td> <td></pre>Shortcut for setting a pause</pre></td> <td> <pre lang="gml"> // Add a half second pause tbyPause(room_speed/2);</pre> </td> </tr> <tr> <th><b>Other</b></th> <th></th> <th></th> </tr> <tr> <td><pre lang="gml">tbyStart()</pre></td> <td>Starts execution of the current action queue</td> <td> <pre lang="gml"> tby("Hello"); ... tbyStart(); // Execution starts now</pre> </td> </tr> <tr> <td><pre lang="gml">tbyReset()</pre></td> <td>Resets the textbox manager and removes any text instances</td> <td> <pre lang="gml"> tby("This will never be seen"); tbyReset(); tby("But this will!"); tbyStart();</pre> </td> </tr> <tr> <td> <pre lang="gml"> tbyCreateProfile(instId:Number &lt;optional&gt;sound:Number, &lt;optional&gt;speed:Number)</pre> </td> <td>Returns a new profile array</td> <td> <pre lang="gml"> var oldManProfile = tbyCreateProfile( oldMan, sndOldMan, 4)</pre> </td> </tr> <tr> <td><pre lang="gml">tbyProfile(profile:Array)</pre></td> <td>Switches to the specified profile</td> <td> <pre lang="gml"> tby("Normal stuff"); tbyProfile(oldManProfile); tby("Now I'm old..."); tbyStart();</pre> </td> </tr> </table>

Control Codes

<p align="center"> <img width="366" height="141" src="https://i.imgur.com/z8rfCtA.gif"> </p>

You can customize the identifiers in the tbyConfig() script.

NameDefault identifierDescriptionExample
Color[c/COLOR]Sets colors from the configuration"[c/blue]I'm blue!"
Wait[.]Waits a set number of frames, can be stackedA long[.....] pause.
Jittery[j]Makes the text jitterAre you [j]crazy[r]?!
Skip[^]Skips to the next actionWait,[.] let me fini-[..][^]
Reset[r]Resets to the default values"[j][c/red]This is red and jittery.[.] [r]This is neither.[.] [c/blue]This is blue."

Callbacks

These scripts get called every time the action is executed.
They are useful for a number of things, e.g. setting a pause state during dialogue.

CallbackDescription
<pre lang="gml">tbyOnMessageStart(speakerId:Number, message:String)</pre>Gets called when a new message is shown
<pre lang="gml">tbyOnMessageEnd()</pre>Gets called every time a message ends
<pre lang="gml">tbyOnQueueBegin()</pre>Gets called when an action queue is beginning
<pre lang="gml">tbyOnQueueFinish()</pre>Gets called when an action queue is finished

Examples

String literals

Game Maker Studio 2 supports string literals with @"string".
Using these, you can define line breaks without having to type \n.

//Both of these produce the same output
tby(id, "Hello\nWorld!");

tby(id,
@"Hello
World!");

Basic dialogue

Assuming the instances player and oldMan.

var oldManSpeed = 6;
var playerSpeed = tbyWaitAfterEachChar; //this is the default speed defined in tbyConfig()

tby(player, playerSpeed,
@"Hello,[.] old man.[..]
Do you know where I can find the [c/red]hidden treasure[r]?");
tby(oldMan, oldManSpeed,
@"[j]Oooohhhhh[r],[.] it is the [c/red]hidden treasure[r]
you seek?[.] Good luck finding it,[.]
nobody knows where it is[.].[.].[.].");
tby(player, playerSpeed,
@"You have to know something!")
tbyPause(room_speed/2); //Half a second
tby("Please?") //speaker and speed carry over
tby(oldMan, oldManSpeed,
@"[j]OoooooOooohhh[r],[.] I am telling you,[.] no o-[...][^]")
tby(player, playerSpeed,
@"I get it,[.] you are no help either.");

tbyStart();

Profiles

Continuing from the example above, again with the instances player and oldMan.

// It would make sense to have these as objects variables and addressing them
// from the instances, e.g. player.profile or something
var playerProfile = tbyProfileCreate(player, sndPlayer, tbyWaitAfterEachChar);
var oldManProfile = tbyProfileCreate(oldMan, sndOldMan, 6);

tbyProfile(playerProfile);
tby(
@"Hello,[.] old man.[..]
Do you know where I can find the [c/red]hidden treasure[r]?");

tbyProfile(oldManProfile);
tby(
@"[j]Oooohhhhh[r],[.] it is the [c/red]hidden treasure[r]
you seek?[.] Good luck finding it,[.]
nobody knows where it is[.].[.].[.].");

tbyProfile(playerProfile);
tby(
@"You have to know something!");
tbyPause(room_speed/2); //Half a second
tby("Please?"); //speaker and speed carry over

tbyProfile(oldManProfile);
tby("[j]OoooooOooohhh[r],[.] I am telling you,[.] no o-[...][^]"):
tbyProfile(playerProfile);
tby("I get it,[.] you are no help either.");

tbyStart();

Resetting the queue

// CREATE_EVENT
tby("This is an ongoing dialogue...");
tby("Still talking, man");
tby("You can take your time with advancing this, you know");
tbyStart();
alarm[0] = 60;

// ALARM_0
tbyReset();
tby(
@"After 60 steps, this box will now appear immediately,
even if something else was showing before!");
tbyStart();

Credits

Code snippets used: