Skip to content

Instantly share code, notes, and snippets.

@JTRNS
Created May 26, 2024 16:56
Show Gist options
  • Save JTRNS/5727b87827ab69953bd1260fae492721 to your computer and use it in GitHub Desktop.
Save JTRNS/5727b87827ab69953bd1260fae492721 to your computer and use it in GitHub Desktop.
Simpler 2D TileMap navigation
class_name AStarNavServer
extends RefCounted
static var map: TileMap
static var astar: AStarGrid2D
static var cell_size: Vector2i
static func _static_init() -> void:
map = null
astar = null
cell_size = Vector2i(0, 0)
static func load_tile_map(tm: TileMap) -> void:
map = tm
astar = AStarGrid2D.new()
cell_size = tm.tile_set.tile_size
map.ready.connect(init_astar)
static func init_astar() -> void:
astar.region = map.get_used_rect()
astar.cell_size = cell_size
astar.offset = cell_size * 0.5
astar.default_compute_heuristic = AStarGrid2D.HEURISTIC_MANHATTAN
astar.default_estimate_heuristic = AStarGrid2D.HEURISTIC_MANHATTAN
astar.diagonal_mode = AStarGrid2D.DIAGONAL_MODE_NEVER
astar.jumping_enabled = true
astar.update()
var floor_tiles: Array[Vector2i] = map.get_used_cells(0)
var world_tiles: Array[Vector2i] = map.get_used_cells(1)
for tile in floor_tiles:
if world_tiles.has(tile):
astar.set_point_solid(tile)
map.ready.disconnect(init_astar)
static func round_global_position(global_position: Vector2) -> Vector2:
return map.map_to_local(map.local_to_map(global_position))
static func is_point_walkable(local_position: Vector2) -> bool:
var map_position = map.local_to_map(local_position)
if astar.is_in_boundsv(map_position):
return not astar.is_point_solid(map_position)
return false
static func find_path(from: Vector2, to: Vector2) -> PackedVector2Array:
if not is_point_walkable(to):
return PackedVector2Array()
var start = map.local_to_map(from)
var end = map.local_to_map(to)
var path: PackedVector2Array = astar.get_point_path(start, end)
return path.duplicate()
static func calculate_velocity(agent_position: Vector2, target: Vector2, path: PackedVector2Array, target_reached: Signal) -> Vector2:
if path.size() <= 0:
return Vector2()
if agent_position.distance_to(path[0]) < 1.0:
path.remove_at(0)
if path.size() <= 0:
if agent_position.distance_squared_to(target) < (cell_size.length_squared() * 0.25):
target_reached.emit()
return Vector2()
return calculate_velocity(agent_position, target, path, target_reached)
return agent_position.direction_to(path[0])
class_name AStarNavAgent
extends Node
signal target_reached
@export var target: Vector2
var path: PackedVector2Array = PackedVector2Array()
var _prev_target_position: Vector2 = Vector2()
func _ready() -> void:
assert(owner is Node2D, "AStarNavAgent must be a (grand)child of a Node2D")
recalculate_path()
func recalculate_path() -> void:
if target && not target == _prev_target_position:
_prev_target_position = target
path = AStarNavServer.find_path(owner.global_position, target)
func calculate_velocity() -> Vector2:
return AStarNavServer.calculate_velocity(owner.global_position, target, path, target_reached)
func set_target_node(new_target: Node2D) -> void:
target = AStarNavServer.round_global_position(new_target.global_position)
recalculate_path()
func set_target_position(new_target: Vector2) -> void:
target = AStarNavServer.round_global_position(new_target)
recalculate_path()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment