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)