I did quite the organizational overhaul in my Multiple Forces scene, but it led me to a simple yet distressing inheritance error. I isolated my gravity force and hand force algorithms inside their own respective scripts and had their scripts inherit from my scene controller script so that I could use it to control all force variables. However, since my scene controller inherits from MonoBehavior, I couldn’t instantiate those other two force scripts unless I used AddComponent. Apparently, anything Monobehavior touches has to be included in the scene. That would be fine, except that when I attached my two force scripts to the same game object my controller script was on, I got all the extra inherited protected controller script variables with them.

At first, I thought I’d just collapse the inspector panel for those two scripts. Then I realized that the property values in my controller script were getting overwritten by the values in these ones. That defeated the entire purpose of putting all variables in my controller script!

I researched a better way to accomplish my goal of setting global variables, which led me to singletons. Supposedly, singletons can be very dangerous if implemented poorly, but the singleton pattern seemed to work fine in my use case. I created a static instance of my controller script within my controller script, then ensured that it was the only instance in the scene.

public static MultipleForces_Controller_1 Instance {get; private set;}
 
private void Awake() {
    if (Instance != null && Instance != this)
    {
        Destroy(this);
    }
    else {
        Instance = this;
    }
}

In my other scripts, I referenced the instance, which I renamed for brevity.

MultipleForces_Controller_1 Controller => MultipleForces_Controller_1.Instance;

This allowed me to reference any of my global controller script variables as Controller.variable. Now that my gravity and hand force scripts were isolated from MonoBehavior, I was able to instantiate them in my controller script and call their public methods.

I put everything together and hit play, but my player wouldn’t move. At first, I suspected this bug to be a result of incorrectly creating the two instances, but I soon realized that the true culprit was my OnPlayerAdded action not triggering an event in my controller script. The event subscription was fine; the problem was that I triggered the OnPlayerAdded action in the player constuctor’s OnEnable() function yet also subscribed to the action event in my controller script’s OnEnable() function. It seemed the player constructor got enabled first, meaning the action fired in my player constructor before the event in my constructor got subscribed to. Once I moved OnPlayerAdded to my player constructor’s Start() function, I was in business.

I rewrote a ton of code today. Here’s a clip of me testing hand and gravity forces together:


Tags: unity csharp gamedev singletons debugging physics