Finite State Machine's state instance fails to grab the reference to another to other objects

Hello, please help, cause I’m starting to lose my mind.

I followed a video on youtube

to create the FSM. This is a second try (different guy - Table Flip Games) on creating such system, so I think I kind of understood how it all works, so then I can properly modify it.

This code I have here, is kind of a mashup of what I learned from Table Flip Games initially, then created the structure using the video I linked, filled in the blanks with the things I learned from Table Flip Games and then modified it different things. Although EnemyPatrolState is mostly the same since Table Flip Games video (I deleted unnecessary parts)

Short description of what I want to achieve - I need a FSM for an enemy, with states such as: IDLE, PATROL, SUSPICIOUS, CAUGHT

The last two are irrelevant to my problem currently, I only explain for the sake of giving you some context.

The system itself seems to work just fine, it switches to IDLE, and then to PATROL.

But here’s the catch - there are PatrolPoints (GameObjects with a PatrolPoint script containing a piece of code that is not needed at this moment, but the script is necessary to be able to reference the objects in the Inspector). While writting this, I just thought that maybe that’s the point - why not just make a list of GameObjects, I don’t really need to reference the script, but the GameObject that will be the target of Enemy GameObject.

So, here’s the FSM code:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class EnemyStateManager : MonoBehaviour
{
    EnemyBaseState currentState;
    public EnemyIdleState IdleState = new EnemyIdleState();
    public EnemyPatrolState PatrolState = new EnemyPatrolState();
    public EnemySuspiciousState SuspiciousState = new EnemySuspiciousState();
    public EnemyFollowingState EnemyFollowingState = new EnemyFollowingState(); //TODO: change name

    public GameObject[] _patrolPoints;

    //[SerializeField]
    //List<EnemyBaseState> _validStates;

    // Start is called before the first frame update
    void Start()
    {
        //starting state for FSM
        currentState = IdleState;

        //"this" is a reference to the context(this EXACT Monobehaviour script
        currentState.EnterState(this);
    }

    private void OnCollisionEnter(Collision collision)
    {
        currentState.OnCollisionEnter(this, collision);
    }

    // Update is called once per frame
    void Update()
    {
        currentState.UpdateState(this);
    }

    public void SwitchState(EnemyBaseState state)
    {
        currentState = state;
        state.EnterState(this);
    }

    public GameObject[] PatrolPoints
    {
        get
        {
            return _patrolPoints;
        }
    }
}

Here’s the BaseState code:

using UnityEngine;
using UnityEngine.AI;

public abstract class EnemyBaseState
{
    public abstract void EnterState(EnemyStateManager state);

    public abstract void UpdateState(EnemyStateManager state);

    public abstract void OnCollisionEnter(EnemyStateManager state, Collision collision);

    protected NavMeshAgent _navMeshAgent;
    protected Enemy _enemy;
    protected EnemyStateManager _esm;
 
    protected FieldOfView _fieldOfView;
    protected Vector3 enemyTransform;
    protected bool _suspicious = false;

    protected LayerMask obstructionMask;
    protected Vector3 directionToTarget;
    protected float distanceToTarget;
}

I don’t think the IDLE STATE code is necessary since it works fine, so here’s PATROL STATE code:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class EnemyPatrolState : EnemyBaseState
{
    GameObject[] patrolPoints;
    int patrolPointIndex;

    [SerializeField]
    float _totalDuration = 2f;
    float _timer;
 
    public override void EnterState(EnemyStateManager state)
    {
        //EnteredState = false;
        if (state)
        {
            //Grab and store patrol points
            patrolPoints = _esm.PatrolPoints;

            if (patrolPoints == null || patrolPoints.Length == 0)
            {
                Debug.LogError("PatrolState: Failed to grab patrol points from the NPC");
            }
            else
            {
                if (patrolPointIndex < 0)
                {
                    //Doing this only the first time to choose a patrol point, because otherwise it would have completely random path -> thus OnEnable contains patrolPointIndex = -1
                    patrolPointIndex = UnityEngine.Random.Range(0, patrolPoints.Length);
                }
                else
                {
                    patrolPointIndex = (patrolPointIndex + 1) % patrolPoints.Length;
                }

                SetDestination(patrolPoints[patrolPointIndex]);
                Debug.Log("Patrolpoint" + patrolPointIndex);
            }

        }
    }

    public override void UpdateState(EnemyStateManager state)
    {
        //code unnecessary, as currently I only have a problem with EnterState method
        //I have a logic prepared, and some basic functionality code, but for now, I just need the Enemy to go to PatrolPoint
    }
    */

    public override void OnCollisionEnter(EnemyStateManager enemy, Collision collision)
    {
     
    }

    private void SetDestination(GameObject destination)
    {
        if (_navMeshAgent != null && destination != null)
        {
            _navMeshAgent.SetDestination(destination.transform.position);
        }
    }
}

