Making an RPG ‘talk box’ in GML.

Here’s how I achieved making a ‘talk box’ in GML for RPGs.

Create a new script called talkObjInit. Call this script in the Create event of your talk controlling object. It’s best if you dedicate an object for this purpose rather than ‘attaching’ the talk scripts onto an existing object. That being said though, if you’re careful, there shouldn’t be any reason not to. You’ll also need an alarm event dedicated to it. If you dedicated an object to this and your alarm number is 0, call talkObjInit(instant_id,0).

/* talkObjInit
arg0 = id of instance to initialize
arg1 = alarm number for the ticker.
Returns true if successful.
*/
talkObjId = argument0;
if (!instance_exists(talkObjId))
{ show_debug_message("talkObj: Instance ID does not exist"); return false; }

talkObjId.talkObjAlarmNumber = argument1;

/*Internal Variables. You shouldn't change em*/
talkObjId.talkObjMsgQueue = ds_queue_create(); //Set up a queue for the messages.
/*Changeable Internal Variables*/

talkObjId.talkObjScrollSpeed = 1; //How many steps to take before the next character appears
/*Temporary Variables. Definitely shouldn't be changed*/
talkObjId.talkObjTmpCharQueue = ds_queue_create(); //Set up a queue for the characters.
talkObjId.talkObjTmpText = ""; //Somewhere to store the text generated for the draw event
talkObjId.talkObjTmpCanMove = true; //Whether the character can scroll to the next message
return true;

Another script called talkObjAlarmTick. Call this script in an alarm (the number should be defined in the init script). So if you specified 0 in the init function, call this script from there.

/*talkObjAlarmTick
arg0 = id of the controlling object
Returns true if successful
*/
talkObjId = argument0;
if (!instance_exists(talkObjId))
{ show_debug_message("talkObj: Instance ID does not exist"); return false; }

if (ds_queue_empty(talkObjId.talkObjTmpCharQueue))
{
   talkObjId.talkObjTmpCanMove = true;
}else{
talkObjId.talkObjTmpText = talkObjId.talkObjTmpText + ds_queue_dequeue(talkObjId.talkObjTmpCharQueue)
alarm[talkObjId.talkObjAlarmNumber] = talkObjId.talkObjScrollSpeed;
}
return true;

Another script called talkObjNext Place this in the event when the player needs to scroll to the next message. The ‘use’ key is a great one to do. I put mine in the Keyboard Release event for Enter but is totally up to you.

/*talkObjNext
arg0 = id of the controlling object
*/
talkObjId = argument0;
if (!instance_exists(talkObjId))
{ show_debug_message("talkObj: Instance ID does not exist"); return false; }

if (talkObjId.talkObjCanMove && !ds_queue_empty(talkObjId.talkObjMsgQueue))
{
ds_queue_clear(talkObjId.talkObjTmpCharQueue);
talkObjId.talkObjTmpNextStr = ds_queue_dequeue(talkObjId.talkObjMsgQueue);
if (string_char_at(talkObjId.talkObjTmpNextStr,1) == "&") //Evaluate all strings with a & ahead of it
{
execute_string(string_copy(talkObjId.talkObjTmpNextStr,2,string_length(talkObjId.talkObjTmpNextStr)))
}else{
for (i=0; i<string_length(talkObjId.talkObjTmpNextStr); i = i+1)
{
ds_queue_enqueue(talkObjId.talkObjTmpCharQueue,string_char_at(talkObjId.talkObjTmpNextStr,i+1));
}
}
talkObjId.talkObjTmpText= "";
talkObjId.talkObjCanMove = false;
alarm[talkObjId.talkObjAlarmNumber] = 1;
}

And another script called talkObjEnqueueMessage Almost self explanatory of what this does. Basically when you want a new message to be displayed to the user, call this function.

/*talkObjEnqueueMessage
arg0 = id of the controlling object
arg1 = message (# for newline)
*/
talkObjId = argument0;
if (!instance_exists(talkObjId))
{ show_debug_message("talkObj: Instance ID does not exist"); return false; }

ds_queue_enqueue(talkObjId.talkObjMsgQueue,argument1);

And finally a drawing script which you’ll have to make. Since I don’t know the graphics background of your game, I cannot say on what to add here. Put this in the draw event talkObjDraw

/*talkObjDraw (template)
arg0 = id of the controlling object
*/
talkObjId = argument0;
if (!instance_exists(talkObjId))
{ show_debug_message("talkObj: Instance ID does not exist"); return false; }

/* BYO CODE */
//Draw a rectangle
//Draw the text talkObjId.talkObjTmpText inside the rectangle
if (!ds_queue_empty(talkObjId.talkObjMsgQueue))
{
    //Draw a sprite somewhere indicating that there are messages to be viewed
}

I should also add that any line with the first character being ‘&’ will be executed so remember to validate user input (otherwise it’s vulnerable to arbitrary code execution similar to a SQL injection attack). The function is for when, for example, you want to change rooms after the character finished reading a particular line.

I adapted these code from my own implementation and haven’t tested it yet. It’s also made to work on most games. Please do read through the code and understand why I did what. Then, you can try implement a custom solution for your game which will probably be more optimal.

It’s far from perfect so feel free to email me if you have a better or cleaner suggestion.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s