Unity Game Programming: Bad Singletons

Unity Game Programming: Bad Singletons

If ( you only make short games || you don't care about clean code || you don't intend to make your code extensible)

return;


One of the biggest questions while programming in Unity is "How do I communicate between classes?" This is a question that has many answers but which answer should we follow, or which answer is the better one?

When I first started with Unity I didn't have any specific way to handle the communication. I used whatever method I felt like using. I didn't worry about performance. As a beginner, getting the code running was a challenge. But at a professional level, we can't use anything we want. We need to know the best way to do something in terms of performance, code readability and code organization.

This article is not about "Performance". Rather, its about code cleanliness and discipline. If you are looking for a quick solution just to get the code running and not worrying about extensibility or cleanliness, then this article is not for you. I always try to write clean and extensible code, and try not to make a mess. Sometimes I can accomplish that throughout the project, Sometimes due to a deadline or frequently changing requirements I fail to maintain clean code throughout the project. That's why I was looking for something that not only helps me to write clean code, but also enforces it. We'll talk about that later. But first a let's get into Singletons.

I used to love singletons. Most of us does. It gives a direct access to a script without any hassle to get the script. It makes communication simpler. But I'll tell you what the biggest problem that I face with Singleton. It's "TOO RIGID". Let me give you an example.

You are making a game where you need to make a player who will move around a map and collect coins. You make 2 singletons

  1. PlayerController.Instance : Controls the player
  2. ScoreManager.Instance: Controls the player score and notifies the UI

You are halfway through development when there's a requirement change and you need to make this a io game where there will be many cars and it's a competition of who can collect most coins.

What do you do? Go.

You see what I mean? Too Rigid. You can't move any further unless you break the Singleton and use direct public references of the scripts

Let's see another example where you want to take your player to a separate scene and test something out. Maybe you want to use the player as base and work on something different, or you want to test the player or some other thing. But when you press Play you will see errors popping up because of other singletons references you had in the PlayerController like

ScoreManager.Instance.IncreaseScore();

Now you bring in ScoreManager into the scene and press play. You see some other Singleton references that are absent and you start to bring in the other references too. If you are too dependent on Singletons, you will see that a few minutes later, you have rebuilt almost the entire previous scene just to avoid errors. This means your code has no modularity. You can't separate one module without bringing in others. That's really not a clean approach. It rejects Unit Testing among many other things.

Now, Image this scenario. You are creating a network of objects that are connected to each other using ropes. So naturally create a RopeConnectionManager who takes 2 positions as input and connects them by a rope. You make it a singleton for easy access. Now, requirements change as they always do. You need to create connections using a laser instead of rope. If this wasn't singleton, you could create an interface named IConnectionManager with a method

void Connect(Vector3 point1, Vector3 point2); 

and then inherited this interface in 2 different systems RopeConnectionManager and LaserConnectionManager. You could reference IConnectionManager instead, and could swap out any of the inherited connection manager when you wanted. But instead you have Singleton making things TOO RIGID. RIP clean code.

These are a few reasons why I avoid Singletons, avoid rigidity and make way for extension.


Muhammad Asad Sohail

Seasoned Game Producer | Hybrid Casual / Casual F2P games expert

5 å¹´

Great findings Rakib. Another handy way I use to avoid missing component references is Dependency Injection pattern. All controller level components assign their instances to the only ONE singleton GameManager at their time of instantiation. This also satisfy Separation of Concerns (SoC) pattern. ????

要查看或添加评论,请登录

Rakib Jahan的更多文章

  • One design principle can increase development speed for prototypes

    One design principle can increase development speed for prototypes

    Hyper casual prototypes demand speed. It's not about reinventing wheels but rather it's about reusing wheels that were…

  • Reduce iteration time to speed up your workflow in Unity

    Reduce iteration time to speed up your workflow in Unity

    I am a hyper-casual game developer. More specifically, I create hyper-casual game prototypes.

    3 条评论
  • Replace "switch" with Scriptable Objects in Unity

    Replace "switch" with Scriptable Objects in Unity

    One of the design patterns in programming in Open-Closed Principle. It is part of the standard SOLID principles and…

    4 条评论
  • Zenject Dependency Injection, First Impression review

    Zenject Dependency Injection, First Impression review

    Dependency Injection is a very important concept in general, not just for games, but also for in general coding…

    4 条评论
  • Hyper casual Gameplay Good-to-Know's

    Hyper casual Gameplay Good-to-Know's

    This is a few list of features that I picked up or learnt along the way by myself or different articles, videos which…

  • InvokeRepeating VS Coroutine

    InvokeRepeating VS Coroutine

    For many, it is a lingering question. Should I use coroutine or InvokeRepeating? Performance wise it doesn’t matter…

    3 条评论
  • Speeding up UI workflow in Unity: DoozyUI + DoTween

    Speeding up UI workflow in Unity: DoozyUI + DoTween

    Unity asset store has a lot of assets. You can find assets for almost anything at this point.

  • Hyper Casual Game 1: Boomerang Throw

    Hyper Casual Game 1: Boomerang Throw

    Hyper casual games are cool! Fast prototyping, nifty mechanics, simple gameplay. The target audience is not specific.

  • Using Native C# Events in Unity

    Using Native C# Events in Unity

    EventSystem_Native Github: https://github.com/rakibj/Unity-Helper/tree/master/Assets/_UnityHelper/EventSystem_Native It…

社区洞察