bevy_northstar 0.3.2

A Bevy plugin for Hierarchical Pathfinding
Documentation
# Debugging the Grid component

The `NorthstarDebugPlugin` adds systems that can be enabled to draw gizmos to display the following:

* Chunk grid: Grid outline of where the chunks are
* Entrances: Calculated entrances at the boundaries of the chunks
* Cached internal paths: Cached paths inside the chunk between its own entrances.
* Cells: Each individual cell on the grid and its passable status
* Paths: Draws the current calculated path components

First, add the `NorthstarDebugPlugin` to your app.

Then insert the `DebugGrid` component a child of the entity that the `Grid` you want to debug is attached to. 

You will likely also want to add a `DebugOffset` component to the same entity as `DebugGrid` to align the gizmos with your world tilemap position. In this example we'll be using components from bevy_ecs_tilemap to assist with determining our offset.


```rust,no_run
use bevy::prelude::*;
use bevy_ecs_tilemap::prelude::*;
use bevy_northstar::prelude::*;

fn main() {
    App::new()
        .add_plugins(DefaultPlugins)
        .add_plugins(NorthstarPlugin::<CardinalNeighborhood>::default())
        // Adding the NorthstarDebugPlugin
        // You need to specify the neighborhood here as well
        .add_plugins(NorthstarDebugPlugin::<CardinalNeighborhood>::default())
        .add_systems(Startup, startup)
        .run();
}

fn startup(mut commands: Commands, asset_server: Res<AssetServer>) {
    // Query or create your bevy_ecs_tilemap TilemapAnchor
    let anchor = TilemapAnchor::Center;

    // Query or create your bevy_ecs_tilemap TilemapSize, TilemapGridSize, and TilemapTileSize. They are required for calculating the anchor offset.
    let tilemap_size = TilemapSize { x: 64, y: 64 };
    let tilemap_gridsize = TilemapGridSize { x: 8.0, y: 8.0 };
    let tilemap_tilesize = TilemapTileSize { x: 8.0, y: 8.0 };

    // Store our offset
    let offset = anchor.as_offset(
        &tilemap_size,
        &tilemap_gridsize,
        &tilemap_tilesize,
        &TilemapType::Square,
    );

    // Let's pretend we loaded a tilemap asset and stored it in a handle and now we're spawning the entity for it.
    let mut map_entity = commands.spawn(anchor);

    // Call `build()` to return the component.
    let debug_grid = DebugGridBuilder::new(64, 64)
        .enable_chunks()
        .enable_entrances()
        .build();


    // Spawn an entity with the Grid and DebugMap component as a child of the map entity.
    let grid_entity = map_entity.with_child(
        CardinalGrid::new(&GridSettingsBuilder::new_2d(64, 64).build())
    );

    grid_entity.with_child((
        debug_grid,
        DebugOffset(offset)
    ));
}
```

# Debugging Paths

Debugging paths for an entity requires you to add a `DebugPath` component to the entity or entities of your choosing. This component allows you to selectively debug specific paths.

Drawing the path gizmos also requires the `NorthstarDebugPlugin` to add the gizmo drawing system.

```rust,no_run
use bevy::prelude::*;
use bevy_northstar::prelude::*;

commands.spawn((
    Name::new("Player"),
    DebugPath::new(Color::srgb(1.0, 0.0, 0.0)),
));
```

If you would like to debug a directly created path (returned from `grid::pathfind()`) make sure you attach the returned `Path` component to your entity. If you're not using `NorthstarPlugin` you will also need to make sure the entity has an `AgentPos` component. This is the query filter used to debug paths `Query<(&DebugPath, &Path, &AgentOfGrid)>`.

# DebugGridBuilder Settings

### `isometric()`

Sets the debug gizmos to draw in isometric perspective.

### `enable_chunks()`

Outline the grid chunk regions.

<img src="../bevy_northstar/images/debugchunk.png" width="300"/>

### `enable_entrances()`

Highlights the entrances created between each chunk. Very useful for debugging HPA* issues.

<img src="../bevy_northstar/images/debugentrances.png" width="300"/>

### `enable_cells()`

Overlay over each tile whether it's passable or impassable. Useful for debugging if you're calling `set_nav` correctly for your tilemap. 

<img src="../bevy_northstar/images/debugcells.png" width="300"/>

### `enable_cached_paths()`

`Grid` precaches paths between all entrances inside each chunk. Noisy, but can help debug HPA* pathing issues.

<img src="../bevy_northstar/images/debugcachedpaths.png" width="300"/>

### `enable_show_connections_on_hover()`

As you can see above, viewing all the connections at once is quite noisy. Enabling show_connections_on_hover will only draw chunk entrance cached connections when the `DebugCursor` position is over the node. Very useful for debugging possible failed node connections without all of the other connections overlapping.

<img src="../bevy_northstar/images/debugonlyonhover.png" width="300"/>

# `DebugCursor` Component

In order for the debug plugin to determine which node your cursor is hovering over, you need to manually update the `DebugCursor` component. While tedious this is required because not every game will have the same windowing and camera setups. `DebugCursor` is inserted along with `DebugGrid` so there is no need to insert it manually.

For most cases you can just dump the raw world cursor position in your input systems or just add a simple system to handle it:

```rust,no_run
fn update_debug_cursor(
    window: Single<&Window>,
    camera: Single<(&Camera, &GlobalTransform)>,
    debug_cursor: Single<&mut DebugCursor>,
) {
    let window = window.into_inner();
    let (camera, camera_transform) = camera.into_inner();
    let mut debug_cursor = debug_cursor.into_inner();

    if let Some(cursor_position) = window
        .cursor_position()
        .and_then(|cursor| camera.viewport_to_world_2d(camera_transform, cursor).ok())
    {
        debug_cursor.0 = Some(cursor_position);
    } else {
        debug_cursor.0 = None;
    }
}
```

# 2.5D Debugging

Drawing all 3D grid debug gizmos over a 2d tilemap render would get pretty noisy so the debug drawing generally only draws information for one z depth at a time. The exception for this is that all entrance nodes will be drawn and y offsets for height will be applied.

You can set the depth with an inspector or use `DebugGrid::set_depth(depth: u32)` to change the depth that is being drawn.

In 2.5D maps each depth layer will generally have a Y offset applied so the tile appears higher to the player. The `DebugDepthYOffsets` component is used so the debugging systems know which offsets to apply when drawing at that z depth. `DebugDepthYOffsets` takes a `HashMap<u32, f32>` where the key is the z depth and the value is the offset.

For example:

```rust,no_run
DebugDepthYOffsets(
    HashMap::from([
        (0, 0.0),
        (1, 16.0),
        (2, 32.0),
    ])
)
```


# Stats
Enabling the `stats` feature on the crate will allow the `NorthstarPlugin` pathfinding systems to calculate the average time spent on pathfinding and collision calls.

It will also log debug level stats for `Grid::build()` times. Useful making sure your grid rebuilds are staying within your frame budget.

```toml
[dependencies]
bevy_northstar = { version = "0.2.0", features = ["stats"]}
```

You can access the statistics from the `Stats` `Resource`.

```rust,no_run
fn print_stats(stats: Res<Stats>) {
    debug!("Collision Stats: {:?}", stats.collision);
    debug!("Pathfinding Stats: {:?}", stats.pathfinding);
}
```

To get the `Grid::build()` timing stats dumped to your log you'll need to enable debug level logging for the crate.
```bash,no-run
RUST_LOG=bevy_northstar=debug,bevy=info cargo run
```

Or alternatively configure it in code when setting up your Bevy logging.