Making a Multiplayer FPS in Unity (E08. Respawn) - uNet Tutorial

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
thanks for tuning in at brakus hello and welcome to video number eight on making a multiplayer FPS in unity in today's video we're going to have a look at respawning our player whenever his health amount reaches zero today we're just going to lay the basic mechanics out there and then later we can have a look at making it look really awesome so today's all going to be about coding this functionality and syncing it over the network so before we get started I of course want to say that if you have any questions go to farm practice comp and if you want to support me in making these videos well then you can do so at brackish calm slash donate any support is greatly appreciated so that's basically all I want to plug and now we can just open up unity and get started so the first thing that we want to do here is go to the player object and I just want to fix a quick bug from an a previous video which is that our mask here stating what we can actually hit when we shoot is currently set to everything and the point of this is that it should actually filter out our local player so I want to remove that from the list we were lucky that this actually worked because we were shooting rays from inside the collider and therefore unity we're registering the hits but this should be way more stable if you should decide to move the collider or whatever so great and we can just save that so now we can go ahead and open up this player script in visual studio or mono developer whatever you're using and remember the player script hosts this a current health variable and it's a sink of iron meaning that the state of this variable will be synced across all connected clients and it also has this take damage method but this is just an ordinary method so how is it called well if we open up a player shoot script we which is only enabled on local clients that the player set up that takes care of that you can see here that if we get a button then it calls this a shoot method on the client and this simply checks if what we hid was a player and all that and if it was at cosig method on the server saying that a player was shot and you can see this is mocked as a command in order to make unity understand that this was on the server and you can say that it throws a debug block here that will only be shown on the host of course and it finds the player and calls the tech damaged method so the tech damage is only currently called on the server or at least by the server but the state of the variable is synced to all of the objects using this Ingvar but I kind of want to change this because we want to have other methods in or have other functionality inside the take damage method method such as checking if we've died or not and if we have calling a method that actually displays this and we want to do that on all clients not only the server and therefore I want to change this from an ordinary method into what is called an RPC call and client our pcs are used to make sure that a method is called on all different clients so that's really cool and let's try and do this in code so it's actually really easy just as we are able to mark a method as a command by simply writing command here we can write it a maggot as an RPC call by simply writing client RPC and now as soon as this take damage method is called it will make sure to do so on all computers connected to the network and just as we have to prefix it with a CMD here we now have to prefix it with a RPC so it's now called RPC take damage and inside of Visual Studio if you want to change the name of all references you can just press ctrl R R and then we can say RPC take damage and hit enter and now we can see in the player shoot here that it's changed it there also so that's just a handy shortcut you can of course go ahead and do that yourself that's called we factoring what we can do now is introduce a boolean which will say whether or not the player is currently alive or is whether or not he is dead so let's make a private pool underscore is dead I'm going to default that to false then we'll make an accessor for this so a public pool a property here is dead and we want to have both a getter and a setter but I want the setter to be protected so get here we'll return underscore is dead so anything that has a reference to the instance can check if it's dead but the setter here I don't want to just write said I want to write protected said and this make sure that only the player class or classes that derive from the player class are able to actually change this variable so this will say is dead equals value cool and now we can sync oops we can sync this is that variable so we'll just make this s async var and of course this is the exact same as saying public Bowl is dead and then simply doing get protected set like this but when you write it out like this you cannot Mack a probability as a sync var so that's why we have to do the other thing there cool and now down here in the RPC take damage we can basically check that well we only want to take damage if we are not dead so if is dead well then we just want to return good and then down here we can check if current health is less than or equal to zero so if we've indeed died well then we want to call some kind of die method awesome so that's the very foundation of how we will handle checking whether or not we've died and now we can make this private void die because I want this to only be cold through the take damage method so if you want the player to instantly dial them will just damage him by a very large amount and in here we'll set is that equal to true and then we want to disable some components on the player object this will make sure that he cannot move anymore he cannot be collided with and maybe will also disable some renderers in that this is not going to look very cool right now because we're not going to be changing settings on the rigid body or instantiating particles or anything like that we're just going to make this functional for now and then we'll throw a debug deadlock statement saying that transform done name is dead like that that should be dramatic enough and then we want to call some kind of respawn method so call respawn method so we kind of just have to fill in these holes now and I think we can pretty much just go ahead and do that so yeah why not okay so let's first have a look at disabling the components here so basically how I want to kind of sketch this out is I had this idea that we would have an array of behaviors of components so we can simply drag the minion in the inspector what we want to disable whenever the player dies and then at the very beginning of the game will check which of these components are enabled on the client because some components might be enabled for the local host or the local player but not for other instances and therefore we need to check which components are enabled and store that whether or not they were enabled in a boolean array and then when we respawn we simply go through all of the components that we disabled and set them equal to the corresponding boolean in the boolean array so if that sounds very way vague that's fine we're just going to sketch it out here so first off I want to make a serialize field but I do want this to be private and that's simply going to be a behavior array and disabled on death is what I'm going to call this and then we'll make a private bol array here called was enabled so you can see here that for any given index we are going to have a component and whether or not it was originally enabled then we are also going to change this from an awake function into something else but we'll have a look at that in a second so actually let's let do let's do this now so we want to change this into a setup method and instead of having this code through the start of the awake we want to have this called whenever the player setup is ready because whenever we are checking whether or not a component is enabled we need to do that after we've enabled or disabled components in the player setup script and therefore we could put a a yield wait for a certain amount of second statement in here and that would time it up but I think it would be better to simply tie these together and have the player setup call a setup method on the player here so we're going to make this a public void called set up and for now it's simply going to call this set defaults method but I want to go through here and set the was enabled equal to a new boolean array and the length of this is going to be the disabled on death arrays length here so those are going to be the same and then we can simply loop through this by the way if you write 4 and then hit tab oops 4 and then hit tab here twice and that will allow you to simply use a template for the for statement so I want in this to be I and I want this to be what's enabled dot length and then enter and there you go so that's a very easy way of creating four statements and then we simply say what's enabled to the eyes increment equals disabled on death i dot enabled so we just loop through all of the different components and store whether or not they're enabled in this boolean array and because we are not going to be reordering any of these arrays we can do it just like this if we were going to reorder stuff we might need to have a dictionary in here or something else but this is going to work just fine and then we go on to setting the defaults here and I'm going to want to have a look at the defaults method so in here we of course want to set instead equal to false we're also going to want to say for and again we can use this shortcut here so int I equals 0 and then disabled on death dot length so we want to loop through that and we simply want to say that disabled on death to I dot enabled equals was enabled again the I on position here so here we're doing the exact opposite of what we just did we are saying that we want to loop through all of the components and we want to set the enable state equal to whether or not they were originally disabled or enabled so we are basically just reversing the process there I also want to have a special case for the collider but because it turns out unity has defined this idea of behaviors you can see up here that this is a network behavior a network behavior derives from mono behavior which derives from behavior and a behavior is just a component as stated by unity that can be disabled or enabled however how however unities colliders can both be enabled and disabled but they are not actually derived from behavior they are just derived from component which behavior also derives from but components cannot be enabled or disabled but colliders can so we cannot actually store a Collider in this behavior array and therefore I just want to create a special case sort of say for this Collider and I want to make sure that if we don't have a Collider well then it's just going to ignore it so we're going to say here Collider coal equals gate component type Collider this will work of course with any Collider and then we check if Collider is not equal to null so if we actually have a Collider well then we want to enable it here so enabled equals true and this is of course going to work for our instance and most instances if you have a Collider and only a single one sitting on the game object where the player is this is going to work if you have multiple colliders or don't want it to be enabled from this side or anything like that then you're going to have to write some more code but this should give you an idea of how to do that you can create a similar array using colliders instead of behaviors and do the exact same thing cool so that should set our default just right so now in the die method we can go ahead and loop through these and disable them so for and again I'll use this shortcut here oops and this is going to be I and the length here is going to be disabled on death that length once again cool and then we can simply say that these are able on death the element that enabled equals false simply loop through all of them and disabled them and then manic again going to kind of copy this down here sim you're going to get the Collider component check whether or not it's null and if it's not null well then we want to disable it awesome and we write out the debug deadlock statement and now we are actually ready to call the respawn method because right now it should actually be working however we once we die we don't respawn but that's fine I mean so let's try and set this up first so let's just make sure that we actually call this a setup method so if we go into our player setup script you can see here that in the stat function we check that whether or not we're local player to save with some components assign a remote layer do some stuff with the scene camera which we are later going to move out of this because it doesn't quite belong and well then down here once all of that is finished we're actually ready to call the method and you can see that we already require the component with type player so we're basically able to just make the assumption that it's there and say get component player dot setup if I'm actually able to type this out I just got a new keyboard uh-huh so ah bear with me here all right so now we are calling that method everything seems good whenever you have to do with networking and making sure that all of these things are calling each other on the right lines and all that it requires a lot of debugging so if this actually works I will be the happiest person on earth so let's just go ahead and make room for two here and the first one is going to be the player controller to make sure that we won't move so if we just completely disable our play input with then of course we'll stop moving the second one here is going to be the player shoot script there we go and it will automatically disable the collider and I think that should pretty much be it I mean you can go ahead and drag in stuff like the network transform and all of that but I don't think it's going to be necessary and this should disable the most necessary components all right and I'll also go ahead and leave the max health at 100 but I think I want to just make our weapon a bit more effective here so instead of a damage of 10 let's do a damage of 40 cool and yeah so in order to actually try this out we could go ahead and just build it all the time and then start shooting players but I'm going to show you a very quick way to just check if this is actually working so in our update method we are just going to check if we are the local player and if we are not local player well then we're going to return we just want this to call on the local player for now and then here we are simply going to check if we get a key down with the key code or and the key we're going to check for it's the KCAL for kill k key for kill and then we want to call the RPC take damage there we go this is going to poop and of course we need to give it a huge amount here so just a bunch of nines there so now we can simply press the K key and that will simulate us being shot so if we go in here under the line host hit K you can see that I'm unable to move now if we go under the player object here player controller is disabled player shooters too is disabled if we go in here up here and change this to debug we should be able to see that is dead is now true and our current health is something a huge negative number here and you can also inspect the disabled on death here and the once enabled so you can see that both player controller and player shoot was enabled at the very beginning and that's true because this is the localhost so of course they were enabled but if other player or if we viewed a connect the clients instance of this player these would be false both of them that's why we have to have this in here so now we can jump out of debug mode again and I think we are ready to code the actual respawning now so in order to do this what we want to do here is here we want to call a respawn method and we'll do this by using an enumerator because we want to wait a certain amount of seconds and therefore they are really smiled and we've done this before at least in other videos so if we haven't done it here this is how you do it so up here we want to be using system dot collections and don't ask me why that's just something that we're going to do then down here we can make an eye enumerator and this is a method like any other this is a return type just like writing void but it just looks very scary but in reality it's very easy to use I will call this respawn and it's not going to take in any arguments here and we're just going to - private not that it matters and then we're going to write a write after me yield return new waitforseconds and this is with all caps and then we want to wait a certain amount of seconds for now we're just going to wait three seconds and then we want to start the respawning so we are going to set our default values then we're going to find a start point that we want to spawn at so we're going to set create a transform start point here and that's going to find the network manager dot singleton which is the instance of the network manager in RC and we should maybe do some checking here whether or not it's actually then all that part let's just go ahead and do write this out so singleton dot and then get start position and that will return one of the spawn points in the registered in the network manager so now we can simply say that transform that position equals start point dot position actually I'm going to rename this to spawn point I think that's more clean and again look here I use the double control RR you need in order to rename all the variables and then we want to set transform the rotation equal to spawn point dot rotation also so that should actually respawn our player and now all we need to do up here is call it so you might go ahead and do respawn like this but that's not actually valid what we need to do instead is we need to call the stat co-routine and for some reason that sparking outs of the start co-routine and then in here we put the respawn method so that's what we want to start and then a semicolon and there we go so that should basically be all and this should be working out so let's just test it out hit play here select host let's just move out here kill ourselves so now we can move you can see it says player one is dead and there we go we respond so let's just make a debug deadlock statement in the respawn - so down here we'll say debug dot block player re spawned we'll give it the name - so transform the name + respond grade um and the last thing here's respond time is a pretty important value for pretty much any fps and therefore hard coding indeed here would be kind of stupid especially if you wanted to later say let the players control how long it's going to take to respond so let's instead create a class that will store important settings settings for a match so let's define a new class here create C subscript called match settings I will just double click that reload all here and it's not going to be using well neither unity engine or system dark elections and it's not going to derive from anything for now it's actually only going to store a public float spawn or respawn delay respawn time and we are just going to set that equal to 3 seconds for now the only thing that I want to do here is I want to mark this as a system that's serializable and that will allow us to use it correctly and it will allow us to make sure to change these values inside of the unity inspector when we embed it into another class which we're going to do now so we are going to open up the game manager and this is going to host or this is going to have a variable storing the match settings for now we've just used this for registering the player here the kind of keeping track of different players and we are going to be using the game manager for multiple stuff but in order to not clutter this completely and have a very long script I'm just going to quickly define a region here so if you rise write a hashtag region and then you write the name of the region and this is just um player tracking or play registering or whatever you want to do I'm just going to call this player tracking and then down here we want to end the region then we can actually here collapse that and that's really cool so now we have this collapsible kind of part of the script and that makes it very easy to kind of get an overview of your scripts I do this all the time when I write longer scripts because sometimes it's just useful to have a lot of functionality in one place and then regions pretty much saved my life without those getting an overview of what you're doing would be so difficult so now we can kind of create the other part of the game manager here and it's going to start a story a public match settings and it's just going to be called match settings here and we're going to be configuring this in the inspector so I don't want to set it equal to something and of course the game manager here there only exists one in the scene scene at any given time and therefore it would be kind of a good idea to turn this into somewhat of a singleton pattern so a single told pattern I don't think I've talked about this yet but it basically say Glee allows us to only have one instance of something running at any time and we're not going to have any control on this but we are going to store a static reference to that instance so if that sounds very weird to you don't worry it's super as easy to set up the singleton ID or this is going to be a very very cheat C easy way of doing a singleton but it's actually going to work just fine so we're going to define this a public static game manager variable and this is going to be the instance some call it singleton as you saw here the network manager calls it singleton network manager that's singleton others just do ins yeah I've seen a lot of different stuff here but I like instance it's very clean I think and it describes what it does and then inside of the wake method here we simply set instance equal to this and we can check if there's another object in the scene so if instance it's not equal to null that means that something else has set this up before us and that means that we have another game manager in the scene so we want to write out an error here saying diverted LOC error more than one game manager in scene and if not well then we can set the instance variable here good so that will make sure that we can always very easily get a reference to the game manager without it and without having to do a game object dot find or anything like that so when we now head into our player script we can go up here and even create a reference to this up here if we want to do that that might even be stupid I think it's even too much to do that instead we are simply going to go down into the respawn method here and then we are going to say game manager dot instance dot match settings dot respawn time there we go so it's simply going to find the game manager that we have in our scene access the match settings access the respawn time value and that should be all hopefully so now I think we can just comment out this update method here that was just for testing so there we go calm that out by the way in order to comment out actually they change that shortcode yeah I don't know no but you can comment out a lot of stuff by making a multi-line comment like that if you want to boobs alright so let's save that and let's try just clearing out the console here there we go let's try building this there we go and whenever we build the player we have to wait for unity to update the lining here and it is done so now like that so we can making may-maybe make this the host and connect this as a client and I'm just going to go down here I'm going to shoot our host you can see it says his he's dead and he responds and we can see it's it's very cheery and the reason why is that it uh it tries to smooth his precision when he's teleported to the right spawn point but we're not going to be worrying about this because well frankly we don't have anything to show that he's currently dead that's in a later video you can see he can now move around again so we can shoot this guy says he is dead you can see he can't move we respawn and now we can move again so that's basically it for responding and this should work pretty well yep so that's all for this video I hope you enjoyed it and I'll see you in the next one
Info
Channel: Brackeys
Views: 83,629
Rating: undefined out of 5
Keywords: unity, unity3d, tutorial, material, materials, settings, how, to, howto, learn, learning, course, series, tips, tricks, tutorials, workflow, fix, tip, technology, game, development, develop, games, programming, coding, basic, basics, C#, spawn, respawn, unet, networking, networkserver, network, waitforseconds, static, singleton
Id: biOL7jCuV1g
Channel Id: undefined
Length: 32min 55sec (1975 seconds)
Published: Tue Dec 22 2015
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.