DEMYSTIFYING linq - UNITY3D!

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
have you ever come across code like this and thought what's going on here why does it look like this why is this so weird and different from my normal code if so you're not alone the first time that i saw a link query i kind of freaked out in fact i think it was probably about 10 years ago i saw it and i thought well i'm never going to use that that looks terrible it looks confusing it looks way too complicated i'm going to stick with what i'm doing and just avoid that link stuff completely but it didn't take long before i started pulling in some of the easy bits and after a short time i decided why not dive in and try to figure out this whole link thing and i have to say that i'm extremely happy that i did because it saved me a ton of time and just a ton of pain over the years as a game developer so if you're interested in saving time and saving yourself some pain want to spend five minutes learning hang on with me i'm gonna run you through some of the fundamentals of link show you some really cool tricks and things that you can do with it and even one thing that i actually just learned about it but before we dive into the video this video is sponsored by backtrace while alpha beta and play testing in general is great it's almost impossible to catch all of the errors and bugs that will without a doubt appear when developing a game but with backtrace you can make sure all of these errors are caught before the release date and ensure a great and smooth user experience for your players backtrace offers an amazing plugin with support for all game engines languages and deployment platforms they fully automate error capture and their web console makes it extremely easy to monitor analyze and debug them across all platforms backtrace lets you capture errors in all instances of your game with a single system and then generate structured searchable error reports from your data they also integrate with popular workflow tools including jira slack and discord but the best thing about all of this is that their developer plan is completely free and lets you manage up to 25 000 monthly errors and gives you 10 gigs of storage so get rid of all your game crashes right now for free by clicking the link in the description before we dive into why link is so awesome and how you can use it in your actual projects let's briefly just go over what link is if you look it up it's short for language integrated query and it says that it's the name for a set of technologies based on the integration of query capabilities directly into the c-sharp language that might sound a little bit confusing and not make a lot of sense in fact that's kind of the thing that kind of put me off to it when i first read it i was like i don't know what any of that means and then it starts to talk about sql and xml and link to sql and you know reading sql data that's what it was originally kind of set up for was to read data from a database query it and put that into your code and do stuff with it those queries are often written in the query expression format which is a little bit different from normal c sharp in fact it's different from what we're going to use completely it looks a lot like sql and if you're familiar with sql you're a database administrator it was an easy way to kind of translate your code right into something that worked into c-sharp or translate your sql into that we're game developers so we don't really need that instead what we care about is the innumerable class and the link extension methods that are available with it you're going to see just how much power we have there when we expand out the methods here scrolling through you can see all of these different options i'm going to show you what most of the important ones mean how you can use them in your project how they'll save you some time and then at the end give you some advice on how to avoid them causing you any problems so make sure that you hang around for the end so you don't miss that i'd say very important part to demonstrate how to use link statements i've set up a little example you can download the example down below just click on whatever link is down there to get to the example and you can go check it out yourself but i'm going to run you through what the code means and then we'll dive into the actual link examples the first thing we're going to look at is the npc class it's a really simple mono behavior just a component we could drop onto any game object and then use as a prefab in the examples here we'll mostly be thinking of scenarios where we've got maybe a set of npc prefabs but we could also be working with a set of spawned npcs for npcs that are alive and running around in fact we'll even do some queries on the health so we've got npcs npcs have stats that are serializable got some damage attack range strength and wisdom we use maybe one or two of those and then we've got factions so that we can separate these out into different groups using some of the cool link functionality let's dive into some examples and start with the first one the first example that we're going to use is the any statement so in link we can use dot any at the end of any collection here to check to see if anything in the collection meets the condition here so let's talk a little bit about link statements and how they're structured we're going to zoom in quite a bit here and we're just going to take a peek at this part right here right now our link query is split into two lines i'm going to go up one line and just delete that out so that we get it into a single line and we can read it really quickly together let's see what this link query looks like we take our collection here which could be an array it could be a list it could be anything that implements i enumerable let me show you we can change this over to list of npc it's going to work exactly the same it'll work as an array though so i'm going to switch it back with undo so we take our collection and we use the dot any method now to get this dot any method we need to have the using system.link statement in here if i don't have that you're going to see that i've got all kinds of errors and that disappears but i can just hit alt enter and then add the statement automatically that's one of the nice things in writer and visual studio to pop up you hit enter one more time and it'll automatically add just make sure that you have using system.link at the top you'll be able to use this method so what is this method doing let's take a look at it the dot any method is going to do this or check this predicate right here against every entry in our collection or every element in our collection t is going to represent each element so it's going to iterate through each element of our collection and tell us whether or not t or that element of its faction is an elf if that's true if any one of them is true so if the first one is true it's going to return back true if the first one's not true it's going to continue on go to the next one continue on go to the next one continue on until it finds one that is an elf if none of them have their faction type set to an elf eventually it'll reach the end of the collection of npcs and return back a false there's just an easy way to check to see if anything in a collection matches some condition right now we're only checking to see one thing but we could also do an and statement here maybe we want to see if we have at least one elf with a big ranged attack range so we could add two ampersands here right after the elf inside the parentheses and say t dot stats dot attack range is greater than 10. so here we'd be checking the c has at least one elf with 10 attack range now here i would probably split up my statement into multiple lines make it a little bit easier to read including right after the ampersands i'll just put that down onto a new line and then fix up my return statement there and we'd have a statement that checks to see if we have one elf with at least 10 attack range now that's probably not the most useful combination of things to query in there but i'm sure you can imagine lots of other useful things like npcs that are close to you or alive or on the other team and alive and aggro or any other way that you might want to filter to see if there's anything matching that let's go on to another example though let's talk about some averages here we've got an example that shows the average strength of our orgs we can use npcs.average pass in the selector again and in the selector we'll use the thing that we want to select which is going to be our strength int notice that the return type here though is not an int because we're taking a bunch of integers and we're averaging them out we're not going to want an integer because that won't be very accurate as an average our average needs to be whatever's in between if we had a 2 and a 1 we'd want a 1.5 not some number that's either one or two somewhere randomly so we do get back at double and uh it's pretty easy way to just average out things so if you've got a big long list of numbers or just a big collection of things that you want to get the average of you can just use average pretty simple let's look at the average where we're filtered though here we're doing an average statement but we're using the where clause let's separate out the two link statements onto their own line and take a peek at it so we're looking at average org strength by going through all of the npcs filtering them down with the where statement which is a very very important one it's probably the most powerful and the one that i use the most often aware statement filters down this list based on the predicate here so we've got our selector here of t which is going to be each npc it's going to check for every npc that is an orc and then it's going to filter it down to just those and then give us the average of their strength so here we'll get back the average orc strength pretty nice and pretty useful and start to see how we can put together some of these queries and combine them to make more powerful statements that don't require very much code let's go on to the next one the sum of total health remaining so if you want to get an average it's average if you want to get a sum it's literally just some here we've got a statement that gets us back the remaining health of all of our npcs that's of course assuming this is no longer a list of npc prefabs but maybe a list of spawned in pcs we get the sum of their total health because some of their total scores some of the total armor on all of their vehicles whatever the thing is that you want to sum up you just use the sum statement let's go on to the count one now count is a little bit interesting so if you've used count before on lists you know that it just returns back the number of items in there and that's not using the link statement that's just getting you back the size of the collection or the number of elements in the collection what count does in a link syntax is allow you to get the number of elements matching a predicate so here you can see we've got the number of humans by counting the npcs using npcs.count and just giving it a faction check predicate against our selector i do want to point out that i don't often use the count method most of the time it's because i want to pull these things into their own collections and then i just get the count of them so if i wanted to find all of the npcs i might do one of the other statements that we'll get into later to put them into their own collection and then get the count of them there are some cases though where i just need the count of a thing filtered down and i don't want to grab a whole new collection of them and this comes in handy for that now before we go any further i do want to mention that i've been using dark mode for this video and if that's something that you actually like please comment down below and let me know and if you hate it let me know too i don't particularly have any love for it but i know a lot of people like it so if it's something that everybody wants me to keep doing i'll do it otherwise i might switch back so just if it's important to you let me know let's dive on to the distinct example now the distinct word here or the distinct keyword or extension method will filter out entries that are duplicates and return back a collection of things that has only unique or distinct items in it you can see in my example here we create a new list of npcs we create a single new npc and we add it to the list twice to make that list distinct or no longer have duplicates we can just use the dot distinct method in it now distinct method returns back an ienumerable and i thought that was kind of important to note because if you have an ienumerable and you happen to want to turn it back into a list the two list method is the one that you want to use that's actually the first one that i started using in link it's the thing that kind of got me converted i was like oh i can just use this to convert an array over and then i realized i could start converting to all kinds of other things not just lists we're going to dive into those shortly though let's move on to the first or default example first or default is probably the second most used one for me might even be the most used outside of where i'm not sure they're probably right around equal but the first or default method allows you to find the first or null or none item out of a list matching a predicate it's a good way to search a list for a specific entry or if you really just want the first entry any old entry from the list it's a good way to find that as well usually when i'm using first or default though it's to find a specific entry i want to find something by a name by a health or an id or something else like that here i've got an example set up where we're finding the first dead npc and if we find nothing at all we'll get back no it'll say no npcs are dead if we do find one though it's going to say that the first dead end pc the one that we got back is the first entry in the list that's dead i'm going to be real clear that this is not the first npc that died this is just the first one in order in that array that has its health less than or equal to zero so that's what you're getting with first or default you're getting them in the order that they come in the first one that matches that predicate let's look at the first keyword though and see what's different here in this example our line 90 here where we check to see if the first dead end pc is null won't work if we don't have anything that matches the predicate here it'll actually throw an exception now you might think that's kind of not very handy not very useful and i tend to agree most of the time there are very few cases where i actually use the first keyword but there are some scenarios where you might want to just throw an exception and not handle it if the entry isn't there most of the time though you want to handle those exceptions and deal with yourself at least when you're building out your game code now we're going to get into some magic and start using the order by keyword or the order by extension this is one of my favorites the first one we'll look at is ordering by name i've got a list of npcs and here we've just ordered them by name they'll go in alphabetically assuming that t dot name is the game object's name or the prefab name remember t is an npc name on a component gets us back the game object's name so this would be whatever that prefab or the instantiated npc's name is whichever way we're using this npc list so this will order them by name and return us back a list or a new i in ordered innumerable collection to make it into an actual list we could just say dot two list at the end and get it back as a list if we needed it as an actual list but what if we wanted them in the opposite order from z to a or maybe we want to go from high numbers to low numbers in that case we can use the order by descending order by descending just goes in reverse order of order by instead of going from low numbers to high it goes from high to low and instead of going from a to z it goes from z to a now we're gonna get into the most exciting and one of the coolest order buys ordering by a random number so when we use the order by we're giving it a selector and we don't have to necessarily use that selector we can use anything that we want here you'll see that we take t and we completely ignore it and then just use a random range from 0 to 100 this is going to randomize the order for every entry it's just going to roll from 0 to 100 and then order them by whatever they rolled this is a really neat trick and a really easy way to randomly order your objects if you have a large number of objects more than maybe 100 you probably want to go with a larger number than this there's nothing limiting you there's no reason that you can't use min intent accent or min float and max float or whatever you want in here now we're going to dive into some more complex statements like the group by one in the group by statement we get back an i grouping based on whatever the selector is that we pass in here we're passing in a faction as the selector so we'll get back four groups one for each of our factions assuming that we have an entry of each faction in our list or our array of npcs and then we loop through that grouping and you'll see that we'd get a log entry for each faction and then underneath each faction we would get a log entry for every one of its npcs the group buy on its own isn't something that i use often but i do use it in conjunction with some other extensions that you'll see in just a moment let's take a look at the next one which is intersect intersect is an interesting one that i don't often use but i thought was kind of useful to cover intersect allows you to take multiple collections so here i've got just two innumerables of npcs npcs who are elves and npcs who have no health and then you can intersect them and get the combination or the things that are in both of those lists so if we have npcs that happen to have no health it'd be in both of these lists and we'd be able to get those back as this new collection of npcs who are in both collections now since these are both coming from the same source it doesn't make a whole lot of sense it'd be better to just have a where statement with an and and just do the query at that time instead of getting two separate collections back and intersecting them but there are plenty of situations where you get two separate lists or two separate collections from different sources and you need to combine them and see what matches or what intersects between them and the intersect keyword will do that for you these next two are actually really simple and just kind of a break from the more complex stuff that we're diving into and that's min and max min and max just returned back the minimum value and the maximum value from a set so here we can get back the minimum strength value or the maximum strength of all of our npcs pretty useful when we have a big collection of stuff and we just want to find the outliers or the things on the edge now let's move on to our select example and select is really powerful select allows you to transform the data that you're getting back and get something other than what it is you're actually querying so we don't have to get back a collection of npcs in this case we could get back just a collection or an innumerable of factions here we're looking at all of the active factions or getting back the active actions by filtering npcs where they have health greater than zero so only things that are alive and then selecting their faction the dot select here on the next line is just a continuation of our link statement is going to just make it so that we return back the faction here of this selector so t dot faction and then we'll get those back as the collection and return them and we don't don't necessarily have to do factions it could theoretically be anything we could just return back all of the stats object and then have this be stats instead and get back all of the stats of all of our npcs we wouldn't have the npc references to them might not be useful but if we had a stats processor that just needed all of the stats hey maybe that's a way that we could use it let's undo that real quick though and just continue on to our next example say we wanted to get distinct factions me what do i mean by that well i mean that in this example here our factions include duplicates so for every npc here we're going to get back an entry of a faction if we wanted to get back only the factions that still have an npc alive we could get back the distinct ones we could say the same exact statement npcs where health is greater than zero select the faction dot distinct and suddenly we've got up to four or zero if they're all dead this next example requires a little extra code here we've got a page number field and a method to get the next page of npcs this is the type of link statement that you might use in a page ui or a couple other scenarios but page uis are kind of the number one thing that popped to mind so here we have a page size set to 10 and then we get back a list or a page of npcs by using the skip method and the take method so we're using two different link statements here we're using skip to skip over some number of entries the first time through this will be zero entries so we'll skip zero entries and we will take 10 entries the take method is just going to select that many entries or up to that many so if we have more than 10 npcs we'll get the first 10 npcs if we have five in there we'll get those five and that's it now the second time we run this because we'll be incrementing page number here on what is this line 170 now the second time we run through it will skip the first 10 entries because it'll be 10 times 1 and it'll take entries 11 through 20 and return those back out this is extremely handy if you're ever building any kind of ui where you need to make pages and tab through things or if you just need to select things in groups and process them in groups you want to process 20 npcs at a time you can use the take method get those 20 and do some processing on them here's another quick easy one before we dive into the final and most complicated and i think most fun ones here we've got a simple conversion to a list and then maybe back to an array we can also convert over to a hash set or a queue or pretty much any type of collection that we want the next one though is the best which is one that i cover in my game architecture course if you're interested in that make sure that you check that out down below as well and that one is two dictionary two dictionary allows us to convert any of our innumerables over to a dictionary with a key value lookup and the way that i really love to do it is to take a collection of objects group them using the group by so you can see right here on line 189 we're grouping by the faction and then selecting v as the value so i use v as a keyword here for value and k as a keyword here for key just you can use whatever you want in these lambda selectors i could use the same thing i could use p t1 t2 whatever it is i like k and v they're very common standards here when we're using a key in value so we group them by the faction select the objects and that gives us back the i grouping from that we take the dictionary and we use the dictionaries key and then we use to list on the grouping so this gives us back a list of objects let's go back here and look at the type again we have a list of npcs for each faction so now we can look at each faction see all of the npcs in that faction and then use that whenever we want now why would we do this why would he put this into a dictionary we probably wouldn't do it if we were just going to throw this dictionary away this is usually the kind of thing that i would do when i'm going to cache the object i'll keep this npcs by faction around maybe keep it as a field and then use that somewhere maybe when i want to loop through all of the npcs of a specific faction i don't want to do the query over and over and over because there are some performance hits there we're going to talk about those in one second first i want to show you really quickly the one entry or the one link statement that i didn't realize existed i totally missed i think i probably learned it a long time ago and completely forgot about it and that's the lookup two lookup does something very similar to what two dictionary does the two dictionary is giving us a collection here for each faction that we can iterate over and do something with qlookup does the exact same thing with a little bit less code but we don't have a dictionary we don't have an object here with a list of objects that we can add to modify and change we can't add to this later on so if we want to have an immutable object an immutable lookup object of all of my entries here the two lookup option may be better so a case scenario for this would be perhaps prefabs the prefabs aren't changing at runtime we might want to make a lookup of them so that they can't be changed later on something that's runtime like npcs that are alive i'd go with the dictionaries option instead so why would you even want to cache these if you can just write a query like this you can just write this link statement and get the data what's the point of putting it into a dictionary and saving it off or putting it into a lookup and saving it off it's a really good question and an important thing to cover the issue here is that link statements while they are fast and performant generally and extremely powerful they do generate a little bit of garbage and by that i mean that they allocate a little bit of memory that the garbage collector needs to clean up later if you're building a mobile game or a vr game or a console game this can be an issue especially if it's in your hot path and the hot path of your code is essentially code that's run all of the time something that's maybe in an update and a fixed update or just regularly running extremely often if it's generating a bunch of allocations like that and then needing to clean it up it can cause some stuttering so you want to make sure that when you're using link statements you use them in a way that they're not firing off all of the time and you cache the data whenever possible if we want to do a big selection of data from a collection we should select it and save it off somewhere if we can if we're going to use that data again like any code or library or package that you might pull in there's always opportunity to do things wrong and cause bad performance problems but in general i would say that link is relatively safe if you're careful with it and you just profile and watch what you're doing make sure you don't do any crazy statements in your updates or just try to avoid linkin updates and move them to on enable starts and awakes and you'll probably be fine i hope this was helpful and i hope this is somewhat useful to you i know that again link statements kind of terrified me for the first many many years so i wanted to try to demystify them a bit and make them a little bit simpler for everybody to understand so if you like it make sure that you hit the like button subscribe and i'll do more of these slightly in-depth videos also again if you have thoughts on the dark mode let me know i'm curious what does everybody think does everybody hate it do they all love it is it something i should stick with is it going to suddenly make my videos the most popular thing ever i don't know i guess we'll find out all right thanks again also don't forget to check out backtrace get started automating your debugging and crash analysis workflow completely for free by simply clicking the link in the description
Info
Channel: Jason Weimann
Views: 12,746
Rating: undefined out of 5
Keywords: unity3d, unity 3d, unity2d, gamedev, game dev, gamedevhq, code monkey, brackeys, dani, jason weimann, unity3d college, c#, linq, programming, game development, game programming patterns, beginner, unity tutorial, unity game dev, list, dictionary, hashset, tolist, todictionary, groupby, orderby, take, skip, min, max, ienumerable, ienumerator, game devlog, unity game devlog, game development for beginners, unity, game, linq tutorial
Id: D2K0J5tiRtc
Channel Id: undefined
Length: 25min 55sec (1555 seconds)
Published: Sat Jun 05 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.