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 “Lifetime management in Unity with UniRx and IDisposables”

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 “Model-view-controller architecture in Unity”

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.

Prototyping for fun and profit

Hello! Long time no blog. I’m still working on Delugional, my puzzle game. As it’s (hopefully) nearing release, I want to talk more about the creative and development process.

I apparently promised, many moons ago, to talk about prototyping. Prototyping is a crucial part of game design.

Here’s the thing. You’re trying to do something new in your game, whether it’s a new mechanic you invent, or a novel combination of existing elements. That’s important – ultimately your game’s identity is whatever you put in it that’s new.

But your cool new idea might not work. Plenty of ideas that’re promising on paper just don’t turn out to be fun in practice. The history of innovation in games is littered with noble failures.

That’s where the prototype comes in. The aim is to take your risky, novel idea, and construct the simplest, quickest test that answers the question: is this fun?

I made a couple of initial prototypes for Delugional – at the time only knowing I wanted to make a puzzle game of some sort. The purpose was to find a fun ‘core mechanic’ with enough depth to build a whole game around.

I thought it could be interesting to make a game inspired by physics simulations. The first prototype took this inspiration very literally – it was a ‘simulation’ of particles that could collide with each other, and off the walls, the idea being that you ‘won’ by finding the right initial configuration for the particles to end up in their proper places.

Here’s a picture.

Atom-smashing game
Screenshot2 The red dots are ‘atoms,’ the arrows and numbers represent their ‘momentum.’ Quotes added for the sake of my physicist street cred.

You can see I didn’t sink any time into pretty graphics. I also put barely any work into the interface. The puzzles were created directly in code, and I even ‘solved’ them by editing the code. That’s all I needed to be able to explore the mechanic.

It took me a couple of days to code the basic interactions between particles, along with a dirt-simple UI, and another day or so to play around with it and reach a verdict.

The verdict? Thumbs down. Quoting straight from my notes at the time:

What I don’t see here is ‘manageable complexity.’ This is something that good puzzle games have. Meaning that the problem is complex, but breakable into smaller parts. …

I don’t see that here. I think the problem is that the simulation component places a big inferential gap between the effect the game enables you to have, and the outcome you’re trying to achieve. Solution steps are either trivially obvious (this atom’s will hit that one) or effectively unforeseeable (multiple atom interactions and multiple reflections rapidly lead to a board situation that can’t be inferred by a player from the initial configuration; that in turn makes it impossible to reason about the effect that small changes to the initial set-up will have). The latter is compounded by the fact that (in my opinion) key simulation rules are non-intuitive.

You can see I was pretty critical of an idea that I’d initially been hopeful about. That’s what you should do in the prototyping phase: generate ideas prolifically, and cull them mercilessly.

Eventually I hit upon a prototype that had legs. That’s a story for another post…

Puzzle game styles: ‘authored’ vs ‘generated’

In this series I’m blogging about the development process for Delugional, the puzzle game I’ve been working on.

There a few broad choices you can make when you start to design a puzzle game. For one, you can broadly divide puzzle games into two categories: ‘authored’ and ‘generated.’ By ‘authored’ I mean a game where every puzzle has been designed by a human. Think World of Goo, or Cut the Rope, or Kami. By ‘generated’ I mean games where every puzzle you play is a fresh creation, generated in the algorithmic bowels of the game’s code. Think of Threes/2048/etc, or Minesweeper, or Dots.

Kami screenshot
Kami, a paper-folding puzzle game.

Continue reading “Puzzle game styles: ‘authored’ vs ‘generated’”