GDScript 75 lines
extends GutTest
## The deterministic grid pathfinder. These pin the routing contract the client and the bots lean
## on: a clear line is a straight shot, a blocked line routes around the obstacle on a
## collision-free path, a target inside an obstacle resolves to free ground, and the same query
## always yields the same path (so a bot's route replays identically). Pure data checks — no engine
## coupling, the same discipline as the rest of the sim tests.
func test_clear_line_is_a_direct_single_waypoint() -> void:
var nav := NavGrid.new()
var from := Vector2(0.0, 0.0)
var to := Vector2(200.0, 0.0) # open ground near the map centre
var path := nav.find_path(from, to)
assert_eq(path.size(), 1, "a clear line needs no intermediate waypoints")
assert_eq(path[0], to, "the single waypoint is the destination itself")
func test_from_equals_to_returns_the_point() -> void:
var nav := NavGrid.new()
var p := Vector2(0.0, 0.0)
var path := nav.find_path(p, p)
assert_eq(path.size(), 1, "a zero-length move is one waypoint")
assert_eq(path[0], p)
func test_routes_around_a_blocking_obstacle_on_a_clear_path() -> void:
var nav := NavGrid.new()
var center := MapData.nexus_for_team(0) # a real obstacle, open ground around it
var from := center + Vector2(700.0, 0.0)
var to := center - Vector2(700.0, 0.0)
assert_false(nav.segment_clear(from, to), "the straight line must run through the obstacle")
var path := nav.find_path(from, to)
assert_gt(path.size(), 0, "a routable goal yields a path")
# Every leg of the realised route (from the unit's position through the waypoints) is clear.
var prev := from
for w in path:
assert_true(nav.segment_clear(prev, w), "each leg of the route avoids the obstacles")
prev = w
assert_lt(
path[path.size() - 1].distance_to(to),
NavGrid.CELL * 2.0,
"the route ends on the requested destination",
)
func test_target_inside_an_obstacle_resolves_to_free_ground() -> void:
var nav := NavGrid.new()
var center := MapData.nexus_for_team(0)
var from := center + Vector2(1000.0, 0.0)
var path := nav.find_path(from, center) # aim straight at the obstacle's centre
assert_gt(path.size(), 0, "a blocked target still yields a path to its edge")
var last := path[path.size() - 1]
assert_false(
MapData.point_blocked(last, SimCore.UNIT_RADIUS),
"the route ends on free ground, not inside the obstacle",
)
func test_same_query_yields_an_identical_path() -> void:
var nav := NavGrid.new()
var center := MapData.nexus_for_team(0)
var from := center + Vector2(700.0, 0.0)
var to := center - Vector2(700.0, 0.0)
var a := nav.find_path(from, to)
var b := nav.find_path(from, to)
assert_eq(a, b, "pathfinding is deterministic — the same query is byte-identical")
func test_each_spawn_can_route_toward_the_enemy_base() -> void:
# The map stays traversable: a team can always route from its base to the enemy's.
var nav := NavGrid.new()
for team in MapData.NEXUS_POSITIONS.size():
var path := nav.find_path(MapData.spawn_for_team(team), MapData.spawn_for_team(1 - team))
assert_gt(path.size(), 0, "a team can route from its base toward the enemy base")