On the state of Unity

I kinda want to say something about Unity that hasn’t been said beforeā€¦ but I really can’t. I turned my back to Unity as a commercial tool years ago and I just hope, I never have to return to it.

5+ years ago, I was very happy with Unity. The tool is easy to extend and build simple stuff in. Then I released my first game with it – simple and on mobile – and thought: Mobile is shit, I will never go mobile again. Then I switched to Unreal. Now I never want to touch Unity again as well.

My main problem with Unity is that there is no structure in what it wants to do or be. The pricing model was always horrendous, the feature releases suboptimal and the quality of anything was always bad. Unity never felt to me like a professional tool after using Unreal.

Maybe because I’ve seen Unreals code which feels like a piece of software that grew organically while working on a game. Maybe it was the high amounts of pitfalls Unity made in its own design compared to Unreal (e.g. not having an equivalent to FName and FText).

A lot of stuff in Unity feels silly in hindsight (remember UnityScript?). And a lot of features never came out properly. With Unreal (for 4 years now) I do not only see improvement everywhere, I also see the abandonment of features when the replacement is there and usually the replacement is better.

Unity has – at the point of writing – 3 different render pipelines (legacy, URP, HDRP) which are incompatible. It has 3 different node editors that you need to understand. It has 2 ways of scripting (GameObject based and ECS). And it has moved a lot of stuff into packages that never feel native.

Unity is a train wreck of a software. I do enjoy working with it at game jams and such, but I could never think about using it again as a base for a big title because it feels to me like a house of cards. And instead of trying to make the base more stable, they always just add more cards on top.

This post was originally a thread on BlueSky, but I felt like it should belong here.

A small localizer for WPF

So, I wanted to localize my WPF application. I thought this should be pretty standard stuff, but then I read about resx and resource dictionaries and gave up. Microsoft, why do you make it so hard to create something simple?

Coming up with a new system

Alright, so first: What do I want?

I want a simple class that can be accessed via my ViewModels that gives me a key-value-storage for retrieving localized strings.

So what I need are three things:

  1. A storage for the languages in non-volatile memory – in other words: Some files with data
  2. A simple class system that stores and manages languages
  3. A way to access this information in XAML

The file system

Because I already use Newtonsoft.Json in the project, I decided to use it in the localizer aswell. It makes the software feel more persistant to the user and other developers. If you do not want to use Json, you can use anything else, but I stuck with Json.

My structure looks like this and it is already very easy to see where I am going:

{
    "name": "English",
    "localized": "English",
    "abbreviation": "en",
    "data": {
        "menu.file": "File",
        "menu.file.new": "New",
        "menu.file.open": "Open",
        "menu.file.save": "Save",
        "menu.file.saveAll": "Save All",
        "menu.file.saveAs": "Save As",
        "menu.file.close": "Close",
        "menu.file.closeAll": "Close All",
        "menu.file.preferences": "Preferences",
        "menu.file.quit": "Quit"
    }
}

We have some information about the language and then the key-value pairs that make up the language. I structured my keys in a way that makes it easy to determine where the string is used, because just translating something like “close” may be hard to translate correctly in another language.

The class system

My system uses two classes:

  1. A manager class called “Strings”
  2. A storage class called “Language”

Let’s start with the storage class. It is pretty straightforward: We store every Json property in their C# equivalents. For debugging reasons I also added the Filename, but it is not necessary and stays unused.

Also note that I use a factory pattern to create new instances of Language. It allows me to create an instance and load the data at the same time.

public class Language 
{
    [JsonProperty ("abbreviation")]
    public string Abbreviation { get; set; }

    [JsonProperty ("data")]
    public Dictionary<string, string> Data { get; set; }

    public string Filename { get; set; }

    [JsonProperty ("localized")]
    public string LocalizedName { get; set; }

    [JsonProperty ("name")]
    public string Name { get; set; }

    public static Language Load (string file) 
    {
        Language language = JsonConvert.DeserializeObject<Language> (File.ReadAllText (file)) ?? new Language ();
        language.Filename = Path.GetFullPath (file);
        return language;
    }
}

Next, we have the storage class. It is a Singleton, because it needs to be accessible from everywhere and I prefer working with instances that I can pass around, instead of having a static class that can’t be accessed the way I want in XAML.