I guess what I’m missing here is actually that reference. It seems my way of doing it, by

    public GameObject[] PatrolPoints
    {
        get
        {
            return _patrolPoints;
        }
    }

and then assigning it in EnemyPatrolState, via “patrolPoints = _esm.PatrolPoints;”
while _esm is declared in EnemyBaseState - isn’t really what Unity needs.

I tried doing that in a separate script called Enemy, but I got the same results.

I think I provided all the necessary stuff, to speed up the response time, maybe I forgot about something but at this point my brain can’t think straight…

This is my position on finite state machines (FSMs):

I’m kind of more of a “get it working first” guy.

Your mileage may vary.

The problem is now there are many places to look for your issue: the actual dry FSM implementation, and the actual use of it.

You must find a way to get the information you need in order to reason about what the problem is.

What is often happening in these cases is one of the following:

  • the code you think is executing is not actually executing at all
  • the code is executing far EARLIER or LATER than you think
  • the code is executing far LESS OFTEN than you think
  • the code is executing far MORE OFTEN than you think
  • the code is executing on another GameObject than you think it is

To help gain more insight into your problem, I recommend liberally sprinkling Debug.Log() statements through your code to display information in realtime.

Doing this should help you answer these types of questions:

  • is this code even running? which parts are running? how often does it run? what order does it run in?
  • what are the values of the variables involved? Are they initialized? Are the values reasonable?
  • are you meeting ALL the requirements to receive callbacks such as triggers / colliders (review the documentation)

Knowing this information will help you reason about the behavior you are seeing.

You can also put in Debug.Break() to pause the Editor when certain interesting pieces of code run, and then study the scene

You could also just display various important quantities in UI Text elements to watch them change as you play the game.

If you are running a mobile device you can also view the console output. Google for how on your particular mobile target.

Another useful approach is to temporarily strip out everything besides what is necessary to prove your issue. This can simplify and isolate compounding effects of other items in your scene or prefab.

Here’s an example of putting in a laser-focused Debug.Log() and how that can save you a TON of time wallowing around speculating what might be going wrong:

Hey, thanks for the reply.

I’m afraid that’s not really helpful in my case.

It IS working. And I know, cause without “patrolPoints = _esm.PatrolPoints;” line, it executes as it should (I mean, it does if I erase the rest of the code from EnterState method, cause it depends on it). And I know the thing works, cause with previous version I mentioned, the patrolling worked as intended. I just liked the current apporach to FSM more.

I know it is executing, cause it enters IDLE state just as it should, I mentioned that.

That shouldn’t be a problem here, unless you’re able to explain how, in the context of my code, which I think is clear enough and there are comments (but I can make things clearer if necessary), is it executing EARLIER or LATER than I think, and how it might be a problem here.

That also shouldn’t be a problem here, as it fails after entering the PATROL state, NOT during its UPDATE method.

It’s almost as if you just read the tittle, and replied with automated message that is not really helpful to anyone but a few particular people, which in this case I don’t think its me.

No, it’s not executing on another GameObject, since it is not using ScriptableObject, and it is placed directly on the Enemy GameObject, while the Patrolpoints are directly referenced in the Inspector.

There ARE, and you would know that, if you actually read the post, and not just the tittle. My situation is not “I just copied and pasted buncha code and idk why its not working, idk what I’m doin pls do it for me”.

yes. all the things that should. as often as it should. in the order I made it run.

irrelevant. yes. yes.

irrelevant in my case.

I know where it breaks, once again sign of an automated message that doesn’t help at all.

I’m not even gonna reference the rest, as it won’t help anyone.

No offense, but there would be no difference whether you replied to my post or not. Are you here to actually help people, or just make the comments number get bigger?

==================================================================================

But, to anyone reading - the problem is not exactly with the Finite State Machine. It works fine.
The problem appears, when I try to get the reference of PatrolPoint GameObjects.

