simvx.core.navigation¶
2D Navigation and Pathfinding for SimVX.
Provides graph-based and grid-based A* pathfinding, plus a NavigationAgent2D node that follows computed paths with steering and emits signals on arrival.
Usage: from simvx.core import PathFinder2D, NavGrid2D, NavigationAgent2D
# Graph-based pathfinding
astar = PathFinder2D()
astar.add_point(0, (0, 0))
astar.add_point(1, (10, 0))
astar.connect_points(0, 1)
path = astar.get_point_path(0, 1) # [(0,0), (10,0)]
# Grid-based pathfinding
grid = NavGrid2D(20, 20, cell_size=32.0)
grid.set_solid(5, 5)
path = grid.find_path((0, 0), (10, 10))
# Navigation agent node
agent = NavigationAgent2D()
agent.set_navigation(astar)
agent.target_position = (10, 0)
Submodules¶
Package Contents¶
Classes¶
Graph-based A* pathfinding. Supports both grid-based and arbitrary graphs. |
|
Grid-based A* with automatic cell management. |
|
2D node that follows A* paths with steering. |
Data¶
How a grid treats a diagonal step past the corner of a solid cell. |
API¶
- simvx.core.navigation.log¶
‘getLogger(…)’
- simvx.core.navigation.__all__¶
[‘PathFinder2D’, ‘NavGrid2D’, ‘NavigationAgent2D’, ‘PathFollower2D’, ‘CornerPolicy’]
- simvx.core.navigation.CornerPolicy¶
None
How a grid treats a diagonal step past the corner of a solid cell.
- class simvx.core.navigation.PathFinder2D[source]¶
Graph-based A* pathfinding. Supports both grid-based and arbitrary graphs.
Initialization
- __slots__¶
(‘_points’, ‘_connections’, ‘_weights’, ‘_disabled’)
- add_point(id: int, position: tuple[float, float], weight: float = 1.0)[source]¶
Add a point to the graph. Weight scales traversal cost (default 1.0).
- connect_points(id1: int, id2: int, bidirectional: bool = True)[source]¶
Connect two points. Both must already exist.
- disconnect_points(id1: int, id2: int, bidirectional: bool = True)[source]¶
Remove connection between two points.
- set_point_disabled(id: int, disabled: bool = True)[source]¶
Disable/enable a point. Disabled points are excluded from pathfinding.
- get_closest_point(position: tuple[float, float]) → int[source]¶
Return id of the closest non-disabled point to the given position.
- class simvx.core.navigation.NavGrid2D(width: int, height: int, cell_size: float = 1.0, corners: simvx.core.navigation.CornerPolicy = 'strict', offset: tuple[float, float] = (0.0, 0.0))[source]¶
Grid-based A* with automatic cell management.
cornersdecides when a diagonal step past the corner of a solid cell is allowed. Cutting a corner is only executable by an agent that is small enough to fit through the gap it leaves, so the four policies trade agent size against path length:"never"No diagonal steps at all; every route is 4-connected."strict"(default) A diagonal needs both of the two cells it passes between to be free, so no agent is ever asked to squeeze through a gap of zero width."relaxed"A diagonal needs at least one of the two free, which lets a point-sized agent slip past a single corner, as between diagonally placed fence posts."always"Diagonals are unconditional, so a route may cross a sealed diagonal wall that no agent of any size can actually pass.Args: width: Grid width in cells. height: Grid height in cells. cell_size: Size of each cell in world units. corners: Diagonal-corner policy, one of
"never","strict","relaxed"or"always". offset: World-space offset of the grid origin.Raises: ValueError: If
cornersis not one of the four policy names.Initialization
- __slots__¶
(‘_width’, ‘_height’, ‘_cell_size’, ‘_corners’, ‘_offset’, ‘_solid’, ‘_weights’)
- property corners: simvx.core.navigation.CornerPolicy[source]¶
The diagonal-corner policy this grid searches with.
- set_solid(x: int, y: int, solid: bool = True)[source]¶
Mark a cell as solid (impassable) or clear it.
- set_weight(x: int, y: int, weight: float)[source]¶
Set traversal weight for a cell. Default is 1.0; higher = costlier.
- find_path(from_cell: tuple[int, int], to_cell: tuple[int, int]) → list[tuple[int, int]][source]¶
Find shortest path between two grid cells. Returns list of (x,y) cells.
Diagonal steps are admitted according to the grid’s
cornerspolicy. Returns an empty list when either end is off the grid, either end is solid, or no route exists.
- class simvx.core.navigation.NavigationAgent2D(max_speed: float = 100.0, path_desired_distance: float = 4.0, **kwargs)[source]¶
Bases:
simvx.core.nodes_2d.node2d.Node2D2D node that follows A* paths with steering.
Assign a pathfinder (PathFinder2D or NavGrid2D) via
set_navigation(), settarget_position, and the agent moves toward it each physics frame.Emits
navigation_finishedwhen the target is reached.Usage: agent = NavigationAgent2D(max_speed=200.0) agent.set_navigation(my_astar) agent.target_position = Vec2(500, 300)
Initialization
- max_speed¶
‘Property(…)’
- path_desired_distance¶
‘Property(…)’
- property target_position: simvx.core.math.types.Vec2[source]¶
- property velocity: simvx.core.math.types.Vec2[source]¶
Current velocity (read-only, computed each physics frame).
- set_navigation(nav: simvx.core.navigation.PathFinder2D | simvx.core.navigation.NavGrid2D)[source]¶
Assign a pathfinder instance.
- position¶
‘_SpatialVecProperty(…)’
- rotation¶
‘Property(…)’
- scale¶
‘_SpatialVecProperty(…)’
- z_index¶
‘Property(…)’
- z_as_relative¶
‘Property(…)’
- render_layer¶
‘Property(…)’
- set_render_layer(index: int, enabled: bool = True) → None¶
- is_on_render_layer(index: int) → bool¶
- property absolute_z_index: int¶
- property rotation_degrees: float¶
- property world_position: simvx.core.math.types.Vec2¶
- property world_rotation: float¶
- property world_scale: simvx.core.math.types.Vec2¶
- property world_transform: tuple[simvx.core.math.types.Vec2, simvx.core.math.types.Vec2, float]¶
- property forward: simvx.core.math.types.Vec2¶
- property right: simvx.core.math.types.Vec2¶
- translate(offset: tuple[float, float] | numpy.ndarray)¶
- rotate(radians: float)¶
- rotate_deg(degrees: float)¶
- look_at(target: tuple[float, float] | numpy.ndarray)¶
- transform_points(points: list[simvx.core.math.types.Vec2]) → list[simvx.core.math.types.Vec2]¶
- draw_polygon(renderer, points: list[simvx.core.math.types.Vec2], closed=True, colour=None)¶
- wrap_screen(margin: float = 20)¶
- hdr¶
‘Property(…)’
- property transform_render_dirty: bool¶
- strict_errors: ClassVar[bool]¶
True
- dev_checks: ClassVar[bool]¶
None
- script_error_raised¶
‘Signal(…)’
- dynamic: bool¶
False
- visible¶
‘Property(…)’
- update_mode¶
‘Property(…)’
- __properties__: ClassVar[dict[str, simvx.core.descriptors.Property]]¶
None
- classmethod __init_subclass__(**kwargs)¶
- property name: str¶
- property visible_in_tree: bool¶
- reset_error() → None¶
- add_child(node: simvx.core.node.T) → simvx.core.node.T¶
- remove_child(node: simvx.core.node.Node) → None¶
- reparent(new_parent: simvx.core.node.Node)¶
- node_at(path, default=_NO_DEFAULT)¶
- find(target, *, direct: bool = False)¶
- find_all(target, *, direct: bool = False)¶
- expect(target, *, direct: bool = False)¶
- ancestor(target)¶
- walk(*, include_self: bool = True) → collections.abc.Iterator[simvx.core.node.Node]¶
- property path: str¶
- property is_scene_root: bool¶
- add_to_group(group: str)¶
- remove_from_group(group: str)¶
- is_in_group(group: str) → bool¶
- on_ready() → None¶
- on_enter_tree() → None¶
- on_exit_tree() → None¶
- on_update(dt: float) → None¶
- on_draw(renderer) → None¶
- on_picked(event: simvx.core.events.InputEvent) → None¶
- on_unhandled_input(event: simvx.core.events.TreeInputEvent) → None¶
- start_coroutine(gen: simvx.core.descriptors.Coroutine) → simvx.core.descriptors.CoroutineHandle¶
- stop_coroutine(gen_or_handle)¶
- queue_redraw() → None¶
- property render_dirty: bool¶
- clear_children()¶
- destroy()¶
- property destroying: bool¶
- call_deferred(method: collections.abc.Callable[..., Any], *args: Any) → None¶
- property app¶
- property tree: simvx.core.scene_tree.SceneTree¶
- property physics¶
- property physics_2d¶
- __getitem__(key: str)¶
- classmethod get_properties() → dict[str, simvx.core.descriptors.Property]¶
- __repr__()¶