As you can see I store a Dictionary of Languages by the name of the language and the language itself. I do not store the current language in this project in this class, because I thought it would be better to have it stored in the Settings class that loads and saves the settings.

The Data-Dictionary property is just wrapping around the current language so other classes don’t need to do that.

The Load method loads the default language first (the one that gets compiled with the application) and afterwards searches for other language files that follow the pattern string.*.json (e.g. string.de.json = German localization file). Finally, it makes sure the current language is set to a valid language.

public sealed class Strings
{
    public const string DEFAULT_FILE = "strings.json";

    public const string FOLDER = "Localization";

    private static Strings instance;

    private Strings ()
    {
        Languages = new Dictionary<string, Language> ();
    }

    public static Strings Instance
    {
        get
        {
            if (instance == null)
                instance = new Strings ();
            return instance;
        }
    }

    public string CurrentLanguage
    {
        get { return Settings.Storage.Language; }
        set
        {
            if (Languages.ContainsKey (value))
                Settings.Storage.Language = value;
        }
    }

    public Dictionary<string, string> Data => Languages[Settings.Storage.Language].Data;
    public Dictionary<string, Language> Languages { get; private set; }

    public void Load ()
    {
        Language defaultLanguage = Language.Load (Path.Combine (FOLDER, DEFAULT_FILE).SanitizePath ());
        Languages.Add (defaultLanguage.Name, defaultLanguage);

        string[] files = Directory.GetFiles (FOLDER, "strings.*.json", SearchOption.AllDirectories);
        foreach (string file in files)
        {
            Language language = Language.Load (Path.Combine (file).SanitizePath ());
            Languages.Add (language.Name, language);
        }

        if (!Languages.ContainsKey (Settings.Storage.Language))
            Settings.Storage.Language = defaultLanguage.Name;
    }
}

Accessing the information in XAML

This one was tricky at first but after some testing, I think I found the best solution.

I have a class called ViewModelBase from which all my viewmodels inherit from. I added a simple line to my ViewModelBase which just wraps the Data member from the Strings class (again).

public Dictionary<string, string> LocalizedStrings => Strings.Instance.Data;

Since all my viewmodels inherit from ViewModelBase, all of them also have the same access to the localization. I can now write the following XAML and it always gets the correct strings:

<MenuItem Header="{Binding LocalizedStrings[menu.file]}">
    <MenuItem Header="{Binding LocalizedStrings[menu.file.new]}" />
    <MenuItem Header="{Binding LocalizedStrings[menu.file.open]}" />
    <Separator />
    <MenuItem Header="{Binding LocalizedStrings[menu.file.close]}" />
    <MenuItem Header="{Binding LocalizedStrings[menu.file.closeAll]}" />
    <Separator />
    <MenuItem Header="{Binding LocalizedStrings[menu.file.save]}" />
    <MenuItem Header="{Binding LocalizedStrings[menu.file.saveAll]}" />
    <MenuItem Header="{Binding LocalizedStrings[menu.file.saveAs]}" />
    <Separator />
    <MenuItem Header="{Binding LocalizedStrings[menu.file.preferences]}" />
    <Separator />
    <MenuItem Header="{Binding LocalizedStrings[menu.file.quit]}" />
</MenuItem>

This is the result:

See, it works!

When the tools is ready, I may publish it under an open source license and everyone can use and extend it. But for now, this is all I have!

Cheers!

The best way to save the rectangles for the sprites in a texture atlas in C#

So while I am writing some code on my Point’n’Click-Adventure-GameEngine (which will be online on GitHub in a few days – hopefully) I suddenly stumble over a small problem: The developer working with the Engine may want to increase performance by putting multiple images into one big textureatlas. But how do I save and access the rectangles in the most performant way?

Using an Array

Obviously one approach would be simply saving it into an array. An array in C# works basically the same way as it does in C: You give it an entry pointer (not entrypoint, that’s something different!) and move it along the length of the saved data to the chunk of bytes that contain the requested object. Definitly the fastest way possible to save and access data. So we are done here. Or are we?

(VSauce music starts playing)

Are there other options?

But of course, there are!

We could use a List, two Lists that are aligned to each other or a Dictionary.

The List itself would be a bad idea, because a List in C# is basically an Array wrapped into another class with some fancy methods built around it.

What about the two Lists? They basically want to be a Dictionary but are not as performant. Let me elaborate:

Imagine two Lists, one contains the keys, the other one contains the values. The keys are saved in List A at the same location as the values in List B, so the following code should give us the desired result:

public TValue GetValue(TKey key)
{
    return B[A.IndexOf(key)];
}

The problem is: What happens when the key is at the last position in the array? We have to iterate through the whole thing, just to get the key-value connection. This hurts my performance-oriented heart.

So we step to the last type: The Dictionary.

The Dictionary saves the day

First, let me explain how a Dictionary works in C#:

The Dictionary consists of two arrays: The Bucket and the Entries.

These Arrays do basically the same as the two lists in the upper example, but there is a big difference. We save the keys and the values seperatly into collections, but we actually get the data from the Entries-array. Which index we use is determined by the hashcode of the given key. (Source)

Funfact: The Dictionary<TKey, TValue> class in .Net has 1382 lines of code and consists of multiple nested classes and structs. Yet it is rather performant.

After more than 3 entries in the collection the Dictionary<TKey, TValue> surpasses the List<T> when it comes to lookup times. Since the engine targets more than two sprites per atlas (I am optimistic about that), the Dictionary is preferred. (Source)

Conclusion

Go for a Dictionary if you want to be performant, except when you know that a regular array can do the job ofcourse.

Creating a fontsystem

Because in a game it is somewhere required to use a line of text, most game engines are able to process fonts on the fly or on startup. XNA supports so called “spritefonts”, a system that uses xml-files as informationcontainer. These xml-files are saved as “*.spritefont”-file, but even inside they reveal their truth: The first line is an xml-validation.

But xml can’t be used to tell the graphics-processor what to draw, so XNA compiles the information into an xnb-file which is just a collection of bitmaps that are connected to Unicode-Characters. When these characters are called, the font provides the required infomation about them.

The problem is: This system can’t be used on the fly, but in compiletime. And thats the problem. I don’t use the regular contentpipeline. I load my stuff into the engine when I need it, spritefonts don’t support this behaviour.

I had to create my own font-system.

The *.gef-system

I created a system that saves characters into a binary-file followed by bitmaps representing them. I will write an article about the file-architecture sometime, but the current article will be about the creation of the font.

The encoders and the decoder are both extracted from the core-assembly of the game-engine. The reason is simple: I wanted an external tool for the creation of the fonts.

I know there are some simple rules about creating object-oriented assemblies and these tell me that one class has only one job and one purpose. Same goes for the assembly itself. I want to have it as a standalone linked-library. The engine uses the decoder, the tool the encoder, but instead of splitting these up, I create an independent assembly. And there is another thing that I want to mention about the independent assembly: I can update and build it without rebuilding a whole gameengine.

Welcome to my Blog

Hey there! My name is Max, I’m a German Gamedeveloper with an M.Sc. in Applied Computer Science, currently working as a Programmer at Sixteen Tons Entertainment.

My greatest interest is the creation of worlds for games and filling them with life (sometimes reffered to as Level- or Contentcreator).

Why don’t you write your own page?
Believe me, It’s not that I hadn’t thought about this. On one hand, sure, it is a nice demonstration of my skills as a developer. I can show that I know how to write and design a website. But on the other hand (let’s face it): Webdevelopment sucks. I don’t like php, I don’t like Javascript. Why should I work with stuff I don’t like, when other people have passion in it and write decent code?

Okay, you don’t like webdevelopment. But why WordPress?
I know there are more Blog-CMS and CMS in general, but since I wan’t to focus on Gamedevelopment and not writing plugins for cms, I chose the most popular cms. It’s not that I don’t like the others, but it seems to be well documented, filled with plugins and it has a nice backend. One thing to mention is the philosophy of wordpress, which I really like: “Code is Poetry”.

Okay, so no webdev, using wordpress, but why a blog?
I like to have a platform which I can use to share my workflow and the things I learned during gamedevelopment. But there is more: I can also express my thoughts about topics which concern me when it comes to anything in games or their development.

Any final words?
Have fun with the things you do. They define you.