0
\$\begingroup\$

I am trying to make a textbox engine for my RPG using Gamemaker Studio 2 as my game engine, and so far I have managed to make a pretty good-looking animation for when the textbox comes in and out. I think it looks really nice...

...However, I've come across some complications when it comes to the actual text itself.

You see, a basic rundown of what I wanted to do was keep the main lines of dialog on separate scripts (labeled as TEXT_EN and TEXT_JP, for the potential different languages), and have the dialog box object print the specific line from the TEXT scripts depending on which one I call, basically how UNDERTALE and DELTARUNE handled it (from what I could tell, they relied on arrays but that's all I know, I'm not sure on how to utilize them to my advantage).

I'm not sure on how I should start doing that... And I tried following along with some guys on Youtube who were better at it, but it didn't really feel right to me... I was planning on having different languages with my game, and these tutorials didn't have that in mind... If any of you guys could point me in the right direction, I would GLADLY appreciate it. Thank you for your time.

\$\endgroup\$
4
  • \$\begingroup\$ Hello, and welcome to GameDev. It seems you want to implement dialogue trees in GMS2, but you don't have actual issues we can help you with at the moment. Since you are asking how to implement one from scratch, answers would result in opinion-based hints rather than objective suggestions, which may not be what you're looking for. You may also want to take a look at other GDSE questions with this tag and get inspiration from alternate solutions before implementing your own. \$\endgroup\$
    – liggiorgio
    Aug 22, 2021 at 8:26
  • \$\begingroup\$ Okay, I see... Thanks for providing some resources! \$\endgroup\$ Aug 22, 2021 at 16:28
  • \$\begingroup\$ Since your question has been edited by mods, I realised I may have misunderstood your point. Help us get this right: are you trying to add support for multiple languages in your game by relying on strings saved on external text files? \$\endgroup\$
    – liggiorgio
    Aug 24, 2021 at 1:53
  • \$\begingroup\$ What I'm trying to do is keep all of the info on dialog text in specific scripts, TEXT_EN for English and TEXT_JP for Japan. Depending on the Global.Language variable, the string value that is called will be different. It's a bit complicated, but I saw that's how Toby Fox did it when making UNDERTALE and DELTARUNE. Unless you can provide me with a different suggestion with how I should go about adding different languages to my game, this is what I want to do. I just don't know where to start... \$\endgroup\$ Aug 25, 2021 at 0:07

1 Answer 1

1
\$\begingroup\$

I don't know how Undertale and Deltarune actually manage localisation from an implementation point of view, but I can propose a simple working solution that works with multiple text files.

The main idea

Let's introduce our main actors:

  • Textboxes: these are objects defined by visual properties (size, position, colours...) and internal data. Specifically, there's a variable holding the string the textbox is going to draw on the screen.
  • Text Files: plaintext files where we save ALL the strings appearing in our game. There're menu strings, UI strings, item strings... Strings for everything, in conclusion. I'll call these localisation files.

Our game checks the current language setting, reads the language strings from the appropriate file, saves them internally, and loads them when needed.

We save strings internally for later use because we don't want to read the disk continuously while the game is running (this is bad for the hardware). Then, we save them at runtime inside a dedicated object:

  • Strings: object (or, collection of objects, if you want to specialise instances with respect to the current context) that hold(s) all game strings, which we can access using a fixed variable name.

enter image description here

Structure of a localisation file

Let's suppose there's a file named LANG_ENG.ini that contains the following:

[menu]
menu_newgame = New game
menu_continue = Continue
menu_settings = Settings

[level1]
l1_intro0 = Welcome to the Dreamworld!
l1_intro1 = There's a lot to do around here. Let's get to work!
l1_barry = Hello there, I'm Barry. What's your name, traveller?
l1_genericnpc0 = Hello, traveller!
l1_genericnpc1 = Have we met before?

...

Different languages will keep the same structure, and only the actual string values will differ. For example, the LANG_IT.ini file will look like this:

[menu]
menu_newgame = Nuova partita
menu_continue = Continua
menu_settings = Impostazioni

[level1]
l1_intro0 = Benvenuto a Dreamworld!
l1_intro1 = Abbiamo molto da fare qui. Mettiamoci al lavoro!
l1_barry = Salve, io sono Barry. Qual è il tuo nome, viaggiatore?
l1_genericnpc0 = Salve, viaggiatore!
l1_genericnpc1 = Ci siamo già incontrati?

...

INI files are useful for they let you retrieve data (real numbers or strings) by using key-value pairs grouped in collections called sections.

Similarly, our Strings object may contain instance variables as follows:

Strings Create Event:

// Main menu strings
menu_newgame = "";
menu_continue = "";
menu_settings = "";

// Level 1 strings
l1_intro0 = "";
l1_intro1 = "";
l1_barry = "";
l1_genericnpc0 = "";
l1_genericnpc1 = "";

The reason strings are empty is because we assign values programmatically via scripts at startup. You may assign hardcoded strings as a fallback solution, but it becomes hard to manage them as the number of strings grows. Plus, you can simply include a base LANG_EN.ini file in your game bundle ("included files"), so that you are sure at least one localisation file exists.

Reading strings

At this point, you may have guessed how the system works. You open a file (given its name), then you read all the needed strings, and save them in the Strings object. A small example may be:

// Load some localised strings
if ( file_exists("Lang/LANG_EN.ini") ) {
    ini_open("Lang/LANG_EN.ini");
    Strings.menu_newgame = ini_read_string("menu", "menu_newgame", "default_string");
    Strings.menu_continue = ini_read_string("menu", "menu_continue", "default_string");
    Strings.menu_settings = ini_read_string("menu", "menu_settings", "default_string");
    // More assignments here
    ini_close();
}

This way, the Strings object will be our single reference for in-game texts and strings, without the need to keep opening and reading localisation files. Similarly, we can call the function above again when the user switches to a different language in the game settings.

Displaying localised strings

How do textboxes and UI objects access the appropriate strings to show? Since we can identify every piece of string by a unique variable name, we can code UI elements so that their text content is initialised when the object itself is instantiated:

TextBox Create Event:

// Init textbox strings
string_title = Strings.tutorial0_title;
string_content = Strings.tutorial0_content2;

TextBox Draw Event:

// Display current text message
draw_text(x + 20, y + 20, string_title);
draw_text(x + 20, y + 50, string_content);

And, that's it. The behaviour of your UI elements may vary depending on the length of the same string in different languages, so you may want to implement some sort of scrollable textboxes. The important thing is that localisation is made simple by removing hardcoded strings (so, no need to create language-specific versions of your game).

In addition to that, the accepted answer to this previous question describes a nice way to deal with UI when localised strings are needed:

Instead of pushing out a change to all text in the game when the player changes the language, instead each text field pulls-in its text when it's time to be displayed.

The advantage is that you delegate string retrieval to each UI element rather than force-update everything from a single function.

Limits

My experience with INI files in GameMaker Studio is limited to simple strings and common charsets. Since you mentioned Japanese as a language, you may need to use UTF-8 character sets to support these languages (Japanese, Russian, Chinese, Korean...). In such a case, INI files may not fit your purpose, and you'll need to implement your own solution for reading strings from well-formatted text files.


Since working with files is not that trivial, always remember to check if a file exists before opening it. This is in order to prevent your game from crashing due to badly formatted localisation files: users may translate and create new files, but may not be aware of INI files structure and usage.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .