Update 34

We quickly noticed a problem with the text boxes from last weeks activity logs - if you had many activities close to each other or zoomed out the boxes would overlap and you couldn’t read a thing.

It seemed like a good idea to automatically space them out to not overlap anymore, so we tried a couple different methods…

…but that didn’t work too well. And even if it did work all these boxes would really block your view.

In the end, the most simple solution worked the best:

As you already know from the previous blog entry and can see here we also worked on adding support for different languages :)
It’s pointless to actually translate things before they’re final but since there’s slowly more text being added to the game it’s good to have this working. One thing less to worry about!

People received names this week. We’re using these lists from the US Census Bureau that handily also contain data on how frequently the names occur. We’re using the peoples names as seed for their appearance and characteristics, so “John Smith” will always look and behave the same. It’s a bit silly and probably nothing you’d have noticed, but I like the thought that these people are all unique somehow.
Speaking of translations, I guess we’ll have to get similar lists for other countries.

You guys convinced Garret to create a raptor entertainer during this weeks stream, and here he is:

He still needs animations before we can properly implement him though.

Here’s a timelapse of the livestream:

March

Unity 5 is getting close to release. It’s a huge update of the engine we’re using with many exciting new features that should make some things easier for us. We planned to switch to Unity 5 from the very beginning and think the time has finally come to do so next month! It should go fairly smooth but we’ll see.

February was tech-focused, so for March we mostly want to take care of polishing and tying up some loose ends.

Translation support for Unity games

Unity provides you with pretty much all the tools you need for creating a game - one really handy feature that’s unfortunately missing though is inbuilt support for doing translations into different languages.

It wasn’t too complicated to add it myself in the end, but since I couldn’t really find any articles on this topic I thought I’d do a quick write-up of how I approached it in case it’s helpful for anyone :)

So, if you want to add translation support to software you’ll have to ask yourself how and where to store your text strings and their translated versions, and how to load them into your program. Especially the latter was really important to me - I wanted to have a system that requires minimal code changes and requires the least possible amount of work when adding new strings that needed translations. What I especially did not want was having to manually manage a database of all strings in the game with cryptic lookup keys like ID_UI_INGAME_WINDOW_BUILDER_TITLE that some systems use, because having to maintain that database would be super uncomfortable and I’d rather not have to copy these keys around where after a couple weeks I don’t know anymore which text exactly is hidden away behind them.

When researching translation systems you’ll quickly stumble over gettext (up-to-date Windows binaries can be found here), and it satisfies the above requirements perfectly.
All you have to do is to wrap your strings that need translations into some function, so for example this:

string text = “Some text”;

becomes this:

string text = I18N.GetString(“Some text”);

You then run a command line program named “xgettext” that’s part of the gettext system over your source code. It looks for appearances of your wrapper function and extracts their string argument into a separate .pot file. Using “msginit” you then take this .pot file and create individual .po files for each language you want to support. The .po is a simple plaintext file containing both your original language strings and their translations.
Here’s an example of what that .po file looks like for German:

msgid “Some text”
    msgstr “Irgendein Text”

    msgid “Another text”
    msgstr “Ein weiterer Text”

You then parse this file and put its contents into a hashtable, using the msgid as key and msgstr as value. Your GetString()-wrapper method from the example above then simply looks up and returns the proper value for the given key (or returns the key if it doesn’t exist in your hashtable, so if some strings are missing translations they’ll at least show up in English).
There’s a source code example of how to do this here that should get you started.

If you’re like me and try to use the Windows command line only if you really have to you can make it even less of a hassle by creating a couple of batch files that do all the gettext stuff and a Unity editor window that executes them. Now you can run the string extraction with a single click, without having to leave the Unity Editor!

Another benefit of using gettext is that it’s a pretty common translation system, so there are plenty of tools already supporting it. For example there’s poEdit, a GUI application for editing the .po files, which makes life easier for your translators. And if you’re neither into command line programs nor Unity editor scripting it can do the string extraction for you as well.

Making it work with Unitys UI system

So, this system is great for text that you’re directly assigning from within your code - but what about the Text components in Unitys UI system? I certainly didn’t want to set all the Text component values from code and wanted to keep being able to visually create my UI in the Unity editor.

My solution is to do the same thing as for the code basically. I “tag” the Text components that need to be translated by adding another special component to them (named “I18NText”):

It does nothing more than take the text value and run it through the wrapper function:

public class I18NText : MonoBehaviour {
     void Awake() {
        Text textComponent = GetComponent<Text>();
        textComponent.text = I18N.GetString(textComponent.text);
    }
}

Of course it’s also necessary to extract these UI strings into the .po file, so I wrote a small editor script that loops over my UI assets, gets their Text components and writes them into a .pot. The .pot containing the UI strings and the .pot containing the source strings are merged into a single .pot (using the gettext tool “msgcat”), that is then used for creating the .po files.

Phew! :)
This sounds like a lot, but once it’s set up all you really have to do in the end is to wrap your strings into the lookup function, mark your UI texts with the additional component, and run the gettext tools before doing a build. That’s it!

Update 33

Art Stream

There’s another art stream coming up! Watch Garret create some Parkitect art on his Twitch channel, on Wednesday from 1pm to 3pm PST.

Devlog

We added guest activity logging! We’re recording certain events for individual guests and there’s a neat visualization overlay showing you what they’ve been up to:

I was a bit concerned what this would do to the filesize of our savegames, but judging by some quick tests it should be alright. And if not there are ways to optimize it.

Guests became cleverer this week - they learned how to properly use transport rides when heading for a specific location. So if for example they want to leave the park they might either walk or hop onto a transport ride and drop off at a suitable station.

Here’s a couple of debug screenshots, with the yellow line showing which path the guests would take if they wanted to get from one endpoint of the line to the other (for rides it marks where they enter the queue and the station they leave at):

It takes into account the average waiting time at a station, the time the ride needs from the entrance to the exit station (on average) and the ride entrance fee in relation to the travelled distance. The weighting of these factors is something we’ll have to balance.

Update 32

Guests are now able to walk to their seats inside the cars of the new transport ride - here’s a view through the cars roof:

Fortunately it was possible to reuse the same waypoints tools I created for flat rides.

We thought about how to display the parks finances this week. We wanted to have something that’s a bit less overwhelming than a big table of numbers and that lets you quickly see how you’re doing. It needs some more polish and isn’t complete yet but here’s what we came up with:

Your parks expenses/income is grouped into these categories. Each category has a colored bar showing the expenses/income of that category. The little black arrow marks the expenses of the previous month - if it’s in the green area it means you’re doing better this month than last, if it’s in the red you’re doing worse.

The categories can be expanded…

…so if you’re interested in the detailed numbers they’re all there.