Bevy Integration
bevy_map_scatter wraps the core crate with asset loading, async execution, and ECS-friendly results.
Install
The plugin enables serde and ron by default so you can author *.scatter assets.
Add the plugin
use bevy::prelude::*;
use bevy_map_scatter::prelude::*;
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_plugins(MapScatterPlugin)
.run();
}
Author a scatter plan (RON)
Plans are assets. Create a file like assets/simple.scatter:
(
layers: [
(
id: "trees",
kinds: [
(
id: "tree",
spec: (
nodes: {
"probability": Constant(
params: ConstantParams(value: 1.0),
),
},
semantics: {
"probability": Probability,
},
),
),
],
sampling: PoissonDisk(
radius: 2.5,
),
selection_strategy: WeightedRandom,
),
],
)
Trigger a run
Load the plan and send a ScatterRequest once it is ready:
use bevy::prelude::*;
use bevy_map_scatter::prelude::*;
#[derive(Resource, Default)]
struct PlanHandle(Handle<ScatterPlanAsset>);
fn load_plan(mut handle: ResMut<PlanHandle>, assets: Res<AssetServer>) {
handle.0 = assets.load("simple.scatter");
}
fn trigger_request(
mut commands: Commands,
mut once: Local<bool>,
handle: Res<PlanHandle>,
assets: Res<Assets<ScatterPlanAsset>>,
) {
if *once || assets.get(&handle.0).is_none() {
return;
}
let domain = Vec2::new(100.0, 100.0);
let config = RunConfig::new(domain)
.with_chunk_extent(32.0)
.with_raster_cell_size(1.0);
let entity = commands.spawn_empty().id();
commands.trigger(ScatterRequest::new(entity, handle.0.clone(), config, 123));
*once = true;
}
fn on_finished(finished: On<ScatterFinished>) {
info!("Placed {} instances", finished.result.placements.len());
}
Register textures
To use Bevy Image assets inside field graphs, snapshot them to ImageTexture and register them in the shared registry. The registry is an Arc<TextureRegistry>, so use Arc::make_mut to register.
use std::sync::Arc;
use bevy::prelude::*;
use bevy_map_scatter::prelude::*;
#[derive(Resource)]
struct HeightmapHandle(Handle<Image>);
fn register_textures(
mut registry: ResMut<ScatterTextureRegistry>,
images: Res<Assets<Image>>,
handle: Res<HeightmapHandle>,
) {
let Some(image) = images.get(&handle.0) else {
return;
};
let Some(texture) = ImageTexture::from_image(image, Vec2::new(100.0, 100.0)) else {
return;
};
Arc::make_mut(&mut registry.0).register("heightmap", texture);
}
If the source image changes, create a new ImageTexture snapshot and re-register it.
Streaming (optional)
For large or moving worlds, enable chunked streaming around an anchor entity:
- Add
MapScatterStreamingPlugin. - Attach
ScatterStreamSettingsto an entity that moves through the world. - Listen for
ScatterStreamPlacementcomponents on spawned entities.
Tips
- Use deterministic seeds during development to compare changes.
- Keep domain sizes consistent with texture mappings.
- Use overlay masks to prevent overlap between layers.
- Inspect
ScatterMessageevents for diagnostics.
Examples
cargo run -p bevy_map_scatter_examples --bin quick-startcargo run -p bevy_map_scatter_examples --bin streaming-minimal