I did the Unity Junior Programmer course, I'm at the last small game for my portfolio. Saw this pop up and thought oh let me check this out. Now I feel like a Freshman Programmer V_V. I get the point of doing this though, it's similar to what I do with having parent and children for my enemies in the game: I have the parent that contains the code everything uses and the children that do things specific to that object. But HSM is a new frontier and your use of getters and setters is... prolific, I'm happy I already knew about them or my head might have exploded. Definitely need to re-watch this or actually go back to the first in this series. I am shocked you aren't at 100k subs yet. The YT algorithm gods haven't descended on this channel yet I guess.
Thank you for such a kind comment! I am always happy to share what I learn and try my best to convey it in a hopefully understandable manner. I wouldn't understate how far you've probably come since the start of your game dev journey though! You have probably grown so much since you first started with Unity, and will continue to grow as long as you try 🙌 Keep going! Keep learning! And looking forward to seeing what you release in the future!
How was that course? I'm a software developer professionally so I already know how to code, but thought that might be a good place to start with Unity.
@@MrFishstickGamer For rogue upstarts like myself it helps create a portfolio to refer back to. You get very small but complete projects that represent a fundamental element of design. For me it became a bit too much when they introduced GitHub resources. It's kind of like when you get home and your body decides at the door that you need to pee so you are in a rush: I enjoyed getting each project done but then practice of working Github after gave me enough distress to want to take a break. If I could start all over I would say starting with Unity Junior Programmer course is best then moving on to YT videos like iHeartGameDev who has a similar but more complex projects. The most important thing though is time and practice.
Man. This was hard, but I'm glad you're tackling complex issues like this, I feel like most other youtube tutorial channels are afraid to make videos on topics like this. Also your presentation was top notch. Thanks for taking the time to make this video.
While this video is great, learning those things should be separated: there are books that showcase the state machine separately on much simpler projects: GoF Design Patterns book and HeadFirst Design Patterns. Then there's Game Programming Patterns book. You want to separate learning the concepts from learning the implementation in an engine.
@@KulaGGin Thanks for the book recommendations. Personally Seeing them in context actually works much better for me than the abstract explanations in books. Everyone learns differently.
Hey all! I'm so excited to share this new tutorial where we go over a player-based hierarchical state machine. Most of the state machine tutorials that I've found have covered AI and have just been single state, so hopefully you find this helpful when making more complex character controllers. The next video lined up is the first Cinemachine tutorial voted for by the Patrons! As always, thank you so much for watching and I hope this helps you on your game dev journeys! Cheers! 🍻 -Nicky
I've recently started making something using Hierarchical State Machines and seems to be working fine but quite excited to see how you'll be handling it to see if what I'm doing can somehow be improved. Thank you for the tutorial!
For cinemachine, I'd really appreciate it if you covered how to make custom cinemachine modules. When I tried to integrate pausable dialog using cinemachine, it was quite a pain to get it working amre there really weren't any resources about it. And then there was the problem making it reset properly after playmode which I had to give up on.
By video Quality and explanation this channel has great potential grow exponential. Make sure to be consistent other only luck can help with algorithms.
I thought of and implemented a small refactor that should provide a nice performance boost to the code. When you use the StateFactory, you're creating a new instance of each state to be applied. It clearly works great, but discarding those classes after you don't need them anymore causes some work for Garbage Collection, which can cause issues down the road. So I went back and in the constructor of the factory I create an instance of each state and store them in a dictionary. Then instead of returning a new state, I just fetch the same state from the dictionary. If you do that, and move the initialize substate method to the Enter functions of the states, then everything works the same. You could even go a step further and have the switch state method take in a state enum instead of having different methods for each state. I'm pretty sure this disqualifies the factory as a factory, but I'm not experienced enough to know the actual name. I should also mention that this ONLY works because the states work entirely off of the data provided by the context. if the states themselves held some sort of data, this would require some extra logic to maintain. Love these videos, btw! I look forward to the next one!
Wonderful job! I also considered storing those instances! But I wasn’t sure how much garbage making new instances would cause. That being said, it’s awesome to me that you took the time to refactor the code! Thank you for watching and sharing your own implementation!
@@anaezesomto8330 A simple or basic example could be if the character can swim, shoot gun, fly etc. then the base states would be onground, swim, shooting, flying and jumping. like left mouse button will fire bullets in shooting state but can dive lower in water while swimming, etc. and you won't have to add bool/flag checks for left mouse button pressed cause the states will handle that. AND MOST IMPORTANT -> ONLY ONE BASE STATE IS ACTIVE IN THIS CASE. you can have multiple active states with some more complex/dimensional state machines. Hope this helps!
I am trying to make my first game and I wanted to learn about this state machine topic. The first time that I watched this video I took notes and didn't try coding anything. Going through the video I found things that I didn't quite understand at first but I just continued to try and understand as much as possible. After watching the video I tried coding a state machine for an object that I want in my game and I had the lightbulb moment several times! Everything is starting to make much more sense now that I pushed myself to figure out something that I didn't quite understand yet. Thank you for this video!
This video is certainly a step up in difficulty from the last ones. Feels like it went from algebra straight to rocket science in terms of complexity. Gonna be rewatching this one quite a few times. Thanks for taking the time to make these videos.
I prototype a game and think to myself, "nahh I won't need a state machine, I got what... two actions?" and then I want to build the game out proper and wished I had just sucked it up and typed out the few extra classes to make it happen. This video is crucial for the new devs out there!
I have a few recommendations 1. Make the states inherit from Scriptable objects. This way you can add different configurations for a specific state. If you game have some "buff" system you can have the states take their stats (like movement speed etc) from the scriptable object, and then you can switch the current state in run time to buffed version and vice versa. You don't need the state factory, all the states are pre-configured. 2. create a "unique name" for each state (states that differ in configurations will have the same name you will see later why) and make a dictionary that holds a name and the scriptable object in context. The player will try to switch states using the name of the new state only, and the level above in the hierarchy will hold the dictionary. This is good because you can have more states, like dodging, climbing ladder, dash, fly, swim ... each of those "know" when they need to be active, when they need to be shut, each can hold its own configurations and functions (in the scriptable object) 3. Add events - (mostly applied to shooters) if you want an action (like shooting) to depend on state, make an event to be fired off the base FSM component (the outmost one that is always in the scene) that when a state changes it fires "OnStateChange()" with information of the new state, make the weapon subscribe to it. and then if the weapon can only shoot on certain states you can use if(state is StateThatEnablesShooting) canShoot=true ... 4. Separate the input system from the context. Create a class of InputHandler that will take in the inputs and process them, this way you can put constrains on the input itself before it reaches the controller. Why do you need it? let's say you want to enter a driving state and you don't want to "hard steer" left and right. You want to simulate a wheel turning and slerp between (0,1) to (0,-1) and you want to reuse the movement (that takes direction from the data) you will need to apply another layer of processing. Another thing is that you might want to change sprint to toggle - first click would enter the state, second exit, you would probably want to pre-process the data outside of the classes (if we are following SOLID we don't want the class to also manage the input types). Overall very very powerful design. It takes a lot of work to get it to work at first, but the amount of work on expanding that is next to nothing. When comparing it to celeste's controller I wanna see the brave guy that will try to implement some new functionality in there.
@@de-souzapatrice1859 Imagine the following architecture for a weapon system. Each state will inherit from scriptable object. The states will be the following (can be expanded) Reload, PrimaryFire, SecondaryFire, Scope etc... PrimaryFire and SecondaryFire will inherit from FireState which will inherit from BaseWeaponState And then each fire state will run their shooting logic in OnEnterFire, They will exit the fire after the cooldown of the fire rate is over (which can be set up through the inspector) back to an idle state or reload. The weapon class (which will hold the state machine) will hold the bullet count and anything related to ammunition and will communicate with the base player's inventory. Then if you want to upgrade the weapon for let's say shoot laser in which u spawn a trigger collider that will inflict damage over time, you can create a new PrimaryFire state, implement its own logic, and put it in the primary fire slot of the StateMachine. This system allows for upgrades, as you can alter the values of the scriptable objects to create many variants of the weapons offline, and at runtime to swap (for example, for upgrading a weapon that fires projectile to a weapon that shoot hitscan to a weapon that shoot laser beams all you have to do is make different variants of FireState) it's just an example, I hope it's clear
@@Doronoss Thanks for explanation. Indeed, it a great way to achieve it. I’ll try and may be send you a link for code review. I’ve sent you a connexion request on linkedin.
This video made me sub to your Patreon. I'm from Brazil so Patreon is kinda expensive to back on, but the effort and quality on this video is incredible, one of the best tutorials on RUclips. I love how you're not shy of explaining more complex topics, most Unity tutorials don't really dive into programming, but this tutorial is incredible not only for Unity but for programming overall. Thank you for this!
Dude, you are just amazing...your videos are even better and explain more than Unity's official tutorials...Keep up the good work sir...please dont leave youtube ever...
I've written several FSM/HSM implementations, but thought I'd give this architecture a try because it's far less complicated than those I've written. Made a few changes, but the primary is that my OnExit method is an IEnumerator and when switching states, I yield until it's exited. The makes it easier to do things like waiting for an animation to finish before exiting. I also am using ScriptableObjects to configure each state. For example, if you have multiple playable characters, each state can utilize properties of the current character scriptable object.
Coroutines generate garbage each frame, try events/delegates. Do tell how you get the remaining time for the animation clip from animator/ or what is you implementation for yield WaitUntil? I hope u don't use hard coded values??
@@safwatahmad7672 so the coroutine is only used in the OnExit in order to block a transition until things have completed, and so they're called only once per state transition. As for the animation remaining time, I've tried a number of approaches, but wound up just using animator events on another animation component that proxies via standard C# event actions. Edit: There are a number of solutions, but I went with one that works well for me. I also cache yielders when possible to reduce garbage.
I just used this in my game. Amazing stuff, thank you so much! :) Although, I did add a little to it that I recommend others do, also. For example, this code as it is doesn't run the EnterState or ExitState on the SubState when changing state to another Root State. For example, when going to the Jump State it will call the function from EnterState to Initialize a substate, but that substate's Enter function is never called. EnterState is only ever called on the Sub States when calling SwitchState, like going from the Walk state to the Run state for example. To implement this just do these basic things. In the PlayerBaseState script, just add this line of code to the SetSubState function "_currentSubState.EnterState();". This will cause the Enter state to be called. Although you'll get the EnterState being called twice when calling SwitchState from Idle to Walk etc. So to fix this just move the line "newState.EnterState();" to inside the if(_isRootState) conditional. Full code is such... protected void SwitchState(PlayerBaseState newState){
// Current State exits ExitState(); if(_isRootState) {
// Call exit on substate as we move to new root state if(_currentSubState != null) _currentSubState.ExitState();
// Call new States enter state newState.EnterState(); // Switch current state of context _ctx.CurrentState = newState; } else if(_currentSuperState != null) { // set new substate _currentSuperState.SetSubState(newState); } } protected void SetSuperState(PlayerBaseState newSuperState){ _currentSuperState = newSuperState; } protected void SetSubState(PlayerBaseState newSubState){ _currentSubState = newSubState; newSubState.SetSuperState(this); // Call enter state for substate when entering it _currentSubState.EnterState(); }
@@CCLawhon the new sub state doesnt " enter state" when we change the sub state forexample : Super state is "on ground" sub is "idol" if you change "idol" to "walk" the "enter state" method of "walk" will not be called if there are no extra line of code
Hey man, I just wanted to say a huge thank you for posting this video! After sitting in front of my computer many days and rewatching this video like a bunch of times, I finally was able to implement the hierarchical state I needed thanks to you. Thank you, thank you, thank you! :)
There are so many comments already so not sure if it's was already mention; But the HandleGravity method should also be included on the groundstate (where it checks if the player is onground or not, like falling off from a stair or so). Thanks for all your vids, it's one of the best explained tutorials I've ever seen. While I'm already an advance programmer, it always nice to learn some different ways on how things could be implemented.
At 13:20, you can add the readonly modifier to _context field. This way _context can only be assigned on the class constructor (or on its declaration).
I needed to see this. Recently wrote a monster state machine like you referenced in the beginning. Now I'm refactoring it and it feels great. You're very good at breaking down each step so I've learnt some basic principles & habits aswell. I can't thank you enough, keep it up. Liked and subed.
This is exactly what i needed, i have been doing C# for years and had a hard time with figuring out how to structure a project so it stayed clean the further i got in, i had this idea in my head that statemachines was the answer but i was unsure of how to implement it in unity, thank you for a very nice in depth tutorial :)
How did it take me so long to find this video?!?! I've been wracking my brain for about 2 months trying to "modularize" my fps controller. Everything I've tried has failed miserably. I'm yet to try this, but 10min into the video I suddenly feel like I might still have a chance Also, I fkn love Nicky. I've seen a few of your videos before, so much more pleasant to watch than 99% of other game dev/programming tutorials
I have watched this video 2 times. The first time i was confused. And this time, i am proud that i can understand this. This may not look like much, but, i am glad that my 6 month of learning does not waste any of my time.
I think using static actions and early exits in update loop for player controller to be a better implementation than state machines especially if you have combat that relies on animation events for animation completion checks, vfx etc. It also structure the code in component pattern rather than state patter. This allows you to enable and disable parts of the character controller on run time without breaking anything or any errors. Basically I was able to make a similar controller but with 0 dependencies so far. I imagine the only dependency in this implementation would be a scriptable object that contains player stats such as run speed, jump height etc.
@@sahsaaryutin Its actually my own custom implementation and ive improved on it since. I'll describe it for you. basically my game has systems like parkour, combat with anim cancle, anim lock etc. I also have casting system where player can cast spells whenever. These advanced mechanics require monobehaviour since you need to access things like anim events, colliders rigidbodies etc. What i did here was make a static class for inputs. it reads inputs and broadcasts them in the form on static actions (look up unity actions). This way my individual compoents like movement , jump, ledge grab etc can subscribe to these actions. since these actions are static you do not need references. now for my player controller intercomunications i use inheritance. basically every script of my controller is derived from base class. and base class contain static protected variables that need to be shared. example, lets say player is not grounded. the base class has a static bool variable isGrounded. this variable is accessable for all chile classes. so in update() of my movement script the first thing is do is if(!isgrounded) return; This way I have 0 references between my controller components . with this implementation say i want to disable jump then iu can just say jump.is active = false and nothing breaks. now lets say enemy needs to know if player is blocking. you can create a new scriptable object that basically holds player status . it contains a bunch of bools like isJumping, isMoving etc and just have one of the controller scripts fill this data out at runtime. This way anything that requires player status (enemies, UI, etc) then get it from this scriptable object and dont need a player references. This also alows you to use multi scene workflow
Oh my god! Finally I could understand State Machine. Thank you so much, I am very happy with the code refactoring. I came from JAVA world and I made a mess up with my code. Really appreciated
Excellent tutorial! Just for the record, you explain genuinely well, with ease, precision and conciseness. Keep up the great work, you'll see your community growing fast for sure!
First of all, thank you for these wonderful tutorials on the new Input System. I love how much detail you put into each one of your videos. While completing this portion of the series, I ran in to a similar issue as others mentioned below. Sometimes it feels like isGrounded isn't working and others it seems like the animations just aren't playing. After several placements of Debug.Log, I was able to determine that the "EnterState()" method of each substate was never being called. My solution to this was to add "newSubState.EnterState();" on the PlayerBaseState.cs class in the protected SetSubState() method, after newSubState.SetSuperState(this); so, the SetSubState method looks like this: protected void SetSubState(PlayerBaseState newSubState) { _currentSubState = newSubState; newSubState.SetSuperState(this); newSubState.EnterState(); } Hope someone finds this useful.
I had a similar problem, but when I tried to add "EnterState" to the "SetSubState" Method the state was called twice. So when I would be grounded it would call Idle two times instead of one. To change it I added : protected void SwitchState(PlayerState newState) { ... if (isRootState) { // Switch root state context.CurrentState = newState; // This // if (currentSubState != null) currentSubState.EnterState(); } .... } to the SwitchState Method, this just Enters the subState of the current root-State.
@@akatizu I don't know why, but even with your code, my Enterstate of my substate is still called twice ... :( It's so weird that @iHeartGameDev didn't show us why substates can't use EnterState...
Great video, I have had so much trouble with HSM since the beginning of my time in Unity. Your tutorials make a complex topic very digestible. Thanks so much for your time!
Incredible video. I always had issues when we have "conditional states" that can be used any time, like Die State, we can die while walking, while jumping, while idle etc. Well, one condition wont hurt. But having greater than one causes issues. I thought i was on Complete FSM level, but seeing Hierarchical made me think why i didnt know this before.
Great tutorial, thanks! I have noticed that a lot of member variables are both accessed and modified from outside. So, in my opinion, would be best to refactore those into public properties. For example, at 20:55, refactor line 56 into public int JumpCount { get; set; } and replace all _jumpCount by JumpCount
I am almost there!! Thank you for this tutorial, your detailed and explanatory approach, and for your presentation skills. I have a couple issues, questions, and some constructive feedback. 1. Feedback: Just as you scroll through previous code at the beginning, it would be helpful if you scrolled through finished code at the end. You change a lot of the code without announcing it (sometimes in between tutorials), and don't reference the changes anywhere. That's a time sucker to figure out where it's different and to go find another tutorial (or ask in forums) as to why it is different. I have found some answers by scrolling through and reading all the comments, but as your comment count grows, that becomes exhaustive. For example, onJump became OnJump somewhere after adding previous code to state machine. You didn't address that in the naming conventions, where I'd expect it. The movement "fixes" in other tutorials were not all present here, or were altered again. If I had to guess, the reason I'm getting "Method 'PlayerStateMachine.OnJump' not found" for "OnJump" and "OnRun" is that you added/removed something to do with those and never announced it or showed it. I think a final check of your working script, then assuring that all your code snippet screens match up (and they show ALL of it, if not comprehensively at the end, at least each piece with corrected errors is shown somewhere & announced verbally and called out with your red screen arrow) would be a best practice. I was going to become a "Patreon" as I wanted to show my appreciation. Monthly $ of more than a few $ is a lot, though (I am a public school teacher). It would be worth it to have a copy of your final, error free, code/scripts as a "benefit" for each # of a series of tutorials. However I cannot see that you included those consistently. So, I think this one best practice would solve your low views (compared to other tutorial channels). 2. Issue: A jump animation which has a "roll" at the end of the jump cuts out when the roll starts. I finally realized that's because on rolling, it becomes "grounded". Probably a best practice would be to clarify at the beginning of the first "jump like Mario" tutorial why you picked the three jumps you did. Clarify that they are "standing" or "running" jumps (it matters with root motion), and clarify how you are going to use them with gravity and grounded state. That way, when people are choosing their own jump (or making one), they know the parameters needed for your technique to work! My overall recommendation would be to look at Ketra Games' tutorials and see how they lay out their tutorials, code snippet screens, etc. I realize yours are more involved, but their structure is perfection. We always see the completed (correct) code. If you have it working without errors, then you have the code to do that. I'm not sure that your final code is making it into your tutorial in an organized fashion. I am going to finish out this series of your tutorials, and definitely refer back to your others due to your extensive explanations of the mechanics (and especially the math) behind every code choice. However, when embarking on my next addition to my game mechanics, I will probably not use iHeartGameDev due to the lack of organization for viewing finalized/correct code. I really do appreciate all you have taught me, and I appreciate your kindness in sharing your learning as you go with us.
I have watched and watched all over again thie state machine videos and cant get it working.. my character gets stuck between falling and jumping animation.. dont know but it is fustrating. i had the same feeling that i was thinking to become subscriber but now i have other thoughts after few days trying to figure out this problem..
Really, really great video. I've used state machines a lot but I needed a little bit of extra knowledge and this was perfect, not only did you have beginner friendly information, for those who don't know state machines you also had information for more intermediate programmers such as myself. Your videos are to the point but theyre explained well without over flowing people with useless information. I really appreciate this video and I'm about to go and watch your other videos. Thank you.
Man this video is pure gold for me!! I have made a platformer character controller and was in the process of refactoring it. I was in a dilemma if i want to eventually put all of the controller code in one script, which i know is bad practise but a lot of things depend on each other so it seems a functional way to do that. I have never used a State Machine before but i kinda thought to go that way cause things started to get messy and if i did i needed an option for sub states as the player actions are kinda complicated in that one. I think this might actually work cause in the end you store all the data in one script here. I think this will improve the controller by much and is probably the missing key i needed to complete it and use it in my portfolio.
@@iHeartGameDev That was hard to understand i won't lie lol! I managed to transfer my controller to the new system only implementing the movement and jumping mechanics yet. I still need to do Dash, WallSlide/WallJump and i think i am also going to need a Fall state. Since my controller used Rigidbodies, i think i should also make the equivalent of UpdateStates for the FixedUpdate method. It was satisfying to go through this process and actually make em work as intended, but i ll definitely need to watch this a couple more times to make sure i understand everything perfectly. This was invaluable for me thnx a lot for doing these kind of more advanced videos! Edit: I just saw you have another video implementing the Fall state. The fact that we continuously create new instances of the states was also bugging me and i see you have addressed this too in that video. I was walking my dog this afternoon and i was thinking why dont we use a dictionary to store those states and just get them from there? I now see my thinking was correct as this is how eventually did it. I am also trying to find a proper way to tackle script execution order. I found something on Google that might help. I ll try that too and see how this goes and i ll post it if it works fine.
I am sure that Unity technology will use your videos in Unity Learn one day or they will put them in their RUclips channel. Explanation is clear and well illustrated. Thank you very much. Please, don't forget Ledge grabbing in your coming videos. Thanks!
Im glad you have the luxury of optimizing with State Machines, I'm having trouble getting the animation to kick in at all. I got run to animate thanks to Jason Weinman's Navmesh animator in the Player object hierarchy. Thanks for your jump script, it helped me crack jumping better than Brackeys' outdated tutorials. Subscribed. You rock dude!! Thanks! Im pretty sure what I did wrong was not implicitly adding a animator component in the Inspector. Clearly My animator is attached to the player, it should be somewhere in the inspector. The problem is since I started not using the animator in an inspector from the beginning, adding it after the fact does not rectify the problem. Its similar to when you make mistakes assigning scripts to the player object instead of the game model. Those errors in organizing are hard to correct, and it is quicker to start over from scratch or at a much earlier build. Gotta love it!!
Thanks for this tutorial. I can see the benefit of doing it this way, but I do see a few cons. My experience: (1A) Jammo gets struck/frozen after jumping because ExitState is not called in PlayerJumpState and isGrounded never gets set to true. Verified with debug statements. Works inconsistently between runs in editor. Mysteriously started working properly. (1B) Check that Root Transform Position Y is baked into pose. (2) Jammo floats when going down ramps. (3) isJumping doesn't seem to be used. (4) Debugging is a PITA.
As @Dustin said in another comment thread, it is a command ordering problem. In the PlayerFSM, two lines need to be swapped, giving this code in the end: ``` void Update() { handleRotation(); _characterController.Move(_appliedMovement * Time.deltaTime); _currentState.UpdateState(); }``` That's because before switching states it makes sense to apply any due movement and only then check for switching factors. From what I've read this fixes the inconsistency problem with CharacterController's isGrounded.
@@furan8477 u are a saviour brother i spent 5hrs what's wrong with my code ,i figured out that player is stuck in animation and not grounded,so I was checking all cases
@@prabalpratapsingh9144 man I'm really happy that my comment helped you!! Yeah this kind of logical problems may be hard to find because behaviors get really messy really quickly
it was a great video, very well made. small addition, the hierarchical state machine allows us to do more complex things but with the cost of checking sub states, which is why we developed state machines in the first place. so it doesn't looks good, I wouldn't suggest it because it will scale badly, but great video anyways.
Thanks very much for watching and for the kindness! I am wondering if there is an alternative to a hierarchical state machine that you know of that can handle more complex characters. Do you know of any?
@@iHeartGameDev I've never needed, so I really don't know. sorry for can't helping :/ I just saw a warning light and wanted to let you know that it might become huge when you add other states in your super state. you will create the same problem that you were trying to solve in the first place, checking lots of conditions.
Ah interesting - I do believe my understanding of the hierarchical state machine and state machines in general is to defer conditions to the states that actually matter, not to remove them completely. So a swimming state shouldn’t be able to switch to a sleeping state - therefor it wouldn’t need to worry about that condition. In other words, not remove all conditional logic but to remove irrelevant conditions. And therefore simplify it. I guess I’ll know more when this character controller gets more complex 🤔 but thank you for pointing out a possible flaw! I’ll keep it in mind!
@@iHeartGameDev "In other words, not remove all conditional logic but to remove irrelevant conditions. And therefore simplify it." Yeah that's true, the advantage of this solution is that now PlayerController script doesn't need to check every different state, states can do that internally. But the very same internal functionality can become a mess, there is a high possibility that your condition checking code will grow up with more functionality, and eventually you will hit a point where it doesn't help you anymore. Because now, your superstate acts like regular class, just like when you just started refactoring your class, just because of reducing complexity of your codebase.
@@ysftulek I am not a professional programmer, but thinking about the video and seeing your comment i wonder: Would making a FSM, using abstract class for the base state, but, having a few interfaces like "Igravitable" and implement those in the desired concrete states reduce the complexity and improve scalability? "In this state, there is gravity, therefore, Igravitable". I mean, it is completely theoretical, i don't know if you even be possible tie all the knots.
Nice video, very educational. The information is logical and well laid out. No knock against your solution, but it seems like it takes a lot of boilerplate code to set up a state machine for every entity type in a game. It would probably be possible to add a layer of abstraction to make it easier to make multiple state machines, but that would make this implementation even more complex. Is this simply the trade-off that must be made to develop complex entity behaviors? The idea of going through all of this every time I would want to create a new entity would discourage me from experimenting with new entities. I hope this comment didn’t come across as negative, I’m genuinely impressed with this and just curious if there’s a way to utilize the same technique in a way better suited to rapid prototyping. Thanks again!
In regards to naming conventions; it is common practice for abstract classes to have the 'Base' suffix, similar to the 'I' prefix for interfaces, so instead of PlayerBaseState it would be PlayerStateBase.
My little question, on all movement states, u configure some parameters without a big relationship with the state, per example on 27:23 into Idle EnterState, u change the AppliedMovement and isRunning animator, but i think, this parmeters not is better changed it into "ExitState" on RunState? On min 28:25 we not need set the _currentSubState to null after _currentSubState.ExitStates() to not call this SubState Update after exit this. Thx for this video, you are awesome to can mount this
Nice video. I am curious as to what the profiler reads for GC since the factory is returning new instances of each requested state. It seems like it would be more beneficial to cache a reference to each state in the factory constructor and pass the cached reference instead. Also, since there is no encapsulation of the data by using a local field and a get/set that modifies the local field, if it wouldn't be cleaner to just use a { get; set; } and ditch the local member fields? Using the { get; set; } approach doesn't really add any benefit but it would lower the line count by quite a bit. Just a thought.
This is how it should be. New Instances are crated each time new states are needed. They are almost empty and it worth nothing to create them over and over. Also they will be switched like once a second or less. And the benefit of it is that you can be sure that nothing is stored from previous use of certain state. They are always fresh and clean. But of course if your states are heavy and switch very frequently you may want to cache them. But it will be additional functionality for a regular state machine use I think. And I am agree with there are a lot of code inside Context class. But encapsulation is a good practice anyway. I think it would be better to split this data to different classes so it would be bore readable.
The hierarchical state machine concept is great as explained here, however, wouldn't it be better to keep the Input handling on a separate code, the animation on another one and then the actual physics/movement one being the one that will handle the movement.
Hi! Yes -- Separation of concerns is something we should always consider. As I'm working through my next tutorial, which is another state machine, I'm trying to explain that a little more clearly. Given that this is a tutorial on youtube, there are a couple other factors that dictate how I make things: scope and time being one of them. Adding a separate class just for handling input would have added more time and complexity to the video which I do need to find the right balance for. However, my plan is to break the next tutorial into multiple parts and have it culminate in one giant release that should be about 45minutes to an hour long. Hope that makes sense
This tutorial was really helpful for teaching me how a hierarchical state machine is constructed. However, when building the project myself when following the tutorial, I came across an error that had less to do with the code that was written, and more to do with how the built-in Character Controller worked. After running some Debug.Log() commands, I found that the Character Controller is pretty finicky with its isGrounded property, with it constantly switching between true and false practically every frame while gravity was being applied, despite clearly being in contact with a plane's Mesh Collider. This didn't pose a problem initially, but it became literally game breaking later down the line once the hierarchical state machine was implemented. For reasons I'm not 100% sure about, my IsGrounded getter always returns false, even if the isGrounded property of the Character Controller is returning both true and false interchangeably. As a result, Jammo can jump and fall, but he will not return to the Grounded State after landing. Further inspection of the colliders in Play Mode show that after performing a jump, no new point of contact is ever generated between the Character Controller collider and the plane's Mesh Collider. I should reiterate that this problem only occurs with the hierarchical state machine implementation and not the conditional statement implementation. For the record, I am doing this in Unity version 2020.3.17f1.
this is a mistake about isGrounded and dont know why. But you can change the if condition like Physics.Raycast(_ctx.transform.position,-Vector3.up,0.1f) or other detection methods to replace CharacterController's api
the fix was said in another comment said in another comment thread, it is a command ordering problem. In the PlayerFSM, two lines need to be swapped, giving this code in the end: ``` void Update() { handleRotation(); _characterController.Move(_appliedMovement * Time.deltaTime); _currentState.UpdateState(); }```
This one was difficult and i dont think i did it perfectly like you did (well my character is not based from the character controller but that of a rigidbody + capsule collider type) However even implementing some of these things and im already seeing great performance from the unity profiler thank you!
Next step I am taking is to incorporate this into Unity 2021 Visual Scripting. I always got confused thinking about character controller state machines because I'm so used to "State Machine" meaning FSM (or at least that is the impression you can get online). I didn't even know about hierarchical state machines (so you can guess how much trouble I've been having with visual scripting). The nice thing about VS is that you can execute code in multiple states in the same state machine simultaneously.
Hi, I'm a bit confused here 13:28 You can't make an instance of PlayerBaseState because it's an abstract class. When you declare those methods that return the type of PlayerBaseState, what are those which they return, if not instances of the the PlayerBaseState class? Sorry if the question sounds stupid, I'm a beginner. Nevermind, I think I get it after rewatching that part. It's a syntax I haven't seen before. :) So it seems a method with the return type of an abstract class can return an instance of any class that derives from that class.
Hey! So because each of the concrete states derive from the abstract class, we can use the PlayerBaseState as their type declaration 👍 what this means is that when we go to declare the current state in the context, we can also use the PlayerBaseState type and we can assign any of our concrete states. Does that make sense?
I have a problem. If you change to left straight after holding up, the player continues to go forwards instead of changing to left direction. And gravity is no longer applied even when jumping. This was after i got to 28:33
I just discovered your videos yesterday and have been having a lot of fun implementing the techniques that you are presenting. A couple thoughts for updates to the state machine: 1. A temporary stun effect if Jammo falls from a height too far up. I would imagine that this stun would be at the same level as grounded / jump. It would have some sort of cool down (like the jump timer) as well as a couple animations while Jammo is actually stunned and when he recovers. 2. A way to interface with the controls without going through the player input, so that Jammo could have automation ai. 3. Equipable items which could change the effects of a specific player input. I would imagine that this could be implemented fairly easily with generics where the generic action is a substate to the run / walk / idle states. Or it could use a scriptable object to set parameters on an equipable action, using the scriptable object as a constructor parameter through the factory class.
on 1, couldn't you just have an animation for "fall 2" and do it through the animator? Where "fall 2" is a stunned animation and it "has exit time" when going back to id.e/run/walk/etc--you just set it so it has to do a long animation of however many seconds you want the stun (or slow the stun aim frame rate/overdrive lower than original aim in mixamo)? Have it as a 4th "jump" so it's not called in the jump count 1-3. Then it would just have one parameter in Jump State script where if isFalling is more than 2 seconds (or whatever), trigger bool from animator "onFall2"? Another thought...Ketra Games did a tutorial for a jump animation with blend tree where there are 3 parts to jump, jump up, fall, land. This allowed for a "falling from a cliff" scenario as opposed to normal descent from jump fall. So, that's another option that could maybe be added to animator within the jump state? The Ketra tut uses old input system, but I think the logic could be applied fairly easily to this...I am going to try that next bc I decided to ditch the 3 Dif jumps in my game and go back to the 3-part single jump. I hope I can extract/remove the jump count logic in this script without breaking it. I'm intermediate on a good day so this is deep for me lol.
PS I like your ideas @nm-hd8rr :) What is "automation ai" and what would be the use case? I saw several recommended not having to go through Player Input (with good reasons) but I'm having trouble understanding what you/they are saying about automation ai. Would one thing be like to trigger "swim" animation/movement when player gets a foot or two into water? Like the water triggers the change in state not the player input? I wanted to do this but scrapped it after implementing this state machine for player movement. Too complicated. But hypothetically, If I had a "swim" state (base state) like "is grounded" but "is in water" wouldn't this work? I'd probably have to add some rigid body physics to the "water" in that case so it would slow the player and I would have a way to check (the velocity) if water was happening in order to trigger the animation? Easier way seems like just "if he touches water, he swims" so is that where your idea comes in? Just brainstorming TY for these points which made me think outside the box!!!
I did the Unity Junior Programmer course, I'm at the last small game for my portfolio. Saw this pop up and thought oh let me check this out. Now I feel like a Freshman Programmer V_V.
I get the point of doing this though, it's similar to what I do with having parent and children for my enemies in the game: I have the parent that contains the code everything uses and the children that do things specific to that object.
But HSM is a new frontier and your use of getters and setters is... prolific, I'm happy I already knew about them or my head might have exploded. Definitely need to re-watch this or actually go back to the first in this series.
I am shocked you aren't at 100k subs yet. The YT algorithm gods haven't descended on this channel yet I guess.
Thank you for such a kind comment! I am always happy to share what I learn and try my best to convey it in a hopefully understandable manner. I wouldn't understate how far you've probably come since the start of your game dev journey though! You have probably grown so much since you first started with Unity, and will continue to grow as long as you try 🙌 Keep going! Keep learning! And looking forward to seeing what you release in the future!
@@iHeartGameDev Thank you! Really, Thank you!
How was that course? I'm a software developer professionally so I already know how to code, but thought that might be a good place to start with Unity.
@@MrFishstickGamer For rogue upstarts like myself it helps create a portfolio to refer back to. You get very small but complete projects that represent a fundamental element of design.
For me it became a bit too much when they introduced GitHub resources. It's kind of like when you get home and your body decides at the door that you need to pee so you are in a rush: I enjoyed getting each project done but then practice of working Github after gave me enough distress to want to take a break.
If I could start all over I would say starting with Unity Junior Programmer course is best then moving on to YT videos like iHeartGameDev who has a similar but more complex projects.
The most important thing though is time and practice.
This guy is becoming the new Brackeys.
Man. This was hard, but I'm glad you're tackling complex issues like this, I feel like most other youtube tutorial channels are afraid to make videos on topics like this. Also your presentation was top notch. Thanks for taking the time to make this video.
Glad you got through it! Thanks for watching! 😊👍
Don’t worry, watch the video multiple times until it clicks.
While this video is great, learning those things should be separated: there are books that showcase the state machine separately on much simpler projects: GoF Design Patterns book and HeadFirst Design Patterns. Then there's Game Programming Patterns book.
You want to separate learning the concepts from learning the implementation in an engine.
@@KulaGGin Thanks for the book recommendations. Personally Seeing them in context actually works much better for me than the abstract explanations in books. Everyone learns differently.
@@KulaGGin is the gof book you're talking about the one by Sean Bradley?
Hey all! I'm so excited to share this new tutorial where we go over a player-based hierarchical state machine. Most of the state machine tutorials that I've found have covered AI and have just been single state, so hopefully you find this helpful when making more complex character controllers.
The next video lined up is the first Cinemachine tutorial voted for by the Patrons!
As always, thank you so much for watching and I hope this helps you on your game dev journeys!
Cheers! 🍻
-Nicky
I've recently started making something using Hierarchical State Machines and seems to be working fine but quite excited to see how you'll be handling it to see if what I'm doing can somehow be improved.
Thank you for the tutorial!
For cinemachine, I'd really appreciate it if you covered how to make custom cinemachine modules. When I tried to integrate pausable dialog using cinemachine, it was quite a pain to get it working amre there really weren't any resources about it. And then there was the problem making it reset properly after playmode which I had to give up on.
Yes! Every state machine tutorial is AI and never character controller! It’s very frustrating so thank you for making this.
By video Quality and explanation this channel has great potential grow exponential. Make sure to be consistent other only luck can help with algorithms.
Thanks very much! The growth is pretty consistent so far. I only wish I could increase the frequency of my video output without sacrificing quality.
I still can't believe the amount of effort you put in on these videos. Cant wait!!
Thank you for the kindness 🙏
This is a damn fine tutorial. More people should know about your channel. You're like an advanced Brackey's spiritual successor.
Hey! Thank you so much for the kind words and comparison!
Facts dude facts
I thought of and implemented a small refactor that should provide a nice performance boost to the code. When you use the StateFactory, you're creating a new instance of each state to be applied. It clearly works great, but discarding those classes after you don't need them anymore causes some work for Garbage Collection, which can cause issues down the road. So I went back and in the constructor of the factory I create an instance of each state and store them in a dictionary. Then instead of returning a new state, I just fetch the same state from the dictionary. If you do that, and move the initialize substate method to the Enter functions of the states, then everything works the same. You could even go a step further and have the switch state method take in a state enum instead of having different methods for each state.
I'm pretty sure this disqualifies the factory as a factory, but I'm not experienced enough to know the actual name. I should also mention that this ONLY works because the states work entirely off of the data provided by the context. if the states themselves held some sort of data, this would require some extra logic to maintain.
Love these videos, btw! I look forward to the next one!
Wonderful job! I also considered storing those instances! But I wasn’t sure how much garbage making new instances would cause.
That being said, it’s awesome to me that you took the time to refactor the code! Thank you for watching and sharing your own implementation!
Thanks for mentioning this. I'm building a mobile game and I need to keep an eye on garbage collection.
@@anaezesomto8330 A simple or basic example could be if the character can swim, shoot gun, fly etc. then the base states would be onground, swim, shooting, flying and jumping. like left mouse button will fire bullets in shooting state but can dive lower in water while swimming, etc. and you won't have to add bool/flag checks for left mouse button pressed cause the states will handle that. AND MOST IMPORTANT -> ONLY ONE BASE STATE IS ACTIVE IN THIS CASE. you can have multiple active states with some more complex/dimensional state machines. Hope this helps!
Expertly visualized. Expertly explained. To the point, concise & articulate. You value - - our time. Thank you. Subscribed!
Thank you for such a kind comment, Papo!
I am trying to make my first game and I wanted to learn about this state machine topic. The first time that I watched this video I took notes and didn't try coding anything. Going through the video I found things that I didn't quite understand at first but I just continued to try and understand as much as possible. After watching the video I tried coding a state machine for an object that I want in my game and I had the lightbulb moment several times! Everything is starting to make much more sense now that I pushed myself to figure out something that I didn't quite understand yet. Thank you for this video!
Heck ya! Welcome to game dev!!
This video is certainly a step up in difficulty from the last ones. Feels like it went from algebra straight to rocket science in terms of complexity. Gonna be rewatching this one quite a few times. Thanks for taking the time to make these videos.
I prototype a game and think to myself, "nahh I won't need a state machine, I got what... two actions?" and then I want to build the game out proper and wished I had just sucked it up and typed out the few extra classes to make it happen. This video is crucial for the new devs out there!
I have a few recommendations
1. Make the states inherit from Scriptable objects. This way you can add different configurations for a specific state. If you game have some "buff" system you can have the states take their stats (like movement speed etc) from the scriptable object, and then you can switch the current state in run time to buffed version and vice versa. You don't need the state factory, all the states are pre-configured.
2. create a "unique name" for each state (states that differ in configurations will have the same name you will see later why) and make a dictionary that holds a name and the scriptable object in context. The player will try to switch states using the name of the new state only, and the level above in the hierarchy will hold the dictionary. This is good because you can have more states, like dodging, climbing ladder, dash, fly, swim ... each of those "know" when they need to be active, when they need to be shut, each can hold its own configurations and functions (in the scriptable object)
3. Add events - (mostly applied to shooters) if you want an action (like shooting) to depend on state, make an event to be fired off the base FSM component (the outmost one that is always in the scene) that when a state changes it fires "OnStateChange()" with information of the new state, make the weapon subscribe to it. and then if the weapon can only shoot on certain states you can use
if(state is StateThatEnablesShooting)
canShoot=true
...
4. Separate the input system from the context.
Create a class of InputHandler that will take in the inputs and process them, this way you can put constrains on the input itself before it reaches the controller. Why do you need it?
let's say you want to enter a driving state and you don't want to "hard steer" left and right. You want to simulate a wheel turning and slerp between (0,1) to (0,-1) and you want to reuse the movement (that takes direction from the data) you will need to apply another layer of processing. Another thing is that you might want to change sprint to toggle - first click would enter the state, second exit, you would probably want to pre-process the data outside of the classes (if we are following SOLID we don't want the class to also manage the input types).
Overall very very powerful design. It takes a lot of work to get it to work at first, but the amount of work on expanding that is next to nothing. When comparing it to celeste's controller I wanna see the brave guy that will try to implement some new functionality in there.
Great suggestions ! If you can provide an concrete example with source code, it’ll be very help full.
@@de-souzapatrice1859
Imagine the following architecture for a weapon system.
Each state will inherit from scriptable object. The states will be the following (can be expanded)
Reload, PrimaryFire, SecondaryFire, Scope etc...
PrimaryFire and SecondaryFire will inherit from FireState which will inherit from BaseWeaponState
And then each fire state will run their shooting logic in OnEnterFire, They will exit the fire after the cooldown of the fire rate is over (which can be set up through the inspector) back to an idle state or reload.
The weapon class (which will hold the state machine) will hold the bullet count and anything related to ammunition and will communicate with the base player's inventory.
Then if you want to upgrade the weapon for let's say shoot laser in which u spawn a trigger collider that will inflict damage over time, you can create a new PrimaryFire state, implement its own logic, and put it in the primary fire slot of the StateMachine.
This system allows for upgrades, as you can alter the values of the scriptable objects to create many variants of the weapons offline, and at runtime to swap (for example, for upgrading a weapon that fires projectile to a weapon that shoot hitscan to a weapon that shoot laser beams all you have to do is make different variants of FireState)
it's just an example, I hope it's clear
@@Doronoss Thanks for explanation. Indeed, it a great way to achieve it. I’ll try and may be send you a link for code review. I’ve sent you a connexion request on linkedin.
This video made me sub to your Patreon.
I'm from Brazil so Patreon is kinda expensive to back on, but the effort and quality on this video is incredible, one of the best tutorials on RUclips.
I love how you're not shy of explaining more complex topics, most Unity tutorials don't really dive into programming, but this tutorial is incredible not only for Unity but for programming overall.
Thank you for this!
Dude, you are just amazing...your videos are even better and explain more than Unity's official tutorials...Keep up the good work sir...please dont leave youtube ever...
Thank you so much for the kindness! I don't plan on leaving any time soon!
I've written several FSM/HSM implementations, but thought I'd give this architecture a try because it's far less complicated than those I've written. Made a few changes, but the primary is that my OnExit method is an IEnumerator and when switching states, I yield until it's exited. The makes it easier to do things like waiting for an animation to finish before exiting. I also am using ScriptableObjects to configure each state. For example, if you have multiple playable characters, each state can utilize properties of the current character scriptable object.
Coroutines generate garbage each frame, try events/delegates.
Do tell how you get the remaining time for the animation clip from animator/ or what is you implementation for yield WaitUntil? I hope u don't use hard coded values??
@@safwatahmad7672 so the coroutine is only used in the OnExit in order to block a transition until things have completed, and so they're called only once per state transition. As for the animation remaining time, I've tried a number of approaches, but wound up just using animator events on another animation component that proxies via standard C# event actions.
Edit: There are a number of solutions, but I went with one that works well for me. I also cache yielders when possible to reduce garbage.
I just used this in my game. Amazing stuff, thank you so much! :)
Although, I did add a little to it that I recommend others do, also. For example, this code as it is doesn't run the EnterState or ExitState on the SubState when changing state to another Root State. For example, when going to the Jump State it will call the function from EnterState to Initialize a substate, but that substate's Enter function is never called. EnterState is only ever called on the Sub States when calling SwitchState, like going from the Walk state to the Run state for example.
To implement this just do these basic things.
In the PlayerBaseState script, just add this line of code to the SetSubState function "_currentSubState.EnterState();". This will cause the Enter state to be called. Although you'll get the EnterState being called twice when calling SwitchState from Idle to Walk etc. So to fix this just move the line "newState.EnterState();" to inside the if(_isRootState) conditional.
Full code is such...
protected void SwitchState(PlayerBaseState newState){
// Current State exits
ExitState();
if(_isRootState)
{
// Call exit on substate as we move to new root state
if(_currentSubState != null) _currentSubState.ExitState();
// Call new States enter state
newState.EnterState();
// Switch current state of context
_ctx.CurrentState = newState;
} else if(_currentSuperState != null)
{
// set new substate
_currentSuperState.SetSubState(newState);
}
}
protected void SetSuperState(PlayerBaseState newSuperState){
_currentSuperState = newSuperState;
}
protected void SetSubState(PlayerBaseState newSubState){
_currentSubState = newSubState;
newSubState.SetSuperState(this);
// Call enter state for substate when entering it
_currentSubState.EnterState();
}
Why do we need the extra calls?
@@CCLawhon the new sub state doesnt " enter state" when we change the sub state
forexample : Super state is "on ground" sub is "idol"
if you change "idol" to "walk" the "enter state" method of "walk" will not be called if there are no extra line of code
@@katmr8096 OHHHH I see! Thank you!
Nice, I couldn´t get it to work at all, but these changes fixed it.
This is awesome! Definitely refactoring my player and monster controllers now and will mention this video in my next one :)
Thank you saved me a lot of time trying to browse videos for an actual working one
I love how this channel videos are very aligned with the games I like to make. Great job, Nicky!
Thanks so much Alex! I hope this helped you out at least a little bit!
you have pushed me down this rabbit hole further than i could ever imagine
Hey man, I just wanted to say a huge thank you for posting this video! After sitting in front of my computer many days and rewatching this video like a bunch of times, I finally was able to implement the hierarchical state I needed thanks to you. Thank you, thank you, thank you! :)
Amazing! All of these design patterns are tough concepts to wrap our heads around so great job pushing through!!
There are so many comments already so not sure if it's was already mention; But the HandleGravity method should also be included on the groundstate (where it checks if the player is onground or not, like falling off from a stair or so). Thanks for all your vids, it's one of the best explained tutorials I've ever seen. While I'm already an advance programmer, it always nice to learn some different ways on how things could be implemented.
Really cool! 🙂
Your channel definitely needs more views!
Thanks so much Alan! Big fan of your work!
At 13:20, you can add the readonly modifier to _context field. This way _context can only be assigned on the class constructor (or on its declaration).
Awesome! Didn’t know that. Thank you!
I needed to see this. Recently wrote a monster state machine like you referenced in the beginning. Now I'm refactoring it and it feels great. You're very good at breaking down each step so I've learnt some basic principles & habits aswell. I can't thank you enough, keep it up. Liked and subed.
This is exactly what i needed, i have been doing C# for years and had a hard time with figuring out how to structure a project so it stayed clean the further i got in, i had this idea in my head that statemachines was the answer but i was unsure of how to implement it in unity, thank you for a very nice in depth tutorial :)
How did it take me so long to find this video?!?! I've been wracking my brain for about 2 months trying to "modularize" my fps controller. Everything I've tried has failed miserably. I'm yet to try this, but 10min into the video I suddenly feel like I might still have a chance
Also, I fkn love Nicky. I've seen a few of your videos before, so much more pleasant to watch than 99% of other game dev/programming tutorials
Thanks so much for the kindness!! Made my night!
I have watched this video 2 times. The first time i was confused. And this time, i am proud that i can understand this.
This may not look like much, but, i am glad that my 6 month of learning does not waste any of my time.
Great work 👏👏👏
The quality on these videos is exceptional. Awesome video thanks a bunch.
Thanks so much Alex!
I think using static actions and early exits in update loop for player controller to be a better implementation than state machines especially if you have combat that relies on animation events for animation completion checks, vfx etc. It also structure the code in component pattern rather than state patter. This allows you to enable and disable parts of the character controller on run time without breaking anything or any errors. Basically I was able to make a similar controller but with 0 dependencies so far. I imagine the only dependency in this implementation would be a scriptable object that contains player stats such as run speed, jump height etc.
Very interesting! I will need to look into this type of implementation! Thank you for sharing 🙏
Wow, that sounds interesting. Can you share refs or better some material to read about?
That would be very appreciated!
@@sahsaaryutin Its actually my own custom implementation and ive improved on it since. I'll describe it for you. basically my game has systems like parkour, combat with anim cancle, anim lock etc. I also have casting system where player can cast spells whenever. These advanced mechanics require monobehaviour since you need to access things like anim events, colliders rigidbodies etc. What i did here was make a static class for inputs. it reads inputs and broadcasts them in the form on static actions (look up unity actions). This way my individual compoents like movement , jump, ledge grab etc can subscribe to these actions. since these actions are static you do not need references. now for my player controller intercomunications i use inheritance. basically every script of my controller is derived from base class. and base class contain static protected variables that need to be shared. example, lets say player is not grounded. the base class has a static bool variable isGrounded. this variable is accessable for all chile classes. so in update() of my movement script the first thing is do is if(!isgrounded) return; This way I have 0 references between my controller components . with this implementation say i want to disable jump then iu can just say jump.is active = false and nothing breaks. now lets say enemy needs to know if player is blocking. you can create a new scriptable object that basically holds player status . it contains a bunch of bools like isJumping, isMoving etc and just have one of the controller scripts fill this data out at runtime. This way anything that requires player status (enemies, UI, etc) then get it from this scriptable object and dont need a player references. This also alows you to use multi scene workflow
@@pewpew518 very interesting, and now i have ideas how to improve architecture, thank you! ☺
Oh my god! Finally I could understand State Machine. Thank you so much, I am very happy with the code refactoring. I came from JAVA world and I made a mess up with my code. Really appreciated
You are most welcome! I’m happy to hear it helped
Overall great video.
thumbnail,
Communication,
Diagrams,
Audio Cues,
Flow.
Keep it up man, you'll be the next Brackey's in no time!
Excellent tutorial! Just for the record, you explain genuinely well, with ease, precision and conciseness. Keep up the great work, you'll see your community growing fast for sure!
First of all, thank you for these wonderful tutorials on the new Input System. I love how much detail you put into each one of your videos.
While completing this portion of the series, I ran in to a similar issue as others mentioned below. Sometimes it feels like isGrounded isn't working and others it seems like the animations just aren't playing. After several placements of Debug.Log, I was able to determine that the "EnterState()" method of each substate was never being called. My solution to this was to add "newSubState.EnterState();" on the PlayerBaseState.cs class in the protected SetSubState() method, after newSubState.SetSuperState(this); so, the SetSubState method looks like this:
protected void SetSubState(PlayerBaseState newSubState)
{
_currentSubState = newSubState;
newSubState.SetSuperState(this);
newSubState.EnterState();
}
Hope someone finds this useful.
I had a similar problem, but when I tried to add "EnterState" to the "SetSubState" Method the state was called twice. So when I would be grounded it would call Idle two times instead of one.
To change it I added :
protected void SwitchState(PlayerState newState)
{
...
if (isRootState)
{
// Switch root state
context.CurrentState = newState;
// This //
if (currentSubState != null)
currentSubState.EnterState();
}
....
}
to the SwitchState Method, this just Enters the subState of the current root-State.
@@akatizu I don't know why, but even with your code, my Enterstate of my substate is still called twice ... :( It's so weird that @iHeartGameDev didn't show us why substates can't use EnterState...
Great video, I have had so much trouble with HSM since the beginning of my time in Unity. Your tutorials make a complex topic very digestible. Thanks so much for your time!
by any ans, but I can make what I envision, and that's the greatest gift to . You are, without a doubt, an expert teacher. You may
I didn't even thought about implementing StateMachine for player character controller. Thanks for video!
Incredible video. I always had issues when we have "conditional states" that can be used any time, like Die State, we can die while walking, while jumping, while idle etc. Well, one condition wont hurt. But having greater than one causes issues. I thought i was on Complete FSM level, but seeing Hierarchical made me think why i didnt know this before.
You are amazing, I just switch to soft softs and I am loving everytNice tutorialng about it. It much easier then my last program.
this channel is just magic, very nice content dude. Really looking forward to all the new content coming
Thank you for the kindness Oscar!
I will be rewatching this video for months, thanks nick
Thank you for watching! I hope it helps!
This is the best free software Ive seen. Respect.
Oh my gosh. You are amazing. Now I can say that I'm a game developer. Thanks to you.
This is what I've been looking for, thanks. Keep up with the amazing series!
Thank you so much! Happy to hear!
Ayyyy Thanks for helping get to know the Software! I just downloaded it in hopes of making resetupes and originals. Props to you for
Great tutorial, thanks!
I have noticed that a lot of member variables are both accessed and modified from outside. So, in my opinion, would be best to refactore those into public properties.
For example, at 20:55, refactor line 56 into
public int JumpCount { get; set; }
and replace all _jumpCount by JumpCount
Sweet! Thank you again for the advice! And for watching!
You will definitely become the top 1 who makes cracks
I am almost there!! Thank you for this tutorial, your detailed and explanatory approach, and for your presentation skills. I have a couple issues, questions, and some constructive feedback.
1. Feedback: Just as you scroll through previous code at the beginning, it would be helpful if you scrolled through finished code at the end. You change a lot of the code without announcing it (sometimes in between tutorials), and don't reference the changes anywhere. That's a time sucker to figure out where it's different and to go find another tutorial (or ask in forums) as to why it is different. I have found some answers by scrolling through and reading all the comments, but as your comment count grows, that becomes exhaustive. For example, onJump became OnJump somewhere after adding previous code to state machine. You didn't address that in the naming conventions, where I'd expect it. The movement "fixes" in other tutorials were not all present here, or were altered again. If I had to guess, the reason I'm getting "Method 'PlayerStateMachine.OnJump' not found" for "OnJump" and "OnRun" is that you added/removed something to do with those and never announced it or showed it. I think a final check of your working script, then assuring that all your code snippet screens match up (and they show ALL of it, if not comprehensively at the end, at least each piece with corrected errors is shown somewhere & announced verbally and called out with your red screen arrow) would be a best practice. I was going to become a "Patreon" as I wanted to show my appreciation. Monthly $ of more than a few $ is a lot, though (I am a public school teacher). It would be worth it to have a copy of your final, error free, code/scripts as a "benefit" for each # of a series of tutorials. However I cannot see that you included those consistently. So, I think this one best practice would solve your low views (compared to other tutorial channels).
2. Issue: A jump animation which has a "roll" at the end of the jump cuts out when the roll starts. I finally realized that's because on rolling, it becomes "grounded". Probably a best practice would be to clarify at the beginning of the first "jump like Mario" tutorial why you picked the three jumps you did. Clarify that they are "standing" or "running" jumps (it matters with root motion), and clarify how you are going to use them with gravity and grounded state. That way, when people are choosing their own jump (or making one), they know the parameters needed for your technique to work!
My overall recommendation would be to look at Ketra Games' tutorials and see how they lay out their tutorials, code snippet screens, etc. I realize yours are more involved, but their structure is perfection. We always see the completed (correct) code. If you have it working without errors, then you have the code to do that. I'm not sure that your final code is making it into your tutorial in an organized fashion.
I am going to finish out this series of your tutorials, and definitely refer back to your others due to your extensive explanations of the mechanics (and especially the math) behind every code choice. However, when embarking on my next addition to my game mechanics, I will probably not use iHeartGameDev due to the lack of organization for viewing finalized/correct code. I really do appreciate all you have taught me, and I appreciate your kindness in sharing your learning as you go with us.
I have watched and watched all over again thie state machine videos and cant get it working.. my character gets stuck between falling and jumping animation.. dont know but it is fustrating. i had the same feeling that i was thinking to become subscriber but now i have other thoughts after few days trying to figure out this problem..
Really, really great video. I've used state machines a lot but I needed a little bit of extra knowledge and this was perfect, not only did you have beginner friendly information, for those who don't know state machines you also had information for more intermediate programmers such as myself.
Your videos are to the point but theyre explained well without over flowing people with useless information.
I really appreciate this video and I'm about to go and watch your other videos. Thank you.
Heck yeah! Thanks John! Love hearing that
Best tutorial on state machines, would u mind doing a tutorial on climbing/parkour?
thanks very much :)
Thanks Nicky! Helped me so much this series.
Casi 4 días con esta clase. Valió cada momento.
Awesome. Happy to hear it helped!
Man this video is pure gold for me!! I have made a platformer character controller and was in the process of refactoring it. I was in a dilemma if i want to eventually put all of the controller code in one script, which i know is bad practise but a lot of things depend on each other so it seems a functional way to do that. I have never used a State Machine before but i kinda thought to go that way cause things started to get messy and if i did i needed an option for sub states as the player actions are kinda complicated in that one. I think this might actually work cause in the end you store all the data in one script here. I think this will improve the controller by much and is probably the missing key i needed to complete it and use it in my portfolio.
Awesome to hear that it was helpful 😊 best of luck on your game!
@@iHeartGameDev That was hard to understand i won't lie lol! I managed to transfer my controller to the new system only implementing the movement and jumping mechanics yet. I still need to do Dash, WallSlide/WallJump and i think i am also going to need a Fall state. Since my controller used Rigidbodies, i think i should also make the equivalent of UpdateStates for the FixedUpdate method. It was satisfying to go through this process and actually make em work as intended, but i ll definitely need to watch this a couple more times to make sure i understand everything perfectly. This was invaluable for me thnx a lot for doing these kind of more advanced videos!
Edit: I just saw you have another video implementing the Fall state. The fact that we continuously create new instances of the states was also bugging me and i see you have addressed this too in that video. I was walking my dog this afternoon and i was thinking why dont we use a dictionary to store those states and just get them from there? I now see my thinking was correct as this is how eventually did it. I am also trying to find a proper way to tackle script execution order. I found something on Google that might help. I ll try that too and see how this goes and i ll post it if it works fine.
Thank you! So glad I found this video. My player code just got 10x cleaner
the moment we all have been waiting for
I am sure that Unity technology will use your videos in Unity Learn one day or they will put them in their RUclips channel. Explanation is clear and well illustrated. Thank you very much. Please, don't forget Ledge grabbing in your coming videos. Thanks!
Thanks so much Patrice!
Wow, just wow! One of the best Unity tutorial i have ever seen
This is one od the best and most usefull tutorials ever Made!
Thank you man for sharing this stuff
THANK YOU SO MUCH FOR THIS VIDEO
You’re welcome :)
I still havent watched the complete video, And I have already liked it
This helped a lot thank you
you are welcome!
Im glad you have the luxury of optimizing with State Machines, I'm having trouble getting the animation to kick in at all. I got run to animate thanks to Jason Weinman's Navmesh animator in the Player object hierarchy. Thanks for your jump script, it helped me crack jumping better than Brackeys' outdated tutorials. Subscribed. You rock dude!! Thanks! Im pretty sure what I did wrong was not implicitly adding a animator component in the Inspector. Clearly My animator is attached to the player, it should be somewhere in the inspector. The problem is since I started not using the animator in an inspector from the beginning, adding it after the fact does not rectify the problem. Its similar to when you make mistakes assigning scripts to the player object instead of the game model. Those errors in organizing are hard to correct, and it is quicker to start over from scratch or at a much earlier build. Gotta love it!!
Subscribed. I needed this. Thank you
it worked! thank you so much!!
As always, awesome job bro! 🤜🤛
Thank you Mark!
drums softing good start learning how to make your own lodies. Good luck bro!
Can't wait for the next episode
This is the exact thing I was looking for!!! Thanks!!!
Thanks for this tutorial. I can see the benefit of doing it this way, but I do see a few cons. My experience: (1A) Jammo gets struck/frozen after jumping because ExitState is not called in PlayerJumpState and isGrounded never gets set to true. Verified with debug statements. Works inconsistently between runs in editor. Mysteriously started working properly. (1B) Check that Root Transform Position Y is baked into pose. (2) Jammo floats when going down ramps. (3) isJumping doesn't seem to be used. (4) Debugging is a PITA.
Got same problem with isGrounded never being set to true. Trying to work out a solution.
@@AngelCorpse666 hi do you find any solution? It eould help me a lot
As @Dustin said in another comment thread, it is a command ordering problem. In the PlayerFSM, two lines need to be swapped, giving this code in the end:
```
void Update() {
handleRotation();
_characterController.Move(_appliedMovement * Time.deltaTime);
_currentState.UpdateState();
}```
That's because before switching states it makes sense to apply any due movement and only then check for switching factors. From what I've read this fixes the inconsistency problem with CharacterController's isGrounded.
@@furan8477 u are a saviour brother i spent 5hrs what's wrong with my code ,i figured out that player is stuck in animation and not grounded,so I was checking all cases
@@prabalpratapsingh9144 man I'm really happy that my comment helped you!! Yeah this kind of logical problems may be hard to find because behaviors get really messy really quickly
you are the best teacher, bro
Big fan of you I was Waiting for your new Videos please keep it up
Thank you! More to come!
@@iHeartGameDev Thank you so uch Iam always waiting for your Videos can you make a video on how to make Car Controller in unity
So informative, thanks a lot!
it was a great video, very well made. small addition, the hierarchical state machine allows us to do more complex things but with the cost of checking sub states, which is why we developed state machines in the first place. so it doesn't looks good, I wouldn't suggest it because it will scale badly, but great video anyways.
Thanks very much for watching and for the kindness! I am wondering if there is an alternative to a hierarchical state machine that you know of that can handle more complex characters. Do you know of any?
@@iHeartGameDev I've never needed, so I really don't know. sorry for can't helping :/ I just saw a warning light and wanted to let you know that it might become huge when you add other states in your super state. you will create the same problem that you were trying to solve in the first place, checking lots of conditions.
Ah interesting - I do believe my understanding of the hierarchical state machine and state machines in general is to defer conditions to the states that actually matter, not to remove them completely. So a swimming state shouldn’t be able to switch to a sleeping state - therefor it wouldn’t need to worry about that condition.
In other words, not remove all conditional logic but to remove irrelevant conditions. And therefore simplify it.
I guess I’ll know more when this character controller gets more complex 🤔 but thank you for pointing out a possible flaw! I’ll keep it in mind!
@@iHeartGameDev "In other words, not remove all conditional logic but to remove irrelevant conditions. And therefore simplify it."
Yeah that's true, the advantage of this solution is that now PlayerController script doesn't need to check every different state, states can do that internally. But the very same internal functionality can become a mess, there is a high possibility that your condition checking code will grow up with more functionality, and eventually you will hit a point where it doesn't help you anymore. Because now, your superstate acts like regular class, just like when you just started refactoring your class, just because of reducing complexity of your codebase.
@@ysftulek I am not a professional programmer, but thinking about the video and seeing your comment i wonder:
Would making a FSM, using abstract class for the base state, but, having a few interfaces like "Igravitable" and implement those in the desired concrete states reduce the complexity and improve scalability?
"In this state, there is gravity, therefore, Igravitable".
I mean, it is completely theoretical, i don't know if you even be possible tie all the knots.
Nice video, very educational. The information is logical and well laid out. No knock against your solution, but it seems like it takes a lot of boilerplate code to set up a state machine for every entity type in a game. It would probably be possible to add a layer of abstraction to make it easier to make multiple state machines, but that would make this implementation even more complex.
Is this simply the trade-off that must be made to develop complex entity behaviors? The idea of going through all of this every time I would want to create a new entity would discourage me from experimenting with new entities.
I hope this comment didn’t come across as negative, I’m genuinely impressed with this and just curious if there’s a way to utilize the same technique in a way better suited to rapid prototyping. Thanks again!
i didnt expect it to work wow thank you so much bro
In regards to naming conventions; it is common practice for abstract classes to have the 'Base' suffix, similar to the 'I' prefix for interfaces, so instead of PlayerBaseState it would be PlayerStateBase.
My little question, on all movement states, u configure some parameters without a big relationship with the state, per example on 27:23 into Idle EnterState, u change the AppliedMovement and isRunning animator, but i think, this parmeters not is better changed it into "ExitState" on RunState?
On min 28:25 we not need set the _currentSubState to null after _currentSubState.ExitStates() to not call this SubState Update after exit this.
Thx for this video, you are awesome to can mount this
Where did you learn Unity or programming in general? Because you are freaking good!
Thanks very much Daniel! I learned JavaScript at a coding Bootcamp a few years ago and use it professionally but I’m self taught with C# for game dev
thank you so much , it worked :)
Nice video. I am curious as to what the profiler reads for GC since the factory is returning new instances of each requested state. It seems like it would be more beneficial to cache a reference to each state in the factory constructor and pass the cached reference instead. Also, since there is no encapsulation of the data by using a local field and a get/set that modifies the local field, if it wouldn't be cleaner to just use a { get; set; } and ditch the local member fields? Using the { get; set; } approach doesn't really add any benefit but it would lower the line count by quite a bit. Just a thought.
This is how it should be. New Instances are crated each time new states are needed. They are almost empty and it worth nothing to create them over and over. Also they will be switched like once a second or less. And the benefit of it is that you can be sure that nothing is stored from previous use of certain state. They are always fresh and clean.
But of course if your states are heavy and switch very frequently you may want to cache them. But it will be additional functionality for a regular state machine use I think.
And I am agree with there are a lot of code inside Context class. But encapsulation is a good practice anyway. I think it would be better to split this data to different classes so it would be bore readable.
The hierarchical state machine concept is great as explained here, however, wouldn't it be better to keep the Input handling on a separate code, the animation on another one and then the actual physics/movement one being the one that will handle the movement.
Hi! Yes -- Separation of concerns is something we should always consider. As I'm working through my next tutorial, which is another state machine, I'm trying to explain that a little more clearly.
Given that this is a tutorial on youtube, there are a couple other factors that dictate how I make things: scope and time being one of them. Adding a separate class just for handling input would have added more time and complexity to the video which I do need to find the right balance for. However, my plan is to break the next tutorial into multiple parts and have it culminate in one giant release that should be about 45minutes to an hour long.
Hope that makes sense
finally found thanks to the author
This tutorial was really helpful for teaching me how a hierarchical state machine is constructed. However, when building the project myself when following the tutorial, I came across an error that had less to do with the code that was written, and more to do with how the built-in Character Controller worked.
After running some Debug.Log() commands, I found that the Character Controller is pretty finicky with its isGrounded property, with it constantly switching between true and false practically every frame while gravity was being applied, despite clearly being in contact with a plane's Mesh Collider. This didn't pose a problem initially, but it became literally game breaking later down the line once the hierarchical state machine was implemented.
For reasons I'm not 100% sure about, my IsGrounded getter always returns false, even if the isGrounded property of the Character Controller is returning both true and false interchangeably. As a result, Jammo can jump and fall, but he will not return to the Grounded State after landing. Further inspection of the colliders in Play Mode show that after performing a jump, no new point of contact is ever generated between the Character Controller collider and the plane's Mesh Collider. I should reiterate that this problem only occurs with the hierarchical state machine implementation and not the conditional statement implementation.
For the record, I am doing this in Unity version 2020.3.17f1.
this is a mistake about isGrounded and dont know why. But you can change the if condition like Physics.Raycast(_ctx.transform.position,-Vector3.up,0.1f) or other detection methods to replace CharacterController's api
exactly the same issue. is there any chance u found the issue? losing my mind rn...
the fix was said in another comment
said in another comment thread, it is a command ordering problem. In the PlayerFSM, two lines need to be swapped, giving this code in the end:
```
void Update() {
handleRotation();
_characterController.Move(_appliedMovement * Time.deltaTime);
_currentState.UpdateState();
}```
@@ssk360 It works for me! Thanks for reposting the solution from other Comments. I checked online that the isGrounded can be extremely buggy:(
you are the best dude
Hello there! For my Visual Studio users, Pressing Ctrl + . will give you some helpful auto completes like the constructors.
This one was difficult and i dont think i did it perfectly like you did (well my character is not based from the character controller but that of a rigidbody + capsule collider type) However even implementing some of these things and im already seeing great performance from the unity profiler
thank you!
Next step I am taking is to incorporate this into Unity 2021 Visual Scripting. I always got confused thinking about character controller state machines because I'm so used to "State Machine" meaning FSM (or at least that is the impression you can get online). I didn't even know about hierarchical state machines (so you can guess how much trouble I've been having with visual scripting).
The nice thing about VS is that you can execute code in multiple states in the same state machine simultaneously.
dedication to what you want to acNice tutorialeve in life! Stay safe and be wise! Much love!
Great job buddy, keep it up!
thanks, it actually let me through so i could download it.
Nice walkthrough! Although I have to play it at 0.1x speed to kind of understand ;)
I understand -- it's a lot to take in!
Huge THANKS for this video!!!
This is AWESOME!!! 👍
You're the man mate! Thank you so much.
Hi, I'm a bit confused here 13:28 You can't make an instance of PlayerBaseState because it's an abstract class. When you declare those methods that return the type of PlayerBaseState, what are those which they return, if not instances of the the PlayerBaseState class? Sorry if the question sounds stupid, I'm a beginner.
Nevermind, I think I get it after rewatching that part. It's a syntax I haven't seen before. :)
So it seems a method with the return type of an abstract class can return an instance of any class that derives from that class.
Hey! So because each of the concrete states derive from the abstract class, we can use the PlayerBaseState as their type declaration 👍 what this means is that when we go to declare the current state in the context, we can also use the PlayerBaseState type and we can assign any of our concrete states.
Does that make sense?
@@iHeartGameDev Yes! This is new knowledge to me, today I learned! Thanks for being so kind to reply man, you're awesome! :D
@@kruth6663 :) that’s what I’m here for! Happy to help!
Damn! This video is a masterpiece
Thank you for the kind words
I don't understand gravity logic, after 23:09 character returns to grounded position but stays in jump animation :/
switch characterController.Move and currentState.UpdateStates in the PlayerStateMachine's Update()
@@oxelador Nice timing could have taken me hours! now at least the character jumps once XD
I have a problem. If you change to left straight after holding up, the player continues to go forwards instead of changing to left direction. And gravity is no longer applied even when jumping. This was after i got to 28:33
Always the good content great work
Jason Storey would be proud 😊
I just discovered your videos yesterday and have been having a lot of fun implementing the techniques that you are presenting. A couple thoughts for updates to the state machine:
1. A temporary stun effect if Jammo falls from a height too far up. I would imagine that this stun would be at the same level as grounded / jump. It would have some sort of cool down (like the jump timer) as well as a couple animations while Jammo is actually stunned and when he recovers.
2. A way to interface with the controls without going through the player input, so that Jammo could have automation ai.
3. Equipable items which could change the effects of a specific player input. I would imagine that this could be implemented fairly easily with generics where the generic action is a substate to the run / walk / idle states. Or it could use a scriptable object to set parameters on an equipable action, using the scriptable object as a constructor parameter through the factory class.
on 1, couldn't you just have an animation for "fall 2" and do it through the animator? Where "fall 2" is a stunned animation and it "has exit time" when going back to id.e/run/walk/etc--you just set it so it has to do a long animation of however many seconds you want the stun (or slow the stun aim frame rate/overdrive lower than original aim in mixamo)? Have it as a 4th "jump" so it's not called in the jump count 1-3.
Then it would just have one parameter in Jump State script where if isFalling is more than 2 seconds (or whatever), trigger bool from animator "onFall2"?
Another thought...Ketra Games did a tutorial for a jump animation with blend tree where there are 3 parts to jump, jump up, fall, land. This allowed for a "falling from a cliff" scenario as opposed to normal descent from jump fall. So, that's another option that could maybe be added to animator within the jump state? The Ketra tut uses old input system, but I think the logic could be applied fairly easily to this...I am going to try that next bc I decided to ditch the 3 Dif jumps in my game and go back to the 3-part single jump. I hope I can extract/remove the jump count logic in this script without breaking it. I'm intermediate on a good day so this is deep for me lol.
PS I like your ideas @nm-hd8rr :) What is "automation ai" and what would be the use case? I saw several recommended not having to go through Player Input (with good reasons) but I'm having trouble understanding what you/they are saying about automation ai. Would one thing be like to trigger "swim" animation/movement when player gets a foot or two into water? Like the water triggers the change in state not the player input? I wanted to do this but scrapped it after implementing this state machine for player movement. Too complicated. But hypothetically, If I had a "swim" state (base state) like "is grounded" but "is in water" wouldn't this work? I'd probably have to add some rigid body physics to the "water" in that case so it would slow the player and I would have a way to check (the velocity) if water was happening in order to trigger the animation? Easier way seems like just "if he touches water, he swims" so is that where your idea comes in? Just brainstorming TY for these points which made me think outside the box!!!