While your approach is certainly better than doing it all in one file, it still has a lot of dependencies. That is, the movement script still needs to know about the player script AND the input script in order to move. In some ways, you have actually made the dependencies worse, as everything now relies on the player script as well as any script that they would have relied on had you just referenced them directly. The only difference is they are getting it through the player script rather than accessing it directly. While this does have some positive implications for inheritence, as you can now specify subclasses in the player script and have your other script use those subclasses instead, there are still (in my opinion at least) better ways to do this. I would recommend making your scripts standard C# classes, rather than monobehaviours. This will lose your ability to drag and drop, but the benefits of having access to the constructor are worth it. Then, I would recommend passing in any needed dependencies through said constructors, creating (and passing) whatever is needed in the PlayerScript's Awake() function. For example, if the movementScript needs a character controller to move, it would be passed in as a constructor argument and assigned to a private variable within that class. By using this method, you can have your movement functions completely independent from input (and other scripts) entirely. This is good for things like code re-use, as your movement controller can now be used completely independently of your input source. The player script would be responsible for telling the objects how to move (by calling relevant functions in the movement controller) based on some events from the input controller. This way input can simply send events, no questions asked, the player can catch those events, and trigger movements based on them. Your input system can then be reused by any other monobehaviour that needs to capture input events, and your movement system can be reused for any charactercontroller independently of input (such as moving characters as part of a cutscene). You can even use interfaces or abstract classes here to completely overhaul functionality, something you can't do using monohebaviours since the unity inspector doesn't support interfaces at all. The only drawback is you lose drag and drop and instead have to create the other classes manually as part of your player script, but I feel the benefits are absolutely worth it, especially since you never have to worry about script execution order or any other unity shenanigans, and your object component heirarchy doesn't get bogged down with monobehaviours which really only exist to implement functionality and don't have/need options (they could all be set on the player component instead and passed to systems as needed instead).
This feels like a waste of time, at least for me. You have one example of it being useful, that of cutscenes, where you would for some reason need to move the NPCs exactly like the player. But that is super niche. And I can't think of any scenario that it would be useful to have my player scripts specifically undependant on each other and not monobehaviour.... It just doesn't make sense. For other things sure I can see the benefits immediately, but not this...
@@NeonValleys Is it super niche though? If your movement code is separate from your input code, then you can re-use it for every character controller in the game - meaning your player(s) and your NPCs can all move in exactly the same way using exactly the same code - in the player's case, the movement is driven by inputs, and in the NPCs case, by AI, but in both cases they can use the same MovementController class to handle the actual movement, resulting in far less re-implementation of movement across multiple systems. Using the model in the original video (AND the model commonly used by a lot of Unity tutorials), you would have to code movement twice - once for the player and once for NPCs. The reason I mentioned cutscenes is because this is a less obvious benefit - not only can you control NPCs and the Player using the same code, but you can essentially turn the player into an NPC and bypass input entirely when you need to, such as in the cutscene example. If you can't see the instant benefits of this, I don't know what to tell you.
@@pt8306 I think so yes. It's only a very particular kind of game where you would even want the player and NPCs moving in the same way to begin with. And losing the ability to use it as a monobehaviour isn't worth it for something like the players movement and NPCs movement, especially for newer people learning from tutorials. It's absolutely useful to learn about using standard classes and interdependent code but not for something like simple player movement tutorials.
@@NeonValleysIt's the same if you wanted things to have health in your game. Your player has health and can take damage, but so can an enemy, an explosive barrel, etc. You are going to want the health system to be the same across all these objects, but not have to write the same health code each time you create a new class. That's where this inheritance method thrives. When you want a mechanic that works not just for one object, but many different kinds of objects, you create a c# script that is modular, and can be attached to any object. But you can't do this if your scripts all rely on one-another to function. There are lots of methods of doing this and I'm still learning to implement them myself -- but in short: modular, decoupled scripts are crucial to a game project's longevity and scalability.
I attempted to break up my code following your video and failed the first time, 2 hours of work and I almost gave up.... But I kept trying and actually did it, I have clean code!!! I learned a lot and I'm inspired learn and code more. Thank you :)
That's epic! These things can be fiddly to setup the first time, but once they are in place they are a good foundation. Well don, all the best with your next steps on this journey!
For the record, whilst messing with script execution order IS a solution, it's a terrible solution. Mostly because it's something you don't see in the code, so problems linked to execution order are horrible to debug. And if someone else goes and mess with execution order (granted, that kind of problem doesn't happen in a solo project) you're up for a headache. GetComponent references should always be done in Awake, and pretty much any other case where you'd want to control the order in which some things happen can be dealt with in code with an Observer pattern.
@level90s still not a good practice, as you can’t use variables inside of your attributes, and attributes are not debuggable anyways. But hey at the end of the day it’s just a matter of good vs bad practice and if it works for you and the people who work with you, nothing is forbidden
Or, you can also go the normal sane way and simply have FULL control over the order of initialization, execution, life, and destruction of your objects. Relying on awakes, starts, and updates in individual components of individual game objects is needless and slow. To do this, you only have one Start() and one Update() in your whole project. In the Start(), you initialize everything, depending on any arbitrary conditions required and in the exact order as required. And the Update() becomes your main game loop, from where you call any other systems and entities and whatever, again, in the exact order and with the exact conditions your game requires. Heck, even Unity themselves preach this.
Good job highlighting an important topic for making your Unity code more manageable! There's also a third method, which I prefer, of controlling the execution order of Start() functions of parent-child scripts such as those shown in this video. In this method you leave the parent script's start code in the Start() function, but rename the child scripts' private Start() functions as something else, such as public CustomStart() so that Unity will no longer call them automatically. Just remember to make the custom start functions public so you can call it from another script. Then, you can call the CustomStart() functions manually in your parent script's default Start() function. This way you have total control over the script execution order, and can even have the custom start functions called in the middle of the parent Start() function, exactly as you deem necessary.
what the heck... if you don't want unity to automatically call Start, just don't tag this method. Incredible, right? I understand that you received information about Init, but something clearly went wrong)
@@sweeepeeee The point here was that you DO want Unity to call Start(), but only for one object. That object then calls the other objects' methods that would otherwise have also been Start(). This way all these methods get called at Unity's "Start() time", but you get to control their order.
Very interesting video, but I think you are making a circular reference. I suggest for decoupled and performant code: 1. Store your input data on a scriptable object, and then reference only that scriptable object in your movement script. This way your InputClass writes data to the scriptable object and your MovementClass reads the data inside your scriptable object. 2. Try to not use an update() on each of your scripts, instead, call your function OnUpdate() and create another script (UpdateManager) that handles all of your scripts that need to run on Update(). For Unity it's better to handle one Update() that do a thousand of things that a thousand Updates() that do one thing.
@@unitydev457 It would make sense that its faster since Start(), Update(), FixedUpdate(), etc in monobehaviours utilize the messaging system I believe, which is slower. Though by how much? You'd have to profile and see for yourself if it's worth it for your specific device and circumstances
@@pokoro97 In very small games, you will not see any difference. In a game with 2000+ game objects, each having 4-5 components, each having an Update() function, this becomes a thing, clearly visible in the profiler. The reason is that these "magical" functions are invoked in C# from the native code, and the marshalling is slow. Invoking a single C# Update() function in the whole project, and then from there calling whatever needs to happen within C# is way cheaper. What Andersen suggests makes perfect sense, of course. Not only do you gain performance-wise, you also have full control over the order of things, in a very natural way. The single Update() function becomes your main game loop, and then nothing prevents you from calling whatever code in whatever order with whatever conditions your game requires at any point. This is pretty cumbersome and error-prone via individual Updates().
1. It is not a good idea, because the scriptable objects stores data outside of play mode. So if you change value in the scriptable object then the file gets modified. So version controllers will see changes in the file every time you enter play mode. 2. Unity update works with reflection but it stores it. It is true you can get some plus performance if you have 1000+ objects with updates, but other way it doesn't really matter. We don't need to optimize everything, but just there where we have performance issues. (For loop always better in performance, but we use lists as well)
@nonododo69 I heard about this, someone once showcased scriptable objects behave differently when using the unity environenment vs actual deployment on a platform when the read / write privlages actually kicks in.
I am new and reading over the code you provided. Could you explain why in the player script isLeftPressed and isRightPressed is declared as private, but in the input script they are declared as internal. You make that distinction several times in the code, what is the point / rule of thumb to keep using this practice?
Clean code is actually undervalued in indie game dev. Having object-oriented analysis and design skills really helps you to build the game and it will save you from hours of work.
Cause a big part of Unity community aren't developers. They are video game enthusiasts. They don't know what is clean coding, separation of concerns, DRY pattern, encapsulation, etc.
@@Alieldinofficial Yeah, but it is not about how good the game. Its about the behind the scense of the game. Without clean and well designed code- your game would not scale. Your bugs will require much more hourse of your time, you will not be able to reuse functionality you already wrote, it will be way harder for new people to understand what you did. I never understand why so many people insist on defending factually bad work habbits
RUclips 3 hrs after upload decided to break the Audio Sync on the video. I'm just re-uploading a new version that will be linked here. Sorry for any inconvenience.
I'm sorry if I'm wrong because I'm a beginner still, but it seems a better way of ordering these particular scripts' executions would be the following: - Disable the input/movement/collision scripts by unchecking their boxes in the inspector. - Enabling them within the player script's Start() function by using playerMovementScript.enabled = true; playerInputScript.enabled = true; etc. This way the Start() functions of each script can be manually run and code could even be run in between if needed. Also it's much clearer what's going on because you don't have to use the unity settings window to figure it out. Lastly ,for me and assumedly all beginners (and probably long time unity users too), the way in which Awake(), Start(), and Onenable() act is very confusing and difficult to remember, so here's a useful pair of links I'm constantly going back to to help remind myself. docs.unity3d.com/Manual/ExecutionOrder.html answers.unity.com/questions/372752/does-finction-start-or-awake-run-when-the-object-o.html (this one's more confusing even) answers.unity.com/questions/217941/onenable-awake-start-order.html
I took this a step further. There are 4 components coupled together here. One method that worked for me was creating super generic components. Specifically, I have two components. "SimpleMotor" and "CircleCaster". Either of those can be attached to any game object. SimpleMotor moves the object every FixedUpdate based on its MoveDirection. CircleCaster performs a Physics2D.CircleCast and invokes a C# delegate when something is hit. Now, you can create your more player-specific script and just set the motor's MoveDirection when input occurs and a collision occurs. Or, you can create AI that is totally independent of a PlayerInput scripts. It has worked VERY well for my project.
Thank you. I learned to program not too long and the term of pumping everything into a single class was deemed as the creation of the blob God. Now knowing how to separate the player controller, I will try and write better code.
I just discovered your videos and like most people here I'm so grateful you put so much emphasis on quality. While there are channels out there that use concepts of quality code, very few teach them. Thank you so much. I can't wait to learn more!
The best part of this practice is that you can reuse components like for example movement if your player controller and an enemy controller inherit from a unit controller script so you can have a unit controller field with either a enemy or player controller script in it. Now both your player and your enemy will be using the same movement script but they'll be called by an input script for your player and an AI script for you enemy, aka you have a bunch less duplicate code.
Thanks a lot man! I am a programming noob myself and often run into problems because I don't exactly understand yet how I'm supposed to structure my code. Your video made that much more clear!
Your videos are so helpful my dude! moving from a web developer into game development it drives me mad how little information there is on good structure and best practices thanks again! :D
How did you directly answer my question about script structure the day I thought to ask it? Awesome! You confirmed my thought process isn't crazy and stupid.
This is a very important concept to learn. The only thing I'm not liking quite in your code is that you have references in both directions. So Player Script knows of the Movement Script and Movement Script knows of the Player. It would be cleaner to have it only in one direction. Called a layered architecture. And components only grab things in layers below them, not above them. So for example the Movement script is in the top layer and the player Script in the one below. The communication between Movement and Input would then work that both change/use the Player Scripts state (making it a Model and having a clean MVC architecture). Regarding what you are calling spaghetti code: this is only a problem when you do it manually. This is where controllers come into play. You create a player controller that injects all the dependencies a subscript needs. So for example Movement Script uses Input Script. Then the Player controller injects this dependency (Input script) into a setup method of Movement script. I know I'm biting myself a bit with mixing layered arch and MVC, but my point is let's try to only use unilateral dependencies. :D Sorry this got long and hope you could follow me at least a part of the way. Great video though.
Great tip! I've started my own game recently and have heard a lot about splitting code up into different classes like this but wasn't sure how it would be done. This video helped a lot! More like this please, and post on reddit - gamedev or unity or whatever I'm sure others would find this useful :)
Really glad you liked it! I think it has been a difficult area for unity users due to how the component system works. But the benefits of separation is worth the work to make it happen! Completed sample project linked in the video description if you needed a closer look! :)
Hey great vids, youtube was absolutely right in suggesting you to me :-) here's an immediate sub. One interesting other approach to take is to have one component (playerscript) internally reference interfaces (IInputController, IHealth, IMover) which are pure C# interfaces. This allows to use the PlayerScript component as entry point for game loop callbacks, and hold global configuration, and have the logic happen in dedicated implementations, which you can adapt and even interchange if the game mechanics calls for it. It's a different approach, obviously, which may or may not be better depending on the use case, but it has the advantage to make for less granularity in your components, which once an object starts holding lots of logic, helps overall readability and usability.
I do this in my game, but with an extra layer. I have "entities", which are effectively pure C# game objects with built-in functionality (such as an inventory with AddItem, RemoveItem functions etc), then I have "controllers" which interact with these entities based on things like game state, then I have my MonoBehaviors which create their own instances of controllers, passing in any entity references as needed (sometimes entities are ScriptableObjects, sometimes not). This allows complete control (and replacement) of things like game rules while keeping object interactions not dependent on each other for functionality. This video means well, but this approach actually increases dependencies rather than reducing them, and will cause issues longer term for many people. It's better than doing everything in one file, but still has it's own share of issues.
You can also put the scripts on children and parent always fires first, i think. So i would make a child object called "Collider" and put the script on there etc.
In my opinion script execution order is good only for attaching libraries and some extensions. Better way for this kind of problem is to create in root "PlayerScript" FlowManager that will have Awake, Start, Update, ect. methods and have a custom order of IUpdatable and so on components within. It will give a nice order control and will be opened for any extension you need later on
Just for some clarity, the values in Execution Order are arbitrary and don't represent time passed. You can use any values that you see fit, as long as they values are in the order you want. You could use 1, 2, 3, or 100, 150, 200, or whatever. It simply executes them in numerical order from least-first to greatest-last, and the gap between values doesn't really make any difference.
In your dry section you could have also allocated the rigid body as a private lambda as Private _playerRigidbody => playerScript.rb2d.velocity; in this case the _playerRigidbody is acting as a delegate stating when this value is used I need you to pass information to or from this path, in this case it does not matter when the Awake/start functions run and you can pass the new vector 2 all day.
The collision script, it has to know that the player script has a ChangeState function that is looking for "Player_happy" or "Player_sad". What if you wanted to use this collision script on an enemy character, or a bullet, or a crate? A follow-up video where you take this concept to the next level would be cool. There are a couple of different ways to skin this cat, maybe you could discuss the pros and cons of each.
This is really helpful as I'm trying to add new thinks to mechanics but as my code mix input, animations, states, movement, etc, is kinda hard to add new things, now I'm going to start again, separate every aspect and try to make it work that way
Well of course separating the codes that are not related to each other is a good thing to make codes cleaner. But what do you do about the performance? Imagine having 1 unit that have 1 script for controlling its behaviors. In a scene you have 1000 of that unit which means 1000 times Update/LateUpdate/FixedUpdate and so on. Now you split the codes into 3 scripts. 1000x units * 3 scripts = 3000 scripts. I'm just saying this to see other aspects as well. Maybe I'm wrong.
Nice video .. events/delegates would be better ... but as it is for beginners this is a nice intro as to how t get things to work and a bit easier to understand . the most important thing is to create your games and just like with everything else you'll get better and find new ways to do things
I have mixed feelings about this approach. But before I delve into this, I'd suggest adding "[RequireComponent]" attributes to each script so that adding one of them to a GameObject automatically adds the rest. Declaring the references as internal hurts my eyes a bit, since in the context of a Unity script that's essentially making them public. I was going to suggest a slightly different alternative but I'd rather actually test it beforehand in case I'm missing something.
omg you started right, but you did it wrong... all you did was just to split the PlayerScript.cs into 4 different files, but they are still highly dependant each other. I mean you changed the player state from the collision script! in order to move your rgb you check the InputScript inside the MovementScript. At 8:37 you said "dispatch" but you did't use any advantages from an event system, which is the right solution to decouple the components.
Hi! Thanks for all your sharings. Got a quick question: In your architecture, there is some benefits of using SerializedField variables (so you need to drag and drop scripts instance like you did) instead of using a GetComponent method to get the references of the other scripts? Hope I'm clear. Thx
Instead of referencing the other scripts we could had used it inheritace right? Using inheritance in that case would provide a gain or loss in perfomance? ou none difference at all? BTW, great video, thanks.
Inheritance does not have an impact in performance, however Inheritance is the last resort in OO programming. Composition is more important than inheritance.
Why inheritance? It doesn't make sense. Are you saying you want the 3 other scripts (Input, Movement, Collision) to inherit from manager (PlayerScript)?
At the time i believe i was thinking playerScript inherit from the others. But you are right, it doesn't make sense. But what i really wanted to know is if there are any methods differente than communication that will result in a gain of performace.
Can you clarify benefit (and cons) of manually defining references between components like that - over alternatives? For example alternative is for each of those components to get and cache reference to other components it needs to interact with? Although I would actually have this inverted (object dealing damage would handle collision trigger and check if other has HandlesDamage component) ... Following your example of checking collision on the Player side - component handling collisions can do something like: void Awake(){ Health health = transform.GetComponent() } private void OnTriggerEnter(Collider other) { // Anything that DealsDamage will have this object DealsDamage damage= other.GetComponent(); if (damage != null) { health.ReduceHealth( damage.damageAmount() ); } } Without tightly coupling it to specifically Player allows reusing same components (e.g.: Health, DealsCollisionDamage, HandlesDamage) also on Enemies/Buildings ...etc
Just curious why are you using internal access modifiers for the variables? Is there some reason that you'd want the scope limited to that assembly unit over just limiting the scope to the class with private?
I am very new to programming and what experience I have is from long ago in Basic and Fortran... yes... longggggg ago! If I follow the discussion, when you talk about breaking up code... is this similar to earlier times when you would use structured programming and put routines that would be used repeatedly in a subroutine that could be called as needed or am I missing the point of this altogether?
I try to avoid Awake and certainly Start as much as possible. I instead have OneTimeSetup (for Get/Add Component and the like) and Initialisation (resting variables etc that can be called between levels/restarting the game etc) functions that I call from whatever the root class is via its Awake function. I then have complete control over calling order and its obvious in code what that is. Also for separating out the functionality - this approach still leaves a lot of dependency. Maybe events would be a better option?
really interesting. thanks for sharing. even if i'm absolutely new in this wonderful world, i found this tutorials really intelligent and logic. this HELP a lot for who want( like me) understand and study. thanks.
What I learned from my lags Do not separate variables that stores data for a method By making reference to another Class I think I should link scripts that only "invoke" methods As possible
Hi mate, this is for convenice. Using internal will hide the value from the property inspector, yet allow puplic access from other scripts. Saves one adding meta tags to from inspector. :)
I'm confused, at 7:30 we see the PlayerMovementScript is calling the PlayerInputScript, albeit indirectly. I thought we wanted to eliminate the back and forth between them? Wouldn't it make more sense to have some public methods on the input script like IsLeftPressed() and IsRightPressed() which simply do something like "return Input.GetKey(KeyCode.D)"? Then expose some methods on PlayerMovementScript like MoveLeft() and MoveRight(). Then inside the PlayerScript Update method we could use the methods on the input controller to check for input, and if they return true call the movement controller methods? That way the input and movement controllers aren't communicating at all.
I'm a newb but so far, I've always heard that you should only mess with script execution order as an absolute last resort when you have absolutely no other option available. I can imagine that if a project gets larger, it would be an absolute nightmare to maintain, especially if multiple people are working on the same project.
how can i use this way for unityEvents ? like if i have a collision detection script that fires an event , do i add another unity event on the Player script and link the two events and make the other scripts listen to the Player script event?
Wow, that is actually very useful. Im very impressed by your videos, they truly are beginner friendly. Also im suprised you dont have as much views as for example Brackeys which videos are in my oppinion much less useful than yours. Now that's an instant subscribe and Blood and Mead wishlist my friend! Also i have a question for you. Could this problem with start method execute order be solved with static method? I could be wrong but i think that static methods are called before non static.
Hey man, thanks so much for the kind words. RUclips has a strange algorithm thay often doesn't reward the small channels. I'll keep pushing on though! Thanks for the sub and wishlist. Come by the discord some time, great place for getting help and sharing progress, it would be a pleasure to have a person with your positive attitude part of the community. Regarding statics, they are sort of bad practice generally, and used more for global referencing.
Great video! Help me: is script separation just about ease of read, or does it improve the performance of everything related to the object? For example, are collision detections weighted down by long scripts, leading to errors, or is it immaterial? Thank you!!
separation will always be less performant than having everything in one single component. This is neither about ease of read (well yeah partly but not essentially), nor about performance, it's about scalability and architecture (single responsibility principle). Referencing other components has a cost, although negligible (unless you do a GetComponent in update... always cache component references in Awake). It's never going to be more performant. The main problem of long scripts is indeed readability, but also changing one small thing may impact the rest of the code. That's why there's the Open/Closed principle and the Single Responsibility principle.
I don't really think it's about performance but more about having a good game architecture. But doing this doesn't bog down your performance in any way either. It makes it more organized rather than having a single monolithic class full of variables and if and else statements(which is extremely hard to manage). Which means it's easier to work with so you don't run into any problems in the future. And I emphasize on "The Future" because it means your code is going to be a lot easier to work with when you add more logic into it. Sure, you can get away with being very careful when handling your scripts because you are the developer but that's not gonna work in the long run especially if you work with other people. Sorry if that's too vague tho. I can't really think of an example right off the bat but script separation is a really simple way to help with just writing great code overall.
Is there a way to use "using x" or maybe an "import"? Having done a lot of scripting in other languages there is always a way to make the hierarchy work, but I am new to C#. So basically I am wondering if you can include or use other scripts at the head of a main script so they can be used. I saw another good comment about making use of an interface. I would be interested to see if there are other good ways of implementing this so that it is more programmatic and less configuration based.
Incredibly helpful stuff! When it comes to related functionality, I might be tempted to construct those sort of sub-MonoBehaviours from the player script without attaching them to any object. But I also have generalized scripts, like "Expire" or "BounceOffBoundary" which are unrelated to the main object type controller script for which the order of execution might be important. I guess I would try to design things to be as loosely coupled as possible, but. That sort of effort is always attempted and never 100% successful, isn't it.
I try to seperate the player into a player movement controller and an entity controller, so the entity one can be reused by enemies and NPCs, and the player controller listens to messages from the Input System’s Input Controller
I was confused as to how the collisionscript doesn't just create a new instance of playerscript when it creates it, but I understand now that it all has to do with connecting the serialized fields to each other. How would this normally be done in C++ I wonder? Passing playercollision what it needs through parameters by reference so it can change things in the manager?
could I use inheritance in situations like these or a static class for the main player script maybe? I’ve gotten into programming in unity recently but I’m not really sure where to use all the different methods, maybe a future video? great tutorial btw, I like these raw videos
Thanks for the informations I wonder is there any way to assign all those three scripts ( movement, collision, input) to main player script via player script itself without doing them directly from inspector. And if so ,does it keeps the scripts order ? Again thanks for the video
Very informative, thank you! Have you found any performative issues with separating the script other than the firing order? Conversely, have you found that this approach makes the project better performing? Thanks again for all of the time you put into these videos!
By setting how many ms before a script runs, can't that potentially make your scripts run slower than they could since they have to wait a certain amount of time?
Hey I don't know if your still looking at these comments but I noticed in your code you often use internal as apposed to what I often see which is using public or private as a variable prefix. What is that doing exactly and how does that differ from the mentioned public/private?
as 3rd possible solution to the null reference problem produced by the scripts firing time: could we declare the children scripts (input/movement/collision) Start method as a coroutine (IEnumerator Start() ) and use WaitUntil to wait for the PlayerScript to initialise its variables?
Hey! I found this tutorial really helpful, but got me thinking: what do you think of using inheritance in unity? I.e.: a character class (that then has player and enemy childs) who manages the basics, like health, death and rigidbody basics. And how could you work both splitting the code and using inheritance?
This is a bad practice, the best solution is using code Inheritance. You make each code dependent on the others, in your example PlayerInput will depend on PlayerScript, PlayerMovement will depende on PlayerInput (which also will depend on PlayerScript) and so on. Also using code inheritance you can make a base script for several other scripts. A "CharacterHealth" script can be based to be used for the player, enemies, player allies, etc.
You structure now depends on however you set up your components (correctly) in the editor. Why not just create simple classes, that get spawned by the player component, get a reference to the playerscript in their constructor and get processed every on update? Less error prone than adding and referencing separate Unity-components.
Hi, Great Tutorial and I subscribe to your channel. Thank you. Can I ask a question about the separation of code you point out in the video? Like in the process if the children want to talk to other children they need to communicate first with the parent is that right? Or can I just like if the movement needs the input, I just listen to the event of input directly that can be set in the movement awake/start? And also the rule is all the reference component will be int the parent and the children cannot communicate directly in the other children? and the last question can, Is having a code like for example the parent have input and movement script, the input fire, the input pass the data in parent, for example, a left button and the parent have a logic to determine if what function in the movement to call, is this code okay? or I need only the parent for referencing the children?
Can you please explain how to utilize these scripts? There are no tutorials that I find that use this sort of separation between scripts so I don't know how to call a function from another script. I'm VERY MUCH a beginner and I would like to use this just to keep things organized from the start.
I don't think this is actually good design. If you go and find official Unity demos I think that's the best place to learn how to write clean code. Some of them aren't great but IIRC the input system video with the cartoon Viking does something similar to this video but doesn't create the upwards dependency by having a player script reference in the delegates. It's a small demo so you should be able to learn from it.
There are a gazillion videos here on RUclips covering how to call functions from other scripts in Unity. Just search for "unity call function from another script" and you'll find loads of them. The most important part is that the function you want to call from another script should be public. If it's private or protected, then other scripts won't be able to call/access it.
Hi! Thank you for your help / explanation. I did something similar in my project, but I had some problem when my "backend or business logic" needs some aditional information from the User/Ui. Could you give me some advice regarding this? (Example: 1) the player plays a card, which is an upgrade card 2) then the card logic needs an additional information which reaource the player wants upgrade.) I have a working solution for it with async tasks methods, but it looks ugly and hard to debug. Im sure there should be a better way, but I dont know it yet. Thanx in advance if you answer.
Hi there. This video is very informative, at least for me since i started to seriously learn Unity / game dev. Also, do you have any tips regarding what does a junior game dev needs to know? I am planning to apply for a position in the field this year and i would appreciate some tips.
Well, technically, the Component architecture is a form of DI There are DI frameworks for unity. Zenject is the most popular afaik. However it doesn't play well with Unity's general architecture, essentially you're putting a DI framework (classic DI) on top of another DI framework (Components). As for script execution ordering, actually this is bad design. Never reference other components in Start, ALWAYS do that in Awake
While your approach is certainly better than doing it all in one file, it still has a lot of dependencies. That is, the movement script still needs to know about the player script AND the input script in order to move. In some ways, you have actually made the dependencies worse, as everything now relies on the player script as well as any script that they would have relied on had you just referenced them directly. The only difference is they are getting it through the player script rather than accessing it directly. While this does have some positive implications for inheritence, as you can now specify subclasses in the player script and have your other script use those subclasses instead, there are still (in my opinion at least) better ways to do this. I would recommend making your scripts standard C# classes, rather than monobehaviours. This will lose your ability to drag and drop, but the benefits of having access to the constructor are worth it. Then, I would recommend passing in any needed dependencies through said constructors, creating (and passing) whatever is needed in the PlayerScript's Awake() function. For example, if the movementScript needs a character controller to move, it would be passed in as a constructor argument and assigned to a private variable within that class. By using this method, you can have your movement functions completely independent from input (and other scripts) entirely. This is good for things like code re-use, as your movement controller can now be used completely independently of your input source. The player script would be responsible for telling the objects how to move (by calling relevant functions in the movement controller) based on some events from the input controller. This way input can simply send events, no questions asked, the player can catch those events, and trigger movements based on them. Your input system can then be reused by any other monobehaviour that needs to capture input events, and your movement system can be reused for any charactercontroller independently of input (such as moving characters as part of a cutscene). You can even use interfaces or abstract classes here to completely overhaul functionality, something you can't do using monohebaviours since the unity inspector doesn't support interfaces at all. The only drawback is you lose drag and drop and instead have to create the other classes manually as part of your player script, but I feel the benefits are absolutely worth it, especially since you never have to worry about script execution order or any other unity shenanigans, and your object component heirarchy doesn't get bogged down with monobehaviours which really only exist to implement functionality and don't have/need options (they could all be set on the player component instead and passed to systems as needed instead).
As someone who doesn’t use Unity, but works as a swe. This solution is much more comforting than the drag and drop.
This feels like a waste of time, at least for me. You have one example of it being useful, that of cutscenes, where you would for some reason need to move the NPCs exactly like the player. But that is super niche. And I can't think of any scenario that it would be useful to have my player scripts specifically undependant on each other and not monobehaviour.... It just doesn't make sense. For other things sure I can see the benefits immediately, but not this...
@@NeonValleys Is it super niche though? If your movement code is separate from your input code, then you can re-use it for every character controller in the game - meaning your player(s) and your NPCs can all move in exactly the same way using exactly the same code - in the player's case, the movement is driven by inputs, and in the NPCs case, by AI, but in both cases they can use the same MovementController class to handle the actual movement, resulting in far less re-implementation of movement across multiple systems. Using the model in the original video (AND the model commonly used by a lot of Unity tutorials), you would have to code movement twice - once for the player and once for NPCs. The reason I mentioned cutscenes is because this is a less obvious benefit - not only can you control NPCs and the Player using the same code, but you can essentially turn the player into an NPC and bypass input entirely when you need to, such as in the cutscene example. If you can't see the instant benefits of this, I don't know what to tell you.
@@pt8306 I think so yes. It's only a very particular kind of game where you would even want the player and NPCs moving in the same way to begin with. And losing the ability to use it as a monobehaviour isn't worth it for something like the players movement and NPCs movement, especially for newer people learning from tutorials. It's absolutely useful to learn about using standard classes and interdependent code but not for something like simple player movement tutorials.
@@NeonValleysIt's the same if you wanted things to have health in your game. Your player has health and can take damage, but so can an enemy, an explosive barrel, etc. You are going to want the health system to be the same across all these objects, but not have to write the same health code each time you create a new class. That's where this inheritance method thrives.
When you want a mechanic that works not just for one object, but many different kinds of objects, you create a c# script that is modular, and can be attached to any object. But you can't do this if your scripts all rely on one-another to function.
There are lots of methods of doing this and I'm still learning to implement them myself -- but in short: modular, decoupled scripts are crucial to a game project's longevity and scalability.
I attempted to break up my code following your video and failed the first time, 2 hours of work and I almost gave up.... But I kept trying and actually did it, I have clean code!!! I learned a lot and I'm inspired learn and code more. Thank you :)
That's epic! These things can be fiddly to setup the first time, but once they are in place they are a good foundation. Well don, all the best with your next steps on this journey!
I'm glad I found out about this before getting too far into my project
Dude, I just rage deleted my project beccause It's really messy...
@@muhammadhilmi2044 haha
For the record, whilst messing with script execution order IS a solution, it's a terrible solution. Mostly because it's something you don't see in the code, so problems linked to execution order are horrible to debug. And if someone else goes and mess with execution order (granted, that kind of problem doesn't happen in a solo project) you're up for a headache.
GetComponent references should always be done in Awake, and pretty much any other case where you'd want to control the order in which some things happen can be dealt with in code with an Observer pattern.
"That kind of problem doesn't happen in a solo project."
Ho-ho-ho my friend, you greatly underestimate my ability to sabotage myself!
@@ArcangelZero7 indeed, my past self and present self are totally different people. Future self is the one getting screwed the most.
@level90s still not a good practice, as you can’t use variables inside of your attributes, and attributes are not debuggable anyways.
But hey at the end of the day it’s just a matter of good vs bad practice and if it works for you and the people who work with you, nothing is forbidden
Or, you can also go the normal sane way and simply have FULL control over the order of initialization, execution, life, and destruction of your objects. Relying on awakes, starts, and updates in individual components of individual game objects is needless and slow. To do this, you only have one Start() and one Update() in your whole project. In the Start(), you initialize everything, depending on any arbitrary conditions required and in the exact order as required. And the Update() becomes your main game loop, from where you call any other systems and entities and whatever, again, in the exact order and with the exact conditions your game requires. Heck, even Unity themselves preach this.
Even on a solo project, I imagine it would get really messy to maintain if you have to manually keep track of the order execution of each script.
I Hope you enjoy this! I truly appreciate each like and comment, they really help get this educational material in front of more people.
Question: When should we use this method
Good job highlighting an important topic for making your Unity code more manageable! There's also a third method, which I prefer, of controlling the execution order of Start() functions of parent-child scripts such as those shown in this video. In this method you leave the parent script's start code in the Start() function, but rename the child scripts' private Start() functions as something else, such as public CustomStart() so that Unity will no longer call them automatically. Just remember to make the custom start functions public so you can call it from another script. Then, you can call the CustomStart() functions manually in your parent script's default Start() function. This way you have total control over the script execution order, and can even have the custom start functions called in the middle of the parent Start() function, exactly as you deem necessary.
Thank you very much for this suggestion. As a beginner it is very helpful for me.
what the heck... if you don't want unity to automatically call Start, just don't tag this method. Incredible, right? I understand that you received information about Init, but something clearly went wrong)
@@sweeepeeee The point here was that you DO want Unity to call Start(), but only for one object. That object then calls the other objects' methods that would otherwise have also been Start(). This way all these methods get called at Unity's "Start() time", but you get to control their order.
@@Jazuhero yes, it's INITIALIZATION
Very interesting video, but I think you are making a circular reference. I suggest for decoupled and performant code:
1. Store your input data on a scriptable object, and then reference only that scriptable object in your movement script. This way your InputClass writes data to the scriptable object and your MovementClass reads the data inside your scriptable object.
2. Try to not use an update() on each of your scripts, instead, call your function OnUpdate() and create another script (UpdateManager) that handles all of your scripts that need to run on Update(). For Unity it's better to handle one Update() that do a thousand of things that a thousand Updates() that do one thing.
@@unitydev457 It would make sense that its faster since Start(), Update(), FixedUpdate(), etc in monobehaviours utilize the messaging system I believe, which is slower. Though by how much? You'd have to profile and see for yourself if it's worth it for your specific device and circumstances
@@pokoro97 In very small games, you will not see any difference. In a game with 2000+ game objects, each having 4-5 components, each having an Update() function, this becomes a thing, clearly visible in the profiler. The reason is that these "magical" functions are invoked in C# from the native code, and the marshalling is slow. Invoking a single C# Update() function in the whole project, and then from there calling whatever needs to happen within C# is way cheaper.
What Andersen suggests makes perfect sense, of course. Not only do you gain performance-wise, you also have full control over the order of things, in a very natural way. The single Update() function becomes your main game loop, and then nothing prevents you from calling whatever code in whatever order with whatever conditions your game requires at any point. This is pretty cumbersome and error-prone via individual Updates().
1. It is not a good idea, because the scriptable objects stores data outside of play mode. So if you change value in the scriptable object then the file gets modified. So version controllers will see changes in the file every time you enter play mode.
2. Unity update works with reflection but it stores it. It is true you can get some plus performance if you have 1000+ objects with updates, but other way it doesn't really matter. We don't need to optimize everything, but just there where we have performance issues. (For loop always better in performance, but we use lists as well)
@nonododo69 I heard about this, someone once showcased scriptable objects behave differently when using the unity environenment vs actual deployment on a platform when the read / write privlages actually kicks in.
I released a Unity Asset to help beginners make platformers- u3d.as/2eYe
Wishlist my game - store.steampowered.com/app/1081830/Blood_And_Mead/
I am new and reading over the code you provided. Could you explain why in the player script isLeftPressed and isRightPressed is declared as private, but in the input script they are declared as internal. You make that distinction several times in the code, what is the point / rule of thumb to keep using this practice?
Clean code is actually undervalued in indie game dev. Having object-oriented analysis and design skills really helps you to build the game and it will save you from hours of work.
Cause a big part of Unity community aren't developers. They are video game enthusiasts. They don't know what is clean coding, separation of concerns, DRY pattern, encapsulation, etc.
I've seen games with 'bad' coding that could easily surpass games with 'good' coding. Game development is all about making a *good* game.
@@Alieldinofficial
Yeah, but it is not about how good the game. Its about the behind the scense of the game.
Without clean and well designed code- your game would not scale. Your bugs will require much more hourse of your time, you will not be able to reuse functionality you already wrote, it will be way harder for new people to understand what you did. I never understand why so many people insist on defending factually bad work habbits
RUclips 3 hrs after upload decided to break the Audio Sync on the video. I'm just re-uploading a new version that will be linked here. Sorry for any inconvenience.
I thought my phone had a stroke while I was watching the video. Thanks for the update!
@@CreepyUncleIdjit It looks like they it fixed automatically! Would you mind checking for me and confirming if it's fixed?
@@LostRelicGames Looks fine to me now, and thanks for the video!
@@LostRelicGames Audio sync is good!
Yep works fine for me but I’m on mobile so I hade to watch real close :) great video, even for not being a total beginner :)
I'm sorry if I'm wrong because I'm a beginner still, but it seems a better way of ordering these particular scripts' executions would be the following:
- Disable the input/movement/collision scripts by unchecking their boxes in the inspector.
- Enabling them within the player script's Start() function by using
playerMovementScript.enabled = true;
playerInputScript.enabled = true;
etc.
This way the Start() functions of each script can be manually run and code could even be run in between if needed. Also it's much clearer what's going on because you don't have to use the unity settings window to figure it out.
Lastly ,for me and assumedly all beginners (and probably long time unity users too), the way in which Awake(), Start(), and Onenable() act is very confusing and difficult to remember, so here's a useful pair of links I'm constantly going back to to help remind myself.
docs.unity3d.com/Manual/ExecutionOrder.html
answers.unity.com/questions/372752/does-finction-start-or-awake-run-when-the-object-o.html
(this one's more confusing even) answers.unity.com/questions/217941/onenable-awake-start-order.html
I took this a step further. There are 4 components coupled together here. One method that worked for me was creating super generic components. Specifically, I have two components. "SimpleMotor" and "CircleCaster". Either of those can be attached to any game object. SimpleMotor moves the object every FixedUpdate based on its MoveDirection. CircleCaster performs a Physics2D.CircleCast and invokes a C# delegate when something is hit. Now, you can create your more player-specific script and just set the motor's MoveDirection when input occurs and a collision occurs. Or, you can create AI that is totally independent of a PlayerInput scripts. It has worked VERY well for my project.
Thank you. I learned to program not too long and the term of pumping everything into a single class was deemed as the creation of the blob God.
Now knowing how to separate the player controller, I will try and write better code.
Excellent tutorial. Never knew we could set the execution order in the editor like that. Thanks a mil!
My pleasure man!
I just discovered your videos and like most people here I'm so grateful you put so much emphasis on quality. While there are channels out there that use concepts of quality code, very few teach them. Thank you so much. I can't wait to learn more!
Only what he teaches has nothing to do with quality code. It's nonsensical code with no benefits.
The best part of this practice is that you can reuse components like for example movement if your player controller and an enemy controller inherit from a unit controller script so you can have a unit controller field with either a enemy or player controller script in it. Now both your player and your enemy will be using the same movement script but they'll be called by an input script for your player and an AI script for you enemy, aka you have a bunch less duplicate code.
Thanks a lot man! I am a programming noob myself and often run into problems because I don't exactly understand yet how I'm supposed to structure my code. Your video made that much more clear!
I'm happy to hear that Zeg! Have a nice day :)
Very cool, didn't really understand the internal access modifier before this. Well-explained!
Your videos are so helpful my dude! moving from a web developer into game development it drives me mad how little information there is on good structure and best practices thanks again! :D
For states, it is better to use enums than strings, is better Performance, prevents misspellings, better auto-complete and debug too
Wish I saw this earlier. Now I'm breaking up a player script and now dealing with the fallout of private variable dependencies.
How did you directly answer my question about script structure the day I thought to ask it? Awesome! You confirmed my thought process isn't crazy and stupid.
haha! Glad to hear it Evan! A lot of things in unity feel unorthodox at times ;)
This is a very important concept to learn. The only thing I'm not liking quite in your code is that you have references in both directions. So Player Script knows of the Movement Script and Movement Script knows of the Player. It would be cleaner to have it only in one direction. Called a layered architecture. And components only grab things in layers below them, not above them. So for example the Movement script is in the top layer and the player Script in the one below. The communication between Movement and Input would then work that both change/use the Player Scripts state (making it a Model and having a clean MVC architecture). Regarding what you are calling spaghetti code: this is only a problem when you do it manually. This is where controllers come into play. You create a player controller that injects all the dependencies a subscript needs. So for example Movement Script uses Input Script. Then the Player controller injects this dependency (Input script) into a setup method of Movement script. I know I'm biting myself a bit with mixing layered arch and MVC, but my point is let's try to only use unilateral dependencies. :D Sorry this got long and hope you could follow me at least a part of the way. Great video though.
Single responsibility principle. First one of the SOLID principles. You're welcome.
Pretty handy video, I just started having same situation with many scripts, this is a good approach to be followed up
Great tip! I've started my own game recently and have heard a lot about splitting code up into different classes like this but wasn't sure how it would be done. This video helped a lot! More like this please, and post on reddit - gamedev or unity or whatever I'm sure others would find this useful :)
Really glad you liked it! I think it has been a difficult area for unity users due to how the component system works. But the benefits of separation is worth the work to make it happen! Completed sample project linked in the video description if you needed a closer look! :)
@@LostRelicGames Top man, cheers!
i've been looking for this for so long, thank youuu :)
the comment section is really educational and helpful! Cheers!
Hey great vids, youtube was absolutely right in suggesting you to me :-) here's an immediate sub.
One interesting other approach to take is to have one component (playerscript) internally reference interfaces (IInputController, IHealth, IMover) which are pure C# interfaces. This allows to use the PlayerScript component as entry point for game loop callbacks, and hold global configuration, and have the logic happen in dedicated implementations, which you can adapt and even interchange if the game mechanics calls for it.
It's a different approach, obviously, which may or may not be better depending on the use case, but it has the advantage to make for less granularity in your components, which once an object starts holding lots of logic, helps overall readability and usability.
I do this in my game, but with an extra layer. I have "entities", which are effectively pure C# game objects with built-in functionality (such as an inventory with AddItem, RemoveItem functions etc), then I have "controllers" which interact with these entities based on things like game state, then I have my MonoBehaviors which create their own instances of controllers, passing in any entity references as needed (sometimes entities are ScriptableObjects, sometimes not). This allows complete control (and replacement) of things like game rules while keeping object interactions not dependent on each other for functionality.
This video means well, but this approach actually increases dependencies rather than reducing them, and will cause issues longer term for many people. It's better than doing everything in one file, but still has it's own share of issues.
I'm just beginning to learn unity and this video is totally relevant and insightful.. The unity option for code-run-order looks very useful. Thanks!
My pleasure Prakaz, wishing you the best on your exciting ahead!
@@LostRelicGames thank you sir 🙏
You can also put the scripts on children and parent always fires first, i think. So i would make a child object called "Collider" and put the script on there etc.
Thank you very much for this video. As a beginner i guess i write too much of spaghetti codes. Now my script management is better than before.
lol I faced this problem but I used just awake function .. Thank you a lot for the new way
haha no problem! :) it's interesting how many ways we can solve the same problem in unity and programming in general.
In my opinion script execution order is good only for attaching libraries and some extensions. Better way for this kind of problem is to create in root "PlayerScript" FlowManager that will have Awake, Start, Update, ect. methods and have a custom order of IUpdatable and so on components within. It will give a nice order control and will be opened for any extension you need later on
13:19 I didn't know this! I thought the order of the components in the inspector determined the execution order ahaha
Putting the project files on github would be a lot nicer than a google drive zip. Thanks for this tutorial! :)
good idea! I'll do a sweep of these in the near future
Just for some clarity, the values in Execution Order are arbitrary and don't represent time passed. You can use any values that you see fit, as long as they values are in the order you want. You could use 1, 2, 3, or 100, 150, 200, or whatever. It simply executes them in numerical order from least-first to greatest-last, and the gap between values doesn't really make any difference.
In your dry section you could have also allocated the rigid body as a private lambda as Private _playerRigidbody => playerScript.rb2d.velocity; in this case the _playerRigidbody is acting as a delegate stating when this value is used I need you to pass information to or from this path, in this case it does not matter when the Awake/start functions run and you can pass the new vector 2 all day.
Modular construction. Something breaks, it only breaks in certain places rather than everywhere, neat.
The collision script, it has to know that the player script has a ChangeState function that is looking for "Player_happy" or "Player_sad". What if you wanted to use this collision script on an enemy character, or a bullet, or a crate? A follow-up video where you take this concept to the next level would be cool. There are a couple of different ways to skin this cat, maybe you could discuss the pros and cons of each.
This is really helpful as I'm trying to add new thinks to mechanics but as my code mix input, animations, states, movement, etc, is kinda hard to add new things, now I'm going to start again, separate every aspect and try to make it work that way
I learned about these problems the hard way.
The question is: how expensive this performance-wise? Because there are a lot of reaching to another scripts variables.
Well of course separating the codes that are not related to each other is a good thing to make codes cleaner.
But what do you do about the performance? Imagine having 1 unit that have 1 script for controlling its behaviors. In a scene you have 1000 of that unit which means 1000 times Update/LateUpdate/FixedUpdate and so on. Now you split the codes into 3 scripts. 1000x units * 3 scripts = 3000 scripts.
I'm just saying this to see other aspects as well. Maybe I'm wrong.
Nice video .. events/delegates would be better ... but as it is for beginners this is a nice intro as to how t get things to work and a bit easier to understand .
the most important thing is to create your games and just like with everything else you'll get better and find new ways to do things
I have mixed feelings about this approach. But before I delve into this, I'd suggest adding "[RequireComponent]" attributes to each script so that adding one of them to a GameObject automatically adds the rest.
Declaring the references as internal hurts my eyes a bit, since in the context of a Unity script that's essentially making them public.
I was going to suggest a slightly different alternative but I'd rather actually test it beforehand in case I'm missing something.
Really great advice! thanks. Time to rewrite all of my code :)
This is a game changer. Literally
After completing my project at last now when I decided to add sounds and sfx to my game everything is just breaking apart.
Awesome topic! Thank you for explaing all of this very well. I really appreciate that.
omg you started right, but you did it wrong... all you did was just to split the PlayerScript.cs into 4 different files, but they are still highly dependant each other. I mean you changed the player state from the collision script! in order to move your rgb you check the InputScript inside the MovementScript.
At 8:37 you said "dispatch" but you did't use any advantages from an event system, which is the right solution to decouple the components.
great video dude! im pretty deep into my first game and I wish I had this guidance earlier haha.
Glad you found value in! Wishing you the best with your project
Hi! Thanks for all your sharings. Got a quick question: In your architecture, there is some benefits of using SerializedField variables (so you need to drag and drop scripts instance like you did) instead of using a GetComponent method to get the references of the other scripts? Hope I'm clear. Thx
Just want to say thanks for nice and usefull tips! For me, as beginner in unity -they're just priceles))
Instead of referencing the other scripts we could had used it inheritace right?
Using inheritance in that case would provide a gain or loss in perfomance? ou none difference at all?
BTW, great video, thanks.
Inheritance does not have an impact in performance, however Inheritance is the last resort in OO programming. Composition is more important than inheritance.
Why inheritance? It doesn't make sense. Are you saying you want the 3 other scripts (Input, Movement, Collision) to inherit from manager (PlayerScript)?
At the time i believe i was thinking playerScript inherit from the others. But you are right, it doesn't make sense.
But what i really wanted to know is if there are any methods differente than communication that will result in a gain of performace.
Can you clarify benefit (and cons) of manually defining references between components like that - over alternatives?
For example alternative is for each of those components to get and cache reference to other components it needs to interact with?
Although I would actually have this inverted (object dealing damage would handle collision trigger and check if other has HandlesDamage component) ... Following your example of checking collision on the Player side - component handling collisions can do something like:
void Awake(){
Health health = transform.GetComponent()
}
private void OnTriggerEnter(Collider other)
{
// Anything that DealsDamage will have this object
DealsDamage damage= other.GetComponent();
if (damage != null)
{
health.ReduceHealth( damage.damageAmount() );
}
}
Without tightly coupling it to specifically Player allows reusing same components (e.g.: Health, DealsCollisionDamage, HandlesDamage) also on Enemies/Buildings ...etc
Just curious why are you using internal access modifiers for the variables? Is there some reason that you'd want the scope limited to that assembly unit over just limiting the scope to the class with private?
I've never heard anyone talk about this problem. How are ppl not having this issue and speaking up about it!?
I am very new to programming and what experience I have is from long ago in Basic and Fortran... yes... longggggg ago! If I follow the discussion, when you talk about breaking up code... is this similar to earlier times when you would use structured programming and put routines that would be used repeatedly in a subroutine that could be called as needed or am I missing the point of this altogether?
Learnt so much thanks to you !
I try to avoid Awake and certainly Start as much as possible. I instead have OneTimeSetup (for Get/Add Component and the like) and Initialisation (resting variables etc that can be called between levels/restarting the game etc) functions that I call from whatever the root class is via its Awake function. I then have complete control over calling order and its obvious in code what that is.
Also for separating out the functionality - this approach still leaves a lot of dependency. Maybe events would be a better option?
really interesting. thanks for sharing. even if i'm absolutely new in this wonderful world, i found this tutorials really intelligent and logic. this HELP a lot for who want( like me) understand and study. thanks.
A good news! People have invented (if ref != null) checks while you fiddle with the script execution order. ;-)
What I learned from my lags Do not separate variables that stores data for a method By making reference to another Class I think I should link scripts that only "invoke" methods As possible
Interesting video! Was just wondering why you use the internal scope for your fields even though the script is in the main assembly?
Hi mate, this is for convenice. Using internal will hide the value from the property inspector, yet allow puplic access from other scripts.
Saves one adding meta tags to from inspector. :)
@@LostRelicGames Ah I see thanks. Basically the opposite of the SerializeField attribute :) You could also put it as a property.
I'm confused, at 7:30 we see the PlayerMovementScript is calling the PlayerInputScript, albeit indirectly. I thought we wanted to eliminate the back and forth between them? Wouldn't it make more sense to have some public methods on the input script like IsLeftPressed() and IsRightPressed() which simply do something like "return Input.GetKey(KeyCode.D)"? Then expose some methods on PlayerMovementScript like MoveLeft() and MoveRight(). Then inside the PlayerScript Update method we could use the methods on the input controller to check for input, and if they return true call the movement controller methods? That way the input and movement controllers aren't communicating at all.
i fking love ur way of talk/teach-ing bruv
I'm a newb but so far, I've always heard that you should only mess with script execution order as an absolute last resort when you have absolutely no other option available.
I can imagine that if a project gets larger, it would be an absolute nightmare to maintain, especially if multiple people are working on the same project.
how can i use this way for unityEvents ? like if i have a collision detection script that fires an event , do i add another unity event on the Player script and link the two events and make the other scripts listen to the Player script event?
Wow, that is actually very useful. Im very impressed by your videos, they truly are beginner friendly. Also im suprised you dont have as much views as for example Brackeys which videos are in my oppinion much less useful than yours. Now that's an instant subscribe and Blood and Mead wishlist my friend! Also i have a question for you. Could this problem with start method execute order be solved with static method? I could be wrong but i think that static methods are called before non static.
Hey man, thanks so much for the kind words. RUclips has a strange algorithm thay often doesn't reward the small channels. I'll keep pushing on though! Thanks for the sub and wishlist. Come by the discord some time, great place for getting help and sharing progress, it would be a pleasure to have a person with your positive attitude part of the community. Regarding statics, they are sort of bad practice generally, and used more for global referencing.
@@LostRelicGames Thanks for the reply, ill surely join your discord server :)
@Lost Relic Games, Why not just make partial Classes in that case?
Great video! Help me: is script separation just about ease of read, or does it improve the performance of everything related to the object? For example, are collision detections weighted down by long scripts, leading to errors, or is it immaterial? Thank you!!
separation will always be less performant than having everything in one single component. This is neither about ease of read (well yeah partly but not essentially), nor about performance, it's about scalability and architecture (single responsibility principle).
Referencing other components has a cost, although negligible (unless you do a GetComponent in update... always cache component references in Awake). It's never going to be more performant.
The main problem of long scripts is indeed readability, but also changing one small thing may impact the rest of the code. That's why there's the Open/Closed principle and the Single Responsibility principle.
I don't really think it's about performance but more about having a good game architecture. But doing this doesn't bog down your performance in any way either. It makes it more organized rather than having a single monolithic class full of variables and if and else statements(which is extremely hard to manage). Which means it's easier to work with so you don't run into any problems in the future. And I emphasize on "The Future" because it means your code is going to be a lot easier to work with when you add more logic into it.
Sure, you can get away with being very careful when handling your scripts because you are the developer but that's not gonna work in the long run especially if you work with other people.
Sorry if that's too vague tho. I can't really think of an example right off the bat but script separation is a really simple way to help with just writing great code overall.
@jean-gobert de coster hey. Thanks for this. Yeah I can see the advantages.
@@gadgetboyplaysmc hey. Thanks. Definitely get what you mean so definitely not vague. Nice one
Stupid question: is internal same as private?
Not stupid at all! Internal is sort of like private. it means that other classes in the inheritance chain can also access it.
Is there a way to use "using x" or maybe an "import"? Having done a lot of scripting in other languages there is always a way to make the hierarchy work, but I am new to C#. So basically I am wondering if you can include or use other scripts at the head of a main script so they can be used.
I saw another good comment about making use of an interface. I would be interested to see if there are other good ways of implementing this so that it is more programmatic and less configuration based.
Incredibly helpful stuff!
When it comes to related functionality, I might be tempted to construct those sort of sub-MonoBehaviours from the player script without attaching them to any object. But I also have generalized scripts, like "Expire" or "BounceOffBoundary" which are unrelated to the main object type controller script for which the order of execution might be important. I guess I would try to design things to be as loosely coupled as possible, but. That sort of effort is always attempted and never 100% successful, isn't it.
Many thanks. It help me so much
Would code separation cause any slowness?
Coming from iOS dev this looks very weird lol. Could you just extend the class in different files? Or does delegation exists in unity?
I try to seperate the player into a player movement controller and an entity controller, so the entity one can be reused by enemies and NPCs, and the player controller listens to messages from the Input System’s Input Controller
I was confused as to how the collisionscript doesn't just create a new instance of playerscript when it creates it, but I understand now that it all has to do with connecting the serialized fields to each other. How would this normally be done in C++ I wonder? Passing playercollision what it needs through parameters by reference so it can change things in the manager?
could I use inheritance in situations like these or a static class for the main player script maybe? I’ve gotten into programming in unity recently but I’m not really sure where to use all the different methods, maybe a future video? great tutorial btw, I like these raw videos
Thanks for the informations
I wonder is there any way to assign all those three scripts ( movement, collision, input) to main player script via player script itself without doing them directly from inspector.
And if so ,does it keeps the scripts order ?
Again thanks for the video
Very informative, thank you!
Have you found any performative issues with separating the script other than the firing order?
Conversely, have you found that this approach makes the project better performing?
Thanks again for all of the time you put into these videos!
Hey mate! As the scripts are stored at startup there is no notable performance cost during runtime.
@@LostRelicGames awesome! Thank you for the feedback.
By setting how many ms before a script runs, can't that potentially make your scripts run slower than they could since they have to wait a certain amount of time?
Hey I don't know if your still looking at these comments but I noticed in your code you often use internal as apposed to what I often see which is using public or private as a variable prefix. What is that doing exactly and how does that differ from the mentioned public/private?
Hi Dovah, in a nutshell, internal acts like public without exposing the variables in the inspector panel as public would.
@@LostRelicGames Oh okay that makes sense, thank you!
This helped me a lot. Thank you
as 3rd possible solution to the null reference problem produced by the scripts firing time: could we declare the children scripts (input/movement/collision) Start method as a coroutine (IEnumerator Start() ) and use WaitUntil to wait for the PlayerScript to initialise its variables?
I started game development by unity
Hey! I found this tutorial really helpful, but got me thinking: what do you think of using inheritance in unity? I.e.: a character class (that then has player and enemy childs) who manages the basics, like health, death and rigidbody basics. And how could you work both splitting the code and using inheritance?
This is a bad practice, the best solution is using code Inheritance. You make each code dependent on the others, in your example PlayerInput will depend on PlayerScript, PlayerMovement will depende on PlayerInput (which also will depend on PlayerScript) and so on. Also using code inheritance you can make a base script for several other scripts. A "CharacterHealth" script can be based to be used for the player, enemies, player allies, etc.
Is there a clean pattern for when movement has to embed collision as it does in tile based 2d (where we separate movex+collx from movey+colly)?
Excellent tutorial!
You structure now depends on however you set up your components (correctly) in the editor. Why not just create simple classes, that get spawned by the player component, get a reference to the playerscript in their constructor and get processed every on update? Less error prone than adding and referencing separate Unity-components.
Hi, Great Tutorial and I subscribe to your channel. Thank you.
Can I ask a question about the separation of code you point out in the video? Like in the process if the children want to talk to other children they need to communicate first with the parent is that right? Or can I just like if the movement needs the input, I just listen to the event of input directly that can be set in the movement awake/start? And also the rule is all the reference component will be int the parent and the children cannot communicate directly in the other children? and the last question can, Is having a code like for example the parent have input and movement script, the input fire, the input pass the data in parent, for example, a left button and the parent have a logic to determine if what function in the movement to call, is this code okay? or I need only the parent for referencing the children?
Can you please explain how to utilize these scripts? There are no tutorials that I find that use this sort of separation between scripts so I don't know how to call a function from another script. I'm VERY MUCH a beginner and I would like to use this just to keep things organized from the start.
I don't think this is actually good design. If you go and find official Unity demos I think that's the best place to learn how to write clean code. Some of them aren't great but IIRC the input system video with the cartoon Viking does something similar to this video but doesn't create the upwards dependency by having a player script reference in the delegates. It's a small demo so you should be able to learn from it.
There are a gazillion videos here on RUclips covering how to call functions from other scripts in Unity. Just search for "unity call function from another script" and you'll find loads of them. The most important part is that the function you want to call from another script should be public. If it's private or protected, then other scripts won't be able to call/access it.
This is another approach that is more modular and decoupled that may be useful for you.
ruclips.net/video/mJRc9kLxFSk/видео.html
Hi! Thank you for your help / explanation. I did something similar in my project, but I had some problem when my "backend or business logic" needs some aditional information from the User/Ui. Could you give me some advice regarding this? (Example: 1) the player plays a card, which is an upgrade card 2) then the card logic needs an additional information which reaource the player wants upgrade.) I have a working solution for it with async tasks methods, but it looks ugly and hard to debug. Im sure there should be a better way, but I dont know it yet. Thanx in advance if you answer.
great tutorial
Hi there. This video is very informative, at least for me since i started to seriously learn Unity / game dev. Also, do you have any tips regarding what does a junior game dev needs to know? I am planning to apply for a position in the field this year and i would appreciate some tips.
I was pretty sure Start was called based on component order.
Managing order of scripts loading in project settings looks like a spike.
Have you ever use DI in Unity? It would be interesting to look best practice
Well, technically, the Component architecture is a form of DI
There are DI frameworks for unity. Zenject is the most popular afaik. However it doesn't play well with Unity's general architecture, essentially you're putting a DI framework (classic DI) on top of another DI framework (Components).
As for script execution ordering, actually this is bad design. Never reference other components in Start, ALWAYS do that in Awake