If I needed to call Unity Events from individual classes then how would I go about doing that? (e.g: OnAttack event from attack state) Since each state is a pure C# class, there’s no way to expose events for each state in the inspector.
The way the states are set, if I were to make a character that could walk but not run or a character that couldn’t jump, then I would need to create a new state machine, base state, and respective states that don’t include transitions to the jump state. I think that’s because the transitions are defined in the states themselves. This reduces modularity. How can we tackle this?
You are correct, the way the state machine in this course work does not allow for that. You could, however:
Have the states as MonoBehaviours with Unity events. Instead of switching to a new state, you would switch to one of these that you retrieved with GetComponent<>, for example. You would have to keep your head when dealing with Update versus ‘Tick’ (and other Unity messages since we won’t be dealing with these) so, perhaps
You could use the observer pattern and set up an EventBus component with Unity events and the states would then emit to this bus. The bus, in turn, would invoke the Unity events. Or
Just use C# events. You won’t be hooking them up in the inspector but who does that anyway?
I never found this to be a problem, so I never thought of changing it.
You cannot Invoke or declare a UnityEvent from within a State, but you can subscribe to them from within a state using AddListener and RemoveListener
There are a number of approaches you can take for this. You could, for example, have a SerializeField boolean on the StateMachine that indicate if a character can enter a given state or not… for example
[field: SerializeField] public bool CanRun {get; private set;} = true;
Now, before switching to a running state, you can test
This 3rd person course has changed the way I do a lot of things. I have modified and mangled the state machine in so many ways to suit my needs.
My base state machine is not a MonoBehaviour anymore, but a pure C# class. I do have a MonoBehaviour version, but that holds a reference to the non-MB class and relays the methods. You can say it’s a ‘decorator’ for the class. It’s also stack-based so I have a PushState() and PopState() in addition to the SwitchState(). When I go into TargetState, for example, I can just ‘push’ it and when I go out I ‘pop’ it and I’m back to whichever locomotion state I was before. It does mean I have to keep my head when I’m designing the flow.
I also have a NetworkBehaviour version that’s the same as the MonoBehaviour and relays the methods. This one is ‘iffy’ because I don’t know the multiplayer stuff well, but it works. I think.
My states have Tick() and FixedTick(). I would add LateTick() but I hadn’t needed it yet.
The reason I moved the base state machine to a pure class is because I wanted state machines in my states, and since they’re not MonoBehaviours I needed to improvise. Loads of iterations later, and I have what I use in almost all my games now.
Before the course, I used a state machine that Jason Weimann showed on his youtube channel. With it you define actual transitions for states; state a goes to state b if condition x is met. This happens automagically on every frame. It also has ‘any’ transitions; any state can go to state b if condition y is met.
I think I only used it in one project because it was a little tedious for me. I had several states with state machines inside them and the setup was a bit rough (I’m redoing that project now with my new fsm). You can check it out here
You’d still have the problem of not being able to bind events in the inspector.
Personally, if I needed this I would go with the observer pattern. I have a bit of a ‘observer pattern’ setup I use and I’d just make a MonoBehaviour with the Unity events on and make that an observer that would, in turn, invoke the event.
Oooh, I like that, a lot. Really good way to handle “walk to a location before engaging” state pair (I usually handle this by passing a closure to the walk to a location state).
I haven’t watched this video, but you’re describing something a lot like more of a Behaviour Tree (which is technically a form of State Machine, actually). I’ve actually been playing with Unity’s new Muse Behavior, which so far seems quite interesting.
since I’m here, I may as well ask. Is there a way to check for the previous state that lead to a current state? So for example, if I’m running, the past event for that can be either I’m idle or walking. Can I possibly program a solution into our current state machine to check for whether I got into running from walking, or running from idle? For example if I want to place specific conditions when entering the state or what not
I don’t know why I need this, but I recall a few times where I just wished I’d have that. Funnily enough, I don’t even remember where, but it was there at one point in time…
(P.S: My priority, at least on GameDev.TV for now (I’m working on something entirely different behind the scenes, and it needs a lot of refining), is still my knockback issue with the NavMesh)
This issue was just something that crossed my mind
These transition gates are checked every frame before the active state is ticked, with ‘any’ transitions having priority over normal transitions. For my purposes this was a little tedious because I wanted to change state from within other states (like we do in 3rd person course) so to get the conditions to work I had a enum property and the conditions would check the value.
Not sure what you mean with ‘place specific conditions’ but the stack-based solution I mentioned above does this. With a stack, when you ‘push’ a state it goes on top of the stack and becomes the active state. The previous state is exited, but it’s still in the stack. When you are done with this state, it gets ‘popped’ out of the stack and the old state is now at the top and becomes the active state again.
Here’s a version of it
Basically, what I meant was a variable that stores the LastState from which the machine switched to another state, basically something to keep track of who called this state. It could be used to ensure, for example, that an action is done only if the call was from a specific state… it’s a little hard to explain, but I’ll try using an example I use in my own project:
I have a variable called ‘IsHostile()’, which Brian helped me develop, which is responsible for whether an enemy is aggressive towards me or not (I created an entire system on my own out of just that, I’m still refining it though). Anyway, since I introduced into my own project an NPC Ally system, to have NPCs that fight side by side with the player, I had to introduce an ‘InitialHostility’ variable as well, which tracks the default nature of the enemy, so we can return to it if the ally is no longer a part of the player’s team for example. Basically, it’s like a storage system that can allow you to tune Hostility at any moment you desire… it’s something that keeps track of who was the last value like for example (it could do better as a list, but for now it’s a starting point), something that holds the value for times of need
Arghh… it’s a little too hard to explain
apart from the crazy-looking code that still terrifies me to this day, that honestly looks somewhat easier to understand once you’re a little better with the language…
AND SOMEHOW, IT PARTIALLY COVERS WHAT I WAS ASKING FOR… - just that it doesn’t do it with our own context
I was thinking of converting the states to MonoBehaviours but I have a lot of states (many of which are set up hierarchically). It will easily clutter up the inspector and soon get out of hand.
I had never heard of EventBus before you mentioned it. The topic is a bit advanced for me at the moment but it seems like an interesting way to decouple code.
I found Unity Events to be quite useful when I wanted to call functions of other systems but didn’t want one system to know the other. It also allows me to quickly change things in the inspector without having to modify the code.
For example, if I have a UnityEvent called OnPlayerLanded for when the Player lands on the ground and I want the AudioManager to play audio and VFXManager to play some VFX, I could drag them in as listeners to the event. I can easily remove them from the inspector if I want. That won’t break anything.
I can also export the AudioManager and VFXManager to other projects and they would work since I didn’t subscribe to any project-specific C# events in those scripts.
But if I have a lot of states, then I have to add a boolean for each state. Also, if I ever decided that I wanted to delete a state, then it would break all of those scripts where that specific state is mentioned as a transition.
That’s interesting, I’m eager to know how it’s an improvement to the current system. I’ve seen something similar being used to handle UI.
For example, if you press TAB it will push the inventory screen and set it as currentScreen. Pressing ESC would Pop it and make the currentScreen back to the top of the stack which is the HUD, let’s say.
I’m eager to learn how you used this for your character controller!
This is what I was searching for! I also came across a scriptable-object based State machine where you could specify the goto state for each state in the inspector.
This is exactly what I’ve done. I’ve created a separate script(MonoBehaviour) that listens to C# events from the states and invokes UnityEvents respectively. This seems like the best way to tackle this problem without changing the way the state machine is set up.
A [Flags] enum is backed by an int, meaning you can have up to 32 values (1<<31). When you add them to the StateMachine with
[field: SerializeField] public StateRules StateRules {get; private set;} the inspector will show them like a LayerMask, where you can select as many or none from a drop down as needed.
Also, I made a boss battle using Unity Muse. I was using Kiwi Coder’s Behaviour Tree earlier but Unity Muse BT has a lot more options. I’ll post it here after a little bit of polishing.