Closed maxfierke closed 1 year ago
Your coordinates are all flipped! landmass
assumes that Y is up and agents walk in the XZ plane, as its mostly meant for 3D navigation although it should be totally capable to do 2D navigation. So your nav mesh needs to use Z as its other dimension, as well as your AgentTarget, AS WELL AS your agent's transform.
The last one is the hardest one to manage. What you can do as a workaround is to spawn a separate entity to be your "proxy". Then add a system to copy its transform to match the "real" entity's transform but moving the Y to be the Z. Then you can read back the desired velocity by querying for the proxy from your "real" entity. I'm not 100% sure this will fix your problem, but it should be a step in the right direction.
I think I would like to support 2D navigation, at least from bevy_landmass
. I'll make an issue for it. I also still need to add better reporting mechanisms so users can actually tell what their agent is doing (or why they're not doing!).
P.S. Thank you so much for trying out bevy_landmass
and landmass
! I'm so excited! :D
Ohhh that makes sense!! I'll give the proxy idea a shot and see where I get with that. Thanks!
I'm really liking the approach of landmass
so far, though! Definitely fits my mental model for this type of stuff and the code is quite readable!
Ah hah! The proxy idea has yielded some progress! I can now navigate within one polygon (connectivity between polygons seems not to be working yet, but I haven't looked into it yet. Probably something easy I'm missing.)
entity=44v0, target=Vec3(-254.54494, 0.0, -1.2148438), desired_velocity=Vec3(-9.9998865, 0.0, -0.047725555)
For posterity, I ended up:
Implementing a PlayerNavShadow
component with a TransformBundle
and the following system to sync the transform from Player
(flipping Z and Y):
fn sync_nav_shadow(
player_transform_query: Query<&Transform, With<Player>>,
mut navshadow_transform_query: Query<&mut Transform, (With<PlayerNavShadow>, Without<Player>)>,
) {
if let Ok(player_transform) = player_transform_query.get_single() {
if let Ok(mut navshadow_transform) = navshadow_transform_query.get_single_mut() {
navshadow_transform.translation = Vec3::new(
player_transform.translation.x,
0.0, // Not sure if this should ultimately be `player_transform.translation.z` but I've just been using Z=0.0 for all navmesh-related stuff
player_transform.translation.y,
)
}
}
}
Realizing that my navmesh vertices were flipped from the expected order (got a ConcavePolygon
error). I just needed to reverse the order for all of the polygons, so I think it was just that they were in clockwise, but needed to be counter-clockwise.
Flipping Y and Z for anything else that touched landmass (debug lines, attaching agent to PlayerNavShadow, etc.)
Thanks for all your help 😁 !
Hey there, I'm playing around with
bevy_landmass
andlandmass
trying to get navmesh-based pathfinding working for a point-and-click adventure game.I think I've got everything wired up correctly, but I'm not able to see
desired_velocity
get updated to anything other than[0, 0, 0]
.Here's what the navmesh looks like in both code and rendered on-screen with
bevy_prototype_debug_lines
:Code
```rust // This converts map coordinates into Bevy world coordinates // context: the map's background image is 480x270, positioned at center 0,0 (bevy origin), and scaled 3x for screen fn map_to_world(x: f32, y: f32, z: f32) -> glam::Vec3 { glam::Vec3::new( (-480.0 / 2.0 + x) * 3.0, (-270.0 / 2.0 + y) * 3.0, z, ) } // Called during scene load. Coords come from a mesh-making tool that uses bottom-left origin, // so map_to_world is used to convert it to Bevy world coordinate space fn spawn_navmesh(mut commands: Commands,) { let navmesh = landmass::NavigationMesh { mesh_bounds: None, vertices: vec![ map_to_world(51.0, 124.0, 0.0), // 0 map_to_world(174.0, 124.0, 0.0), // 1 map_to_world(174.0, 106.0, 0.0), // 2 map_to_world(36.0, 106.0, 0.0), // 3 map_to_world(304.0, 79.0, 0.0), // 4 map_to_world(124.0, 79.0, 0.0), // 5 map_to_world(144.0, 106.0, 0.0), // 6 map_to_world(293.0, 106.0, 0.0), // 7 map_to_world(293.0, 106.0, 0.0), // 7 + 8 map_to_world(208.0, 106.0, 0.0), // 9 map_to_world(223.0, 124.0, 0.0), // 10 map_to_world(291.0, 124.0, 0.0), // 11 map_to_world(457.0, 94.0, 0.0), // 12 map_to_world(473.0, 79.0, 0.0), // 13 map_to_world(302.0, 79.0, 0.0), // 14 map_to_world(297.0, 94.0, 0.0), // 15 map_to_world(454.0, 99.0, 0.0), // 16 map_to_world(457.0, 94.0, 0.0), // 12 + 17 map_to_world(397.0, 94.0, 0.0), // 18 map_to_world(394.0, 99.0, 0.0), // 19 map_to_world(457.0, 180.0, 0.0), // 20 map_to_world(473.0, 187.0, 0.0), // 21 map_to_world(473.0, 79.0, 0.0), // 13 + 22 map_to_world(457.0, 79.0, 0.0), // 23 ], polygons: vec![ vec![0, 1, 2, 3], vec![4, 5, 6, 7], vec![7, 9, 10, 11], vec![12, 13, 14, 15], vec![16, 12, 18, 19], vec![20, 21, 13, 23], ], }; commands.spawn( Archipelago::new( landmass::Archipelago::create_from_navigation_mesh( navmesh.validate().expect("is valid") ) ) ); } // Just printing the desired velocity from the player's agent fn print_desired_velocity( query: Query<(Entity, &AgentTarget, &AgentDesiredVelocity), WithValidNavigationMesh
```rust ValidNavigationMesh { mesh_bounds: Box { min: Vec3(-612.0, -168.0, 0.0), max: Vec3(699.0, 156.0, 0.0) }, vertices: [Vec3(-567.0, -33.0, 0.0), Vec3(-198.0, -33.0, 0.0), Vec3(-198.0, -87.0, 0.0), Vec3(-612.0, -87.0, 0.0), Vec3(192.0, -168.0, 0.0), Vec3(-348.0, -168.0, 0.0), Vec3(-288.0, -87.0, 0.0), Vec3(159.0, -87.0, 0.0), Vec3(159.0, -87.0, 0.0), Vec3(-96.0, -87.0, 0.0), Vec3(-51.0, -33.0, 0.0), Vec3(153.0, -33.0, 0.0), Vec3(651.0, -123.0, 0.0), Vec3(699.0, -168.0, 0.0), Vec3(186.0, -168.0, 0.0), Vec3(171.0, -123.0, 0.0), Vec3(642.0, -108.0, 0.0), Vec3(651.0, -123.0, 0.0), Vec3(471.0, -123.0, 0.0), Vec3(462.0, -108.0, 0.0), Vec3(651.0, 135.0, 0.0), Vec3(699.0, 156.0, 0.0), Vec3(699.0, -168.0, 0.0), Vec3(651.0, -168.0, 0.0)], polygons: [ValidPolygon { vertices: [0, 1, 2, 3], bounds: Box { min: Vec3(-612.0, -87.0, 0.0), max: Vec3(-198.0, -33.0, 0.0) }, center: Vec3(-393.75, -60.0, 0.0) }, ValidPolygon { vertices: [4, 5, 6, 7], bounds: Box { min: Vec3(-348.0, -168.0, 0.0), max: Vec3(192.0, -87.0, 0.0) }, center: Vec3(-71.25, -127.5, 0.0) }, ValidPolygon { vertices: [7, 9, 10, 11], bounds: Box { min: Vec3(-96.0, -87.0, 0.0), max: Vec3(159.0, -33.0, 0.0) }, center: Vec3(41.25, -60.0, 0.0) }, ValidPolygon { vertices: [12, 13, 14, 15], bounds: Box { min: Vec3(171.0, -168.0, 0.0), max: Vec3(699.0, -123.0, 0.0) }, center: Vec3(426.75, -145.5, 0.0) }, ValidPolygon { vertices: [16, 12, 18, 19], bounds: Box { min: Vec3(462.0, -123.0, 0.0), max: Vec3(651.0, -108.0, 0.0) }, center: Vec3(556.5, -115.5, 0.0) }, ValidPolygon { vertices: [20, 21, 13, 23], bounds: Box { min: Vec3(651.0, -168.0, 0.0), max: Vec3(699.0, 156.0, 0.0) }, center: Vec3(675.0, -11.25, 0.0) }], connectivity: [[], [], [], [], [], []], boundary_edges: [MeshEdgeRef { polygon_index: 0, edge_index: 3 }, MeshEdgeRef { polygon_index: 3, edge_index: 1 }, MeshEdgeRef { polygon_index: 4, edge_index: 2 }, MeshEdgeRef { polygon_index: 0, edge_index: 2 }, MeshEdgeRef { polygon_index: 3, edge_index: 0 }, MeshEdgeRef { polygon_index: 0, edge_index: 1 }, MeshEdgeRef { polygon_index: 5, edge_index: 2 }, MeshEdgeRef { polygon_index: 5, edge_index: 3 }, MeshEdgeRef { polygon_index: 2, edge_index: 1 }, MeshEdgeRef { polygon_index: 4, edge_index: 3 }, MeshEdgeRef { polygon_index: 5, edge_index: 1 }, MeshEdgeRef { polygon_index: 5, edge_index: 0 }, MeshEdgeRef { polygon_index: 1, edge_index: 2 }, MeshEdgeRef { polygon_index: 2, edge_index: 0 }, MeshEdgeRef { polygon_index: 3, edge_index: 3 }, MeshEdgeRef { polygon_index: 2, edge_index: 3 }, MeshEdgeRef { polygon_index: 4, edge_index: 0 }, MeshEdgeRef { polygon_index: 4, edge_index: 1 }, MeshEdgeRef { polygon_index: 1, edge_index: 0 }, MeshEdgeRef { polygon_index: 1, edge_index: 1 }, MeshEdgeRef { polygon_index: 0, edge_index: 0 }, MeshEdgeRef { polygon_index: 1, edge_index: 3 }, MeshEdgeRef { polygon_index: 2, edge_index: 2 }, MeshEdgeRef { polygon_index: 3, edge_index: 2 }] } ```When clicking a destination to move, here's what I see printed every frame (indicating it's at least updating
AgentDesiredVelocity
every frame):As far as I can tell, both based on the visual representation and the numbers itself compared with the generated navmesh coordinates, the
target
is within the navmesh, so I would expect it to find a path. (small white line is from the center of the actor's feet to the target. There's some simple math involved to shift the Y to make it all based on the actor's feet, but I removed it from the example above and the behavior is the same either way.)Any ideas on what I'm missing or doing wrong here?