Random Level Generation with a Walker - Godot Tutorial

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
good morning afternoon or evening wherever and whenever you are my name is Benjamin and welcome to another Godot tutorial video in this video I'm going to be making a random level generator in Godot and it's going to be something like this okay so I'm going to be using a simple walker or digger as some people call them to generate tiles in Godot here or generate a level like this so this is what we're going to be doing you can see I'm getting some tile flickering here I wasn't getting that until I started recording so this is what we're gonna we're going to do I want to make this into a series of some sort but I don't have an exact plan for it so I don't know how many videos there will be in this series but I am planning on making some sort of of a series maybe to explore some different ways of doing random level generation and this is what I consider to be one of the most basic forms of random level generation so we're going to start with it so let's create a new project in Godot so we're going to come into here select folder gonna name this Walker level generation and create folder create and edit okay this is also going to be open source under the MIT license so you all can grab it on my github page a link to that in the description including the resources that you'll need for this so you're going to need a tile set and I've set this one up to be 32 by 32 I'm gonna grab that here I'm grabbing this tile set and I'm copying it into here you'll want to click on it and I'm just gonna do import turnoff filter and re-import so it's nice and clean we don't get any blurry blurriness on the pixels so let's delete this here real quick and we're current gonna create a new scene this will be our world I'm gonna save this scene and we'll go into the project settings and just set our window size so it's 1280 by 720 close save will turn on snap and we'll set our snap to 32 by 32 [Music] the tileset sighs so that'll get us an idea of how big each tile is going to be inside of this room save again we'll add a new tile map node to our scene and we'll come over to sell make sure you set this to 32 by 32 and we'll come into tile set new tile set and we'll add a new tile set select our random level generation tile set do new Auto tile and select turn on snap select this region here and will come into our snap options they look good selected tile we'll want to set our bit mask Auto tile bit master the 3x3 minimal and we can come to our icon will select this tile for our icon bit mask now you've seen me do this before in other videos so I'm not going to describe in great detail how to set this up I'll probably actually fast-forward this but at the end of it you can just pause the video and copy to make sure yours looks like mine if you haven't done this before if you have watched my videos on how to set up a bit mask like or a few if you haven't watched my videos on how to set up a bit mask like this and the kind of pattern that is associated with it I will have a video linked at the top of this video as well that you can click on to get access to that and see that okay once your bitmask is set up like this you should be able to come into your world here and draw and it will Auto tile correctly with this so we're not where something's messed up with our Auto tile we want to make sure that it is correct I missed something I almost always do especially when I'm recording let's see here that'll looks good oops this should be up here was it come back in here let's do this it's all correct and yeah that looks good okay so what you can do now is we're going to come up to the top left hand side of our view and we're going to hold ctrl and shift and click and then drag all the way down to the bottom right hand side and you can see I went just past the edges of the screen and created a big giant black square for our tile set now we can save so now we're going to be creating a new script we'll come into our scripts here the new script we'll call this Walker and we'll do class named Walker that just allows us to use this Walker without having to preload it or load it we can just use this class name to instance it and this is going to have a few variables and constants first of all let's set up our constants these are going to be the different directions that we can move in and this will be an array and we'll have vector two dot right vector two dot up vector vector 2 dot left and vector 2 dot down so that will just be a list of all the different directions we can go in and we're going to set up a position so of our position and we can just set this to vector 2.04 now we'll set up a direction we'll set this to vector two dot right starting off we'll set up the borders now this is important this helps prevent our Walker from going outside of a certain area so we're gonna have the borders here it's going to be erect to will have a step history step history this is where we're going to store every single step that our Walker takes and then we'll have steps since turn so basically we want to keep track that's just that's just a little bit of polish to keep track of how many steps we've taken since our last turn so that we don't have super long hallways in our level generation and so that's not necessary but it's something you can you can add as well and I like to do it I think it looks nicer not to have super long hallways so we're gonna have an init function and this function is where when we create our new Walker where we can pass in a starting position and a new border so we'll say the first thing we need to do is make sure that our starting position is inside of our borders so we'll say assert new border new borders dot has point starting position so this will air right here if our starting point isn't inside of our borders and we'll say position equals starting point and borders well step history dot append position because we want our very first position to be inside of our step history so we'll add that to our step history then we'll say borders equals new borders there we go that's all we need for our knit function now we're going to set up our walk well we're going to set up we're gonna set up our step function next well we'll set up our walk function because we're gonna have a walk function that will take an amount of steps that we want to walk but for now just do pass we're gonna have a step function this is for taking a single step we can just do pass and we're gonna have a change direction function so this will be every time we want to change directions we'll just pass here as well for now so we'll start with the step function because it's pretty straightforward we'll just say var target position this is a position we want to step 2 equals position plus direction so we're going to get a target position and then we'll try and move towards that target position if borders dot has point target position steps since turn plus equals one so we'll take another well we'll add to our step since the last time we've turned and we'll move in that and then we'll move in that direction position equals target position and then we want to return true this basically just says yeah we were able to take a step else return false no we weren't able to take a step because that direction would go outside of our borders that's what this says if the target position is inside the borders take a step else return false because we can't actually go there it's outside of the borders okay so once we have that set up we can set up our change direction function so we'll come down here and we'll say steps since turn equals zero because if we're changing direction then we want to say we want to set that we want to reset our steps since the last time we turned because we're turning now our directions make sure you have an S here equals directions capitalized this is our array and I think I don't know if we have to duplicate it we'll see we'll do directions make sure you have an S again dot erase direction so what does this do I'm going to add a few returns here so it's not solo on my screen what does this do this removes the current direction that we're going from this list of all the possible directions to make sure that we don't ever go in the same direction that we were just going in that wouldn't make sense right so it removes it from that list so then we'll say directions dot shuffle so now we're shuffling the list because we're going to pick a new direction and then we'll say while not borders orders dot has point position plus direction but we got to do this first though we gotta say direction without the S this time because this isn't our list of directions Direction equals directions actions with the s dot pop front so what does that do that grabs the very first direction from our list of directions so you could imagine that if this list was shuffled it might be the up direction okay and then it sets our direction equal to that but when you say pop up front it the pop part also removes it from this list so so this list will get smaller each time we pop a direction from it and that allows us to make sure that we don't check the same direction multiple times when we're checking to see if it's inside the border so this will then check to see if we can move in that direction and if we can't then it will try to grab another direction instead Direction equals directions dot pop front [Music] so if we're unable to move in this direction it will just pick another direction right after [Music] that's it now we can set up our walk so our walk we can it will walk for a certain amount of steps and then it will return the step history basically a list of a raise that includes all the positions that we walked on so we can say here we can say for step in steps and the first thing we want to do is check to see if we want to change directions so we'll say if R and F is less than or equal to 0.25 or steps since turn is greater than or equal to 4 change direction so this gives us about a 25% chance to change directions and a hundred percent chance to change directions if we've gone for more than four steps that means we'll never have a hallway that's longer than four steps and this seemed pretty good but you can tweak these numbers if you want to try messing with it if you want to lower these odds or raise this so you can have longer hallways you can mess with those numbers a little bit and they could be stored in variables up here too Const the next step here inside of our walk function is to actually try and take a step so we'll say if step now remember this will return true if we're able to take a step and false if we can't because it's outside of our borders so we'll say if step step history dot append position so that was say if we're able to take a step then add our new position it will actually take that step and then it will add our new position to our step history else change direction we need to change directions because we can't actually take a step there's a it would try and go outside the border and then finally we just call at the end of all of this so make sure you're lined up with the four here we return step history so this will return our step history back out to whoever needs it and we can use that so now we'll come to our world and we'll create a new script and inside of our world script we're just going to have the ready function well first we need to get access to our tile map actually I lied so let's do on ready var tile map equals dollar sign tile map so I did this lower case in this upper case here so then we get access to this tile map we can create the borders that we want up here - so of our borders equals rect - so now it's going to take - well we can pass either four floats in to represent the borders or two vectors so let's do the four floats it's easier so we'll start at position one and one because we want a one tile border at the edge of the room and then we'll go to position 38 and twenty-one so why did I pick these numbers I can show you save here we'll come back to 2d and we'll grab this convenient little tool up here called ruler mode in Godot and this allows me to click anywhere in here and make measurements with this little ruler okay and it will give me the pixels and it'll also give me the units now the units is determined by our snap which is 32 by 32 so we want our borders to be we want a one tile border all around the view so we want to go from here down to here I'm sure that's not quite a one tile border at the bottom but I don't mind it should be fine so that gives us you can see 21 units high and 38 units wide and if you come back into here you can see I did 38 wide 21 high just like that so that gives us the border that we need so if you were gonna do a different size for your world you could use that same ruler to measure and get the border or you could try and figure it out programmatically but for the first video I decided to just use this tool and measure you'd only really need to figure it out programmatically if you were going to have different sized rooms for your levels but I'm not going to be doing that so let's create a new function called generate level like this now in this function we can we need to actually create our Walker so let's start by doing that var Walker equals Walker uppercase this time so lowercase first uppercase now dot new now we need to give it a starting position so for the starting position it'll be a vector two and I'm gonna do half of the path of what we have up here so I'm going to do well it looks like I didn't do half actually but I want to do half so so half of this 38 is going to be let's see 19 that's that right and then half of 21 the closest we can get to is we'll just do 11 and then for the then we need to pass in the borders when we're creating a new Walker so we'll do borders which we already set up here right so now that we've created this Walker we need to get a map from it so we'll save our map equals Walker dot walk and we're gonna walk for five hundred steps once again this is a value you can tweak that basically just determines the size of your route the size of your room like how many steps it takes obviously so we're going to take five hundred steps now that we have the map we can get rid of the Walker so Walker dot Q free so we can get rid of it we don't need it anymore and then we can do for location in map so that will do it will loop through each location inside of our map we can say tile map dot set cell V so that sets a cell in our talent based on a vector and the vector is going to be location and what do we want to set the tile to we want to set it to negative one which actually means remove the tile or erase the tile at that point because in our world we've already set these tiles we actually want to remove the tiles from the world that's how we're going to create our level is something like this as our Walker moves around in the level right and so we'll do negative one that will remove the tile and then at the end of the day we actually need to update the bitmask region so that basically just takes a region and it says okay we messed with the tiles in this region so update the Auto tile so that it reflects the changes that we just made because if you don't do that then it won't work so your Auto tile won't work so we say tile tile map the update bitmask region and the region we're gonna have a start and an end so the start is going to be borders dot position and the end is going to be borders dot and that will get the end of our borders there and now if we run our game and we'll want us to select a level so we'll set the world okay so we got an error here step history dot append it looks like I have a typo here so you can see that it says non-existent function append in base array well that's because I spelled append wrong right so this error is telling me that that function wasn't a real function and I need to spell it right did I spell it right now it looks weird to me now looks like I spelled it wrong again okay I did spell it right this time okay so we got another error message here this is saying that the vector two and nil up let's see invalid operands vector two and nil and operator plus so that says that our operator for addition here has one of these can't to be added it doesn't know how to add them together and that's because one of them is nil and if we look at our direction it's actually null so our direction doesn't have a value in it now this is probably because when we set directions equal to this we're getting let's see directions dot pop front I'm pretty sure what this means is that our directions here we can't just reference this constant up here we need to actually duplicate it so duplicate like this that will make sure that we can actually remove an item from it because this is constant right so constants can't change it's always going to stay the same and so if we just set directions equal to the constant then when we try and change it down here it says no you can't change it that's a constant and we get a direction here of nil so there you go maybe you'll learn a little bit extra from my mistakes there and now you can see it is generating a level however every time we run the game it generates the same level and that is because we need to randomize our seed which determines how the random numbers are created inside of Godot so inside of our ready function here we can just call a function called randomize and this will give us a new random seed every time we run the game now what's the benefit of not having randomized you might ask well the benefit is for debugging you could actually you could actually have a specific seed that ran every time and then you could use that to try and debug situations like oh if I use this seed then it creates this scenario that I need to try and solve and so it's beneficial to be able to not have it be random every time exactly it's sort of random but not really so but we can call a randomized here to make sure that it does it different and then just for fun we can add an input event here we can say if event dot is action just it is action pressed you I accept which is generally the return key get tree dot reload current scene that way we can reload the current scene so we can run our game and then just hit enter over and over to generate new levels and you can see we still sometimes get hallways that are a little bit longer but generally when those happen it's because it's actually walked one direction so see if we can find when this hallway looks really long right but probably what happened is it walked this way came down came up here and then came back down and then walked some more [Music] has some hallways that look longer it's probably a similar situation so the next thing on my list to do would be to potentially remove any single tiles because I found that these levels look quite a bit better if you remove any single tiles so you can imagine if we remove this one this one and this one it would look a little bit cleaner and this is the type of level generation that's used in games like nuclear throne and I'm sure they tweak their algorithm a little bit to try and generate the best interesting levels they can and I think if I do some more videos on this particular Walker I'll be tweaking the algorithm a little bit to try and make it look better and showing you guys some alternatives so let me know in the comments if that's something that you would like to see hopefully you enjoyed this video and learn something from it if you did be sure and give it a like subscribe to my channel and hit the bell and I will talk to you all later
Info
Channel: HeartBeast
Views: 46,901
Rating: undefined out of 5
Keywords: Tutorial, RPG, Pixel Art Game, Indie Game, Game Development, Learn gamedev, Gamedev
Id: 2nk6bJBTtlA
Channel Id: undefined
Length: 26min 55sec (1615 seconds)
Published: Wed Jul 08 2020
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.