Uno Under the Hood

I wrote an article about Uno, the cross-platform UI framework I work on which has recently been open-sourced.

Advertisements

Lifetime management in Unity with UniRx and IDisposables

Previously we discussed the Model-View-Controller pattern as it applies to games, and how C#’s events allow you to pass information between layers without creating dependencies.

In this post I’m going to expand upon the pain point I touched upon at the end of the previous post – managing lifetimes for event subscriptions so that you don’t unwittingly create memory leaks.

Enter UniRx, a Unity implementation of the Reactive Extensions library.

Continue reading

View/model separation in Unity using events

In the last post I discussed the Model-View-Controller pattern and sketched a Unity-specific implementation for it. In this post I want to dive into the details. In particular I want to talk about the ‘observer’ pattern and the subtleties of using C# events. In a subsequent post I’ll cover how reactive extensions via the UniRx library can make your life easier.

Did you change yet? Did you change yet? Did you change yet?

One of the conceptual challenges of Model-View-Controller separation or any layer-based architecture, particularly for newcomers to programming, is how to propagate information from layer A to layer B without A’s code referring to B’s code.

It’s tempting, with Unity’s model of explicit update loops, to simply check every ‘tick’ in an Update() method if some property in the game model changes. But we want to avoid this – it’s performance unfriendly when you have large numbers of objects, and moreover it’s just ugly.

One answer is the Observer pattern. In essence, a subject type provides a contract allowing any interested observers to say ‘notify me whenever such-and-such happens.’ In our case, the game model is the subject and the controller layer is the observer.

C# implements the Observer pattern as a first-class language feature via ‘event’ declarations. For example:

public class Terrain
    {
        private int _terrainElevation;
        public int TerrainElevation
        {
            get { return _terrainElevation; }
            set
            {
                var elevationHasChanged = value != _terrainElevation;
                _terrainElevation = value;
                if (elevationHasChanged && ElevationChanged != null)
                {
                    ElevationChanged(value);
                }
            }
        }
        public event Action<int> ElevationChanged;
    }

    public class TerrainController : MonoBehaviour
    {
        private Terrain _terrain;

        public TerrainController(Terrain terrain)
        {
            _terrain = terrain;
            _terrain.ElevationChanged += OnElevationChanged;
        }

        private void OnElevationChanged(int newElevation)
        {
            UpdateGameObjectPositionForNewElevation(newElevation);
        }
    }

Now TerrainController will be notified whenever the TerrainElevation property changes, and it can adjust its view accordingly.

The beauty is that anybody can subscribe to the ‘ElevationChanged’ event as long as they have a Terrain object. This achieves the layer separation that we talked about: the Terrain object in the game model layer doesn’t ‘know about’ the TerrainController in the controller layer. This makes development much easier: when you change your game logic, you just change the code pertaining to game logic – you don’t have to make a bunch of changes to your display code.

Once in a lifetime

So we’re golden, right?

Not quite; there’s one essential consideration we’re neglecting, which is lifetime management.

When you subscribe to the event on Terrain, you effectively pass a reference to TerrainController, so that its callback can be called. Now, remembering that Terrain is a Component attached to a Unity GameObject, what happens if you unload the scene it’s in – perhaps because you’re navigating back to the menu screen, say? You’re expecting TerrainController to be destroyed, but Terrain (which is sitting in your model layer, not going anywhere) still has a reference to it. We’ve created a memory leak.

The good news: there’s an easy fix. We simply unsubscribe from the event:

    public class TerrainController : MonoBehaviour
    {
        …

        private void OnDestroy() {
            _terrain.ElevationChanged -= OnElevationChanged;
        }
    }

Voila, leak patched, crisis averted.

The bad news? Well, if you have more such event subscriptions, or if deciding when they should be unsubscribed is a bit more complicated, it rapidly becomes easy to accidentally introduce bugs. Even writing the example just now, I almost forgot to change the + to a – when I copy-pasted.

In the next post, I’ll discuss a nifty toolset for making lifetime management less error-prone.

Model-view-controller architecture in Unity

This is going to be a more technical series of posts. I’m going to look at what’s going on under the hood in Delugional, and some of the approaches I took to keep the code manageable.

DelugionalOutside the world of games, the longstanding best practice for building a user interface is the ‘Model View Controller’ or ‘MVC’ pattern. This pattern has spawned many variants, but the basic principle remains the same. You have a ‘model’ layer, the raw information that your application is concerned with. (Eg, this puzzle has water here and some huts here, and this many hexes, and so on.) You have a ‘view’ layer, which is responsible for showing stuff to the user, and accepting input. And finally you have a ‘glue’ layer which is responsible for passing information between the model and the view. The golden rule is that the model knows nothing about the view layer, and the view layer knows nothing about the model. The ‘glue’, implemented in various ways and known as a ‘Controller’ or a ‘Presenter’ or a ‘View Model’, exists to allow and enforce this separation.

The advantage of this approach is simple and profound: you can make changes to your model without changing your view layer, and vice versa. This isn’t such a big deal in the early stages of development, but it saves you a huge amount of pain on a large project.

Does this pattern transfer to game development – or, specifically, to Unity3D development? I admit it must be tricky to apply to, say, a 3d shooter, where the ‘model’ (eg, the game physics) and the ‘view’ (eg, Unity’s rendering) are closely intertwined at an engine level. But for something like Delugional – a puzzle game with a turn-based mechanic – it’s eminently achievable. I’ll explain how I did it. Continue reading

Delugional is out for Android!

After a long and patient labour, Delugional is released today for Android! You can download it right now from the Google Play Store.

If you like solving puzzles, or you like waterfalls, or if you like killing a few minutes on your phone from time to time, I invite you to try it out.

Heartfelt thanks to everyone who helped make this game a reality: Monserratt, for the lovingly hand-painted graphics; Yasamine, for the beautiful music and sound effects; and Rami, for his enthusiastic evangelism for the game. I’m indebted also to all the people who provided feedback at every stage of development, and particularly to the intrepid beta testers, particularly Chris, Myriam and Mark.

Delugional screenshot
When time permits (and another recent release is demanding much attention), I’ll post more about the development process. Until then, try Delugional!

Delugional screenshot

Delugional is looking for beta testers

Delugional for Android, a handcrafted puzzle adventure, is now in beta! This means we’re looking for testers.

To get in on the beta action, send an email to dissolutegames@gmail.com with ‘Delugional beta’ in the title. We’ll send you a link to download the beta version of the game, as well as information on how to provide feedback and bug reports. If the email associated with your Google Play Store account is different from the one you use to contact us, make sure you send us your Play Store account email. (You can check by opening up the Play Store, opening the left-side menu, and checking the email in the upper left corner.)

Beta testers will get early access to the game, a mention in the credits, and our eternal gratitude. The first 50 beta testers will also receive a free promo code for the first premium puzzle pack in the game.