video is great. one reccomendation: better variable names. right now, as you are writing the code, you know what a1 and a2 and b2 and b3 are. If you revisit this code after too long, or if you share this code to someone else, it will slow you/them down making certain what each variable is. Good variable naming should convey clearly what they are. Its a second or two slower, but naming a variable room1 or intersecting_room will make reading your code an order of magnitude easier to understand, even if you havent looked at this code in a few weeks/months. While there is an extreme on the other side of nameing (room_to_check_for_intersection_and_maybe_remove is an insane name) finding a good middle ground for solid variable naming is tantamount to the longevity and maintainability in your code.
small addition: abbreviating words in variable names is another slippery slope. while SOME abbreviations may be universally understandable (a file name named proc_gen_driver within the context of a procedural generation project will make sense every time) but abbreviations should be sparing.
Point taken. My poor naming convention habits stem from majoring in applied math in college, were everything was named using at most a single character and a subscript or two. I've been working on code readability as I learn, but old habits die hard, thanks for pointing out both ends of the extremes. If you check out some of my more recent content , I think it's improved but yeah it's something I need to work on.
I have prepared random generation for my game based on a HeartBeasts tutorial but I see that it won't be a good solution for me. Having premade rooms seems like a better option for me. good video man. I see your solution being basically what I need :D
Nice! After doing some more work on this project, some of the layouts didn't have reachable rooms. Using a floodfill algorithm to check that each room is reachable, and regenerating the dungeon when they weren't helped.
To generate the hallways, you could use the A-star pathfinding algorithm to find the shortest path between two rooms. Once we have the path for the hallway, we mark each of the tiles as SOLID for the algorithm. Same goes for when you allocate the tiles for a room. Then, as you continue to draw the hallways, none of them will overlap.
Thanks, that's a neat idea. I got a basic implementation working, do you have any tips for getting the algorithm to favor simpler paths with less corners?
@@TimmyGobbles-pp8pf If you’re using the built in astar pathfinding nodes in Godot, you can change the heuristic function from Dijkstra to Euclidean and you should see the effect you’re looking for. I believe it defaults to using the Dijkstra heuristic, which won’t necessarily generate an optimal path.
Which heuristic you use depends on how you want the hallways to connect. If you want just NESW connections, the manhattan distance will be just fine. However, if you want diagonally connecting hallways, straight hallways, and L shaped hallways, you should probably use the Euclidean heuristic. You can disable diagonal search movements as well, by setting astar.diagonal_mode to DIAGONAL_MODE_NEVER.
Welp, I should have checked if godot had an a-star class, I thought you were just referring to the algorithm in general. I got my own janky implementation working, and it does produce paths between rooms that don't overlap other paths or rooms. Definitely a neat solution to the problem, I just need to work out some kinks like having the tree using the same room too many times for connections.
Hey, the Level Editor and the Lobster videos are part of the roguelike project, but aren't really proc-gen related. Is there anything specific you want to see more of?
I suppose one fairly easy alternative to having the intersecting corridors just create new doors on rooms and stuff could be to have some or all corridors follow the paths of the partition lines. As in, a corridor can go from a room to the nearest partition line, and then follow that web of lines until it breaks off to connect to its target room. And maybe this could be a last resort to solve intersections, or maybe it could be default behavior. Or maybe it's not what you're going for at all, but I wanted to mention it since those partition lines are already guaranteed to not intersect any rooms. So it's kind of like free pathfinding for corridors.
I really like this suggestion. Because I stored corridors as 2 points, I was limited to only straight and L shaped corridors. This lead to my desperate "make it work" jank. When I revisit the room generation, I want to make corridors able to have any number of bends, and I'll give this a shot.
I did this video like half a year ago, I'm not even sure what code from this video survived redoing things, refactoring, and whatnot. If I ever get around to redoing this video I'll probably make a git repo for it or something.
@@TimmyGobbles-pp8pf I'm know that language is GDsharp. I'm know a him basik, but so much code in video. I'll see video again . Thank you Timmy gobbles for video, but I'm scared from that large code
I'm sorry the code is a mess, I'm still learning and usually my first solution to a problem isn't the cleanest answer. It might be easier for you to try following the big picture rather than my code. This dungeon generator should: 1. Make a binary tree by splitting rectangles into 2 smaller rectangles each. 2. When there are enough rectangles, put a "room" in each of them. 3. Connect the rooms with paths. Start on the ends of the binary tree, and work back to its base node 4. Display the dungeon somehow. I had the most trouble understanding how to make a binary tree, you might want to research that data structure first. Hope that helps!
@@TimmyGobbles-pp8pf Thank you so much for the comment, but I have another serious problem. I do not know where to find the code that does what I need. For example, I want to make blocks from tile map appear in one place, but I can't find what code does it. Please write me a comment in which you will find out where you get the information about the code. Otherwise, I don't even know this and I can't even start studying generation normally.
So I go over using the TileMap class in code in both the Breakable Tiles and 2D Swimming tutorials on my channel. All the built in nodes in godot should have a page in the documentation that lists out that class's variables, methods, enumerators, and any signals. You can pull up the page you're looking for by hitting F1 and then using the search bar, or if you have that class name typed in your code, click on it with ctrl+LMB.
Good video, would definitely prefer no music though.
Interesting to watch someone do it from scratch. I have seen others use wave collapse algorithm. This was fun to watch. Thanks.
Glad you liked it! I've heard of wave-collapse used for terrain generation but I'll have to check out its other applications.
video is great. one reccomendation: better variable names.
right now, as you are writing the code, you know what a1 and a2 and b2 and b3 are. If you revisit this code after too long, or if you share this code to someone else, it will slow you/them down making certain what each variable is. Good variable naming should convey clearly what they are. Its a second or two slower, but naming a variable room1 or intersecting_room will make reading your code an order of magnitude easier to understand, even if you havent looked at this code in a few weeks/months. While there is an extreme on the other side of nameing (room_to_check_for_intersection_and_maybe_remove is an insane name) finding a good middle ground for solid variable naming is tantamount to the longevity and maintainability in your code.
small addition: abbreviating words in variable names is another slippery slope. while SOME abbreviations may be universally understandable (a file name named proc_gen_driver within the context of a procedural generation project will make sense every time) but abbreviations should be sparing.
Point taken. My poor naming convention habits stem from majoring in applied math in college, were everything was named using at most a single character and a subscript or two. I've been working on code readability as I learn, but old habits die hard, thanks for pointing out both ends of the extremes. If you check out some of my more recent content , I think it's improved but yeah it's something I need to work on.
Tnank you Dr Drew!
This is exactly what I thought within the first 10 seconds LOL
I have prepared random generation for my game based on a HeartBeasts tutorial but I see that it won't be a good solution for me. Having premade rooms seems like a better option for me. good video man. I see your solution being basically what I need :D
Nice! After doing some more work on this project, some of the layouts didn't have reachable rooms. Using a floodfill algorithm to check that each room is reachable, and regenerating the dungeon when they weren't helped.
To generate the hallways, you could use the A-star pathfinding algorithm to find the shortest path between two rooms. Once we have the path for the hallway, we mark each of the tiles as SOLID for the algorithm. Same goes for when you allocate the tiles for a room. Then, as you continue to draw the hallways, none of them will overlap.
Thanks, that's a neat idea. I got a basic implementation working, do you have any tips for getting the algorithm to favor simpler paths with less corners?
@@TimmyGobbles-pp8pf If you’re using the built in astar pathfinding nodes in Godot, you can change the heuristic function from Dijkstra to Euclidean and you should see the effect you’re looking for. I believe it defaults to using the Dijkstra heuristic, which won’t necessarily generate an optimal path.
Which heuristic you use depends on how you want the hallways to connect. If you want just NESW connections, the manhattan distance will be just fine. However, if you want diagonally connecting hallways, straight hallways, and L shaped hallways, you should probably use the Euclidean heuristic. You can disable diagonal search movements as well, by setting astar.diagonal_mode to DIAGONAL_MODE_NEVER.
Welp, I should have checked if godot had an a-star class, I thought you were just referring to the algorithm in general. I got my own janky implementation working, and it does produce paths between rooms that don't overlap other paths or rooms. Definitely a neat solution to the problem, I just need to work out some kinks like having the tree using the same room too many times for connections.
Hi Timmy, please continue this series
Hey, the Level Editor and the Lobster videos are part of the roguelike project, but aren't really proc-gen related. Is there anything specific you want to see more of?
I suppose one fairly easy alternative to having the intersecting corridors just create new doors on rooms and stuff could be to have some or all corridors follow the paths of the partition lines.
As in, a corridor can go from a room to the nearest partition line, and then follow that web of lines until it breaks off to connect to its target room.
And maybe this could be a last resort to solve intersections, or maybe it could be default behavior.
Or maybe it's not what you're going for at all, but I wanted to mention it since those partition lines are already guaranteed to not intersect any rooms. So it's kind of like free pathfinding for corridors.
I really like this suggestion. Because I stored corridors as 2 points, I was limited to only straight and L shaped corridors. This lead to my desperate "make it work" jank. When I revisit the room generation, I want to make corridors able to have any number of bends, and I'll give this a shot.
Please share the code shown in the video, consider either pushing it to a git repository or even pastebin
I did this video like half a year ago, I'm not even sure what code from this video survived redoing things, refactoring, and whatnot. If I ever get around to redoing this video I'll probably make a git repo for it or something.
Where from am I must have that all large code. 😢. I'm a beginner. How Am I write this code?
Do you know any coding languages?
@@TimmyGobbles-pp8pf I'm know that language is GDsharp. I'm know a him basik, but so much code in video. I'll see video again . Thank you Timmy gobbles for video, but I'm scared from that large code
I'm sorry the code is a mess, I'm still learning and usually my first solution to a problem isn't the cleanest answer. It might be easier for you to try following the big picture rather than my code. This dungeon generator should:
1. Make a binary tree by splitting rectangles into 2 smaller rectangles each.
2. When there are enough rectangles, put a "room" in each of them.
3. Connect the rooms with paths. Start on the ends of the binary tree, and work back to its base node
4. Display the dungeon somehow.
I had the most trouble understanding how to make a binary tree, you might want to research that data structure first. Hope that helps!
@@TimmyGobbles-pp8pf Thank you so much for the comment, but I have another serious problem. I do not know where to find the code that does what I need. For example, I want to make blocks from tile map appear in one place, but I can't find what code does it. Please write me a comment in which you will find out where you get the information about the code. Otherwise, I don't even know this and I can't even start studying generation normally.
So I go over using the TileMap class in code in both the Breakable Tiles and 2D Swimming tutorials on my channel.
All the built in nodes in godot should have a page in the documentation that lists out that class's variables, methods, enumerators, and any signals. You can pull up the page you're looking for by hitting F1 and then using the search bar, or if you have that class name typed in your code, click on it with ctrl+LMB.