Unity to Defold: GameManager Singleton

Post author: Orenji Spark
May 12, 2026
Unity to Defold: GameManager Singleton

Unity to Defold: From GameManager Singleton to Lua Modules

In the previous post, we talked about how Unity developers often bring the multiple MonoBehaviour mindset into Defold, and how that can lead to overusing scripts and message passing.

In this post, we’ll look at another very common Unity pattern—especially in simple or one-scene games:

The GameManager Singleton

And how that idea translates naturally into Defold.


The Unity Pattern: GameManager Everywhere

If you’ve built small games in Unity (arcade, hypercasual, jam games), you’ve probably done something like this:

public class GameManager : MonoBehaviour
{
    public static GameManager Instance;

    public int score;
    public GameObject gameOverPanel;
    public Text scoreText;
    public Player player;

    void Awake()
    {
        if (Instance != null)
        {
            Destroy(gameObject);
            return;
        }

        Instance = this;
    }

    void OnDestroy()
    {
        if (Instance == this)
        {
            Instance = null;
        }
    }
}

Sometimes it grows into:

All accessible globally.


“Singleton is Bad”… but Is It?

In large-scale software, singletons are often discouraged.

But in small games?

They’re everywhere.

Why?

So in practice:

For small games, singletons are often a pragmatic choice


Translating This to Defold

Defold doesn’t have MonoBehaviour, and you don’t attach scripts everywhere the same way.

But here’s the important part:

The pattern itself still works

In Lua, modules are naturally shared because of require() caching.

That means:

A Lua module can act like a singleton.


Simple Example: Gameplay State Module

Here’s a basic version:

local gameplay_state = {}

function gameplay_state.init()
    gameplay_state.score = 0
    gameplay_state.current_hp = 3
	
	print("gameplay_state init")
end

function gameplay_state.cleanup()
	print("gameplay_state cleanup")
end

function gameplay_state.decrease_hp()
    gameplay_state.current_hp = gameplay_state.current_hp - 1
end

function gameplay_state.add_score(amount)
    gameplay_state.score = gameplay_state.score + amount
end

return gameplay_state

Usage:

--- in your gameplay.script
local gameplay_state = require "modules.gameplay_state"

function init(self)
    gameplay_state.init()
end

This already behaves very similarly to a Unity singleton.


Important Difference: You Control the Lifecycle

In Unity:

In Defold:

So you must explicitly reset:

--- in your gameplay.script
function init(self)
	--- call it once
    gameplay_state.init()
end

And optionally clean up:

--- in your gameplay.script
function final(self)
    gameplay_state.cleanup()
end

A Better Version: Treat Module as API, Not Just Data

A common mistake is exposing variables directly:

gameplay_state.score = gameplay_state.score + 10 -- ❌ risky

A better approach:

local gameplay_state = {}

local state = {
    score = 0,
    current_hp = 3,
}

function gameplay_state.init()
    state.score = 0
    state.current_hp = 3
end

function gameplay_state.get_score()
    return state.score
end

function gameplay_state.add_score(value)
    state.score = state.score + value
end

function gameplay_state.decrease_hp()
    state.current_hp = state.current_hp - 1
end

function gameplay_state.is_gameover()
    return state.current_hp <= 0
end

return gameplay_state

Why This Pattern Works Well in Defold

Using modules like this gives you:

It fits especially well for:


The Trap to Avoid

Just like in Unity, this pattern can go too far.

Be careful not to turn your module into:

A hidden “God Object”

Avoid stuffing everything into one module:

-- ❌ Don't do this
gameplay_state.player
gameplay_state.enemies
gameplay_state.ui_nodes

Keep it focused on global state, not object behavior.


Key Insight

The singleton pattern itself exists in both Unity and Defold.

The difference is mostly in how developers commonly implement it.

In Unity, singleton-style systems are often built around:

In Defold, the equivalent approach is often much simpler:

No GameObject is required unless you actually need one.

This makes Defold’s approach feel more lightweight and explicit, especially for small games.


Final Thought

The “GameManager Singleton” pattern doesn’t disappear when you move from Unity to Defold.

It simply becomes:

A Lua module with controlled state and functions

Singleton-style architecture is one of those patterns that is very easy to misuse, but also very easy to understand and work with, especially for small games.

That’s why despite all the warnings around singletons, many developers still use them.

In Defold, Lua modules make this approach feel very natural and lightweight.

The important part is not whether you use a singleton-like pattern or not, but:

Understanding the scope and complexity of your game

A simple architecture that fits your project is often better than an overly “correct” architecture that slows development down.

In upcoming posts, we’ll explore other ways to structure game logic in Defold. Thanks for reading!

Latest Posts