A Bevy plugin that puts the A5
pentagonal cell hierarchy under your game world. bevy_a5 is to spherical
games what big_space is to deep-space games:
the same floating-origin precision pattern, but the cell space is the
surface of a planet instead of an integer Cartesian grid.
- Cell-anchored coordinates. Every entity is
(GeoCell, Transform)— which A5 cell, plus a small offset within that cell. Float precision stays tight even when the underlying world position is on the other side of the planet. - Floating-origin recentre. Walk past
recenter_thresholdand the plugin shifts the origin to a neighbouring cell, rebasing both translation and rotation so the world-space pose is unchanged. Recentres are visually invisible. - A5 spatial queries.
grid_disk,vertex_neighbors,spherical_cap,compact/uncompact— none of which a Cartesian grid can give you on a sphere. All return uniform-resolution cell sets by design (tested invariant). - Cell → entity index.
CellEntityIndexmaintained by an observer-style system onChanged<GeoCell>;O(1)"what entities are in cell X?" lookup,SmallVec-backed buckets to avoid heap-allocation churn. - Display helpers.
build_grid_line_mesh(cells, radius) -> Meshfor one-call wireframe grids;DrawCellOutlinemarker for ad-hoc per-entity cell debugging via gizmos. - Reusable fly camera.
FlyCamcomponent +CameraPluginlifted from the duplicated example boilerplate, ready to drop on aCamera3d.
[dependencies]
bevy = "0.18"
bevy_a5 = "0.1"Bevy 0.18 is the supported version.
use bevy::prelude::*;
use bevy_a5::prelude::*;
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_plugins(BevyA5Plugins) // core + camera + cell hash
.insert_resource(PlanetSettings::earth())
.add_systems(Startup, setup)
.run();
}
fn setup(mut commands: Commands) {
// Spawn the floating-origin camera at Paris.
let here = GeoCell::from_lon_lat(2.3522, 48.8566, 9).unwrap();
commands.spawn_floating_origin(here).insert((
Camera3d::default(),
FlyCam::default(),
Transform::from_xyz(0.0, 5.0, 0.0).looking_at(Vec3::ZERO, Vec3::Y),
));
// Place an entity at a neighbouring cell's centre.
let neighbour = GeoCell::from_lon_lat(2.3525, 48.8570, 9).unwrap();
commands.spawn_cell_anchor(neighbour);
}cargo run --example planet_grid # Whole-planet wireframe, fly camera
cargo run --example overhead_map # Top-down map of Paris with slippy tiles
cargo run --example flock # Spatial-query demo: brownian flock + neighbour highlighting
cargo run --example cell_origin # Live cell / heading / position HUD on the planet gridoverhead_map and flock cache OSM tiles under assets/tiles/. The first
run needs network; subsequent runs hit the cache.
bevy_a5 makes sense if your game world is the surface of a sphere
(Earth, a moon, a fictional planet) and you need consistent positioning at
metre precision across the whole surface, with topologically correct
neighbour lookups (no pole singularity, no longitude-180 seam).
If your world is flat, use big_space (Cartesian high-precision) or
just plain Bevy Transforms — they're faster and simpler. The
benches/spatial_index.rs bench quantifies
the cost difference: on flat ground, a (i32, i32)-tile index is ~30–100×
faster than the A5 equivalent. You're paying for spherical correctness;
don't pay for it on a plane.
0.1.0 — pre-release. The public API is stable enough to build against,
but expect breakage at minor versions until 1.0:
- Floating-origin recentre (big-space style — origin always renders at world
(0, 0, 0)) - Vertex-aligned cell-local frame (
-Ztoward first boundary vertex) - Spatial queries with uniform-resolution invariant
-
CellEntityIndexspatial hash -
CellTrackertemporal-coherence helper for user-driven movement - Reusable
FlyCam - Adaptive slippy-tile zoom in the
overhead_mapexample -
criterionbenchmark vs Bevy's observers-style cartesian index - Multi-planet support (one
Planetper root entity — currently single globalPlanetSettings) - Multi-
FloatingOrigin(split-screen / networked players) - Observer-based
CellEntityIndexmaintenance for instant reactivity
MIT — see LICENSE.