Edit. From my perspective, there is a missing link between the PatrolState - which is a class implementing patrolling behaviours - and another class that contains the PatrolPoints (is able to get them from Inspector). I tried doing that via different script called Enemy, that is placed on the same GameObject (my Enemy GameObject) that has FSM script. I also tried just putting it on EnemyStateManager (FSM) script that handles the state instances, and then referencing it in a PatrolState - but I can’t really use GetComponent in PatrolState as it inherits from EnemyBaseState, and not Monobehaviour, so the only way was by using “get”, but I’m missing on why that is not the solution.

Anyone else?

You’re going to have to be a lot more specific in what is going wrong.

Here is all I can suss out of your post, which is why I gave you a canned response:

What does that mean? Did Unity give you a "CS9999: That's not what I need!" error?

I suppose that means still not “really what Unity needs.”

Personally I disagree with this, but it is at the end of the day your problem.

I had hoped trying some simple Debug.Log() style investigation would bring you a new perspective, but I suppose that didn’t happen.

If you care to elucidate more specifically WHAT your problem is, I suspect you may find some good help on these forums. This is an excellent pattern to follow:

  1. what you did (got that)
  2. what you expected (got that, FSM, four patrol states, waypoints, etc.)
  3. what happened instead (MISSING)
  4. what you tried (again, good description of lots of stuff, but what is happening?)

EDIT: ah yes, from the title I see this:

fails to grab the reference to another to other objects

What does that mean? Where is anything “grabbing?”

It really makes me suspect this entire post is just “you got a null reference that you can’t find.” Null references only have one three-step canned response, and that is:

  • Identify what is null
  • Identify why it is null
  • Fix that.

I was half-way through replying, but something happened and everything got erased so I’ll try a different approach.

I still appreciate your replies, there’s still a chance I might understand what I don’t know and don’t understand.

Don’t be petty just like I got petty with you, cause you couldn’t read between the lines a little, especially since not everyone is a native speaker and natural languages aren’t a perfect tool to convey ideas that are in the brain, and instead of just asking to elaborate, you basically posted a “tips and tricks” for a Finite State Machine, while I specified that the FSM works fine, there is a problem with some reference. Please understand that I could have gotten a little annoyed, for other personal reasons too.

========================================

Before I proceed, let me explain a little the nature of my problem.

  • Unity claims that in EnemyPatrolState class, the list of PatrolPoints I’m trying to assign to the list declared in that class is null
  • It isn’t, but Unity says otherwise
  • I can’t, nothing I try works, that’s why I’m here

===================================

Alright, since words alone have failed me

