How to bring to work MonoBehaviour and non-MonoBehaviour scripts together?

Hello,

I have written a state machine for character movement. It’s non-MonoBehaviour. I have there this script:

using System;
using UnityEngine;
using System.Collections;

[Serializable]
public class StateData
{
    [SerializeField] public string currentState;
    public LeanBack leanBack;
    public IEnumerator upperBodyCoroutine;
    ...
}

Besides this state machine I have also a PlayerCamera script, which is MonoBehaviour and attached to the CameraGame object:

using System;
using UnityEngine;

public class CameraMovement : MonoBehaviour
{
    public StateData data = new StateData();
    ...
    private void OnCollisionEnter(Collision collision)
    {
        if (data.upperBodyCoroutine != null)
        {
            StopCoroutine(data.upperBodyCoroutine);
        }

        data.upperBodyCoroutine = data.leanBack.LeaningBack();
             // Getting an error in the above line: 
             // NullReferenceException: Object reference not set to an instance of an object
        
        StartCoroutine(data.upperBodyCoroutine);
    }
}

There I have added OnCollisionEnter - if the Camera collides with any object, a coroutine should start. But it’s not. It seems for me, that the connection between those two scripts is not working and I think it might be due to the fact, that one is MonoBehaviour and the other not. But I don’t understand why. I had a similar problem in another script and I don’t know, how to make it work. I was searching for some articles, which would explain, how the connection between such scripts work, but haven’t found anything.
Any ideas, how to make it work together?

Thank you
Huxi

Kk, now what you need to do is define currentState and pretty much every other variable of StateData, you initialized a new instance with:

But you haven’t given a value to its variables, you should do something like this:

public StateData data = new StateData();
data.currentState = "YourState";
data.leanBack = LeanBack.something;
// etc...

The reason why they’re null is because they’re not defined, you can define them like I just showed, or you can define a set of default values with a Constructor like this:

[Serializable]
public class StateData
{
    [SerializeField] public string currentState;
    public LeanBack leanBack;
    public IEnumerator upperBodyCoroutine;
    ...

    public StateData()
    {
        currentState = "YourState";
        leanBack = LeanBack.something;
        // etc...
    }
}

You can learn more about Constructors here:
Constructors - C# programming guide - C# | Microsoft Learn

I suspect this is the actual problem:

Instead of the connection between those scripts.

To make sure add 2 * Debug.Log(), one for data and the other for leanBack

Hello @JiRo_Dev Ok so I guess you are right. Even though I am not able to debug this script because of this error. But I have another script with the same problem:

public class Health : MonoBehaviour
{
    public StateData data = new StateData();
    public int health = 100;
    
    public void Update()
    {
        string currentState = data.currentState;

        if ( data.verticalVelocity < -8 && data.isGrounded)
        {
            if   (data.verticalVelocity < -13) { health -= 100; } 
            else (data.verticalVelocity < -12) { health -= 20; }
        }
    }
}

When I debug here, I see that data is correct, but the currentState isn’t.
image

So I guess I need to reference each field I want to use separately? I tried like this:

string currentState = data.currentState;

but it doesn’t work. I guess that’s incorrect? What would be the correct way?
Same problem with data.verticalVelocity; it’s always 0.

I’ve fixed it:

stateManager = this.GetComponent<StateManager>();
data = stateManager.data;

Now it works