Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add_edges and add_grid helpers for DirectionalNavMap #17247

Open
wants to merge 14 commits into
base: main
Choose a base branch
from

Conversation

alice-i-cecile
Copy link
Member

@alice-i-cecile alice-i-cecile commented Jan 8, 2025

Objective

Prompted by #17224, I realized that we need more helpers to make configuring DirectionalNavMaps for directional (gamepad) navigation easier.

Solution

  • Add a simple add_edges helper, which does not loop around the end of the list.
  • Add a add_grid helper for working with grids.
    • Obviously, this is really helpful for wiring up e.g. Terraria-style inventory screens.
    • Less obviously, this is a powerful mid-level API for defining directional nav layouts more broadly. The coordinates don't need to be physical, and the ability to duplicate entities in the map makes modelling large objects a breeze.
  • Added more helpers to CompassQuadrant / CompassOctant to make this code prettier: these simple methods should be generally useful to users.

Testing

I'm currently relying on unit tests for these changes. Once #17224 is merged, we can update that the example to test these in a more hands-on way.

To do

  • make sure tests pass and logic is correct

@alice-i-cecile alice-i-cecile added A-Input Player input via keyboard, mouse, gamepad, and more A-UI Graphical user interfaces, styles, layouts, and widgets C-Usability A targeted quality-of-life change that makes Bevy easier to use A-Math Fundamental domain-agnostic mathematical operations D-Straightforward Simple bug fixes and API improvements, docs, test and examples S-Needs-Review Needs reviewer attention (from anyone!) to move forward labels Jan 8, 2025
@alice-i-cecile alice-i-cecile changed the title add_edges and add_grid helpers for DirectionalNavMap` add_edges and add_grid helpers for DirectionalNavMap Jan 8, 2025
@alice-i-cecile alice-i-cecile added S-Waiting-on-Author The author needs to make changes or address concerns before this can be merged and removed S-Needs-Review Needs reviewer attention (from anyone!) to move forward labels Jan 9, 2025
@alice-i-cecile alice-i-cecile added this to the 0.16 milestone Jan 9, 2025
Co-authored-by: IQuick 143 <[email protected]>
// which uses u16 values. We need signed integers here, but we should be able to cast them losslessly.
// PERF: This is a very flexible / "clever" implementation, but it won't be the fastest for simple cases.
// If there's user demand for it, we can add a more optimized / less flexible version that requires non-sparse rectangular grids.
pub fn add_grid(&mut self, entity_grid: NavGrid, should_loop: bool) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This promises support for placing entities at multiple locations, however it's not well defined what the result is.
Consider the following grid:

X A
Y A

Now... what is the left neighbour of A? It seems to be completely implementation dependent.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, we should probably choose, document and test a rule for this.

// Inserting the same entity at multiple locations is supported,
// so we need to check for this case
if neighbor != entity {
// PERF: we could also add the reverse edge here, to save work later
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Multiple positions for the same node would make this very tricky/not possible.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right 🤔 Okay, I'll cut the PERF note.


if let Some(neighbor) = maybe_neighbor {
// Entities should not be neighbors of themselves
// Inserting the same entity at multiple locations is supported,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: This collision can happen also by just an entity looping to itself, which may or (probably) may not be desired.

@@ -114,6 +137,18 @@ pub enum CompassOctant {
}

impl CompassOctant {
/// The list of all possible [`CompassOctant`] variants.
pub const VARIANTS: [CompassOctant; 8] = [
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might be nice to test that this is in the same order as from_index (could we implement from_index like that?)

@@ -21,9 +21,11 @@ use bevy_ecs::{
prelude::*,
Copy link
Member

@cart cart Jan 9, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As a general thought, I think my ideal system is an automatic system that is overridden by manually defined nav targets.

Ex: label ui nodes as "navigable", then for each "navigable" node, compute the closest/best-fit navigable node in the direction specified, unless a node for that direction has been manually specified.

Forcing users to define the graph up front is too cumbersome for the majority of use cases. Ex: a flat list of navigable nodes is trivially implicitly navigable.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is especially important because many lists of nodes will have different targets based on their current layout. We essentially need those cases to automatically/implicitly adapt to the current context.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As a general thought, I think my ideal system is an automatic system that is overridden by manually defined nav targets.

Fully agree here! I've been exploring APIs and algorithms to make this possible :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-Input Player input via keyboard, mouse, gamepad, and more A-Math Fundamental domain-agnostic mathematical operations A-UI Graphical user interfaces, styles, layouts, and widgets C-Usability A targeted quality-of-life change that makes Bevy easier to use D-Straightforward Simple bug fixes and API improvements, docs, test and examples S-Waiting-on-Author The author needs to make changes or address concerns before this can be merged
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants