Dynamic Footsteps! : For Terrains and Imported Meshes (Unity3D)
anyone who has worked with standard unity assets before will immediately recognize these sounds changing the default sounds can instantly improve our game's appeal but we can do even better than that g'day everyone in this video we're going to set up a system to detect what surface the player is walking on and change the footsteps to match i'm using the first person controller that comes with the standard assets as it already has the logic in place to call random footstep sounds incrementally in this project i have sound effects for five different surfaces and for each surface there are four footstep sounds and a jump and a landing sound so with our standard assets imported let's head to where our first person controller prefab is stored and we'll drag one into the scene over in the inspector under footstep sounds we'll click on the little arrow here and expand that to see that we only have two footstep sounds in here and they don't sound that great this is where we're going to load in our own footsteps so before we start we'll have to take our first person controller script drag it out of the standard assets folder and put it into our own scripts folder and this is because all of the scripts that sit within the standard assets folder will be compiled before the scripts from most other folders so we won't be able to reference any custom classes from a script that sits inside our standard assets folder so let's open up our first person controller script and we'll start by adding using system dot collections dot generic at the top here that'll give us access to change this audio clip array into a list of audio clips right here we'll set this to be a new list of audio clip and this is because we want to dynamically add and remove audio clips into this variable here which can't be done with an array so because we've changed this to a list it'll also bring up an arrow down here where we need to change length to count save that head back in unity and we'll have a look at the terrain if we navigate over to the paint textures tab you can see that we've got four different terrain layers here each with a very simple and descriptive name grass rock mud gravel and these names are what we're going to be checking for in our code so let's create a new script we'll call it terrain checker and this script will contain all of the logic we need to figure out which layer of the terrain our player is standing on so we can get rid of start and update and we also don't need to derive from monobehaviour the first function we need will be private and will return an array of floats we'll call this get texture mix and for the parameters we'll pass in a vector3 which will be the player pause and a terrain which we'll call t now we want to store a few of the components attached to our terrain here so we want to store its position we'll type in vector 3 t pos is equal to t dot transform.position and the terrain data which we'll call t data and this will be equal to g dot terrain data so we also want to store our players x and z positions relative to where they are on the terrain and this line can be a bit confusing so we'll start with the x-axis we'll create a new int call it map x this will be equal to player pause.x minus t pos dot x so the player position minus the terrain position we'll wrap this in brackets divide that by t data dot size dot x and then multiply the whole thing by t data dot alpha map width now this will come up as an error because we're trying to put a float value into an integer so we'll just round this off to an int math f dot round to int and there we have it we have our players x position relative to where they're standing on the terrain so to get the z position we can just duplicate this and change all of the x's for z's and we want to change alpha map width to alpha map height then from these two values we're going to create a 3d array of floats and we'll call this splat map data this will be equal to t data dot get alpha maps so if we look at the description for get alpha maps it returns a 3d array of floats where the third dimension represents the mixing weight of each splat map at each xy coordinate and while that is an accurate description of what it does it's not exactly user-friendly i have an example to show you what that line does so head back into unity disable my first person controller and enable the example game object here so i'll hit play and i can drag around this cross here and it will tell me all of the different texture weights at that point if i drag it in the middle here we've got a combination of all of the different texture weights over here we can see that the gravel is the only texture at this point grass is the only texture at this point rock and mud and these are the values that will be going into the third column of our splat map data array so we'll stop that and head back into visual studio what we want to pass in here is map x map z and we want a width and a height of one now again what this is going to be doing is populating the third column of our array with all the different texture weights at these two points with a width and height of one so let's create a new array to store all of those values it'll be a float array we'll call it cell mix i will set this to be a new float array the size of which will be splatmap data dot get upper bounds and in here we'll pass in two and then we'll plus one to that now we just need to extract all of the values into cell mix so we want a for loop and this will go into cell mix dot length and all we want to do in here is set cell mix at the position of i to equal splat map data and we don't care about the first two columns all we care about is the third one so we'll put an i there now outside of the for loop we can just return cell mix next up we want to create a new public function which will return a string and we'll call this get layer name this will take in the same parameters as get texture mix vector3 play a pause and a terrain which we'll call t and in here we want to store the result of get texture mix so float and we'll call this cell mix and this will be equal to get texture mix and pass in the player pause and t now we want to create a float value for the strongest texture we'll call that strongest we'll set this to zero and we want to create an int for the index of the strongest texture so we'll call this max index and this will also be set to zero now we can loop over all of our values and find the strongest texture so we'll loop until cell mix dot length and in here we want to check if cell mix i is greater than strongest then we want to set the max index to equal i and the strongest to equal cell mix at the position of i now outside the loop here we can just return t dot terrain data dot terrain layers at the position of max index dot name save that we'll head back into unity and we'll create a new script and we'll call this footstep swapper in here we'll want a reference to the terrain checker so private terrain checker and we'll call this checker and we also want a reference to the first person controller so at the top of the script here we want to make sure that we're using unity standard dot first person now underneath the terrain checker we'll make a private first person controller call it fpc and we also want a private string for the current layer that we are standing on in start we'll assign our references so checker is equal to new terrain checker and fpc is equal to get component first person controller and this is the script that we're going to stick on the first person controller and we'll have all of the logic inside it to raycast down and check if we actually need to swap our footstep sounds so we'll save that create a new c-sharp script and we'll call this footstep collection and this class is actually going to be a scriptable object so we can get rid of start and update and at the top here we want to type in create asset menu file name is equal to new footstep collection and menu name is equal to create new footstep collection so in the class we want to create a new public list of audio clips we'll call this footstep sounds we also want a public audio clip for the jump sound and a public audio clip for the land sound save that we'll head back into unity and in my assets folder i'm going to create a new folder called footstep collections if i right click here and go create you can see that we've got a new menu option for create new footstep collection this is an instance of the class that we just wrote so we'll call it grass we'll lock the inspector head over to where our grass audio clips are and we can drag in all of our footstep clips into the list our jump sound and our landing sound now let's create three more for each of the other terrain layers now with all of those collections created we can head back into our footsteps swapper script and create an array of footstep collections we'll call this terrain footstep collections so we can get rid of update we can create a new public void function called check layers and with this function we're going to raycast down from the center of the player we're going to check to see if there's a terrain underneath us check if the layer we're standing on matches our current layer and if it does then we can swap the footsteps so first off we'll create a raycast hit and then we can do our raycast so if physics dot raycast will pass in the transform dot position and we want to recast down so vector three dot down then we'll store the hit information at a distance of three now we want to check if the terrain exists so if hit dot transform dot get component terrain is not equal to null then we want to check if the layer we're standing on matches our current layer so before that we'll store our terrain we'll call it t is equal to hit dot transform dot get component terrain and now if our current layer is not equal to checker dot get layer name we'll pass in our transform dot position and pass in t so if they don't match then we have stepped on a new layer and we can set our current layer to equal checker dot get layer name transform.position t alright so now we have the layer name stored in current layer now we want to do a for each loop over all of our footstep collections we'll call this collection in terrain footstep collections and we'll check to see if the current layer is equal to collection.name and that is the name of the
actual asset file of our footstep collection and in here we haven't created the function yet but we're going to tell the first person controller to swap footsteps and we're going to pass in the collection so we'll head over to the first person controller script create a new function called swap footsteps this is going to take a footstep collection and in here we're just going to clear out the m underscore footsteps list then we're going to loop over everything in the collection dot footstep sounds and we're going to add it back into m underscore footsteps outside of the loop we'll set the m underscore jump sound to equal collection dot jump sound and m underscore land sound to equal collection dot sound now we want to head up to the top of the script and add in a reference for the footstep swapper we'll call this swapper because this exists on the same game object we can just set this to get component footstep swapper and there are three places that we need to check to see if the footstep sounds need to be changed so at the start of play footsteps audio we can type in swapper dot check layers we can copy that we also want to check at the start of play jump sound and we also want to check at the start of play landing sound and here's a little tip in play landing sound if we change this to play one shot and pass in m underscore land sound it sounds a lot better now that was a lot of work so let's save our scripts and we'll head back into unity we'll enable our first person controller disable the main camera and the example game object and we'll add in our footstep swapper to the first person controller i'll have to drag the first person controller up a little bit i just realized i'm not getting anything over here in the corner because i need to make the footstep collections public okay so let's go ahead and lock the inspector and drag all of our collections onto the list over here and if we hit play we'll walk over to the gravel area we can see that the jump sound has changed to gravel jump gravel land and we've got all the footsteps in there we'll head over to the mud over to the rock and head over to the grass you can see that if we jump off one surface time and land on another it will update on the landing now this will work for terrains but what if we're standing on a mesh that we've imported and has a different surface type to anything on our terrain so i've got a game object here which is just a cube with a wooden texture we'll turn that on we'll drag up our first person controller and this functionality is actually really easy to add there are a few different ways we can do it we could just tag the object as would and check that against the name of our collection however that might not work in all situations like if the collider extends the bounce of the mesh or if we want to use the tag in another way so instead i'm going to head back into the scripts folder create a new c script call this surface type and we'll drag that onto our wood game object here we'll open it up in visual studio we'll get rid of start and update and all we really want in this is a public footstep collection and we'll call this footstep collection save that head back into unity and create a new collection for the wood footsteps lock the inspector and drag in all of our audio clips all right now we can just drag this onto our wood game object head back into our footsteps swapper script and just after we're checking for the terrain we can check if the hit.transform dot get component surface type is not equal to null we want to store our footstep collection is equal to hit dot transform dot get component surface type dot footstep collection we want to set our current layer to equal collection dot name and we want to tell our first person controller swap footsteps pass in the collection and that's it that's all we need to do to create a dynamic footstep system that is easily scalable and will work with any type of surface in your game thank you very much for watching i hope you enjoyed the video if you did please like and subscribe leave any thoughts and suggestions down in the comment section below thanks for watching
2021-06-29 17:22