(one reason being that maybe in this case I’m missing some information on how things are done, so I tried to be less specific to my project, and more general about Unity, C#, “grabbing and storing references”, btw I still don’t know how else to say what happens when Unity “grabs” a reference)

Let me use pictures along with words.

In the class EnemyPatrolState, in EnterState method, there is (line 20)

patrolPoints = _esm.PatrolPoints;

Unity gives me NullReferenceException for “_esm.PatrolPoints”, but obviously only during runtime, after it enters the EnterState method, and tries to assign “_esm.PatrolPoints” to “patrolPoints”.

The “_esm” is declared in EnemyBaseState abstract class (protected EnemyStateManager _esm)". However that alone gives me nothing.

So, I made an array in EnemyStateManager class, via

    public GameObject[] _patrolPoints;

and then

    public GameObject[] PatrolPoints
    {
        get
        {
            return _patrolPoints;
        }
    }

The “_patrolPoints” in EnemyStateManager (as you can see, the Object reference IS set to an instance of an object)

Now, let’s get back to EnemyPatrolState class.

I got an array(line 7)

GameObject[] patrolPoints;

which is later used in “patrolPoints = _esm.PatrolPoints;” (line 20)

So, as you can hopefully see now (if not, please ask for further clarification), nothing is null (cause I assigned it in the Inspector), and yet Unity gives me a NullReferenceException.

Hmm, maybe that will help:

If EnemyPatrolState was just a normal script, I would place it on the Enemy GameObject, along with EnemyStateManager script (that already is there).

Hypothetical situation. It would look like this:

EnemyPatrolState would inherit from MonoBehaviour, and I could reach PatrolPoints in EnemyStateManager via

EnemyStateManager esm;

and then

esm = GetComponent<EnemyStateManager>();

then I could easily write

patrolPoints = esm.PatrolPoints;

and there shouldn’t be a NullReferenceException, right?

But, EnemyPatrolState is a state, that is running in the background via

public EnemyPatrolState PatrolState = new EnemyPatrolState();

that is in EnemyStateManager.

So. If EnemyPatrolState isn’t reachable via Inspector (as it doesn’t inherit from MonoBehaviour, but EnemyBaseState instead, and it is running in the background, because it is one of the states of Finite State Machine), how can I reach the PatrolPoints that are in the EnemyStateManager, or any other script that I might write?

Is it just impossible to do that, cause it doesn’t work that way?

I’m starting to think, that is what I don’t know, whether it’s possible - but I just don’t know how - or maybe it doesn’t work - simply because it just doesn’t work that way.

Maybe it just doesn’t work that way.

If _esm.PatrolPoints is giving you null reference, it CANNOT be the .PatrolPoints part… it is the _esm part. That is the part you are dereferencing.

It needs to not only be declared but populated, and it needs to be populated before you attempt to get _esm.PatrolPoints , which is where you say the null reference is thrown.

Yes, that is my problem. I think I finally managed to communicate to you, what exactly my problem is (I knew what the problem was from the start, but as you can see, I had a trouble conveying it with such words, so that you can understand)

As per one of the screenshots I posted, I did populate it, in EnemyStateManager. Look.

Once again - THAT is the problem. The problem I’m having is, that it IS populated. If that is not how I should populate it, so the EnemyPatrolState can reach it, then please try to explain to me how to do it.

Could you please explain? How can I reach exactly this instance of EnemyStateManager on the Enemy GameObject, while being in the EnemyPatrolState script.

Or, how to populate it using different solution.

The Unity™ approach is to make each state a MonoBehaviour.

This means you would do your initializations in Start(), where you have access to the reference way to locate shared services on your GameObject, namely by using GetComponent<T>();

Keep in mind that GetComponent(); is NOT available as a class initializer, as the constructor call when a MonoBehaviour is created is not run on the main thread.

This approach has the side benefit of scaling nicely because as you add more behaviours you simply add more instances of these states.

Now putting on the CIS OO hat, I would actually turn it around and have the Manager discover the States available to it. Unity supports interfaces fairly well for this, such that you would have an IEnemyStateMachine interface that each State implements, and then the Manager would look for those at startup, so that it knew what states were available to it and be able to turn them on/off appropriately.

Here’s my standard interface goodness blurb:

Using Interfaces in Unity3D:

https://discussions.unity.com/t/797745/2

https://discussions.unity.com/t/807699/2

Check Youtube for other tutorials about interfaces and working in Unity3D. It’s a pretty powerful combination.

Ah, so the suspicions I started having, that my approach might be impossible to do, because it just doesn’t work that way, were correct.

I think I understand. So we’re ommiting the EnemyBaseClass, and instead I’d create an interface that inherits from EnemyStateManager, and this way I can actually make Unity get the object references I need.

Basically it means that I had a FiniteStateMachine that was not really compatibile with Unity, and your approach allows me to actually do what I need.

Alright, thank you. And I apologize for getting a little snarky at the beginning, I shouldn’t behave like that. It’s for my Thesis, it’s been a looong time working on my project, and I’m getting little frustrated with it, and also the deadline is floating over my head (I postponed it a few times already).

I think I’ll manage to finish it on my own from this point onward, but I will come back here, in case I won’t.

Alright, have a nice day.

You’re very welcome.

Unity has a lot of “Unity™ ways” and most of them stem from the fact that your code is NOT your application code. This throws a lot of people used to a more “my program is my program!” mindset.

Unity is actually the application and it does a ton of init work, then purely by convention it loads the first scene.

That’s it. That’s all Unity does.

Part of that first scene loading may produce instances of objects (MonoBehaviours) and that is really the only first place your code can take a foothold, in the Awake() / OnEnable() and so forth.

Technically there are other ways, but the above is the main way, and when you play well with that system, you quickly find your friction goes down drastically.

Given the above, this lifecycle chart can kinda help you plan your approach:

https://docs.unity3d.com/Manual/ExecutionOrder.html

Best of luck with your thesis!

1 Like

Right! I forgot classes could inherit from several classes/interfaces! I haven’t done that in a while, so I totally forgot. This is the fix I was searching for.

So, if anyone that comes by this thread and has a similiar problem - the solution:

Yeah, it should be easy to do it now. These states can now just inherit from Unity’s native class, along with my interface, and I can acomplish what I want.

Unity even has a tutorial on it

Alright, once again thanks for help, and thanks for wishing me luck with my thesis

1 Like