YOU helped make our State Machine BETTER!

  Рет қаралды 41,863

iHeartGameDev

iHeartGameDev

Күн бұрын

Пікірлер: 166
@AlexBlackfrost
@AlexBlackfrost 2 жыл бұрын
Most of the time tutorial creators don't address the problems and bugs or just do it in the comments (which is hard to find unless they are pinned comments), so kudos for making this video. 14:43 In the last FSM I made I fixed this problem by calling the CheckSwitchState() method from the PlayerStateMachine class. Pseudocode: class PlayerStateMachine{ private State currentState; void Update(){ State newState = currentState.CheckSwitchState(); //returns null if there is no transition available if(currentState != null){ // Transition conditions are met and we can transition to newState currrentState.ExitState(); newState.EnterState(); currentState = newState; } currentState.UpdateState(); } }
@iHeartGameDev
@iHeartGameDev 2 жыл бұрын
Ooooo! This is super interesting Alex! Totally a different take than I anticipated seeing and it seems like a super clean way to do it too! 👏👏👏
@LuizMoratelli
@LuizMoratelli 2 жыл бұрын
The next part could be adding attack to HFSM, it would be very interesting to see how it would be do, and I believe it would complete most of the base of a game.
@Luciphear
@Luciphear 2 жыл бұрын
Seconded!
@ElDonitazz
@ElDonitazz 2 жыл бұрын
thirdonded!
@arakielgazorkull
@arakielgazorkull 2 ай бұрын
Another optimization you could make in the Factory is to not create ALL states at construction time, but at each request, check to see if it already exists with Dictionary:ContainsKey and create/add if it doesn't, like this: public PlayerBaseState Idle() { if (!statesCollection.ContainsKey("Idle")) { statesCollection.Add("Idle", new PlayerIdleState(context, this)); } return statesCollection["Idle"]; } this way you aren't creating a state until you need it the first time. ContainsKey is super efficient and shouldn't slow anything down, while a mass creation at construction time could slow you down depending on how many states you have and how complex they are.
@uheartbeast
@uheartbeast 2 жыл бұрын
Excellent video!
@iHeartGameDev
@iHeartGameDev 2 жыл бұрын
Thanks very much, HeartBeast! Big fan!
@Hyphen-M
@Hyphen-M 2 жыл бұрын
Hey it's heartbeast! Watching your stuff has gotten me from the point of wanting to make games but not knowing now, to wanting to make games and having a much better idea on how while not following through in the slightest after getting some quick little mock ups going.
@__--_--_-----
@__--_--_----- 2 жыл бұрын
Looking forward to this one, I used your state machine as a template and then promptly spaghetti'd it up as I expanded on it haha. Would you ever consider making a video on adding hit/hurtboxes for your animations? This seems like a pretty important component for a lot of games, but surprisingly there's not a professional and up-to-date tutorial for it. It would also fit in very nicely as the next video in the animation playlist.
@iHeartGameDev
@iHeartGameDev 2 жыл бұрын
That totally sounds like a video I would love to do in the future!
@iHeartGameDev
@iHeartGameDev 2 жыл бұрын
Hey all! It's been a minute, but I'm super excited to share the next video in our character controller series. This video made it really feel like we're building it together because we made all of these changes thanks to this amazing community. Big shoutout to SimonGS, StudioAtmaRob, JasperJavillo and TheWightOne! ⭐ Literally couldn't have made this video without the help of this amazing community! Thank you to Unity for reaching out to sponsor this video. And, of course, to all of the amazing IHGD patrons for helping to keep the lights on. If you're interested, check out the current Unity sale, and for access to this projects files/voting on the next tutorial check out the Patreon: 🛍: assetstore.unity.com/?on_sale=true&rows=96&aid=1011lexqa 💛 www.patreon.com/iHeartGamedev Thanks for watching and I hope this video helps you on your gamedev journeys! Cheers! 🍻 -Nicky
@ScientObject40
@ScientObject40 2 жыл бұрын
You're an amazing tutorial creator.
@iHeartGameDev
@iHeartGameDev 2 жыл бұрын
@@ScientObject40 thanks very much!
@blackroberts6290
@blackroberts6290 2 жыл бұрын
maybe make checkswitchstate return something then decide to continue depending on the value of the thing
@gabrielerossi3333
@gabrielerossi3333 2 жыл бұрын
@@iHeartGameDev Hi I'm having a problem with the is grounded property, even if it's always true I'm still having the continuous change between grounded and fall state in addition when I try to jump it makes only the first jump and then it stays locked in the jump animation even after reaching the ground , any ideas of what could be wrong? If needed I can show you the code
@scottdoherty5808
@scottdoherty5808 Жыл бұрын
@@gabrielerossi3333 In PlayerStateMachine, in the void Update move the _currentState.UpdateStates(); to below _characterController.Move . Movements need to happen before Updates.
@thewightone7441
@thewightone7441 2 жыл бұрын
Yo I was NOT expecting a shoutout this morning. I'm glad I could be of service!
@iHeartGameDev
@iHeartGameDev 2 жыл бұрын
Thanks so much for the help here! You’re not only helping me, but the whole community!
@christophbornhardt7888
@christophbornhardt7888 2 жыл бұрын
Ok, I'm pretty proud of myself because most of the problems I had already fixed in my version of this exercise. I'm currently running this pattern with 5 layers of states (Meta, Time, Vertical, Horizontal and Action). For problem number 1, I did the same thing, though i didn´t implement the Interface and am now considering doing that for each later. For problem number 2, you want CheckSwitchStates to return a bool, indicating if switching states is neccesary or not. Then, in UpdateState you write something like: void UpdateState() { if(CheckSwicthState()) { return; } ... rest of the code } That will make the rest of the code below CheckSwicthStates unreachable, and ergo not executed. You could also insert it into the else block, but that would use more resources on runtime, because in C#, going into an else block takes 2-3 times more resources. As explained by Nich Chapsas in one of his videos. For problem 3,... Grounding detection has been always a problem in unity and I never used it beacuse of it. Instead, I added a FixedUpdateState() (with all that entails) and Cast a Box under the feets to check for ground (via layer and Physics.BoxCheck). More so, I added a second Box over the first one, to check for approaching ground. This was done, because the animation would change between grounded and falling while going up and down steps, so basically, the isApproachingGround bool checks if its necessary to change the animation, but not chnage the state. As for problem 4, I'm against the proposed solution, because as I'm using a 5 layer StateMachine, each time I switch States I'm initializing 3-4 different substates. Caching the states would mean no more Initializing the substates, which would give me problems on runtime. I guess that could be remedied moving the InitializaSubStates method from the constructor to EnterState, but that would break the intention of the fix. Anyways, thank you very much (as always) for the time you spend in this videos. I've learned a lot with this. And I guess I should enter the discord community for this discussions ^^
@jameslafritz2867
@jameslafritz2867 2 жыл бұрын
The purpose of the Enter State Method is so you can "Initialize the state" when entering it. If you have things that need to be reset when you Enter the state you set those here.
@5thBabbitt
@5thBabbitt Жыл бұрын
I'm having trouble adding a third layer for actions, could I see the logic you used
@joeundso8141
@joeundso8141 2 жыл бұрын
My suggestion for problem 2: Declare a return type of bool in the base class for the CheckSwitch method. Then you only execute the rest of the update method if CheckSwitch is true :) it works fine for my state machine.
@jameslafritz2867
@jameslafritz2867 2 жыл бұрын
I did the same but instead only continued if Check Switch returned false. I went with If I am changing States then return true.
@Andrew-tl9gk
@Andrew-tl9gk 2 жыл бұрын
I would like to have a follow-up on the state machine without actual programming, just with conceptional explanation how further other things would fit into the state machine like attacking, getting hurt, being invincible, grabbing something, getting hurt on large fall with animation, talking to someone, opening a door, having a cut scene where the character is not controllable, etc... The state machine currently only has one sub-state but in "real life" you can be grounded, walking and at the same time getting hurt and shoot and eat a chewing gum. There are some scenarios where I wonder if this wouldnt require another state machine because it would end up in endless amount of sub-states. I just dont understand how it would fit in the system.
@DentekaZaramoth
@DentekaZaramoth 2 жыл бұрын
For your question about the factory still being a factory after caching, I think it would make more sense to be a pool rather than a factory in this context. You instantiate once, and reuse the state when you need it. Like a pool, even though it's a pool that only contains 1 instance of each state
@sjoervanderploeg4340
@sjoervanderploeg4340 Жыл бұрын
If you can, always store references in some array. For example, you can use the jobs system to iterate over the array when you need to and it generally results in faster code!
@szyslay
@szyslay 2 жыл бұрын
You truly have one of the best tut yt vids out, there showing how AAA is done with other amazing people
@iHeartGameDev
@iHeartGameDev 2 жыл бұрын
Thanks so much Szymon!!
@JohnK68
@JohnK68 2 жыл бұрын
Seen my fair share of GameDev/Programming video's. But here it's explained the best and thank you for putting so much efford in not only explaining things but the videoediting is a full time job of its own.
@iHeartGameDev
@iHeartGameDev 2 жыл бұрын
Thank you very much! You kind words mean a lot and you are correct in assuming the editing takes rather long 😅
@jasperjavillo686
@jasperjavillo686 Жыл бұрын
In regards to caching states, the SetSubStates() function of PlayerBaseStates needs to run _currentSubState.EnterState() or the whole State Machine falls apart if there are more than two levels to the hierarchy. Since substates are initialized in their superstate's EnterState() function, rather than in their constructors, the substates will not be initialized when called from being cached unless EnterState() is run.
@jasperjavillo686
@jasperjavillo686 Жыл бұрын
@@you_what319 It’s a result of this particular state machine and what it was trying to accomplish. Since the second layer of the state machine controls Jammo’s horizontal movement and walking animations, it is more influenced by the CheckSwitchState() function which constantly checks the button inputs to determine which state it should be in. Also, this particular problem doesn’t become apparent until you get 3 layers deep. I only discovered the issue myself when I tried applying the structure to a more complicated state machine.
@kylebaker2641
@kylebaker2641 2 жыл бұрын
I would have personally changed the jumping super state to airborne and set jumping to a substate, then had an isgrounded check to swap the states
@iHeartGameDev
@iHeartGameDev 2 жыл бұрын
You can totally do that! I hope that people learn more from the concepts of my videos and make variations! It would be great to see what the community can make!
@i_am_set
@i_am_set 2 жыл бұрын
I really liked your community post warning me of this video because I've been very excited to watch it! Was hoping for a follow up like this.
@iHeartGameDev
@iHeartGameDev 2 жыл бұрын
Heck ya! So happy to hear that you enjoyed it!
@__dane__
@__dane__ 2 жыл бұрын
I’ve been thinking maybe Jammo should enter the falling state after reaching the apex of each jump. I understand this might complicate implementing the Mario jump behavior. However, if the player were to jump from a ledge rather than walk off a ledge Jammo will never enter the fall state I presume. I can see changing this being useful for other functionality such as the player rolling after landing on the ground. You could then implement different landing animations based on the height difference from where Jammo left the ground versus where he lands (you could also implement this by taking into account the speed/gravity of Jammo right before landing). It would make sense for Jammo to play a different animation for landing from running, landing after jumping, landing after walking off a ledge, or landing after falling a long distance. Lastly, if Jammo travels a long distance while falling you could add a new fall idle animation (freefall?) that plays after falling for a set time and/or when Jammo’s gravity passes some threshold.
@Grandalf3004
@Grandalf3004 2 ай бұрын
I know this is 2 years old but another suggestion would be to set root default as true, then only set it false when a state is given a superstate, that way we can have grounded , falling, and jumping as superstates, but if in the future we wanted to add another layer above, it would be as simple as passing in the current super states as substates. also in enterprise web development, a factory that caches is just a caching factory or a factory pool
@EgorBakanov
@EgorBakanov 2 жыл бұрын
18:21 I personally would use Type as the key of the Dictionary. Than I would add generic "public PlayerBaseState GetState() where T : PlayerBaseState" methods, which would try to get state from dictionary cashe or create new one and than cashe it. That way you would have to do less work when adding new state, just add 1 new method without extending enum and constructor(you dont even need it at that point).
@WheremyPoptart
@WheremyPoptart 2 жыл бұрын
How would that look in psuedo code?
@guille_sanchez
@guille_sanchez 2 жыл бұрын
This is so instructional, shout out to you and you're community members! you got a new subscriber
@IgnitedMans90
@IgnitedMans90 2 жыл бұрын
For the second problem, you can return a bool in “CheckSwitchState” representing if it is changed or not to continue or return.
@IgnitedMans90
@IgnitedMans90 2 жыл бұрын
Maybe that logic should be moved to the base class if you need to call that function in all “UpdateState” methods
@blgamedev
@blgamedev 2 жыл бұрын
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!
@RadianceCOD
@RadianceCOD 2 жыл бұрын
Amazing video as always, thank you for bringing such quality contents. Huge respect to you 🙏
@iHeartGameDev
@iHeartGameDev 2 жыл бұрын
Thank you so much Ritansh!! More to come!
@Relativ9
@Relativ9 11 ай бұрын
Fantastic series, something I would like to see added/demonstrated is having multiple layers/levels of nesting, having for example an any state that has transitions to all other states, allowing that to be the default state which all other states transition back to when no conditions are met. Would simplify conditional transitions.
@dasboshitt209
@dasboshitt209 2 жыл бұрын
Mans literally teaching better than my comp sci professors Absolute madlad.
@kmud7750
@kmud7750 2 жыл бұрын
Thanks for detailing about the character controller. That's been something I didn't find info on. Thank you!!
@masterz0
@masterz0 2 жыл бұрын
Suggestion for the next video: Create a Crouch Super State and implement the ability to attack in all Super States.
@tomdriver6733
@tomdriver6733 Жыл бұрын
Yes, that would be great.
@invertexyz
@invertexyz 2 жыл бұрын
On the subject of accessing the Dictionary cache, while not using a string is smart, I wouldn't go the enum route either, as you're just creating further work to update each time a state is added. Instead, the Dictionary could simply use the actual TYPE of state as the key, `Dictionary` and then: `_states[typeof(PlayerIdleState)] = new PlayerIdleState(_context, this);`
@aumudin6184
@aumudin6184 Жыл бұрын
To fix the issue with the checking of switching states I ended up just moving the check to LateUpdate and making it a virtual function. I rarely use LateUpdate so it worked for me if needed I can always call base at the bottom if needed. Not sure if it makes sense but works beautifully for me!
@hernans10
@hernans10 Жыл бұрын
I love your channel and the way you teach, awesome work dude!. My suggestion would be on the jumping animations, maybe you could switch to the falling state after you reach the highest point in the air? i know it's complicated because you have to make sure the jump animation is completed before you reach that point, in the case of the first two jump animations they are simple pose ones, but maybe its complicated for the third animation that has the backflip. Greetings from Uruguay!
@purplelizard0102
@purplelizard0102 Жыл бұрын
I don't know if it's been already suggested or not, but what if Gravity is the main state, and every other state is a substate. So, you could have the same grounded and jumping state logic without the need of implementing gravity for each one (since they are already subjected to it automatically). The logic of switching between grounded and jumping is still there, and it functions exactly the same.
@jonmcfluffy9699
@jonmcfluffy9699 2 жыл бұрын
i am sure lots of devs would appreciate a "rolling" animation that automatically applies an "" or something like a grab attack/knock back/knock down and then a further "break out action" where the player can time an input correctly to end the effect early with a roll or spin.
@AyItsKevin
@AyItsKevin 2 жыл бұрын
I used the LateUpdate hook to call my state’s CheckStates. This way it can execute both update and fixedUpdate and check transition conditions once all update functions have been called
@titaniumtomato7247
@titaniumtomato7247 Жыл бұрын
I think this series of iterations on the player controller is very cool and useful
@AnEmortalKid
@AnEmortalKid Жыл бұрын
Probably too late BUT.... here's a couple changes i'd make. IsRootState could be a function that returns true/false based on if the current type of the object is of type IRootState , you're already enforcing all root states to handle gravity. A factory that caches things is still a factory, from the consumer's perspective the factory returns instances of a type, whether that type is cached or not is an implementation detail. A consumer just states "Hey factory, gimme an X". Now the CheckSwitchStates() method..... the current name is tricky because the function already has a side effect (Check AND Switch states), and you want to short circuit operations around it. I think I would introduce a new function here that returns a boolean if the state will (or is/has) transitioned to a new state, and then do an early return, like so: UpdateState() { if(IsTransitioningState()) { return; } HandleGravity(); } IsTransitioningState() { if(Controller.IsGrounded() { SwitchState(Grounded); return true; } return false; }
@iHeartGameDev
@iHeartGameDev Жыл бұрын
You are not too late! This is awesome feedback and I appreciate your input!
@beardordie5308
@beardordie5308 2 жыл бұрын
Do you have a Trello or list of your next features to add? A solid platformer controller is going to want to have Coyote time jumping, input caching for when jump is pressed just Before becoming grounded, and beyond that it would need to be extensible enough to add states/substates like double jumping, rolling, dodging, crouching, crawling, ledge-hanging, ledge-climbing, ladder climbing, cliff-balancing, long-idle, long-falling, hard landing, pushing, pulling, wall-sliding, wall-jumping, and on and on.
@Kathlar
@Kathlar 2 жыл бұрын
What would make this code even cleaner, would be to make the dictionary keys be types instead of enums. You could also remove writing all the methods separately and do a generic method that ether returns the state (if it exists) or creates a new one and adds it to a dictionary.
@iHeartGameDev
@iHeartGameDev 2 жыл бұрын
That does sound cleaner! Could you possibly share what that looks like??
@Kathlar
@Kathlar 2 жыл бұрын
Oh, my original reply was deleted... Could it be because of the pastebin link? Thanks KZbin... Anyway, I understood that using a type as key would require a different type of collection. But, it can still be made much cleaner IMO using the name of the type as key: //Code using System.Collections.Generic; public class CharacterStateFactory { private readonly CharacterStateMachine context; private readonly Dictionary states = new(); public CharacterStateFactory(CharacterStateMachine context) { this.context = context; } public T GetState() where T : CharacterStateBase, new() { string className = typeof(T).Name; bool exists = states.ContainsKey(className); T result = exists ? states[className] as T : new T(); if (!exists) states.Add(className, result); result.Set(context, this); return result; } } //Code call if (context.Statistics.CurrentHealth == 0) SwitchState(states.GetState());
@AlexBlackfrost
@AlexBlackfrost 2 жыл бұрын
@@Kathlar Very interesting, thanks for sharing. Regarding the deleted reply: yes, you're right. If you post a link in a comment chances are that KZbin is going to label it as spam, I've experienced this problem myself many times. Creators don't receive a notification when a comment is marked as spam, so they would need to go into the spam folder and unmark it.
@bufferoverflovv
@bufferoverflovv 2 жыл бұрын
@@Kathlar Hey I realise you posted this 4 months ago but I'm struggling to figure out what result.Set(context, this); is. Is it a method in the PlayerBaseState that sets the context and factory?
@Kathlar
@Kathlar 2 жыл бұрын
@@bufferoverflovv I think so. Honestly, I changed these scripts a little later, so if you want I can send you the updated version :D
@vonriddarn
@vonriddarn Жыл бұрын
I know this is a very old video, but if anyone is interested in the whole SwitchState thing, you could simply use the early return pattern. This pattern works by indenting logic and exiting code blocks early to hinder their execution. In this example we could send back the result of the attempted transition and use that to exit out of the Update method. Like so: public override bool CheckSwitchStates() { if(SomethingThatMakesMeChangeState) { SwitchState(Factory.OthersState()); return true; } return false; } public override void UpdateState() { // Early return pattern if(CheckSwitchStates()) return; // All code below is safe and will never execute unless this state is still active. HandleGravity(); } EDIT: Also, when caching states like this, it is no longer considered a factory (although opinions on this might fluctuate). It is now considered a StateRepository, which makes a lot more sense in this context. Great video, thank you for sharing this knowledge freely for everyone to take part!
@celinas3182
@celinas3182 Жыл бұрын
Thank you! I did it like this and its really convenient.
@stefan429
@stefan429 2 жыл бұрын
to answer the last question: i think its still a factory even if you cache states because all the factory classes ive ever seen cache states instead of making new ones, when appropriate
@DanielMescoloto
@DanielMescoloto 2 жыл бұрын
Honest question: How do you scale this? Because it seems it's gonna be really complex with a few more states and a lot of transitions. Imagine if you can Attack while idle/running/jump then you wanna add a "crouch" state. And you can be idle crouch, walking crouch , idle crouch attacking, walking crounch attacking then you wanna add parry and glide states see what i mean?
@iHeartGameDev
@iHeartGameDev 2 жыл бұрын
Hey Daniel -- Totally fair question! While yes, that does get complicated, I'd like to pose the question: what is the alternative? We switched to a state machine to avoid the gigantic files that lack structure and contain an insane number of conditional "if" "else" statements. The idea here is to create a reproducible structure that simplifies the alternatives and makes the states self-contained. There might be a ton of states, and possibly even separate state machines, but at least it is structured and understandable. For example, we might switch to a completely different "AttackStateMachine" and rename the "PlayerStateMachine" to "MovementStateMachine" or something along those lines and those could be activated/deactivated depending on some kind of external controller. Or, we could keep the "PlayerStateMachine" and just add a different "BaseState" like "Attack" and that state could be more or less complicated than the other Base states. What do you think? I hope that helps a bit.
@DanielMescoloto
@DanielMescoloto 2 жыл бұрын
​@@iHeartGameDev first of all, thanks for the quick response :) > what is the alternative? I don't think there is a good one, really. Huge if/elses/switch statements are the worst. about having one state machine for movement and another for combat, I think it works. Even thinking it might break the pattern having 2 states in 2 state machines instead of having one state. it's a good way and having one state root then it sub states, I think it's the best option.
@iHeartGameDev
@iHeartGameDev 2 жыл бұрын
@@DanielMescoloto For sure :) That makes sense to me too! Happy to clear things up a bit.
@Tony-vg1cd
@Tony-vg1cd 2 жыл бұрын
Thanks for the awesome and professional tutorials! You got a new subscriber. In the next part, I would liike to see how to add the aim system with gamepad and mouse (smoothing for both, no instant turns). Aim-system could be optional if you want to keep the Mario-style. When walking, there could be a small acceleration for gamepad left stick, so that you could also walk slowly. Adding swimming could also be interesting, because it would only happen in certain areas(walking if your feet reach the bottom of the water).
@pewpew518
@pewpew518 2 жыл бұрын
I highly disagree with using a strict state machine for more complex character controllers or character controller in general. A real production open world character controller could have things like swimming, combat, weapon in hand but not in combat, weapon in hand but climbing, fall from high ledges, out of stamina , Spell Casting ,dodge, transition state from swimming to walking , etc etc and most of these state are usually highly dependent on one other and share code. As you build out your character controller and add more features, your current grouping of states might become more ambiguous .You can see how this can get out of hand really fast . Also a game isn't just a random character on a flat ground. You have things like VFX , Sound, game Events, animations, Hit boxes, UI, IK etc that could be highly state dependent. All of this requires monobehaviours and extremely tight interstate communications. A character controller is one unit, its ok for it to be monolithic class just use private enums like a lose pseudo state machine to track things. This is however an excellent video explaining state machines as a concept I just wouldn't use one for a character controller.
@iHeartGameDev
@iHeartGameDev 2 жыл бұрын
Hey Pew Pew! I actually remember having this discussion with you a few videos ago XD I'm still interested in the direction you're stating, but I haven't really seen any reason as to why it's "better" than the state machine we're building here. Are there publicly accessible examples of character controller's from some of these larger games that showcase the monolithic class?
@pewpew518
@pewpew518 2 жыл бұрын
​@@iHeartGameDev Actually most of it comes from personal experience. I'm currently building a character controller for a production OpenWorld game. Something similar to ghost of tsushima. I started off with state machine pattern and it turned into a real mess. There was a ton of code repetition, and I was having to constantly refactor. Lets take an example of jump. you can jump on ground, there's jumping when running off of a ledge (basically more powerfull jump ), in combat player can jump and press attack to basically do a jump attack, There might be quick time events involving jump, There's also jump prediction for parkour, etc In this case what state do you put jump under? grounded? combat? parkour? Lets say your game has a skills menu and you have a double jump/ mid air jump skill. Well now your jump is dependent on gravity, grounded state and falling state. There's also 'cancels ' . lets say you are currently in combat and swinging your sword. is dodge able to animation cancel the sword swing ? is jump able to cancel sword swing. What if player swung the sword close to an edge and before that animation completed, the player is no longer grounded? does falling override combat? These design decisions can very quickly lead to a spider web of dependencies. I wasted two months prototyping with state machine pattern, it got to a point where all the complexity was impacting performance. My current implementation so far has two scripts. one of them is about 2k lines this includes some basic parkour moves and its so much simpler and easier to manage. If you are lookin for an example check out Kinematic Character Controller from asset store made by Philippe. Also I don't think my implementation is "better" its probably just I'm working on a character controller that is more open-ended but for a basic character controller I guess state machine is perfectly fine. Im be very interested in seeing a fully built out production version of character controller you are building here, with animations, transition and more importantly design decisions implemented.
@weckar
@weckar 2 жыл бұрын
@@pewpew518 So use the right tool for the right job. An open world game is one thing, a platformer is quite another,
@Andrew-tl9gk
@Andrew-tl9gk 2 жыл бұрын
I am also very critical about the state machine to be honest. Such a state machine can only be in one state at a time so in more complex scenarios you might end up with hundreds of states and tons of duplicate code. It seems very inflexible to me, @pew pew made a few very good examples. Anyway I am still searching for a better solution... or maybe it should be a combination of different patterns? For example it seems to make sense to have high-level states like grounded, in water and airborne but this doesnt require to have a state machine IMO, it is just an enum state variable. Or maybe a character should have tons of different state machines and a brain that combines them to the actual desired movement/animation/action...
@pewpew518
@pewpew518 2 жыл бұрын
​@@Andrew-tl9gk since I made that comment I have entirely quit unity and switched to unreal 5 for good. Now I'm using the same character controller system that's used in Fortnite , gears of war and final fantasy basically any AAA unreal game out there. Here what I think so far. The controller that's being created in this video series if totally useless. Apologies if it sounds a little rude but that's just how I think it is and here the reason why. Everything i said in my previous comment still stands + C# is a managed programming language. meaning the memory management, allocation and deallocation in your ram is done automatically. Because you dont have controller over your memory, it can lead to fragmentation. This mean one piece of data is at one location of your ram and next piece of data is at some other location. because of this your cpu wastes a whole bunch of cycles to find this fragmanted data. Now whats the problem with this character controller? There's two types of memory one is stack and other one is heap. stack is allocated at compile time while heap is your RAM, its allocated dynamically. So stack can never get fragmented. If you have programmed in c++ you would know that every time you use the keyword "new" you are creating a new object and allocating memory to it in your heap (RAM). This means every time you switch states your cpu is quite literally wasting cycles finding the next state object in heap. Also When you destroy an game object that uses this state machine, guess what, you also need to destroy all the states you just created using "new" keyword because they are objects too. There's another term for this and its called garbage. So the unitys built in garbage collector now needs to find all this in your heap (wasting cpu) then clear that memory. This causes frame spikes. All of this can be completely avoided if you just use a monolithic class and use enums to keep track of states. If you look through UE5 source, the movement component alone is over 20,000 lines of code, I'm not even joking go look for yourself, and its being used in AAA games. I think this object driven approach to state machine is just fundamentally wrong not sure why almost every unity youtuber is doing this when literally AAA games are using simple monolithic classes and component model.
@EmreCan-ky1vn
@EmreCan-ky1vn 2 жыл бұрын
Why do we use "InitializeSubState" every time we change root states? Substates have their own transition conditions and are already able to change themselves. Also sometimes my characters jump too high. Is there anyone who faced the same problem?
@bbfizzle_
@bbfizzle_ 8 ай бұрын
Question: Why would you ever make it so that every root state has to implement gravity anew? Can't you just define the behavior in the BaseState and inherit that to all the others? It needs to be done on every frame anyway, why would you repeat yourself instead of handling it once for all states? Love the videos, thanks so much 👏🏻👏🏻
@jameslavery2958
@jameslavery2958 2 жыл бұрын
Nice series. The next States imo should be crouch and mantle and then attack.
@joseluisRueda
@joseluisRueda Жыл бұрын
Congratulations on the series, how could you add substates and have them run at the same time, for example, walk and pick up an object, or run and shoot, etc?
@Alguem387
@Alguem387 11 ай бұрын
a factory that caches is basicaly a pool, but i had seen the sufix provider begin used
@attenurmi936
@attenurmi936 2 жыл бұрын
Just wow! Top quality content!
@linkybramble8482
@linkybramble8482 2 жыл бұрын
More like a "State Warehouse" than a "Factory" now.
@Hyphen-M
@Hyphen-M 2 жыл бұрын
For the order problem I don't know if this is a good way of going about this, but worked for what I wanted. I create a bool to check for entering a new state in the state machine and did a check for it at the start of the update method before any other state logic would run. if (enterNewState) { currentState.EnterState(); enterNewState = false; } Then in the switch states method of the base state I removed the newState.EnterState() and change it to set the new enterNewState bool to true. So it finishes off the frame setting the new state to switch to and exiting the old, then at the start of the new frame it enters the new one and proceeds with its logic. At least I think? I may be incredibly wrong since I'm just blindly flailing around in C Sharp so far since I've just come across to trying to learn Unity.
@woodigel9700
@woodigel9700 2 жыл бұрын
Hi there, first time into Unity and I just have to say your videos are really wonderful to get the hang of things and brush up on rusty c# expertise! I do have a problem though, despite following your tutorial to a tee, I seem to have troubles getting the animations for walking, running and falling to work. Jump works fine though. From Logs I could tell that the State is never being switched from grounded or jump to their substates. Would you happen to have any tips?
@tomdriver6733
@tomdriver6733 Жыл бұрын
You could add a delay for the fall state. That could help also for running down stairs. How can I implement that?
@mohsenmousavi2313
@mohsenmousavi2313 2 жыл бұрын
💚
@iHeartGameDev
@iHeartGameDev 2 жыл бұрын
💛
@LuizMoratelli
@LuizMoratelli 2 жыл бұрын
If we add ability to shoot, that'll be a new state? If so, the better way is add as a substate or rootstate? And in the case of hurt/die what is the best approach?
@iHeartGameDev
@iHeartGameDev 2 жыл бұрын
In reverse order, "Die" definitely sounds like a root state. I guess I would need to know more about "Hurt" to decide. Is it quick or does it last? Like should the character play a quick recoil animation after being hurt and then goes back to a normal state? Or does being hurt have its own set of animations and logic involved? Shooting sounds like its own root state to me too. You can still use the same idle walk and run sub states, or if you're not supposed to be able to run when shooting, create variations of idle and walk like "shootingIdle" and "shootingWalk" that only transition between themselves.
@LuizMoratelli
@LuizMoratelli 2 жыл бұрын
@@iHeartGameDev All of this seems to make a lot of sense to me. But if it is possible to jump and shoot at the same time, being shooting a rootstate, would it be at an even higher level than jumping and grounded? About hurt, I figured it with its own rules, so I think it could be a substate of each rootstate.
@himanshukumar8880
@himanshukumar8880 2 жыл бұрын
When I jump and come back to ground while running then sometimes the currentSate is ground but my _currentSuperState is jump so my player got stuck I think you are also facing the same issue.
@RadianceCOD
@RadianceCOD 2 жыл бұрын
I just wanted to discuss a thing: what is the purpose of hierarchical state machine over regular one in context of player controller. I see every states are different and have nothing to bind in hierarchy at any point. If anyone can explain any example or in context to player, i will be really thankful 🙏
@iHeartGameDev
@iHeartGameDev 2 жыл бұрын
Hey! So I think it's important to note that State Machines themselves are not "necessary". In fact, all design patterns including the state pattern are just widely accepted solutions to common problems that we run into during development. With that being said, I think that a hierarchical state machine offers the benefit of deeper encapsulation of logic relevant to given states at the cost of increased complexity when initial setup. I think that's about it, to be honest. However, using a regular state machine can of course work just as well! Hope that helps answer your question :)
@RadianceCOD
@RadianceCOD 2 жыл бұрын
@@iHeartGameDev Thank you for your time. I too think that hierarchy may not be necessarily visible in some cases.
@RadianceCOD
@RadianceCOD 2 жыл бұрын
@@bezoro-personal Thank you for your time. What if player jumps into water? He still goes into swimming state but was not initially in grounded state. Hence we again need to write the transition here, similiar to grounded state. Do yo have any link i can visit to see HFSTM more
@IndieWafflus
@IndieWafflus 2 жыл бұрын
@@RadianceCOD There's probably multiple ways of doing Hierarchy, but with a simple State Inheritance: Hierarchy is useful to encapsulate common logic. For example, every "Grounded State" can enter the "Jumping State", so instead of setting that transition in every normal (Idle, Walk, Run, ...) State, you do it in the "Grounded State", which "Idle", "Walk", "Run", etc. inherit from. If every "Grounded State" can enter the "Swimming State", then you also add that transition to the "Grounded State". With "Jump", you could have an "Airborne State" that took care of the transition from air to water as well. You want to remove the transition from one of the "Grounded States"? You can override the method to not transition in the desired State. You want it to be for another State instead of the "Jumping State"? Simply swap the line once and it's all set. It's good because common logic will be in one single class, it's bad because of inheritance, which people are somewhat against, likely because it can become a bit of a mess and it's a bit harder to understand what each State has once you had more and more inheritances to it.
@maxus921
@maxus921 2 жыл бұрын
I've recently been trying my hand at tackling all that is unity. Following this series has been one of if not the most helpful but man... oh man... c# really didn't want to tell me that in my base state I had a certain SUB instead of SUPER state @-@
@imEvoohz
@imEvoohz Жыл бұрын
Had a question about physics updates. Since we always call our states' update function in the Update Method of the gameObject, isn't there gonna be a problem about physics ? Cause it's time dependant and the physics changes need to be called in the FixedUpdate function. Or am I missing something ?
@joshuhigashikata9871
@joshuhigashikata9871 Жыл бұрын
ty
@_skeletoon
@_skeletoon 6 ай бұрын
Would it be okay to modify the setter of the player boolean member variables to also modify the animator booleans?
@mateop607
@mateop607 Жыл бұрын
Hello! I think this a bug that's related to what's shown here. Even if there is no mention of it in the InitializeSubState() method, the player is still switching to PlayerRunState(). It's not initialized in this superstate. There are transitions from the substates. Is it obligatory for each superstate to hold every substate? Maybe that's intentional.
@VEOdev
@VEOdev 2 жыл бұрын
I suggest to use Animator.CrossFade method for animation transitions rather than this messy spider web of unity animator, it is simple now because you have 4 animations and you already have many many transitions for no reason, think later when you have like 15 animations this will be pain to work with.
@iHeartGameDev
@iHeartGameDev 2 жыл бұрын
That’s a great refactor and one that is planned for the future
@VEOdev
@VEOdev 2 жыл бұрын
@@iHeartGameDev It is life changing for programmer you should try it, It works well with sprite animations, didn't try it with 3D rigged animation but sure will work the same just rising the transitions for smooth transitions, would be interesting to see it in this project
@gabrielerossi3333
@gabrielerossi3333 2 жыл бұрын
Hi I'm having a problem with the is grounded property, even if it's always true I'm still having the continuous change between grounded and fall state in addition when I try to jump it makes only the first jump and then it stays locked in the jump animation even after reaching the ground , any ideas of what could be wrong? If needed I can show the code
@gabrielerossi3333
@gabrielerossi3333 2 жыл бұрын
Unfortunately not yet, I've controlled all the scripts again and rewatched the videos but nothing seems wrong, I don't know what to do
@jimmyyu3383
@jimmyyu3383 2 жыл бұрын
I had the same issue previously and then realised that I have to put isJump back to false when "Exit" Jump State. Otherwise even if you are "Grounded", you cannot jump again.
@gabrielerossi3333
@gabrielerossi3333 2 жыл бұрын
@@jimmyyu3383 ok thanks, when I'll get back from holidays I'll try it out.This solution fix only the jump part not the continuous change between fall state and grounded right?
@jimmyyu3383
@jimmyyu3383 2 жыл бұрын
@@gabrielerossi3333 for the ground part, I adopt another method. My movement codes are also different from the video. So I cannot test out. Here is the code to check grounded (From unity). private bool GroundedCheck() { // set sphere position, with offset bool isGrounded; Vector3 spherePosition = new Vector3(Ctx.CharacterController.transform.position.x, Ctx.CharacterController.transform.position.y - Ctx.GroundedOffset, Ctx.CharacterController.transform.position.z); isGrounded = Physics.CheckSphere(spherePosition, Ctx.GroundedRadius, Ctx.GroundLayers, QueryTriggerInteraction.Ignore); return isGrounded; }
@jimmyyu3383
@jimmyyu3383 2 жыл бұрын
GroundedOffset is -0.14f; GroundedRadius = 0.28f GroundLayers = Depend on what layers you set as ground or it could be "everything" you choose from inspector.
@pablomansilla2497
@pablomansilla2497 2 жыл бұрын
it would be nice to see a "hide" state, i'll need it to my project xD
@pitchblack5422
@pitchblack5422 2 жыл бұрын
You the best man!
@gitaecookiemonster2892
@gitaecookiemonster2892 2 жыл бұрын
You are awesome!!!!
@MrBalinSuperTV
@MrBalinSuperTV 2 жыл бұрын
Thoughts on entering fall state from Jump State once CharacterController y velocity changes to negative?
@sorokan6036
@sorokan6036 2 жыл бұрын
I was also wondering about the continuos creation of new state instances... Is this only a efficiency concern due to the constructor beeing called or will this also effect memoy usage... or phrased differently: Are instances of classes automatically discarded from the memory, when no longer referenced?
@Maverickkk
@Maverickkk Жыл бұрын
I know this is a super late reply but as far as I know, the garbage collection system within Unity will remove unused data from the heap when the heap is full - reclaiming that memory. The problem is that whenever garbage collection is run, all other processing is suspended which can cause stutters in your game - especially on lower end machines (budget laptops, mobiles etc). When writing code, it is important to be mindful of this and architect it in a manner that reduces the necessity for garbage collection as much as possible.
@trillobit3sIndieGames
@trillobit3sIndieGames Жыл бұрын
Hei #Nicky #iHeartGameDev Man, if I change the movement speed, the character gets all messed up, so I created two variables for walking and running but that interferes with jumping a lot, so I removed it, how can I modify just the walking speed without affecting other parts of the code? public float walkSpeed = 3.0f; public float runSpeed = 6.0f;
@jimmyyu3383
@jimmyyu3383 2 жыл бұрын
It is great tutorial. Although the concept is tough for me, as a newbie, I am able to implement the concept. Here are my comments. 1. In the jump state, since I initialize sub state like run, I can then jump in the mid air and then press movement key. So long as the key remains pressed, the character would not fall back to the ground because the run state takes over and there is no gravity set in run state. To solve this, I have to delete the initializesubstate in the enterstate function. Honestly, I am not sure why I need to initialize idle, walk and run while I am jumping. Anyone who knows, please enlighten me. (if it is attack state, I can understand. I can jump and attack in the air). 2. Similarly, in the falling state, since we initliaize sub state, I can hit move key in the air (switch to run state), and then hit jump in the air. Without hitting the ground, the jump state (and jump animation) will take over (from run state) and it would not go back to other states (until I hit ground): meaning the jump update states will keep running and the animation is stuck there. So, again, I am not sure why we need to initialize idle, running etc in falling state, which allows the jump state to somehow sneak in. 3. Actually, Unity ThirdPersonController provides a function to do GroundCheck, which uses "physics.checksphere". I am not sure if this is better, but it works for me. Since isGrounded is required in a few states, in order not to "repeat" the same code in relevant state, it seems to make sense for me to keep it in PlayerStateMachine. This however raises a question to myself as to how to deal with such cases in an efficient way or in a "state" way. I am not sure if Interface makes sense since the GroundCheck code is the same for the relevant state. 4. For State Factory, I once encountered a method which uses "Add" and "Get" (to and from Dictionary) rather than "manually" adding new State in the Factory. It seems to me a better way (but harder to understand). For points 1 and 2 above, I am not sure if they are specific to my codes as I don't exactly follow the video. I basically adopt input method under third person controller (which uses PayerInputMethod and PlayerInput Manager). I also uses speed to control idle, walk and run situation (i.e. float, not bool). So, anyone who follows exactly can test whether he/she has the same issues. In any case, it is an awesome tutorial! Keep it up!
@jimmyyu3383
@jimmyyu3383 2 жыл бұрын
There is another issue I faced with "initialize sub state". This initialization actually directly goes into the "updatestate" of the sub state, which means that whatever I set in the "enterstate" of the sub state is not loaded. The result is that it skips some setting or parameters that are supposed to set up only once in the "enterstate". For example, I have a few idle animations, which will be run randomly after the character is idle for a few section. If I set the "idletime" in enter state, then in the update state, it would have the information of "idletime" i.e. it turns into zero. Then, a random idle animation is directly played when initiated.
@vima9046
@vima9046 Жыл бұрын
I have a problem with the characterController isGrounded property. It always return me false from the state machine class while true from the player state machine class even if i degub them in the same frame. Its looks really buggy and unreliable. Do you know why?
@wasdexe
@wasdexe Жыл бұрын
Even after fix i have alternating isGrounded state. Tried to debug it with simple code like void Update(){ Debug.Log(CharacterController.isGrounded); Vector3 testMovement = new Vector3(0, -9.81f, 0); _characterController.Move(testMovement * Time.deltaTime); } And it still alternating. Can`t understand why... Only switch to raycasting ground check fixed my problem.
@andrewknutson8584
@andrewknutson8584 Жыл бұрын
Hey man, I don't know what I'm doing wrong, but even following the tutorial 1 for 1, my character is now in a semi-perpetual fall in idle. My code is 1 for 1, and the animation conditions are identical. Got any thoughts?
@iHeartGameDev
@iHeartGameDev Жыл бұрын
Maybe root motion is toggled on in your animator component. A handful of other devs have had that issue
@andrewknutson8584
@andrewknutson8584 Жыл бұрын
It was checked on. Thank you!!!!
@andrewknutson8584
@andrewknutson8584 Жыл бұрын
@@iHeartGameDev I knew I missed something as a Newbie, but couldn't find it. Thank you!!!
@chrisredfield439
@chrisredfield439 2 жыл бұрын
So, after watching all of the videos up till now, I still have a problem, a couple to be precise, first I still get the swaps between true and false without touching the controls and I have checked the code over three times and I have no idea what could happen, second, if I jump the character just stays in jump state and doesnt change, it stays there forever, maybe I need to run more experiments but ATM I'm stuck, and last when rearanging the StateFactory i use the _state to name them but it appears that somehow it doesnt let me summon that _state and now I have 12 errors, which means I basically cant run the code EDIT: Ok this was quick, I dont know if this was like this since the beginning or if I'm just dumb but I literally just ticked the option "Apply Root Motion" to off and now the jumps and falling work, I dont exactly understanded what happened so if someone can explain it I would love it, I still have problems with the code for the StateFactory where I cant name it _states , I think it has something to do with the StateMachine but I dont know how I could tweak it If someone sees this or even IHGD I would apreciate and love some help, I'm still a beginner and some of this things are starting to get over me and I can't think of a solution
@davidffortesmeireles5328
@davidffortesmeireles5328 2 жыл бұрын
this is it good to slopes?
@SentinelAsset
@SentinelAsset Жыл бұрын
Great video thansk.There were a few issues that didn't work for me and I fixed it. Order of Operations Problem: For me the solution didn't work. According to my own project I fixed it as follows: PlayerStateMachine > Update => if (!_currentState.CheckSwitchStates()) // It checks if there is switch and returns bool. _currentState.UpdateStates(); You don't need to call CheckSwitchState() inside UpdateState(). So I deleted CheckSwitchState() in UpdateState(). But this time the sub-states input and output functions are not working and I solved it as follows. PlayerBaseState > UpdateStates => if (_currentSubState != null) { if (!_currentSubState.CheckSwitchStates()) _currentSubState.UpdateStates(); } I haven't tested too much, hope it helps you. 😅
@gamheroes
@gamheroes Жыл бұрын
You have strong academic skills as you explain features more clearly than people with 20 years of programming experience. Mate, you should do more videos Lists
@Switchboy1
@Switchboy1 Жыл бұрын
Why not just make CheckSwitchStates() return a bool true for when it has switched then do if(CheckSwitchStates()){ return } Then order of operations does not matter.
@hurshwardhannashine6128
@hurshwardhannashine6128 2 жыл бұрын
Hey Nicky, It'd be really cool if we could work a little to make it more inspector friendly. for example being able to see the current root and sub states, current states
@draconhawke4737
@draconhawke4737 2 жыл бұрын
I would like to see some attack states (kicking, sword swing, punching).
@iHeartGameDev
@iHeartGameDev 2 жыл бұрын
Me too!!
@ponix1004
@ponix1004 7 ай бұрын
public override void UpdateState(){ if(CheckSwitchStates()) return; // next line } public override bool CheckSwitchStates(){ if(condition){ SwitchState(~); return true; } // other conditions ... return false; }
@masterz0
@masterz0 2 жыл бұрын
Could you share the repository? 🙏
@tomdriver6733
@tomdriver6733 Жыл бұрын
How can I add shooting?
@nm-hd8rr
@nm-hd8rr 2 жыл бұрын
I would think that if you are caching the states, then you have a singleton pattern.
@mailmaxxxx
@mailmaxxxx Жыл бұрын
Not really. the singleton pattern would return an instance of the state from a static class function - so it would not be possible, ever, to have two instances of the same class. But just because the Factory caches _its_ instances doesn't mean some other class couldn't instantiate a state (for some reason). I know it's kinda semantics - but otherwise you could argue that if I only happen to ever instantiate a particular class once in my game, then it's a singleton - which clearly isn't the case.
@chuenyauho3693
@chuenyauho3693 2 жыл бұрын
If an unity tutorial didn’t have enough information for the beginners to rebuild in others unity, it is meaningless
@hosseinse4079
@hosseinse4079 2 жыл бұрын
i am still wonder why unity support you
@alanyoung4256
@alanyoung4256 Жыл бұрын
Just stumbled on this great series and already learning a lot of new techniques, thanks. One issue I noticed was that if you jump then hold the run button before you land the player moves at the run speed but the animation is the idle one, pretty cool but unintended. After a little digging I noticed that when the switch from the JUMP state to the GROUNDED state happens and the sub states are initialised in PlayerBaseState.SetSubState the EnterState of the sub states are not called and this is where the run animation is started. To fix it I simply added an EnterState() call so my PlayerBaseState.SetSubState looks like: protected void SetSubState(PlayerBaseState newSubState) { _currentSubState = newSubState; newSubState.SetSuperState(this); newSubState.EnterState(); } Not sure if this is the best method, as I'm still getting my head around the whole HSM design, but it works and now my character starts running as soon as the jump lands. Nice :)
@jasonfurr2272
@jasonfurr2272 2 жыл бұрын
Convert CheckSwitchState() to a bool, return true if switching, and use if (CheckSwitchState()) return; in the Update
@user-aaaabb
@user-aaaabb 2 жыл бұрын
check your email or spam pls
@user-aaaabb
@user-aaaabb 2 жыл бұрын
check your email pls~
How to Program in Unity: Third Person Movement Explained
11:31
iHeartGameDev
Рет қаралды 32 М.
Smart Sigma Kid #funny #sigma
00:14
CRAZY GREAPA
Рет қаралды 103 МЛН
Yay, My Dad Is a Vending Machine! 🛍️😆 #funny #prank #comedy
00:17
Do This Instead Of Representing State With Booleans
12:23
Joy of Code
Рет қаралды 115 М.
Procedural Animation in Unity: Environment Interactions [FINAL]
33:06
iHeartGameDev
Рет қаралды 3,2 М.
Unity Devs, don't forget THESE if your game has animation!
9:41
Jason Weimann (GameDev)
Рет қаралды 10 М.
Starter state machines in Godot 4
10:58
The Shaggy Dev
Рет қаралды 63 М.
Build a Better Finite State Machine in Unity
20:58
git-amend
Рет қаралды 25 М.
The Most Impressive Scratch Projects
11:00
DenshiVideo
Рет қаралды 5 МЛН
When to use Factory and Abstract Factory Programming Patterns
12:13
Creating a Cheat Console in Unity
9:46
Game Dev Guide
Рет қаралды 86 М.