Better Coding in Unity With Just a Few Lines of Code

297,558
0
Published 2020-04-02

All Comments (21)
  • @Zicore47
    State machines are great, but they don't reduce spaghetti code. In all your examples you could invert the ifs and return early to reduce nesting. Also keep in mind that virtual methods can add a performance overhead. Stick to KISS and composition over inheritance. Still a good tutorial for learning the concept.
  • It:s not a bad approach but it can devolve into an inheritance hell with 30 classes for something. If you wanna keep things simple, you can do the same by just organizing your code well with functions. A different function will be called depending on the conditions. So you will treat functions as objects. Also, don't have variables like isDead or isJumpinh. Have functions that return the result instead (e.g. isDead() returns true if HP is 0). That way you avoid setting the state, you always have it ready.
  • @Gortart
    You generally don't want a seperate class with just 1 method to override because you can just use delegate. And rather than returning a new instance of the state, the states should return a state flag that the caller should use to look up what to do next. Enum with a dictionary to look up would work well. And this is not really fixing spaghetti code. You would have to constantly make seperate classes for each new state as you add mechanics. If you added silence that stops some of the abilities but not all, you would have to make IdleSilenced, JumpingSilenced etc. The player should have some kind of attack timer and shouldn't be able to attack every frame. So should I make IdleCanAttack even though some attacks are only possible while in the air? Or name it IdleAttackTimerZero and have quite a bad time writing them down all the time? How do you even manage going from JumpingSilenced to IdleAttackTimerZero? At some point you HAVE to use nested ifs or you're just gonna make the state list grow 2x times each time you add something. In the given example, the isDead check should be at the very top of the update method and just return if the player is dead(or just do some being-dead logic then return). Checking isGround and isRunning could be quite confusing and you can add get-only property(something like CanUseBigAbility) and just return isGround && !isRunning. It's pretty much the same, but it's a lot better to manage. Spaghetti codes are bound to appear in any kind of complex system. Coder's job is not to eliminate them entirely, but to contain them in a safe box so it doesn't spill to everywhere. And haha your mom joke funni yes very funni
  • @polarisinglol
    Awesome video! I recently got into Unity due to an assignment in my University which will be graded and am really loving it so far. Even though I already knew most of the stuff in the video I have to say it was a pleasure to listen and watch and I think you definitely helped a lot of people who are just getting started with programming languages and coding in general :) Thank you!
  • @ZeroSleap
    I believe the CharacterState would be better as an Interface,as there's no real reason for a base class implementation of handleInput. Plus the interface route enables inheritance of another class or interfaces. If a base class implemantation of handleInput is needed,an abstract modifier for the CharacterState class can be used instead.
  • Men Please I want a bunch of Tutorials on State machine pattern programming, You're now officially my fav Youtuber. keep doing this stuff a lot I love it! :)
  • This was extremely understandable and helpful. State management seems to be one of the trickier initial hurdles in Unity, so I think your subject matter was on target as well.
  • Spent the past week having a headache and a half trying to fully implement a state machine. And damn you just alleviated my headache.
  • @seb6861
    I still don't consider my self a game dev until i could make at least one game and not just little project that i do to learn different stuff.
  • @TGameDev
    Imo you could also save the headache by implementing functions and guard clauses. So for instance that nested nightmare would look more like this: If (isDead) return 0; // he ain't moving anyways If (!isGrounded) return 0; If (attackPressed && isIdle) attack(); // Etc... also, to those curious you don't need brackets if there's only one action following the statement. Notably a break or continue (in place of return) work better in certain scenarios, such as being in a for loop. Hopefully this helps.
  • @7oca7hos7
    Well, idk. I think using oop for this problem is a bit of an overkill. You just could have handled all the conditions inside the attack() function, using boolean operators and the return keyword to avoid nesting. The user presses the attack button, then the function is triggered and it checks the conditions for doing the attack. In this way you have all the conditions in one place for that specific context, making the update function much cleaner. I think also that the code will be easily understandable for other people, and for you too when you'll read it after a while
  • @LordBordNoob
    Much like others have said, using enums and a dictionary with delegate functions is a much better solution to this. Or simply having functions that take care of each behaviour. If you constantly assign new objects and get rid of them like this on the fly, you will inevitably cause more memory fragmentation and a much bigger overhead for the CPU and the garbage collector. The 'new' keyword is something that should be used only when there is nothing else that you can do.
  • @thatoneuser8600
    12:28 that conditional statement looks like something that could easily be duplicated across multiple states, which isn't a good thing. It also violates TDA (Tell don't ask principle) where you're querying the state of Input and performing operation based off of the returned value, so to me, it would make sense if the update state functionality based off input would be in some update method in the Input class that returns a state, depending on the factors you require for it to return the proper state. Then, all you would do is return the result of that method in handleInput()
  • @martinmica4260
    I love how slowly you explain stuff. It easy to understand the point :))
  • @3_14pie
    You have no idea of how much this video changed everything for me
  • @magnusm4
    I've seen Table Flip Games's tutorial and the great Unity finite state machine tutorial. But honestly it's really complicated. You send a new state from another state, which I honestly find scary to land in a soft lock. Flip Games makes a Finite State Machine class that handles everything and makes a reference to it in his main player class. And the guy in Unity's version he handles the current state in the player's main control script. And even has a function for transitioning to a new state where he sets the new current state and calls Enterstate, passing in his player class so that the state can access his Rigidbody and move it from the state.
  • @kreed1415
    State machines rule, however I would suggest you look into a more efficient solution that has less boilerplate code. If you have to create a brand new class for every state it gets incredibly tedious as your game grows. Consider making a StateMachine class that inherits from monobehavior that has a dictionary of which represents state then simply run the method for each state. it also makes declaring each state very simple and concise
  • @matthewmathis62
    Wow! You just revealed the state example, and it makes sense. It's a good way to write code. I like it! I'm glad you've said this, because I'm sure that I've written spaghetti code before. Coding is one of my favorite things to do, because it's so fun! And I appreciate you taking the time to make this tutorial. I would like to all of the concepts like the one in this video, shared conveniently in one YouTube video. Perhaps you're up to the challenge? Hopefully someone is. Thanks,
  • IDK, I think this boils down to whether you want your code to "look pretty", or you want a more performant/optimized game. This approach would probably be much more expensive than other options... certainly more expensive than nested 'if statements' checking conditions. Or just use a 'state' enum, or a single 'PlayerState' class. No need to over engineer anything.