Godot Multiplayer Tutorial - Syncing Animations and Attacks | Godot Dedicated Server #16

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
in this godot multiplayer tutorial i'll teach you how you can make sure that all the animations in the game world from every single player and projectile are visible for all the players let's get started so let's first work on that idle and walk animations and we'll leave the attack and the ice spears for just a moment from now i'm right here on the client project i'm on the player script the player that you're controlling in a previous tutorial we already created this function define player state the play state which is then send off to the game server 60 times per second we already had the timestamp and the player position and i've now added the a for animation vector the animation vector is going to help us determine which animation we need to be playing north west south east or top bottom left right however you've caught your animations one note to take here and i've changed the operating system time into the synchronized client clock this is not important for this tutorial or the code thus far in this entire series but it will become important once we start moving the physics to the server in the next couple of tutorials so with that said let's get into this animation vector how do we get it and how do we use it for the animation vector i have first defined it on the top of the script as a vector 2. to determine that animation vector we actually already have the code available to us we just need to make a couple of slight changes right here on line number 31 and 32 we're setting the blend position of the animation tree which helps the animation tree pick the right animation direction the input for the blend position and let me make this a little bit bigger is actually a normalized vector perfect for what we need for our animation vector so instead of these two lines and calculating that animation vector inside this these functions i'm simply going to be first determining the animation vector as that same piece of code and then we'll push the animation vector into the animation tree that makes the code more readable and it makes the engine doesn't have to recalculate these vectors now on every time that this action is pressed attack we are not only setting the correct animation for this player but we're also going to be pushing the animation vector into our player state so we can display this animation for any other player that sees this player on the screen now of course this is only for attack so i've done exactly the same in the movement loop which is called on every single delta frame in the physics process engine right here we have the two lines for the animation tree which used to have instead of the animation vector movement normalized now i've also added the extra line of code by defining the animation vector first so that it can be pushed into the player state that is then being sent off to the server now as these player states are going to be sent off to the server the server is not going to do anything with them we're not playing any animations on the server there will be a waste of resources so the player states are simply going to go into the world state as we've done before and all the world states are going to come back to all the players so that all the players have the correct animation vector which which they can show the correct animations for any other player that they see on the screen so let's go into that piece of code now for every other player let's first have a look at where we are processing that world state we do that on our map script within the physics process function where we do all our interpolation and extrapolation of both enemies and players for every player we were in previous tutorials already defining the new position and pushing that new position into the move player function of that other player now on top of that we are also distilling the animation vector out of the world state and will push that animation vector to the move player function as well now we can switch to the player template and see how we are using that new animation vector on this script there is a lot of new code as previously this only used to be two lines of code it used to be move player function with a set position now we got a couple of variables here on the top that i'll skip over as those have to do with attacking and i spears and we'll start here on line number seven first we have to define the animation tree and the playback parameter within the animation tree as the animation mode those are two lines of code that are also existing on the player script as they come straight out of that tutorial that i've mentioned earlier about the animation tree now keep in mind that i've made a one-on-one copy of the note 3 for our other player that means that my note 3 is exactly the same as the original player that also means i have the same animation player with all the animations and the same animation tree that governs the behavior of those animations so we're going to be making use of very similar code as we had on our player every time that move player is being called which happens 20 times per second as it happens on every time that a world save is being processed we're going to push an animation vector into the blend position of the animation tree now the only thing that's left to do is determine when are we idle and when are we walking for that we can make use of the new position that's being sent we can compare that to the current position of this player if they are exactly the same that means that the player must have been idling and we can travel to the idle animation if that is not the case and the positions are different then we can travel to the walking animation if we are walking and if that position is indeed different that's of course the moment that we have to set the position to the new position as we previously did in previous tutorials now on to the fun stuff attacking and projectiles i'm going to start on the player script under our function unhandled input is action pressed attack we're running the attack function there's nothing new here this has all been in place since episode number one under the attack function we have the code that we had previously already which instances in an isp for this client now of course we want this i spear to also instance on all the other clients and for that we have this extra line of code game server send attack with the position of this player and the animation vector now there's an important question to answer here and that is why do we not put this attack in the player state if we were to put this in the player state we're going to have to be adding a couple of variables to the player state something like we are attacking and maybe what skill name or weapon we are using if we were to do that we are increasing the size of the packet that is being sent to the server 60 times per second now ask yourself are you attacking 60 times per second even in a hacking kind of game you have to be moving from enemy group to enemy group you got your cooldown time for your skills you got your attack speed for your weapons in a shooter kind of game like a battle royale pop g you are most of the times busy with looting and moving and positioning you don't actually pull the trigger that often if we were to increase the size of the packet that's being sent to the server 60 times per second with empty variables because we're not attacking in that moment we're just having variables which are dead weight in all of those packets we're just going to increase our network bandwidth usage that's basically going to make our players unhappy plus once the player state arrives on the server the server has to be doing a check with probably an if function if there is actually an attack in that player state it has to be doing that check 60 times per second for every single player in other words we're going to be burdening the server we're doing a lot of if checks with most of the times will be invalid or not true so we're basically using a lot of server power for nothing so instead of burdening the network and instead of burdening the server with all those requirements we're just going to be sending this attack straight off to the server so we only need to use the network bandwidth for the attack we're actually doing and we only use server capacity the moment an attack actually happens enough of the talking let's get coding again we tell the game server to send the attack switching to that script on send attack we receive those two variables we're going to call the server we send those two variables to the server and a third variable which is the client clock that's the timestamp that this attack happened we need that time step so that all the other clients will know at which precise time they need to be displaying the animation and instancing the ispear switching to the server that's going to receive this call is going to receive that remote function called attack it receives those three variables it determines the player that made the attack by determining the player id is then going to rpc call every single pair in the network indicated by that zero there and it's gonna return those four variables to the function called receive attack switching back to the client on receive attack we first have to determine if the player id determined by the server is equal to the network unique id of this client if that is the case it means that this is the client that made the attack in the first place it's its own attack in which case we won't of course want to skip this one otherwise it means that is another player's attack in which case we're going to get the note of that particular player using that player id again and we're going to be adding this attack to the attack dictionary on that player template script on the attack dictionary we're going to be making use of the client clock that is now defined as spawn time as the dictionary key and we add the position and the animation vector oh the animation vector as elements of that key so now we can switch back to the player template where we had a couple more lines of code that i needed to explain to you first of all these three on the top it's a good time to talk about these we have the ispear which is a pre-loaded scene of the ispear we have the attack dictionary that starts out empty but as you just saw we're going to fill that one up and we have the state that's going to be important to handling our animations now you might be wondering why are we adding this attack to a dictionary and why don't we process it immediately there's a time stamp on that attack and it might be the case as this client is rendered 100 milliseconds in the past for interpolation that the attack is actually once the client receives it still an attack that needs to be happening in the future so we may not want to display that attack immediately therefore we're first saving it then under the physics process delta function we're going to be checking if the attack dictionary is not empty in which case we want to run the function attack on our attack function and let me make this a little bit bigger we're going to go over every attack within the attack dictionary keys remember those keys were timestamps so we can check that attack against the client clock on the game server and if that attack is smaller or equal to that client clock we know that time has passed along far enough that we can now instance in this i sphere and do the attack animation let's first do the animation of the actual character we are setting the state to attack now get back to that state in a moment we're going to set the blend position of the cast animation within an animation tree to the animation vector that was received by the attack we are going to travel to that cast animation and we're gonna set the position of this player to the position that was communicated in this attack we have to set this position on top of the set position we already do in move player because there might be through to interpolation and extrapolation a very small deviation and if there's a very small deviation it might look like the ice spear doesn't come out of the hands of the player that might come out of the arm or if you got a spaceship with guns the the bullets not going to come out of the muzzle of the guns but are going to come out of the spaceship hole or same case with a shooter so we don't want any of those weird glitches or artifacts so by heart positioning the player based on the position that was communicated by the original client that made the attack we can make sure that those animations and those instances of the bullets or projectiles are lining up exactly so once we've got that done we can now instance in the i sphere and we use this code here this code is very similar as you can see to the code of the original player we're instancing the ice sphere the only difference is that the player is using the get global mouse position on a number of occasions and of course we don't have access to the mouse location of the client that is somewhere else in the world so instead of that we're going to use that animation vector so have a quick look at this code pause it if you have to and have a look at this code where we use the animation vector in a couple of instances pause it if you have to and write over the code make the small adjustments that are necessary now what about those states now as you have seen i'm setting the state to attack at the start of the attack and back to idle at the end that makes sure that for the 400 milliseconds that this animation lasts our state is in the attack mode if we were to continue the code as is 15 milliseconds later a new world state is going to come in and this move player function is going to be called which is going to set the animation mode to either travel to idle or travel to walk we don't want that we want that animation to stay on attack as long as that animation needs to be happening so i'm going to make a small adjustment to the code here on move player we're first going to check if the state is not attacked and only if it's not attacked we're gonna allow the code to run on top of that i've set the state here to idle and walk for the idle and walk moment we're not really doing anything with idle or walk state but this could be the start of the implementation of a finite state machine within this other player script now there's one last change we need to make to make this code fully functional and i can show you a demonstration on line number 40 we got ispear instance original false and we only have this line of code for any i spear that is instance when it originates from another player and not the actual player that you're controlling the original is a new variable on the isp script with a default value of true so that means that original will only remain true for the i spear which actually originates from the player that's being controlled now on i spear body entered we can not only check for is in group enemies which we did originally since episode number one but we can also check if original is true this is the original ice sphere of the original caster only in that case we're going to run the on-hit function on the body that was hit in this case a weber if we were not to implement these changes then every single client that witnesses that isp hitting that weber is going to hit the on hit function in other words the amount of hits the webvet takes is going to be equal to the amount of players on the map that is of course completely undesirable so we need to make sure that no on hit functions are being called for any instances of i spears that originate from other players now all that's left for me is to give you a quick demonstration as you can see i'm moving around on my client on the left side and the client on the right side is displaying this other player with all the correct animations both walking and idling and when i shoot an i spear the ispear is instant on both sides both clients and of course we can still most importantly kill ourselves somewhere there's that was it for today guys hope you like it if you did smash that like button hit subscribe don't forget that little bell icon to make sure that you don't miss out on the next tutorial in this multiplayer series in the next tutorial we're going to be having a look at moving the physics from the client to the server currently the client is still doing the hit detection for when the wearable actually needs to receive a hit that is very exploit sensitive and we won't want our players to be able to exploit so by moving our physics to the server we're gonna be making sure that our clients cannot exploit and we get more fair and equal gameplay get ready for that one and until then keep on gaming keep on coding see you later guys
Info
Channel: Game Development Center
Views: 3,758
Rating: undefined out of 5
Keywords: Godot Multiplayer, Godot Multiplayer Tutorial, Godot Multiplayer Syncing, Godot Multiplayer Syncing Animations, Godot Multiplayer Sync Players, Godot Multiplayer Synching players, Godot Multiplayer syncing Attacks, Godot Multiplayer Attacks, Godot Network, Godot Networking, Godot Dedicated Server, Godot Multiplayer Server, How to make a multiplayer game, Godot MMO, Godot Beginner Tutorial, Godot 2d Tutorial, Godot Tutorial, Godot
Id: xkDMBsXKTSE
Channel Id: undefined
Length: 15min 38sec (938 seconds)
Published: Sun Jan 03 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.