5 ways to make your unity3d code faster

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hey what's up jason here have you ever been working on a game that seemed like it was working great everything was running fine in the editor everything was good on your computer but then you went to deploy it to a device and suddenly it fell apart or maybe you gave it to somebody else and they tried to run it and the performance just wasn't there it fell apart and broke and wasn't playable if so then this video might be perfect for you because that's the scenario that one of my students ran into she's building a game got it all going everything seems good plays fine in the editor plays fine on a laptop but you go out to an ipad and suddenly well performance just isn't up to par and doesn't work so i'm going to give you some tips today on how you can avoid that some really quick simple code tips that will resolve most of these problems and my number one tip that'll solve just about all of them now before we get going if you have any good game performance tips that you can share please drop them in a comment below they're really helpful and everybody reading them i'm sure we'll get some use out of them also don't forget to like and subscribe and if you're curious about being a student of mine just check out the link below you can see my new course that just opened up all right let's get started with the most important tip and that is to learn to use the profiler before we get into debugging code issues and fixing minor code things you need to understand how to use the profiler or that it's there it will save you a ton of time in fact it could save you years of just pain and frustration it's one of the few things that i wish i'd learned about earlier so here i've got a project open this is from my new angry birds tutorial that'll be coming out for unity 2020 and it's just a bird that i can drag around nice simple game and i can launch birds over there it runs fine but there might be some performance issues when i deploy it out to a device in fact i know there will be because i intentionally put them in now i'm going to open up the profiler and show you how i would find those issues if i didn't put them in intentionally so what we do is go to window and then go to analysis and profiler by the way there's a new standalone profiler that's really cool pops out a second window that's not completely tied to this unity instance so that we can profile without getting the downside of the performance impact of the actual editor so you might want to check that out if you're not new to the profiler let's go into the actual profiler window though so go to analysis and profiler or ctrl 7 to open up the window this should pop up a window like this it might be off screen if it is just grab it and drag it over here what i usually do is take the profiler and dock it down here by the project and console this makes it a little bit small so i can't see everything so i'll just drag it up a bit now there are a bunch of different areas in here that we can scroll through there's the cpu usage which is where we're going to be focused today there's rendering memory usage audio stuff video physics 2d physics networking ui ui details global illumination all kinds of different stuff you can profile again we're going to focus on the code stuff today it's the simplest and easiest to fix and it's also the most common problem that just about all of us will face so here you can see just a bunch of bars going by if i stop playing those bars stop playing it's just showing me the profiling data for every single frame of the game so imagine we run at 60 frames a second this is going to show me 60 frames worth of data every second here you can actually see the frame counts that it's done so if i just click anywhere what will happen is the game will pause and it'll show me the data about the specific frame that i clicked on so i clicked on this frame right here which has a frame number 26 121 and it's going to show me the information about that frame on this little bar chart or i guess it's an area chart but also down here in this overview if you don't see the overview you might be in timeline view switch over to hierarchy view timeline view is useful if you're doing a lot of multi-threading stuff if you're not hierarchy view tends to be a lot easier to use so i would recommend starting with hierarchy view until you get really familiar with it then maybe looking at the timeline view so here it says we've got an editor loop and a player loop i'm going to expand out the player loop there's something to note here i have the deep profile button checked if you don't check this what you'll see is that you'll get some of this data but as i expand it out you won't see all of the script specific details you have to check deep profile before you play to actually get the script specific details of your script so let me show you what that looks like here we've got our player loop and you can see here it says update run script behavior update and if i scroll over to the right or just move my mouse over to the right you'll see that the total percentage of the time was 16 so that means that 16 of our games time or our cpu usage was spent just running our scripts updates so whatever it was in there took 16 of the time that may be a big deal it might not be a big deal because it might just be that our game isn't doing anything else and the rest of the time it's just sitting there waiting so don't always worry about the percent you want to worry about the percentages when your frame rates are dropping then it makes it really easy to tell which thing is the highest the thing that i want to look at though is the time in milliseconds right here you can see it's at point five i also want to look at the gc aloo because this is another big one garbage collection allocation is a big problem and it will cause issues with our game where we'll get stutters or freezes through the game especially if we're building out to a mobile device so let's expand it out and here you see it says behavior update i'll expand one more time and we can get to the actual code that's offending so it says our monster update has an issue or our monster update not necessarily has an issue but is the top thing in our profiler it's the most expensive or slowest thing and it's the most expensive by a lot if we look at the time in milliseconds it's half a millisecond again tiny because we're running on a really really fast device we run on a slow device this is going to be much bigger but if you compare that to everything else here which is like point zero five point zero two point zero two and point one five it's by far the biggest thing now your numbers are definitely gonna be higher if you're in a real game by the way let's expand this out though and we can see a little bit more and look at that debug.log this is probably the number one thing that ends up killing performance for people is that they start writing out a bunch of logs and they don't realize they're also writing them out two devices i'm going to show you how to fix that in just a minute in the next tip now i don't want to go too deep into the profiler i have a whole video on that you can check it out if you're curious but i do want to show this little spike here these little bump areas if i scroll over or just kind of click and drag over you can see the numbers adjusting for the frame and i can get to these big areas where there's a peak and this is usually what you want to look at you want to look at a couple frames along here and then find these big peaks and see what's happening in these peaks and if we expand it out expand out our behavior we'll see that we're actually getting this collection this gc dot collect that's what these big spikes right here of this orange are and that is the thing that's going to cause the big freeze or frame loss or just kind of a pause on a slower or older device or especially on a mobile device and that kind of leads us into some code for our next issue which was that debug log how do you stop debug logs from spamming on a device and killing performance there's actually a really easy trick that you can use i'm going to expand out this awaken my monster and show you what it looks like we can actually call debug.unitylogger dot log enabled equals true to turn it on or false to turn it off and i'm using the if defines or the pound or hashtag if defines a compound defines for if it's in the unity editor or if it's not in the unity editor what this is going to do is compile this code only if we're building for an editor build so if we're basically hitting play in the editor if we're doing a release build or even a debug build that's not a release build but we just did a development build this will still run because we want to be in the editor and it will turn off all of our logging this is just an easy way to disable all logs on all of our builds pretty cool trick right all right let's go on to the next one the next tip will take us back to the profiler but first we're going to look at the code and that's right here in our update this is the code that was actually running slow when i looked at it in the profiler initially and here we're trying to find the nearest other monster these are just monsters in our game so you see these little bad guys right there and we just want to find the nearest one and he's just spamming out that he's closest to that one imagine we want to do some kind of friendship or allyship or healing or something between them right now we're just logging it out so this code right here seems relatively simple and straightforward if you're very familiar with link if you're not familiar with link it might look terrifying don't worry i'll explain it real quick and then i'll explain why this might be an issue so here we're finding all of the objects of type monster so we get back all of our monsters and this is just going to give us an array of monsters or a big collection of them then we're going to filter them using the where statement this only works because we have using system.link up there if we don't have that our wear won't work it won't show up as an autocomplete we'll have a compile error it might recommend that we add using system.link so what is this where statement doing well it's saying hey for every object in this list so for everything in this set of monsters refer to each one as t for a little do a little comparison right here so we'll say for every one of them if it's not equal to this monster so the actual monster that's running this update then it's filtered into our list so where means hey only include the ones that match this case so the ones that are not equal to this then we're going to sort them with the order by and the order by does the same it'll use this t variable for every instance of them by the way i can change this doesn't have to be t it could be m for monster or i could even use like a full variable name like monster and they can be different in between these or they can be the same the scope of this variable right here is only in the va in the context of this one statement this order by so this is filtering them and then ordering them and then finding the first one or default default for monster is null because it's a class and that means it's nullable by default so it's going to find us the nearest monster in our update seems pretty simple it's actually a really really fast code to run if we go into the profiler and just take a peek at it go back to the profiler and i expand it out you'll see that our first or default was really fast 0.1 milliseconds our where statement right here is zero our order by a zero so might think hey this is all great it's nice and fast it's easy to understand if you're familiar with link and it just kind of works there's an issue though this gc alok right here we're allocating a tiny amount of garbage a couple hundred bytes every frame but it adds up right now without the log i don't know exactly what we're at but it's still a good amount of um i guess 1.3 kilobytes of allocation and that adds up because it's every frame so if we do that 100 times a second you know it's going to build up really really quick and we start to hit these issues so with link statements don't use them in an update don't use them in cases where they're going to be run regularly it's fine for one offs it's fine for an update or not an update in a wake a start or just a one-time method that needs to run and generate some garbage is fine but don't do it in something that's running every frame avoid link statements in updates essentially and in fixed updates or in anything that's just constantly running minimize them and again go back to profiling this next tip is a pretty simple one but it's one that people forget about or miss often especially when they're getting started out and that's that we don't want to be getting components constantly it's best if we cache them and do these slow operations once instead of a bunch of times this doesn't only apply for getting components but that's the easiest scenario to show and the most common one so that's what i'm going to show you here i've got my bird set up and i've got this awake method that goes through and does some setup on the rigid body to control that bird that was flying around and does some stuff for the line renderer to show the dots showing the angle that i was going to launch my bird at and then if we look down here a little bit further you'll see that we do some more work on the rigid body when we're resetting and then when we hold down the mouse we get our sprite renderer change the color and then we do some more stuff with the line renderer again continuing on and on and on in every one of these methods all of these methods are constantly doing a search to get components on this object now that's not extremely slow git component is not a very very slow call but if i did this on something that was not just my single bird maybe i did this on a character that i have a hundred of maybe it's on my monsters and i'm constantly getting components it's going to add up and it's needless slowness that's just going to hurt my game so it's an easy thing to fix and i'm going to show you how to fix it now also if we were doing something other than git component like a find object of typing trying to do that every frame it gets much much worse and just kind of builds up so let me show you how we cache these really quickly the easiest way to do it is to take one of these little chunks where i'm getting a component like git component rigid body 2d i know that i want to cache all of my rigid bodies and just save them off i normally do that in an awake i'm already in an awake so i'm not going to add a new one but if i didn't have an awake method say that this was start in fact i'll change it to start just to make the case what i would do here is add an awake method and then i would say underscore rigidbody if i'd spell it right though equals and then i would paste in the git component rigidbody2d and hit home hit alt enter and generate a field for it this will give me a private field for my rigid body that i can cache the rigid body reference on delete that private keyword in this private keyword just because they're unnecessary and i don't have them everywhere else get rid of that one too and then what i would do is copy this rigid body well first keep this on my clipboard hit ctrl shift f no not control shift f control f and then hit the expand button right here so if you're in visual studio this is the find in the current file ctrl shift f is find in all files bad habit of mine so hit ctrl f and hit this and then what i want to do is paste down here on the bottom what this does is make it so it goes from a find to a find and replace so on the bottom i'll paste in my git component of rigidbody2d oh no i want to do that on the source paste that in as the source and then for the bottom i just want to replace that with underscore rigidbody there we go and then what i can do is either replace next or because i'm confident in it and i know i can undo i can just hit find all or replace all i hit okay notice that that does break this first one so i need to change this back actually i have that on my clipboard so i'll just paste it in and here i just continued along and did the same for the other two so you didn't have to watch me do it but went in and made a line renderer that's cached as well with the field up here and a sprite render and then did the find and replace here this will fix a lot of the issues there's one other little thing in here though that experts might have caught if we scroll down here one thing people don't realize is that calling camera dot main actually finds the object of type with a tag so if we're doing that in our mouse drag or in our update we're also wasting performance so we should probably cache this camera as well to do that i'll just take this camera.main i'm going to hit shift delete to put it on my clipboard and say underscore camera then i'll hit control home to go up to the top and in my awake i'll say underscore camera equals and then i'll just paste in camera.main this next tip applies to just about everybody it's an issue that every unity developer i've ever known has run into and had to fight with and then learn their way around and that comes with spawning a bunch of objects and allocating a ton of garbage usually what happens is we spawn an object we use it for a little while and then we destroy it and then we spot an object use it for a little while and destroy it and if we keep following this process we can run into problems especially if we're doing it rapidly here i've set up a simple example where i can spawn a bunch of objects with this particle clicker and i just hold down the mouse and these little firework particles from the free cartoon effects pack up here and you see them over on the left just filling up my hierarchy and i'm going to stop and click on the profiler if i go to any one of these frames here you'll see that the gc alok amount is 112 bytes i'm allocating that much memory for every single one of these particles these are very simple particles too if it was a bigger prefab or object it could definitely be quite a bit bigger so how do i stop that well first let's look at how it's done right now how it's done wrong and then we'll look at how to fix it into a simple pooling system for particles and then we'll show it in action all right so we'll open up the particle clicker script and here you see that we have a reference to a particle system using this particle prefab name and the serialized field attribute that was assigned to a cartoon effects prefab let's go look at that real quick so here i've got my particle prefab and it's assigned to the ctfx2 spark hit so i'm going to stop playing and go look at that because i did make a small change to it so if i go select it and click on it you'll see that it has an auto destruct script i actually turned that off the reason for it is primarily that it generates some garbage when it runs it runs a co routine which allocates so even leaving it on with only deactivate still causes a little bit of garbage and i don't want to clutter it up so that's turned off and that's what we're using to spawn the object that's the particle that we're spawning we get our mouse position right here on line 11 see where i clicked and we're doing the nice slow non-cached camera.main call and then we spawn the particle by calling instantiate of the prefab at the position using just the default rotation not much in here so let's look at the cleaned up version how do we speed this up so that we're not spawning a particle every frame if we go into our particle system pooled and remove my break point here you see that it starts off very similar we've got a particle prefab and then changes kind of right here update looks exactly the same no difference but we do have a field here on line eight for a queue of particle systems and a q if you're not familiar with it is just like a cue in the real world or a line in the real world where things go in at the end and they come out at the beginning so the longer something has been in the queue the sooner it will come out first in first out is essentially what it is so we've got this list of particle systems or q of particle systems that's in order and then when we spawn a particle at a position instead of just instantiating it we're doing something different on line 20 here let's just zoom it in a little bit zoom.1 there we go on line 20 first we look to see if there are no particle systems in the queue if there's nothing in the queue then we aren't going to be able to pull anything out of it and reuse it so we're going to need to do the lines here on 22 to 24 to instantiate a new one play the particle and then enqueue it the other thing that we do so we check to see if there are none in there but we also check to see if the top one or the next one ready is playing if the next one ready is still playing then hey that one's not actually ready it's just the next one in line so we'll spawn another one and add that one to the queue so this way because my particle systems are all playing at the same amount of time i can just reuse the last one or the oldest one and know that when that one's done playing the one after that should be done playing two and just kind of keep going on so assume that i didn't find one we'll spawn one and we add it to this list what if we do find one well then we dequeue it using the dequeue which is just the opposite of enqueue which takes that first one from the line we set it to active just in case anything turned it off then we need to do the important part of setting its position and telling it to play again and then we'll add it back to the queue so that it'll be at the end of the line next time so next time we want to spawn a particle it will keep knocking them down out of the line and let this guy move up that's all we really need to do this now if you're not doing it with particle systems you won't be able to check like is playing instead you might want to check something like whether or not the object is active but also if your objects aren't deactivating and activating at the same time what you might want to do instead is set up an event that fires off whenever the object is disabled that just re-adds it to the queue or add some code into that object on disable so that when it disables it just adds itself back into the queue if you're curious about that i've got a bunch of different pooling videos and i'm going to do another one that's a lot deeper on different pulling techniques later just make sure you're subscribed or go look at the channel you should be able to find the pulling videos all right i've got a lot more tips but this video is already getting pretty long so i'm going to wrap it up here but if you're curious about just game programming or learning more about game programming make sure that you're subscribed and that you just check out some of the other videos or of course check out my course that's down below as well and also i wanted to say a special thanks to everybody who's already subscribed and already one of my students i really appreciate you guys you're all awesome and definitely a special thanks to everybody on patreon as well alright i hope this was helpful and you're able to apply it in your actual game projects thanks again for watching thanks for subscribing and hitting that thumbs up and goodbye
Info
Channel: Jason Weimann
Views: 36,412
Rating: undefined out of 5
Keywords: unity3d, learn to code, learn unity, game development, game development course, game development tutorial, game development unity, unity tutorial for beginners, unity performance, unity profiler, debug.log, jason weimann, brackeys, pooling, how to learn to code fast, unity, unity2d, game development for beginners, unity tutorial, computer science, unity tutorial for beginners 2020, unity game dev, unity3d college, unity 3d, game dev, unity3d 2020
Id: KErkmxbkBs8
Channel Id: undefined
Length: 20min 14sec (1214 seconds)
Published: Sun Oct 04 2020
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.