How to make Rimworld in Godot 4: Pathfinding & Pawns

Поделиться
HTML-код
  • Опубликовано: 2 июл 2024
  • Next Video: Camera Pan & Zoom
    • How to make a 2D Camer...
    Discord: / discord
    Previous Video: Terrain Generation
    • How to make Rimworld i...
    Full Code: gitlab.com/realrobots/rimworl...
    In this series I'll show you how to make your own remix of Rimworld, or any similar top-down colony management/strategy game.
    In this particular video we'll make a pawn and use Godots built in pathfinding to teach them how to find an efficient path across different types of terrain, and how to make the different terrains effect the movement speed.
    Puzzling out how to make a game you know is a great way to learn, we're obviously not going to make an exact copy, but we'll develop a lot of the features that make the game, and maybe even spin it off into something unique.
    You can find the character sprite I used here.
    realrobots.net/files/youtube/...
    Here is my Patreon if you want to give me a dollar.
    / realrobots
    00:00 Introduction
    01:05 Create Pathfinding Class
    03:44 Apply movement cost to tiles
    10:04 Generate a path
    18:07 Create a path following pawn
    31:01 Apply terrain difficulty to movement speed
    33:14 Creating impassable terrain
    35:35 Target pathfinding to center of tiles

Комментарии • 65

  • @real_robots
    @real_robots  2 месяца назад +10

    BUG! If you're finding your pawn getting stuck while walking around the edge of your impassable snow tiles, that's because I forgot to prevent him making diagonal crossings across them and he's getting his movement speed reversed by the -1 move difficulty. In the InitPathfinding function you need to add the following just before calling "astar_grid.update()"
    astar_grid.diagonal_mode = AStarGrid2D.DIAGONAL_MODE_ONLY_IF_NO_OBSTACLES #

  • @pynthax5154
    @pynthax5154 2 месяца назад +15

    "Ive taken enough of your time today"
    No sir, you GAVE us a lot of YOUR time, thanks for taking the time to make these videos!

  • @chendrak
    @chendrak 2 месяца назад +8

    If you right click a node, you can select "Change type". No need to delete and re-add the Pathfinding node. All you have to do afterwards is change the type in the script as well.

  • @srboromir452
    @srboromir452 Месяц назад +1

    just remembered this series and had to search for it, I'm so glad you've kept this series going. (also now I can watch a bunch in a row)

  • @_...Seal..._
    @_...Seal..._ 2 месяца назад +5

    Great stuff!
    I'm excited to see what we'll learn next.
    Thanks for the Rimworld series.
    Subscribed.

  • @wonderer-ox2br
    @wonderer-ox2br 2 месяца назад +7

    these videos deserve more traction

  • @rudefriends9922
    @rudefriends9922 Месяц назад +2

    Thanks for these videos, I really enjoy them :)
    I noticed one thing you might want to change though:
    The "rendering_quadrant_size" is not the size of a tile but how many tiles are grouped together for rendering.
    It just happens to be the same for you because your tiles are 16x16 and that´s the default value for "rendering_quadrant_size".
    You can get the "tile_size" like so: "terrain.tile_set.tile_size".
    Anyway, I hope this series is successful and fun enough for you that it goes on for a long time :)

  • @TminusDoom
    @TminusDoom 2 месяца назад +4

    Liking the series so far.
    Just so you know, the bitrate for these videos are quite low. Not unwatchable, but for things like the path line, after RUclips's compression, we sometimes can't see it. (example @ 35:35 )
    For this exact issue, if upping the bitrate isn't possible, maybe consider increasing the width of the line?

    • @real_robots
      @real_robots  2 месяца назад +5

      Just watching now and you're right, that line practically disappears. I'll keep that in mind in future.

  • @CoFloCipher
    @CoFloCipher 2 месяца назад +3

    These are great! Please keep updating!

  • @FrankieDev
    @FrankieDev 2 месяца назад +2

    Will you be covering how to set up the project so that the camera properly scales when maximizing the window and fullscreen capabilities? Love the work so far, keep it up!

    • @jakes-dev1337
      @jakes-dev1337 Месяц назад

      Just go to project settings > window > turn mode to viewport and the thing below that to expand.

  • @1000_Gibibit
    @1000_Gibibit 2 месяца назад

    This is an awesome way to learn about how to do (or a possible way to do) grid based anything in Godot. Much appreciate the insight!

  • @iowenyou1
    @iowenyou1 Месяц назад +1

    love the tutorial, I'm gonna do all parts. Thx a lot!

  • @PSPbrtag
    @PSPbrtag 2 месяца назад

    This is a great series :)

  • @Redwan-wg4si
    @Redwan-wg4si 2 месяца назад

    Here before this blow up + nice work bro the godot community is really showing these days

  • @Jeff_Auger
    @Jeff_Auger Месяц назад

    Golden Axe! Hell yeah!

  • @sphynxcolt4030
    @sphynxcolt4030 2 месяца назад +1

    Hey, I found your channel only because of your first tutorial in this series and this is exactly what I was looking for!
    I havent found many godot tutorials about such topics like pathfinding and procedural worlds, until now! :D
    Always great to see a fellow Rimworld enjoyer.
    I was wondering if the procedural terrain generator does support connected textures/"texture Blending" (obv. not for pixel art) with custom sprites for each connection type. I assume sooner or later, there will need to be a framework for connected textures anyways, such as for walls etc? And will you switch the pixel textures for higher resolution textures later?
    Thanks for this amazing series!

    • @real_robots
      @real_robots  2 месяца назад +4

      Yes, once I've gotten some of the bigger gameplay features down I hope to come back and make the textures a bit nicer. Combining neighbouring textures properly and also whatever Rimworld does to tile together much larger textures. I'm more going for the aesthetic of how to quickly put together a prototype early on though.

    • @sphynxcolt4030
      @sphynxcolt4030 2 месяца назад

      @@real_robots don't worry, just do it at your own pace!

  • @alanharyaki4890
    @alanharyaki4890 Месяц назад

    Wow, just wow!

  • @ElenaOcone
    @ElenaOcone 2 месяца назад

    Subscribed ⚡⚡⚡❗

  • @wonderer-ox2br
    @wonderer-ox2br 2 месяца назад +1

    it might just be my browser but the link to the character sprite shows the tileset

    • @real_robots
      @real_robots  2 месяца назад +1

      Oops, thanks for letting me know, it's fixed now.

  • @myxtro7933
    @myxtro7933 6 дней назад

    Hey, I'm getting stuck at 29:45. When I click, my character doesn't move and instead I get the following error:
    "RequestPath(): Can't get id path. Point (2, 1) out of bounds [P: (0, 0), S: (0, 0)]"
    So far I've figured out that Point (2,1) is the position of my pawn at the start. I've compared the code in my Pawn script to yours and it's identical. I even copied your code from GitLab just to be sure, so the problem probably lies elsewhere. Any idea what could be wrong? Help would be appreciated.
    And thanks for making this tutorial series. It is exactly what I was looking for!

    • @real_robots
      @real_robots  5 дней назад

      I had a play around and couldn't get that error myself. Since you're getting an out of bounds error that so low I'm guessing that the astar_grid hasn't initialised properly.
      All I can suggest is go back a step and see if you can draw paths to and from where you'd expect to without the pawn complicating things and work from there.

    • @myxtro7933
      @myxtro7933 5 дней назад

      @@real_robots Thanks for checking it out. I will give the backtracking a go to see if I can find the issue that way.

    • @myxtro7933
      @myxtro7933 9 часов назад

      @@real_robots I found the issue. It's the same you had at 16:42. What I did wrong was I moved InitPathfinding() to _process instead of copying it. So I just had to add it to _ready as well to fix it.

  • @xcoder2205
    @xcoder2205 2 месяца назад

    Hi everyone, I could use some assistance. I’m currently facing an issue where I get stuck while trying to move in the game. Specifically, when I try to pass through the protruding grid of the snow mountain, my character starts shaking in a loop and doesn’t move forward unless I reset the pathfinding.

    • @real_robots
      @real_robots  2 месяца назад

      If he's shaking then I'd guess he's reached a point but it's not being removed from the list so he can go to the next one. Go to your pawn script adding a few extra pixels to the check
      if position.distance_to(path[0]) < SPEED * delta + 4:
      path.remove_at(0)

    • @xcoder2205
      @xcoder2205 2 месяца назад

      @@real_robots Printed Position.DistanceTo(path[0]) The specified position has not been reached yet, position.distance_to(path[0]) < SPEED * delta + 4: Invalid, I modified it to position.distance_to(path[0]) < SPEED * delta + 20: The error still occurs

    • @real_robots
      @real_robots  2 месяца назад

      @@xcoder2205 That's weird. I'd try printing the actual distance, then you can know how close you're actually getting. It might also be something else happening, if it works until you hit snow then maybe its something about the difficulty setting you've got on that tile. Printing the actual distance, alongside the minimum distance you're trying to reach will help you diagnose whats going on.

    • @xcoder2205
      @xcoder2205 2 месяца назад

      @@real_robots When finding the path, this problem occurs when searching along the edge of the snow tile, that is, the walk_difficulty is set to -1. This is the gif I recorded: photos.google.com/share/AF1QipP_AMXI553mMHFVyRDTN6pev6ou9khkr7dO5eYsxEKoiWA5Te9Hhh0l1VTYq0MBPw?key=ZzVTSS1Rd2NkNENVckNw Qjc3b1NBQkEzdnZ4Nzln

    • @xcoder2205
      @xcoder2205 2 месяца назад

      @@real_robots When finding the path, this problem occurs when searching along the edge of the snow tile, that is, the walk_difficulty is set to -1.

  • @brunch1572
    @brunch1572 Месяц назад

    Great video. I love the series. I got this working with 8-way character animation and thought I would share with anyone interested. First I used an Animation Player node and set up idle and walk animations. Then I used an Animation Tree node to set up transitioning between states. These two videos by Chris' Tutorials will help anyone set this up.
    Video 1: Animation Player setup ruclips.net/video/fZdU0W96Cqs/видео.htmlsi=iPhlSMB_1OvgOqGS
    Video 2: Animation Tree setup ruclips.net/video/WrMORzl3g1U/видео.htmlsi=CKfAF5xqcvubgmwS
    I made 2 conditions for transitioning between states, like in the second video: idle and walking
    Here is the modified version of the pawn script physics_process to make this all work:
    func _physics_process(delta):
    if len(path) > 0:
    var direction = global_position.direction_to(path[0])
    var terrain_difficulty = pathfinding.get_terrain_difficulty(position / 16)
    velocity = direction * SPEED * (1 / terrain_difficulty)

    animation_tree.set("parameters/conditions/idle", false)
    animation_tree.set("parameters/conditions/walking", true)
    animation_tree.set("parameters/Idle/blend_position", direction)
    animation_tree.set("parameters/Walk/blend_position", direction)

    if position.distance_to(path[0]) < (SPEED * delta):
    path.remove_at(0)
    else:
    velocity = Vector2.ZERO
    animation_tree.set("parameters/conditions/idle", true)
    animation_tree.set("parameters/conditions/walking", false)

    move_and_slide()

  • @mrussogamedev
    @mrussogamedev 2 месяца назад

    awesome!

  • @jlsonline
    @jlsonline 14 дней назад

    I'm not sure what's up here... but my pawn never wants to move. If I print path, I get the list of vectors and that looks fine (and the the path draws correctly on the terrain)... But if I print direction after using var direction = global_position.direction_to(path[0]) ... I always have 0,0 in the list and thus he never has any velocity ... so move_and_slide() doesn't work (my pawn starts in 0,0).
    If I set my position to 8,8 first, then my direction ends up negative if I click positive... very odd
    My code is the same:
    if len(path) > 0:
    print("Path > 0")
    var direction = global_position.direction_to(path[0])
    print("Direction: " + str(direction))
    velocity = direction * SPEED

    if position.distance_to(path[0]) < SPEED * delta:
    path.remove_at(0)
    else:
    velocity = Vector2(0,0)
    And as mentioned, path seems fine if I print it

    • @real_robots
      @real_robots  14 дней назад +1

      That is strange, I can't think what the problem might be that would cause that. Go check the gitlab link in the description and you can more easily compare to my code.
      The script is on your lawns characterbody2d yeah?

    • @jlsonline
      @jlsonline 13 дней назад

      @@real_robots Yep .. I was able to get it moving.. Apparently it was heading to 0,0 every time from my RequestPath (which made the direction -7,-7), presumably because my pos was less than 1 after dividing by terrain.rendering_quadrant_size. I actually ended up doing: var pos = snapped((global_position / terrain.rendering_quadrant_size), Vector2(16,16))
      Now the issue is that it never seems to do the path.remove_at(0) even as it approaches

    • @real_robots
      @real_robots  12 дней назад

      @@jlsonline First of all I'll note that "rendering_quadrant_size" is not the correct value to link to (my mistake that's fixed in a later video".
      if the remove_at isn't happening then you just need to print out what you're getting, print the distance, print if the distance check bool is true/false, it't probably just that the speed your guy is moving at is making him not quite get within the range you specified. My distance checking math probably isn't foolproof.

    • @jlsonline
      @jlsonline 12 дней назад

      @@real_robots Gotcha! I got it all working now. I also threw in pathfinding.queue_redraw() after path.remove_at(0) ... just so it would clear the traversed part of the pathfinding line as the pawn travels (like Rimworld does)

  • @podmike
    @podmike Месяц назад

    Can someone help me?
    I keep getting this error:
    W 0:00:00:0532 The parameter "delta" is never used in the function "_process()". If this is intended, prefix it with an underscore: "_delta".
    UNUSED_PARAMETER
    Terrain.gd:22
    I've even just copy and pasted his code from the link but I am still getting this error.

    • @real_robots
      @real_robots  Месяц назад

      Don't stress about that, it's just letting you know you've got a variable you haven't used. You can do as it says and add the underscore "_delta" and you won't get the warning anymore.

    • @podmike
      @podmike Месяц назад

      @@real_robots Thank you so much for the help!

  • @CoFloCipher
    @CoFloCipher 2 месяца назад

    If you add a way to donate I’ll gladly give to keep this going.

    • @real_robots
      @real_robots  2 месяца назад

      That would be greatly appreciated
      www.patreon.com/realrobots

    • @CoFloCipher
      @CoFloCipher 2 месяца назад

      Done. I’ll keep giving if the series continues. Thanks again! I’m excited to see where this goes.

  • @simoneabelo
    @simoneabelo Месяц назад

    I think I did something wrong because my sprite wasn't moving at all, so after rereading the code and comparing it to what's on the gitlab, I'm starting the video over to see if there's something I missed. 😮‍💨😔

    • @real_robots
      @real_robots  Месяц назад +1

      Guaranteed it'll be something small and dumb.
      Print your path to make sure you're actually getting one.
      Try making a path manually with an array of vector2s and see if your guy follows it. Gotta narrow it down

    • @simoneabelo
      @simoneabelo Месяц назад +1

      16:57 (responding to RR adding InitPathfinding() to the button) I hit "Reload Current Project" after adding InitPathfinding() to the ready function, which seemed to fix the error message. It just needed to be reloaded again, that's all

    • @simoneabelo
      @simoneabelo Месяц назад

      @@real_robots thanks I'll try that once I've rewritten it, if it continues to not work.

    • @simoneabelo
      @simoneabelo Месяц назад

      @@real_robots You were right, it was something stupid. I somehow managed to delete the instruction telling my guy to move when I clicked 🤦🤦

  • @wonderer-ox2br
    @wonderer-ox2br 2 месяца назад

    also for those using an older versions of godot 4, replace the Rect2i with Vector2i

    • @real_robots
      @real_robots  2 месяца назад +3

      Thanks for the note, but I think you've mixed it up. The old deprecated way was to use AStarGrid2D.size, which is a Vector2i, the new way is to define the AStarGrid2D.region, which is a Rect2i.
      docs.godotengine.org/en/stable/classes/class_astargrid2d.html#class-astargrid2d-property-region

    • @wonderer-ox2br
      @wonderer-ox2br 2 месяца назад

      @@real_robots you right, thanks for the tip, I hope this series feels fun to make

  • @Alexik222
    @Alexik222 2 месяца назад

    On a bike trip rn, i think i will stop and watch :D

  • @SFoX-On-Air
    @SFoX-On-Air Месяц назад

    Unfortunately, the AStar system is also the biggest weakness of RimWorld. Experienced players build their base around AStar, but new players just find it frustrating. This "find the shortest path" usually leads to food spoiling because the shortest path to the table goes through the freezer and pantry. Or through an area that should be avoided due to dangerous animals or enemies. Without Mods, Player have to live with it and cant do anything.
    In a rip-off, I'd rather not replicate the mistakes of the original.

    • @real_robots
      @real_robots  Месяц назад

      How else would you do it though? It would still have to be astar but with additional costs added for walking through danger areas or opening freezer doors.

    • @SFoX-On-Air
      @SFoX-On-Air Месяц назад

      @@real_robots Yeah, well... You could invent some special doors that players can mark as "Emergency Use Only!" But then the hunter wouldn't haul shot animals to the cooler anymore but would run through all the other rooms with them.
      Assigning higher-value tiles seems impractical because in-game, you don't just lay floors to make it look prettier but because the pawns walk faster on them.
      One idea might be to draw a zone. AStar would recognize this as Difficulty 10. But the roles "Butcher," "Hunter," and "Cook" have a built-in ignore function for this zone. So at least only these three would walk through it, not the entire colony.
      One could also use such a zone for the hospital, which has the same problem. Because everyone runs around in there and dirties everything. This leads to patients getting infected wounds. Again, a zone around it, and only pawns with the flag "Patient," "Doctor," or "Nurse" ignore the zone.
      But I don't know if it's possible to retrofit AStar through the player afterward.

  • @rerere1569
    @rerere1569 2 месяца назад +1

    Thank you for the video, very helpful!
    Btw not sure if you know this but if you drag a node into the script and start holding ctrl while dragging it, then release it in the script window it will automatically create @onready variable for you and add the correct type (even works if you declare a class_name in the script attached to a node):
    @onready var terrain_generation: MyClassName= $"../TerrainGeneration"

  • @artcrtc5028
    @artcrtc5028 2 месяца назад

    how to restrict movement of a pawn to move only diagonaly or only vertical/horizontal?

    • @real_robots
      @real_robots  2 месяца назад

      You probably couldn't do that with AStarGrid2D, it's pretty simplified. If you use AStar2D, it lets you define all your walkable points, and then manually connect them to each other. So you'd loop through your points only making horizontal connections, or vertical connections etc. If you had different pawns with different possible movements, I'd just give each type their own grid, each with the same points but with different connections applied.