# nav_test.ludic - ludic.nav on ground built by hand: a 40 m meadow of metre squares, a post in its # middle, a river across it (area 0) with a ford or without one. A path goes round the post and over # the ford, stops at the bank when there is none, and a saved mesh answers as the built one did. import "ludic.nav" import "ludic.base" import "fakes/meadow.ludic" program NavTest { numbers float function meadow(nav_st: mut NavState, kind: int, river: int, post: bool) -> bool { let g = ground(40, river) if post { g.cyl = post_at(20.0, 20.0, 2.0) } if post { g.nc = 1 } return nav_build(nav_st, kind, g, new NavConfig) } function last_x(nav_st: NavState) -> float { return nav_corner_x(nav_st, nav_corners(nav_st) - 1) } function last_z(nav_st: NavState) -> float { return nav_corner_z(nav_st, nav_corners(nav_st) - 1) } test "a path goes round a post, and the straight line through it is not walkable" (nav_st: mut NavState) { expect(meadow(nav_st, NAV_PERSON, 0, true)) expect(nav_polygons(nav_st, NAV_PERSON) > 0) let n = nav_path(nav_st, NAV_PERSON, 0, 5.0, 0.0, 20.0, 35.0, 0.0, 20.0) expect(n >= 3) expect(not nav_partial(nav_st, NAV_PERSON)) expect(Math.abs(last_x(nav_st) - 35.0) < 0.1) for i in 0 .. n { let dx = nav_corner_x(nav_st, i) - 20.0 let dz = nav_corner_z(nav_st, i) - 20.0 expect(dx * dx + dz * dz > 2.0 * 2.0) } expect(not nav_straight(nav_st, NAV_PERSON, 0, 5.0, 0.0, 20.0, 35.0, 20.0)) expect(nav_straight(nav_st, NAV_PERSON, 0, 5.0, 0.0, 5.0, 35.0, 5.0)) } test "a river is crossed at its ford" (nav_st: mut NavState) { expect(meadow(nav_st, NAV_PERSON, 1, false)) let n = nav_path(nav_st, NAV_PERSON, 0, 5.0, 0.0, 10.0, 35.0, 0.0, 10.0) expect(n >= 3) expect(not nav_partial(nav_st, NAV_PERSON)) var ford = false for i in 0 .. n { if nav_corner_z(nav_st, i) > 29.0 { ford = true } } expect(ford) } test "without a ford the path stops at the near bank and says so" (nav_st: mut NavState) { expect(meadow(nav_st, NAV_PERSON, 2, false)) let n = nav_path(nav_st, NAV_PERSON, 0, 5.0, 0.0, 10.0, 35.0, 0.0, 10.0) expect(n >= 1) expect(nav_partial(nav_st, NAV_PERSON)) expect(last_x(nav_st) < 18.0) } test "the nearest walkable point, and nothing off the mesh" (nav_st: mut NavState) { expect(meadow(nav_st, NAV_PERSON, 0, false)) expect(nav_nearest(nav_st, NAV_PERSON, 10.0, 1.0, 10.0)) expect(Math.abs(nav_near_y(nav_st)) < 0.3) expect(Math.abs(nav_near_x(nav_st) - 10.0) < 0.1) expect(not nav_nearest(nav_st, NAV_PERSON, -50.0, 0.0, -50.0)) expect_eq(nav_path(nav_st, NAV_PERSON, 0, -50.0, 0.0, -50.0, 10.0, 0.0, 10.0), -1) expect_eq(nav_path(nav_st, NAV_LARGE, 0, 5.0, 0.0, 5.0, 10.0, 0.0, 10.0), -1) } test "a random point near is always one a walker there can reach, and a seed is always the same point" (nav_st: mut NavState) { expect(meadow(nav_st, NAV_PERSON, 2, false)) for seed in 0 .. 50 { expect(nav_random_near(nav_st, NAV_PERSON, 0, 5.0, 0.0, 10.0, 30.0, seed)) expect(nav_near_x(nav_st) < 18.0) } nav_random_near(nav_st, NAV_PERSON, 0, 5.0, 0.0, 10.0, 30.0, 7) let x7 = nav_near_x(nav_st) let z7 = nav_near_z(nav_st) nav_random_near(nav_st, NAV_PERSON, 0, 5.0, 0.0, 10.0, 30.0, 8) expect(Math.abs(nav_near_x(nav_st) - x7) + Math.abs(nav_near_z(nav_st) - z7) > 0.01) nav_random_near(nav_st, NAV_PERSON, 0, 5.0, 0.0, 10.0, 30.0, 7) expect_eq(nav_near_x(nav_st), x7) expect_eq(nav_near_z(nav_st), z7) } test "the next corner is the path's second, read back as the nearest point" (nav_st: mut NavState) { expect(meadow(nav_st, NAV_PERSON, 0, true)) let n = nav_path(nav_st, NAV_PERSON, 0, 5.0, 0.0, 20.0, 35.0, 0.0, 20.0) let cx = nav_corner_x(nav_st, 1) let cz = nav_corner_z(nav_st, 1) expect(n >= 3) expect(nav_next_corner(nav_st, NAV_PERSON, 0, 5.0, 0.0, 20.0, 35.0, 0.0, 20.0)) expect_near(nav_near_x(nav_st), cx, 0.0001) expect_near(nav_near_z(nav_st), cz, 0.0001) expect(not nav_next_corner(nav_st, NAV_PERSON, 0, -50.0, 0.0, -50.0, 35.0, 0.0, 20.0)) } test "a filter that dislikes a band of thicket walks round it; the plain one goes through" (nav_st: mut NavState) { expect(meadow(nav_st, NAV_PERSON, 3, false)) nav_area_cost(nav_st, NAV_PERSON, 1, 2, 20.0) nav_path(nav_st, NAV_PERSON, 0, 5.0, 0.0, 10.0, 35.0, 0.0, 10.0) expect_eq(nav_corners(nav_st), 2) let n = nav_path(nav_st, NAV_PERSON, 1, 5.0, 0.0, 10.0, 35.0, 0.0, 10.0) var round = false for i in 0 .. n { if nav_corner_z(nav_st, i) > 29.0 { round = true } } expect(round) expect(not nav_partial(nav_st, NAV_PERSON)) } test "a boulder's footprint is walked round" (nav_st: mut NavState) { let g = ground(40, 0) g.foot = square_at(20.0, 20.0, 3.0) g.nf = len(g.foot) expect(nav_build(nav_st, NAV_PERSON, g, new NavConfig)) expect(not nav_straight(nav_st, NAV_PERSON, 0, 5.0, 0.0, 20.0, 35.0, 20.0)) expect(nav_path(nav_st, NAV_PERSON, 0, 5.0, 0.0, 20.0, 35.0, 0.0, 20.0) >= 3) } test "a mesh saved and loaded answers as the built one did" (nav_st: mut NavState) { expect(meadow(nav_st, NAV_PERSON, 1, true)) let path = Os.temp_dir() + "/ludic_nav_test.navmesh" expect(nav_save_file(nav_st, NAV_PERSON, path)) expect(nav_load_file(nav_st, NAV_SMALL, path)) let a = nav_path(nav_st, NAV_PERSON, 0, 5.0, 0.0, 10.0, 35.0, 0.0, 10.0) let ax = last_x(nav_st) let az = last_z(nav_st) let b = nav_path(nav_st, NAV_SMALL, 0, 5.0, 0.0, 10.0, 35.0, 0.0, 10.0) expect_eq(a, b) expect_near(last_x(nav_st), ax, 0.0001) expect_near(last_z(nav_st), az, 0.0001) nav_reset(nav_st) expect_eq(nav_polygons(nav_st, NAV_SMALL), 0) } test "the time paths take is counted, and only while a mesh is loaded" (nav_st: mut NavState) { expect_eq(nav_us(nav_st), 0) expect(meadow(nav_st, NAV_PERSON, 0, true)) for i in 0 .. 2000 { nav_path(nav_st, NAV_PERSON, 0, 5.0, 0.0, 20.0, 35.0, 0.0, 20.0) } expect(nav_us(nav_st) > 0) expect(nav_us(nav_st) < 2000000) nav_reset(nav_st) expect_eq(nav_us(nav_st), 0) } }