Godot 4.4 || A* Grid2d Adding Solid Points Issue

Godot 4.4

Hi everyone,

I’m working on a chess game in Godot 4.4 where all the pieces move on a 2D grid. The player can pathfind to a destination based on mouse input, and that part works perfectly. The issue I’m facing is with the pawns: when they pathfind, I want them to avoid each other.

My solution was to create a system where the world script converts the positions of all the pieces into grid tiles. Then, I create an AStarGrid2D and mark the tiles occupied by pieces as “solid,” so pawns should avoid them. Unfortunately, this approach doesn’t work as expected.

Can someone help me understand what I’m doing wrong? I’ve been stuck on this problem for days. Thanks in advance!

Hierarchy:

World
   - TileMapLayer
   - Player
   - Pieces (Node2D)
       - Pawn1
       - Pawn2

– Pawn Script –

extends Node2D

# ---- Components ---- #
@export_group("Components")
@export var loop_animation_component : LoopAnimationComponent 
@export var movement_component: MovementComponent

@onready var animation_player: AnimationPlayer = $AnimationPlayer

var target 

var tile_map : TileMapLayer
var astar_grid : AStarGrid2D

var current_id_path : Array[Vector2i] = []
var highlighted_tiles : Array[Vector2i] = []

var target_position : Vector2

var unhighlighted_tile : Vector2i = Vector2i(0, 0)
var highlighted_tile : Vector2i = Vector2i(0, 1)

var move_speed : float = 50.0

var is_moving : bool = false
var player_in_range : bool = true

func _ready() -> void:
	astar_grid = get_tree().root.get_child(0).astar_grid
	tile_map = get_tree().root.get_child(0).tile_map

func _input(event: InputEvent) -> void:
	# ---- TEMP ---- #
	if event.is_action_pressed("ui_accept"):
		target = get_tree().root.get_child(0).find_child("Pieces").find_child("OppPawn")
		caluclate_new_path()

func _physics_process(delta: float) -> void:
	astar_grid = get_tree().root.get_child(0).astar_grid
	for tile in highlighted_tiles:
		tile_map.set_cell(tile, 1, unhighlighted_tile)
	
	var tile_position = tile_map.local_to_map(global_position)
	tile_map.set_cell(tile_position, 1, highlighted_tile)
	highlighted_tiles.append(tile_position)
	
	if player_in_range == false:
		caluclate_new_path()
	if current_id_path.is_empty():
		return
	
	global_position = global_position.move_toward(target_position, move_speed * delta)
	
	if global_position == target_position:
		current_id_path.pop_front()
		if current_id_path.is_empty():
			is_moving = false
			animation_player.stop()
		else:
			movement_component.start_movement(current_id_path.size() + 1)

func caluclate_new_path():
	is_moving = true
	var id_path
	
	if is_moving:
		id_path = astar_grid.get_id_path(tile_map.local_to_map(target_position), 
		tile_map.local_to_map(target.global_position))
	else:
		id_path = astar_grid.get_id_path(tile_map.local_to_map(global_position), 
		tile_map.local_to_map(target.global_position))
	
	# Remove the last tile in the path so the pawn stops one tile short
	if id_path.size() > 0:
		id_path.pop_back()
	
	current_id_path = id_path
	movement_component.start_movement(current_id_path.size() + 1)

func _on_area_2d_area_exited(area: Area2D) -> void:
	if area.is_in_group("Player"):
		target = area.get_parent() # Set the target as the player
		caluclate_new_path()
		player_in_range = false

func _on_area_2d_area_entered(area: Area2D) -> void:
	if area.is_in_group("Player"):
		player_in_range = true

– World Scrip –

extends Node2D
@onready var pieces: Node2D = $Pieces
@onready var tile_map: TileMapLayer = $TileMapLayer

var astar_grid = AStarGrid2D.new()

var occupied_tiles : Array[Vector2i]

func _process(_delta: float) -> void:
	occupied_tiles.clear() # Clear every new frame
	
	for piece in pieces.get_children():
		var piece_tile_position = tile_map.local_to_map(piece.global_position)
		occupied_tiles.append(piece_tile_position)
		set_up()

func set_up():
	var tile_map = get_tree().root.get_child(0).find_child("TileMapLayer")
	var used_cells = tile_map.get_used_cells()
	
	if used_cells.is_empty():
		return
	
	var min_coords = used_cells[0]
	var max_coords = used_cells[0]
	
	for cell in used_cells:
		min_coords = min_coords.min(cell)
		max_coords = max_coords.max(cell)
	
	var size = max_coords - min_coords + Vector2i(1, 1)
	astar_grid.region = Rect2i(min_coords, size)
	
	astar_grid.cell_size = Vector2(16, 16)
	astar_grid.diagonal_mode = AStarGrid2D.DIAGONAL_MODE_ALWAYS 
	astar_grid.update()
	
	for tile in tile_map.get_used_cells():
		if tile in occupied_tiles:
			astar_grid.set_point_solid(tile, true)
		else:
			astar_grid.set_point_solid(tile, false)