Interacting with Objects and Code in Unity3D

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
one of the most common things that you'll need to do in game development is have one object talk to another object whether it's your player talking to an npc or your weapon talking to its ammo or maybe your input system telling some knight to move around all objects need to be able to interact with other objects to make a game actually work so today i'm going to cover some of the top ways to interact with other objects some of the best ways to find and get the other objects so that you have a reference to them and you can interact with them and i'll show you some interesting and cool tricks that i didn't learn until i'd been using unity for quite a while but before we get started please hit that like button it doesn't cost you anything and it really helps if you like these technical videos where we dive into code or you're just getting started with game development and want to learn more hitting that like button makes a big difference and if you have any questions about the content that i'm putting in here or just comments or things that i might have missed that you think people should know about drop those down below too i try to read them all and reply to as many as possible for this tutorial we're going to use a scene with a bunch of knights in it i've got two orange knights and three blue knights and we want to be able to send these knights commands and i want to be able to send specific knights commands at different times so we're going to run through all of the different ways that we can get access to these nights and then make them do what we want them to do in my scene hierarchy you can see my five nights i've got an orange knight here with a night script attached a nav mesh agent and an animator so that it can perform some animations the same for this other orange knight and the blue knight they're all pretty much exact clones except for their visual representation and up here i have a finder example object with a finder example script that we'll use to add in code to find objects and interact with them in a bunch of different ways the first way that we'll interact with them is the simplest which is just using a scene reference here you'll see that we have a toggle object field that takes a game object and i can take one of my knights and just drag it right into that field now if i hit play i should be able to toggle this orange knight on and off let's see it in action and then we'll take a look at the code if i left click my knight should disappear you can see the game object actually turned off there and if i right click he should reappear let's stop playing and take a look at that script now i'll open up my finder example and you can see here on line 5 we have a serialized field for a game object for our toggle object and this is the field that's showing up in the inspector we could alternatively have this be a public field but if you've watched any of my other videos you probably know that making it public isn't the best option if serialized field will work go with serialized field by default that'll allow you to assign it in the inspector and not make it publicly accessible to be misused somewhere else once we've got our toggle object assigned though in our update method we just check to see if i've clicked the left mouse button with fire1 or click the left control or if i've clicked the right mouse button which is fire2 if i do left click then we just call the gameobject's setactive method with false to turn the object off and if i right click we set it to true to turn the object back on what if we want to access multiple objects at once though one option is to convert our single serialized field into a list or array here i've set it up as a list of game objects let me expand out that toggleable object section now and i'll assign my two orange knights by dragging them onto the toggle objects field i'll take orange knight 1 and orange knight 2. now if i hit play i should be able to toggle both of those knights at the same time let's give it a try i'll left click they disappear and i right click and they reappear one cool trick here by the way is that i can hit the lock button and then go hold shift and select multiple nights click and drag them over and then add them all at once this comes in really handy when you need to add a lot of objects to an array or list let's take a look at how this list works in code now i'll open up my finder example and you can see that i've changed my serialized field from a single game object to a list of game objects this requires the using statement using system.collections.generic to allow for this generic collection of game objects and a small change down here inside of my if statements instead of toggling a single object i need to loop through all of my toggled objects in fact you can probably see that i've renamed this to make it plural by adding an s to the end of the field here to deal with multiple objects we need to change line 12 and 18 into being four each loops a for each loop will iterate over each object in the collection or in that list or array and then give us back a reference to it i've named that reference toggle object and then on line 13 we just call the setactive method on that toggle object so the first time through it'll toggle orange knight 1 then orange knight 2 then blue knight 1 blue knight 2 and then finally blue knight 3. let's see it with all of the knights in action so you hit play left click they disappear right click they reappear let's try removing blue knight 1 while we're playing i'll hit the minus button left click everything about blue knight 1 disappears right click and they all reappear now let's call some other code instead of just toggling an object on and off let's make one of them animate or in fact let's make them all animate i've got it set up now so that when i left click all of my knights that are in my toggle object list will do a cheer let's remove the blue knight one and see if i can get just those footage here there we go let's take a look at how this works the first thing to note here is that we're still using a list of game objects we haven't changed anything there what we have changed is inside of our for each loop now instead of calling the toggle object's set active method we get an animator component from it and then we tell it to set the cheer trigger on that animator but what happens if we have an object that doesn't have an animator on it in our toggled objects collection let's take a look at the problem that might cause and then the solution to that i'm going to take my environment drag it over to be one of my toggled objects and maybe put it somewhere near the middle right after the two orange nights we'll click play and then i'll left click and let's see what happens so i left click and noticed that only the two orange guys played their chair animation and then we got an error the characters after the environment in my list didn't play their animation and if i double click on this error i can see that it's right here on the animators set trigger call the problem is that the animator doesn't exist so i need to be a little bit more opinionated about the type of objects that can be allowed into my toggled object section let me show you how we can fix that the easiest solution is to just change this list of game objects to a list of animator that'll allow me to only put animators into this field now i don't need to call this var animator equals toggled object dot get component animator i can actually delete that line completely and just call toggle object dot set trigger in this case though i'd probably want to rename this to animator and then call animator set trigger again the reason that this works like this is that these objects are no longer game object references but they're animator references so if i iterate through those it's going to be able to just call the set trigger method on them directly without getting that animator component let's jump over to unity now though and see what's happened to my toggle objects collection you can see i've got my knights here with the environment in element two and now i have a type mismatch for all of them i actually need to reassign them this generally happens when you change the object type of any serialized field same thing happens if you make it public there's no difference you do need to reassign these let's go assign them now i'm going to lock oh i've actually got it locked perfectly i'll go select the first knight here hold shift click on the last knight and i'm going to drag these over to my toggled objects then i'm going to select these first set of knights and hit the minus button to remove them save the scene and then let's take a look at the big difference that we've got here i can now no longer assign my environment as a toggled object i can only assign things that have an animator in fact if i clear all of these objects out let's just hit minus and hit plus one more time you see that it only takes animator objects i can't take my finder example and drop it on there i can't drop my camera on there or anything else only the valid knights that actually have an animator on them now let's take a look at something else we might want to do with our knights like tell them to move around here i've changed our example to take nav mesh agents instead of animators and made it so that when i click on a position in the world my nav mesh agents get that destination let's take a look at that code and see how it's set up you can see here in my if check we do another if check using a raycast we check to see if the player has clicked into the world by using the camera.main.com array method which just generates array directly into the world underneath the cursor looking for an object that we hit we're not checking against layers so technically we could click anywhere and if it's not on a nav mesh it's not going to work but if it is on a nav mesh what we're going to do is loop through each of our nav mesh agents and call the set destination method on that nav mesh agent now technically we'll call that even if they click off of a nav mesh but if the point's not valid it just won't do anything let's take a real quick look at the knights and the navmesh setup just in case you're not familiar with those each of the knights has a nav mesh agent added onto it which is just a built-in unity component and then we have a navigation mesh baked which you can do under window and then ai and navigation any objects that are marked as navigation static will get marked in as bakeable and bake in with this little blue outline the blue outline shows where my navigation mesh is and where my characters are able to walk to toggle walkability for a specific piece of terrain you can just select that object or the entire terrain go to the object section of navigation and uncheck or check navigation static or even use the navigation area section now let's move on to something a little bit more advanced what do we do if we want our knight to both move and cheer well in general in a game our npcs are probably going to do more than one thing and we don't want to be referencing them by individual components at least not very often in this case what i would like to do is build a night class and then reference that single night class and have it do multiple things that way i only need one reference to it i know that it's the right object and it can do all of the things that a knight needs to do here i've set it up with multiple knights and my blue knights assigned i'm going to left click they'll move and if i right click they'll start to cheer if i left click over here they'll move again and i right click and they start to cheer let's take a look at how this works the first thing to note on our finder example is that we're now referencing a type of knight instead of a nav mesh agent or an animator we're using a knight if i clear out all of these nights you'll see that i can hit the plus and it will only allow a knight in there if i take my environment again it won't allow something invalid but i can take my two orange knights and drop them in let's see drop number one and drop number two right on top of the word knights it'll add to that list now how did i limit it to my specific night so first let's take a look at the knight if i unlock my inspector and scroll down here below my nav mesh agent i have this night script on it let's take a look at the night script and see how it works the first and most important parts are on line six and seven where we have a reference to a nav mesh agent and an animator these aren't serialized fields so they're not showing up in the inspector and in fact they're filled out in line 12 and 13 or they're assigned by line 12 and 13 using a get component call git component is a method built into mono behaviors or built into any script that you can attach to a game object in unity the git component call will find another object or another component on that game object specifically that uses or matches that type so here on line 12 we find the nav mesh agent component and we assign that to our reference that we have on line six this underscore nav mesh agent now the underscore part is completely mine it's just the personal preference thing for my private fields it is absolutely not necessary and you'll see lots of examples that don't use that it's just a personal preference on how i like to see and read my code now caching the components is less of a personal preference and more of a general rule if you're going to be accessing a component regularly it's generally considered good practice to cache that in an awake method and have a reference to it so that you don't need to call git component multiple times the reason for that is simply that calling git component too many times on too slow of a device can cause performance problems you probably won't run into that for quite a while so it's not something you need to worry about too much but it is something to note we're going to cache our components using the git component call and then we can use them down below let's take a look at how these are used now in my update method i set my animator's walking bool to either true or false based on what my nav mesh agent's velocity is if it's greater than zero it'll be true if it's less than or equal to zero the walk boolean will be set to false that turns on and off my walk animation we also have a move to method that takes a position that just tells our nav mesh agent to set its destination to that position we have a reset position method which will reset the object right back to its starting position that we cache on line 14 in the awake and then stop the nav mesh by calling the nav mesh agent's reset path or stop the navmesh agent technically and then on line 27 we have a cheer method that calls the animators set trigger passing in chair to cause the chair to happen let's go look at the finder example and see how this is all actually hooked up back in the finder example you'll see that we've changed that list of navmesh agents to knights and then in the loops on line 14 and 21 we loop through each night and just call them methods that are public on that night the move to method that we've made public and the cheer method this gives us access to both of those functions without needing to know about the internals of how a knight cheers or how a knight moves this comes in really handy when you're building out your games and your classes so i highly recommend that you build classes to wrap this type of functionality what do you do if your game objects don't exist in the scene though maybe there's something that spawns over time like my knights here spawning from a night spawner there are a lot of different ways that we can find objects like these knights at runtime so let's take a look at them now the first one in our finder example is to use the find objective type method here you'll see that on line 11 we find all of the objects that are of the type night what this does is actually look through our scene and find every object with a knight component added to it as we run you can see that we're spawning nights and they all have that night component added onto them so this find objects of type call will find every one of them and return back an array then we call the to list extension method on it to just convert them over to a list of knights now you don't necessarily need to do this but i thought it was an important thing to show another alternative way to do this would be to just store them in an array we can remove the list and add in two square braces which just means that we now want an array of knights an array of knights is almost exactly like a list except that we can't add and remove to it as easily a list and array are almost exactly alike except a list is a little bit easier to add and remove things too since i don't need to add and remove things though i'm going to get rid of this assignment to a list and improve our performance converting it to a list like that does actually make a complete copy of that collection which isn't huge but it can add up and it can take up some memory now there are some other performance considerations here like we don't want to necessarily be calling find objects of type every frame in an update that's generally a bad idea it's not good for performance and it's unnecessary work we only really need to keep track of knights when they're added if we have a list that was active of all of the knights that exist we could just use that instead of calling find objects of type let's see one way that we could do that here i've changed the way this works instead of creating a new list of nights every update and finding them all every update we've got a list that we create and initialize on line six now we just need a way to add nights to this list as they're spawned the simplest way to do that would be inside the night spawner when we create a knight we could just find the example find the list of knights on it and then add our knight to it now this will work fine until we get to the point where one of our knights disappears maybe we've despawned him or he dies let's see what happens when i do that i'll delete my blue knight and let's try to move and notice that we're getting an exception or an error if i go to my finder example you'll see that it's because we've got this missing element here we've deleted or destroyed a knight and we need to remove it from the list the simplest solution to this is to just make our knights remove themselves from the list whenever they get disabled or destroyed depending on what your use case is here i've hooked into our on disable i look for our finder example script find the nights list and then remove this knight from that list whenever he's disabled let's go see what that looks like at run time i've got my finder example selected there and i'm going to lock the inspector to it we'll hit play and then i'll let a couple nights spawn and then i'll delete a night out of here and watch what happens to the night as i delete it so we've got knight spawning there's number one number two and then once number three spawns i'll delete number two and look at that he's removed himself from the list automatically and i can still move my guys around without any errors now i want to show you a keyword that can simplify a lot of this code we've been referencing objects by using the find object of type but there are a lot of other ways to reference objects in unity and c-sharp what we're going to use next is the static keyword and here you can see i've changed my finder example it no longer keeps a list of the knights or has any way to find knights at all instead on line 11 and line 18 we loop through an already existing collection called night dot all nights that's a static property on my night class let's take a look at how that's implemented and how it works to give us all of the nights that are available here we have our night class with our all nights list let's take a look at that list and see how this works on line 12 we have public static read-only list of nights named all nights and then it's initialized to a new list there are a couple of interesting keywords here first it's public so that we can read this from other classes our finder example is referencing our knight dot all nights if we don't have that public keyword we wouldn't be able to access that from there the static keyword is a little bit different the static keyword means that there's only one of this there's only one list of all nights normally when you add a field or a property like our nav mesh agent animator and starting position to a mono behavior it's what we call an instance field or an instance property it's something that will be created for each instance of the night so for every knight that i spawn or place it would have its own reference to its own nav mesh agent its own animator and its own starting position that was cached when we have the static keyword though it means that there's always just one of those we don't create multiple and we always just reference it in a single point in memory which is one of the nice benefits when we have a static field or a static property like this we're actually just reading and writing or accessing directly to one spot of memory i guess we're not technically reading and writing directly to it but we're accessing it in that one spot and we have a nice easy way to reference it the third keyword there is the read-only one and that's not actually necessary for this it just prevents the list of knights from being recreated or destroyed somewhere else it doesn't however prevent us from adding or removing entries from the list when i don't want to have my lists or collections recreated accidentally though it's a keyword that i like to just add on there because it adds a little bit of extra safety so how do we add and remove things to this list of all nights well on line 13 we call the allnights.add and pass in our own instance so we pass in the night that's been enabled and on line 14 we just remove ourselves from that list if you haven't seen this format by the way this is just an expression body method it's the same as a normal method just shorten down when you only have one line to call you can write it like a little lambda and it makes your code a little bit smaller now let's talk about another way to interact with and find objects in your scene one that doesn't require you to write code or have a specific script for the objects that you want to find or get and that's to use tags tags are actually a really powerful feature in unity that allow you and your designers to essentially tag an item or a game object to be used by your code in some specific way say for example we want to make our gates light up when the player presses a button and i don't want to write a specific gate code and i also don't want to find things for all of the renderers because i've got lots of renderers in here what could i do well i could add a gate tag onto my gates here i've got one of my gates selected and i'll just go to my tags and choose the gate tag that i've created if you want to create your own tags you just choose the tag option and then hit add tag make sure that your inspector is not locked and then hit plus type in the tag name and hit save that will add a tag and then you can use it from code let's see what it looks like to use that tag from code here you can see i've changed my finder example so that when i left click or press fire 1 i find all of the gates by using the game object find game objects with tag and passing in gate you can see that on line 9. that'll actually return back an array of game objects then i loop through that array of game objects on line 10 and this is an important part we need to get the component that i want to interact with in this case i want to interact with the renderer component of that gate i know that my gates all have renderers on it so i'm not being very safe i'm assuming that i'm able to get that component setting the materials color to red so what do i do if i right click on line 16. i set the materials color to white exactly the same now one thing that you could do to add a little bit of safety here is change this line up so that we assign the renderer and then check the renderer to make sure that it's not null to do that i'm going to add a semicolon here i'm going to add a little bit up here i'll say var renderer equals and then on the next line i'll say renderer.material.color equalscolor.red but only if renderer is not equal to null this will just double check that my gate actually has a renderer before trying to set the color on it because if i tried to set the color on something that's tagged as a gate that doesn't have a renderer on it in this loop it would fail break out of the loop and not tint the rest of the objects i should probably theoretically do the same down here on fire too so i'll just copy that paste it in replace the red with white which is again going to be probably the default color if you look at your materials when you're setting up a game object it's usually slid all the way to white so the colors match exactly and it's not tinted just matching with your texture all right let's try that out and see what that looks like in game so i press play and i should be able to left click turn my gates or anything tagged as a gate red and right click and it turns back white let's try just changing something else at runtime though let's maybe add this well and instead of making it a well let's pretend it's a gate go back to the game view i left click it turns red i right click it dwight again and if i stop playing that tag gets unassigned so you got to make sure that if you're assigning tags that you want to keep on you do that when you're not playing now i want to talk about one of the most commonly used ways to find game objects that i almost never use i'll talk about why i don't use it but first show how to use it here you'll see that i've changed up and added a start method my start method's actually set up to work as a co-routine just to show that you can do that by returning an ienumerator that allows me to add in that yield weight for seconds on line 11 and have a little bit of a delay on line 9 you'll see the code where we find the object and i'm using the gameobject.find method that takes a game object by exact string name the name has to match exactly if i rename that nightspawner object it won't find it the game object also has to be on if that knight spawner's not enabled or activated it won't find it so i have to turn it on in my scene find the object here by name and then on line 10 i turn the object off after five seconds i turn it on and we start spawning nights after five seconds let's go see that in action and see how it works and it'll talk a little bit about why i'm not such a big fan of it so you can see i've got my night spawner here i've got my finder example script running i'll hit play and after about five seconds you should see that night spawner turn back off it turned it or turned back on it turned off right away there we go and now it turns back on so why am i not a big fan of this well one of the key reasons is that say i add in oh some square braces around my knight spawner or i name it night spawn or two or anything else and then i hit play let's see what happens i get an exception a no reference exception because it couldn't find that object now i could probably handle the null reference exception and make it a prettier log but it's still something where i'd have to either go change the game object's name back or change the code to handle it so that's one of the key reasons that i don't like it the other problem that i have with it is that the game objects have to be active so i have to make sure that i'm managing the state of those objects before we do a find on it or that i'm defaulting things to being active and on all the time because as soon as i change that up it's no longer going to work so in general i would recommend not using gameobject.find but it can be handy if you really need to find a specific object by a specific name it's kind of the easiest way to do exactly that problem or solve exactly that problem but it's probably a problem that you shouldn't get yourself into one scenario that i do recommend you get yourself into though is separating out your logic from your visuals and that'll change the way that you need to get components on occasion here i've modified my blue knight so that the visual part of the blue knight is actually a child i have a knight model child underneath the actual character that i can turn on and off that way i can swap out my visual at any time without changing my actual game object the downside of this however is that my animator is no longer at the same level as my night script so if i use git component i'm not going to actually find the animator because that only finds components on the same level on the same game object there is however a nice easy way to get components in our children and that's using the get component in children method there are two different methods that we could use here there's get component in children which gets a singular instance of it or get components in children which will get all of the components that match so if i had multiple animators i might want to get all of those animators it's probably not something i would do i'd be more likely to get all of the renderers or text objects or something else underneath there it's very rare that i have multiple animators but if i did i would add in an s and use get components in children one thing to watch for is that it's easy to accidentally add or miss the s and then end up with an error and get a little bit confused just make sure that you have the plural or non plural version based on what it is that you're looking for that's 90 of the time the error that you run into there's one more method that i want to call out and that's the get component in parent this isn't one that i use very often but it does exist if you need to look for something up the hierarchy here you can see that i've changed it and technically broken my code but if you need to look up the hierarchy that's a problem you run into just remember that that method actually exists all right i hope this has been helpful if so and you don't mind hitting that thumbs up button i really appreciate it or subscribe so that you can learn more about unity and game development or check out some of my courses down below or some of the other videos where i run you through the game development process building a game from beginning to end i've also got some free courses on that that you can find down below as well again thanks again for watching please if you have a question by the way drop a comment if there's something that i didn't cover or something that you're curious about in here with this referencing and just interacting with objects or just in unity in general drop a comment and let me know all right thanks again for watching
Info
Channel: Jason Weimann
Views: 18,507
Rating: undefined out of 5
Keywords: Unity3d, unity, gameobject, c#, getcomponent, findcomponent, interact, reference, static, readonly, findobjectoftype, gameobject.find, interaction, brackeys, programming, development, game development, beginner, tutorial, unity tutorial, coding, game development unity, dani, game, how to make, unreal engine, 3d, unity3d singleton, jason weimann, quill18, gamedevhq, unity what is monobehaviour, unity3d, code, unity 3d, how to make a game, code monkey, how to make a game in unity
Id: XT3SxKyANjk
Channel Id: undefined
Length: 30min 2sec (1802 seconds)
Published: Tue Sep 14 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.