Godot Endless Terrain With Collision - Tutorial

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
Oh everyone welcome to another tutorial this one again is we encoded which is becoming my editor of choice lately my game engine of choice this time we're going to do a bit of endless terrain generation using threads and also generating the collision shape that allows us to basically navigate this terrain and as you can see as we move along the terrain gets generated in front of us and it gets deleted from behind us so this is basically a great system where we have like 9 chunks the one in the middle plus the 8 around it and these chunks get generated dynamically as we move from one shot to another and it's basically using part of the noise to generate this and also to generate the collision shape so let's get started I'm going to move back to our project list and I already started an empty project basically and let's see we are going to start with a special node as our root node here and I am going to quickly add a bunch of stuff here I will leave the directional lights and we're gonna call this our Sun I'm just going to move this out of the way somewhere up there and I will probably rotate it a little bit just so it kind of illuminates our objects as we want so good values for this I kind of just put it up there so I don't really see it and let's put 45 degrees here and the bonds 180 here and that should give us some live illumination for our objects next up I am going to create an empty node let's call it this spatial it can be say a special I think I'm just going to call this terrain generator this is going to be the object where we're going to generate where are we going to attach our strip to generate the terrain basically next I am going to add a mesh instance that is going to be our trade floor just for reference or you just want to see something here so I'm going to basically set this to be a blemish here and I'm going to give it some transform information let's say minus 0.7 here oh not 0-7 seers just so it's like 7 centimeters below the zero and let's scale this up to 100 by 100 so we can you know see something here I also want to give it some material just so it's not so bland so I'm gonna do a new layer material my guess and I'm gonna make it the usual trade or sure what not and let's edit the this I am just going to drop in here a small texture for reads and let's drag this in and okay here and then I think I also want to scale a little bit see I'm gonna I think I'm gonna take the input here inputs terrific the UV input I am going to do any vector op which is going to be a multiplication I'm gonna multiply by 200 here and I'm just gonna set this as the UV so this means that it's really well maybe that was too much oh I get the coordinates from for sorry about that yeah that looks much better so it should be roughly 1 meter which salad it should be roughly 1 meter so going back we have our floor now let's see what else we need we the player and but first I'm going to add also like another mesh instance and they start gonna make it here maybe and we let's see my stuff last month ok wait last geometry so I am going to make it 2 point 5 by 5 and here 12 X 6 and we liked it rough kind of see you just so we can see I'm gonna give this terrain like a flat shading kind of thing so this is just gonna help me see if material for the flat shading is okay or not and I also want to change it around a little bit here I'm gonna move this to 0 put 7 on X and actually well just move it like to just so it's not in front of our player when we start at 0 here I'm gonna put it at 3 and minus 2 just so it's not directly in the origin when we start having our player inside so now I want to give it a material and this is going to be the material that I'm going to use I'm not going to spend a lot of time with this material I'm just gonna copy it from where I already have it I can give you a brief explanation of how it works but yeah I'm just not gonna spend a lot of time with this see just doing this off-screen to copy the to copy the material to this project and it should be here now and I'm just going to drag this in here and we have like a flat shading kind of thing I can show you the exact visual shader so this basically does a derivative on the X&Y vertex coordinates there's a cross product between them normalizes and that applies normal and that's basically how you can achieve like really simple flat shading thing and I think I'm gonna I'm gonna drop the energy of the Sun a little bit because I think it's too high it's gonna mess up so 0.2 yeah that looks much better so the Sun is there light dark perfect so now that we have this set up I am going to create the player and the player is basically going to be a kinematic body so let's just add that in this is going to be the player and the player is going to needs let's see it's going to need a body just for reference so this is going to be a mesh instance and it's also going to need collision shape and the collision shape that's final - I'll change this later and I also want camera just so we can track the player around the brush instance I'm just going to set it as the cylinder capsule which is pretty standard for those games to use a capsule for the for the collision shape I'm actually using it for the mesh but that's okay it's just for reference take this on the x-axis and that's final touch anymore the clean shape I wanna say for capsule when I had some problems with the player dropping off from the the collegian shape of the terrain in the past so I'm just gonna set it to you know what I'll just leave it as a capsule so moving on the camera I want to move the camera a little bit further from the player just so we see it so let's move it to 12:15 here so basically a bit higher and what am i doing yeah and let's put some rotation here as well and nine degrees here so in principle this camera should be pointing down towards our player cool we can also I think we can also make this camera the current one which is it's not required it's fine so let's save this let's say this is our scene it doesn't really matter what you call it I'm just doing this for the tutorial so I'll just call it scene you could call it butter level one or whatever you want so now we're gonna right click here on the player and we're gonna do Sabra jazz scene called player just so this is instance theme to our scene and it's now its own thing so if you click here you haven't seen from the player and seeing how the player inside so let's run this let's select the main scene as our scene see what this does okay we're looking down it looks okay so now we need some way to move the camera I also have a script to to move the camera so I'm just going to attach a script here camera sure why not and I'm just gonna copy pasted inside this is a simple screen for the rotation of the camera feel free to take a look at it if you are interested you can set the mouse sensitivity here and basically have the reference to the player which is its parent no matter body and then basically captures the mouse and whenever you rotates basically rotates one to one place or the other and that should be enough to give us some motion on the camera let's see yeah sure enough we can orbit around player and you can move a little bit up and down so next up let's see our player also needs some let's set up the inputs first so here in the project settings we need to go to input map and we need to add a new a bunch of new inputs here we're just gonna say we're gonna have a four words so we can move forwards we're gonna have a back the left right and the jump pilot and let me just quickly assign these here okay we should be set our keys are set so it's all good let's see what we want to do we'd be player so I'm gonna add a script here I'm gonna call it player and this script is if we're going to control the movement or power player it also does stuff like rotating the player forwards and like jumping moving and you know applying gravity sliding along where you when you're going to be yeah so it should be good at the starting point so let's see if this works oh we broke it in X rotation body oh yeah we need to call that body instead of mesh instance I forgot to rename this guy because we're referencing it in signed player script so okay it's good we're falling through the ground but that's okay because that our faith floor does not have a Collider so that is basically why we can just add a child node here static body with a collision shape and we just do like you know playing shape or something like that maybe we can swarm it to roughly the same size hey that's too much it's probably 10 yeah that's too much Oh needs to be half half of the actual size well I have no idea what this does let's say five five seems to be bigger than what we actually need so yeah let's try that yeah let's go save oh we gotta fall because we're inside the ground so let's just move the player up a little bit just so we see actually gravity starting to occur and yeah sure it up with you but we're not moving so something is wrong here and I'm going to check why okay so I figured out we shouldn't use the plain shape it actually it says that it works really poorly and it's going to be released removed actually in future versions of the engine so don't use it and I believe use it so let's just change this to our box play or box shape and now should be able to move around yes okay we can move and we can also jump that's fine cool so let's move on to the actual generation of the terrain so let's see what we need to do our terrain generator needs a script right we said we will do it here so let's touch this with you I'm gonna call this chapter in general why not let's just ring this let's see what we need to do so first things first I'm going to declare the function ready here and I am going to create a variable for our noise that we're going to need and I'm going to randomize our noise with a bunch of variables you can tweak these to generate the train as you see fit I just did it like this and it gives the results that you saw so now things that I need I need to keep track of all the threads that I'm going to use for the terrain generation and I need to track the chunks that are that are generated already in the scene I also need to track chunks that are being generated just so I don't repeats generating the same chance by accident in case they're already generating and they take a little bit of time I also want to set up the material for our train and what else I need to track our player and also our position in the grid and yeah I think that's pretty much it so the way this is gonna work is I am going to constantly keep track of where the player is in terms of street let's say like the first chunk is at zero zero and then the next Chuck is at zero one and so on and so forth so it's not the position it's actually the grid position of the chunk not absolute world position and when the player moves from one chunk to the other I'm going to trigger a generation of all the trends around it and if they are already there I don't generate them if they're not there they're going to get generated in a thread so each of the eight surrounding chunks of the current chunk where the player is he is going to get a dedicated thread for generation and okay let's get started so it's clearly complaining that I need to store the player somewhere I had the player general stored on the Global's script so what I'm going to do is I'm going to the new script here called Global's where I'm going to store my my Global's and what do I want here I want actually to keep track of the layer for now and I also want to store some information about the chance and the size of the quads and see when we are ready to start I want to store the player in our player constant so that being said I'm going to go to project settings go to auto load and I want to load this script by default when it starts just so we are able to access this ok so let's get started first off I'm going to create a new script this is going to hold my chunk or the information about one chunk and what I'm gonna do this is going to extend from a distance so which chunk is going to be a rush instance I'm going to give it a class name chunk just so we can reference it easily on the other script and let's see I need a bunch of stuff here I'm just going to copy paste from the other project that I have opened basically position is going to be the position the absolute world to vision of this chunk where it starts to get written to get generated the grid position is going to be the position I was talking about so 0 0 for the center chunk and 0 1 0 2 etc for the rest the key is going to be a string that I used to reference this chunk in the main script just so I can can keep track of which chunks I need to add or remove from our dictionary I am going to get the noise and the material from the other script and I'm gonna store the vertices and the UVs for this particular chunk so first thing I'm going to do is I'm going to create the init function for this class it's going to take in the grid position to generate the junk the noise and the material and then I'm just gonna do like associate this baby with the associate a great position in a great position and I'm going to actually calculate the position the absolute position based on this and based on the values on the Global's so the great position x times the chunk size - Trent size divided by 2 is going to give me where I want to start drawing this chunk and these chunks are going to be drawn from the middle that's why I'm subtracting here Gentiles divided by 2 next up I want to set up the key for this chart which is basically a glorified name it strange chunk and the grid position like zero underscore one or whatever and then I'm just going to assign the noise in the material that comes from the outside that associates this chunk now I need to set up this material so if I don't set up this material outside I basically want to give it a standard stuff then I basically want to give it a standard material and that's going to be a special material in the color white well actually not why I think this is yellow so other than that I need a function to generate this chunk okay so the way this generates function is going to work is I need a surface tool and now I need to generate some quads and these quads are going to be generated based on the number of parts that I want for each chunk and based on the position that I want this chart to be in and the position of this child is going to be positioned on X and then I just add x times the quad size as it increases it moves the quads basically by quad size like what size like what size until we have like creative watts in the end so but I still need to generate this quad and generating this quad is going to be a function that I'm going to create next and then I'm going to come back to to that function in in a bit but generating this quad is basically taking a position absolute world position and the size and what this means is I need to push back a bunch of vertices remember that I store the vertices array and the UVs as well I'm just gonna copy paste this because it's a bit long and I don't want to type it all but basically what we're doing here is pushing back creating vertices at position X Y X Y X value well I said excellent excellent yeah so this create vertex I'm also going to create this this function here and this store chain is super simple it basically gets for position X and Z I generate noise for that position I multiply it by 3 just to have like a small incremental noise and then I return the vector with the three or less grammar but that's basically our vertices or vertex and then the UVs are basically just you know the three rectangles coordinates always in the same direction basically and this generates a quad or at least puts a bunch of vertices and a bunch of these in the respective arrays so this means that we can now start creating some triangles based on the vertices that we generated so I'm just gonna begin using the surface tool I'm going to begin creating primitive trials I said I set the material this is important and then I just go through all of the vertices and since you've ease and vertices have the same number of elements in the array I just go through the range I until where this is not size which is going to be the same as your beans that size and I add this to the surface tool it's important to add the UVs first do you always need to be able first otherwise you're gonna get a bunch of errors and only then add the vertices to the surface tool and then after all of this is done we can ask the surface tool to generate the normals and we can get a mesh from committing the - this gives us a match and when we have a mesh we can basically just do assign to ourselves of all of this stuff so I set our name just so when we add this to the tree it gets a proper name and it's properly tracked and I set the mesh and I said castor cast shadow to one so the terrain also cast shadow this isn't you don't need to do this is it's just I was experimenting some stuff later and I added this but you can add as well that's okay so I'm gonna add one later you know what I'm going to leave the Keynesian shape for later so large chunk is pretty much complete it basically generates so much one chunk in at a given position so I suppose if I would go here and do chunk dot me you and ask for chunk dot generate and do add child trunk in principle I should have a chunk in the middle of our origin and sure enough I do and I can move it doesn't have an illusion collision as you can see I'm just going over to terrain and side the terrain basically but yeah we have a chunk so we can generate chunks on and the illumination books like shaded as well but it's still using the yellow standard so let's just go ahead and go to the terrain and assign our material here as well and if we do this we should get the same material that we have on the ball in our ground cool so this is all good but we don't have collision and we don't have other chunks and we don't have threading so moving on instead of generating one chunk here what I'm gonna do is I am going to get the player chunk grid position so I know where in the world in terms of chunk reads in terms of the chunk read the player is if is is going to be in 0 0 in the beginning but you might not if you start the game from a safe game or something like that so let's just figure out where it is in the world and for that I need this function then I'm going to create down here and I'm also going to copy let's go just like this and then leave that so I need this function these fancy weird stuff that I have here is related to the fact that I'm drawing the chunks from the middle and I need to do these checks some of them might not be necessary but I I was experimenting a lot and I kind of they almost gave up on life something like that is working but this seems to work and this does seem to give me like the proper position in terms of grids in terms of the track that the player is in so I left it there so after getting this I basically need to generate the chunk at the origin which is going to be very similar to what we just did to experiment with passing all of this and I'm going to create destruction generate chunk and this January chunk function is going to be something like this so I am passing an array and the reason I'm passing an array is not and not passing the parameters explicitly it's because I'm going to use this function to be called from to be called from a thread and it needs to be an array it only accepts one argument so that's that's why I'm doing it like this and the first argument is going to be the newly initiated chunk but not generated this is important it's just instantiate and the thread I want I'm running this generation in you might notice I'm passing null here so I'm not using any threading for the first chunk which kind of makes sense because you load the game and there's some time to generate I can also generate the first eight or the first time like this but I figure I just generate the first one so the player has some ground to stand in and all the other ones the rod can be generated by threads so basically in this side this function I'm going to ask the chunk to generate and then I'm going to call the shirt finished generating chunk with the thread and the chunk and this means that the thread after it finishes it's going to call this function on the main thread and that's where we're actually going to do stuff like the collider and all that because apparently Godot is not like when threads start messing well start messing with things like physics and all that so we're gonna do all that finishing and adding objects in the tree and generating collisional all that we're going to do the other main thread and this function that I'm going to create here is going to do the following so it's going to store our newly created chunk on the chunks dictionary using the chunky and it's going to remove it from the chunks being generated dictionary this is this will make sense in in a little bit after I create another function for start generating the chunk I added to the chat being generated all right but for now bury me and after this I'm going to create the collider for the trunk are you know what I'm not going to add it gladly just yet I'm just gonna add yeah I'm just gonna add the chunk to the tree with a call deferred and I'm gonna set the owner of the chunk to be the this script here so and the reason it's called it's using fall deferred is because Korky okay so now I just need to basically add the chunk to the tree as a child of this terrain generator note and also set the owner of the shop to be the terrain generate a note and now I need to do a check if I'm not in a thread which is the case of the first chunk that we generate I just returned otherwise if I am in a thread I want to do some cleanup basically wait on the main thread you wait for this thread to finish we should have finished short so it should return immediately but behind the scenes it does some stuff to stop the thread and keep its internal statements and whatnot so we need to actually call this way to finish for correctness and then I'm gonna find this thread on our threads array and I'm going to remove it basically so it's not used anymore there's no references to it so we can just get rid of it and we create a new one when we start to generate a new a new chunk so that's all fine this should in principle allow me to generate the first chunk as well I'm gonna give it a try I'm not sure it's gonna work but I'm gonna try anyways well let's see yeah it does generate the first chunk again so it's all good so next up we want to generate we want to generate all the chunks around the the first one so I'm gonna go back to the ready function and after generating the first chunk I'm going to create a new function that generates all the chunks around well the current chat where the player is so generate runs around playin grid position which is going to be 0 0 in the beginning and this function is basically going to ask for generating or bunch of chunks and this is just references to be up to the 8 chunks or to the 8 great positions around the current chant word player is and we're going to call a new function start generating function and if you remember there's something to do with this the threat that's being generated so this function basically accepts the vector 2 which is a great position of the chunk that we want to generate instantiates a new chunk on this grid position with the noise immunity and checks if it's not already generated and not already generating so if it's not then we create a new thread we add this chunk to the list of chunks being generated and we start the threads with a function generator chunk and we pass it to chunk and thread and we push back the thread into the threads array just so we get a reference and we can remove it later so that's why this generate chunk that I mentioned before accepts an array because when you do strive dot start you need to pass it one single argument and the way to pass multiple arguments is just to pass an array so if all goes well I should be able to just start this and see a bunch of other chunks being generated they're honest and we do we get like a bunch of others around this I think the camera is clipping so I'm going back to the player and get some more far here on the camera and I think if I do this I can see a lot further yeah so we have the all the eight chunks around those are there now I'm also going to do another thing I'm going to activate visible collision shapes because we're going to do that next and I want to see the collision that gets generated actually if we run now we should see it around our player at least yeah so you see it there and yeah we can see the same and the train when once we generate it so what do we need to do now um well let's see we need to detect when the player changes from one grid the other and wait so we can update and ask for new chance to be generated and all that and also clean up all all the chunks so the way I'm going to do that is on the since function which is an internal function for godot i am going to check where the player is where word player was and where the player is so and if they are different so if he's not in the same position he was one frame ago I am going to basically generate the chunks around him around the new position and yeah let's do that so I don't clean up yet just so you see something and if I run this as as I moved I should see new chance being generated so I'm not going to move out of the blue stuff otherwise I would fall down but you can see that it's being generated but it's not being cleaned up so I'm here and there are a bunch of them that should be cleaned up by now so what I need to do to do this is I'm just going to call the third cleanup old chums after we generate and this function is basically going to well clean up all chunks and it's a bit ok the way I did this function I don't really like it's not my best work but it works so what is seven hanging there but it works and so I basically I basically keep track of the what I considered to be valid chunks which are going to be like the center the current position where the player is the center plus all the other eight chunks around and I store some keys in an array of valid chunks and then I'm going to try to see which Keys I need to erase from the current existing ones so if I go through all the keys in the current shunts I'm keeping track and if all the ones that are not in this valid shunts get pushed back into these keys to erase and then I just go through all these keys to erase and I did leave them from the chunks and I delete them from the tree as well with Q free and this should make sure that as I move throughout the terrain if I move backwards so yeah see all of the other ones the other chunks that get left behind they get deleted and this ensures that I only have at any given point I only have like nine chunks being drawn which is pretty cool okay so what do we need now we are cleaning out so we just need the basically our collision shape just so we can walk on top of our terrain and how do we do this well I left on the chunk oh I don't have here yet okay so we need a new function on the chunk to generate a Collider and since we already generated all the vertices from the mesh we can reuse those vertices to generate a Collider so I'm just going to add a function here called create Collider and this is going to create a concave polygon shape based on the vertices that we already created before then it creates a collision shape with that particular shape adds a static body with that shape as well and set some collision layering and masking which I actually need to change that I didn't change yet and then adds to this chunk or to the mesh instance it adds the static body so it should it should all just work as long as we call this create Collider and we go into we're going to create this quite create collided on the main thread after the chunk is done generating just because the physics engine doesn't like multi-threading for now and but first I'm going to the project settings and I'm going to D let's see what our 3d physics yes so this is going to be drain layer and this is going to be the player layer here and I'm just going to go to the scene the player collision it should have player and doesn't interact with other players but those direct leads the Train and it should be fine also for the terrain because I do set it correctly I think so it is on the terrain and to means that it interacts with player but not with any of the other ones the police in the mask it should be fine we'll just see if it is or not so now we know the rain generator we can just go back to let's see what we want to do this I think we want to do this on the finished generating thread if I'm not mistaken so as soon as the child finishes generating before we added to do to the tree we're just going to create the collider and this should make sure that we get a proper collision shape on our terrain there you go you see from the from the debug flag that we set for the editor we can see the collision and now you are actually traveling on top of the of the terrain you should be able to see the player climbing and we're going down and yeah seems to be working so yeah that's it I hope you enjoyed this tutorial I hope it was fun for you and I hope you learn something took me a while to get all this rides especially because of the multi-threading thing things kept crashing and the whole chaotic but in the end it all goes well so I'm pretty happy with how it turned out yeah I hope you enjoyed I see the subscribing and the talk to you later you
Info
Channel: noozo
Views: 3,931
Rating: undefined out of 5
Keywords: game development, unreal engine 4, ue4, tutorial, development, games
Id: 4gk4GmkmCsg
Channel Id: undefined
Length: 41min 31sec (2491 seconds)
Published: Tue Apr 28 2020
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.