Hello, fellow gamedevs! 👋
In our last session, we set the fundamentals for our NPC and environment. Today, we have a clear goal: make an NPC traverse our city like a real citizen — using TileMapLayer custom data and NavigationAgent2D
.
Before we start, I recommend brushing up on some basic programming concepts. A great starting point is this interactive website: [link].
We also need:
Motivation
Godot 4.4.1
Let’s create! 🎮
1. Add custom TileMapLayer data
We are going to create a variable included on our TileMapLayer called “walkable” with boolean type to really identify if the tile is walkable for our NPC or not. (Road vs sidewalk kind of)
2. Attach NPC script using GDScript
This is our code to have a smart NPC 😊(starting on second 0:30)
extends CharacterBody2D
var tilemap_city: TileMapLayer
var npc_target: Vector2i
var npc_in_map_position: Vector2i
var speed = 30
func _ready():
tilemap_city = get_parent().get_node("NavigationRegion2D/TileMapLayer")
npc_target = position
npc_in_map_position = tilemap_city.local_to_map(position)
set_walk_target()
func last_walkable_cell_in_direction(cell, direction) -> Vector2i:
var cell_data = cell
if (cell != tilemap_city.get_neighbor_cell(cell,direction)) && tilemap_city.get_cell_tile_data(tilemap_city.get_neighbor_cell(cell,direction)) && (tilemap_city.get_cell_tile_data(tilemap_city.get_neighbor_cell(cell,direction)).get_custom_data("walkable")):
cell_data = last_walkable_cell_in_direction(tilemap_city.get_neighbor_cell(cell,direction), direction)
return cell_data
func set_walk_target() -> void:
var next_target = [ TileSet.CELL_NEIGHBOR_BOTTOM_SIDE, TileSet.CELL_NEIGHBOR_RIGHT_SIDE, TileSet.CELL_NEIGHBOR_TOP_SIDE, TileSet.CELL_NEIGHBOR_LEFT_SIDE ].pick_random()
npc_target = last_walkable_cell_in_direction(npc_in_map_position, next_target)
$NavigationAgent2D.target_position = tilemap_city.map_to_local(npc_target)
func walk():
var direction = ($NavigationAgent2D.get_next_path_position() - global_position).normalized()
velocity = direction * speed
func _physics_process(delta):
npc_in_map_position = tilemap_city.local_to_map(position)
if $NavigationAgent2D.is_target_reached():
set_walk_target()
walk()
move_and_slide()
3. Make it move!
Success at Gamedev today 🚀
Our little city just got its first citizen walking the streets — and this is only the beginning.
I’d love to hear how you bring life to your NPCs, or what tricks you use to make them feel natural.
Share this post with a fellow dev, drop your thoughts in the comments, and subscribe to join our growing community of creators building games together.
Thanks for reading!