use bevy::{ diagnostic::{FrameTimeDiagnosticsPlugin, LogDiagnosticsPlugin}, math::Vec3Swizzles, prelude::*, utils::HashSet, }; use bevy_sprite_instancing::{ InstancedSprite, InstancedSpriteRenderPlugin, InstancedSpritesheet, SpriteInstancingGroup, }; pub const ENTITY_COUNT: usize = 100000; fn random_transform(s_base: f32, s_mul: f32) -> Transform { let x = (rand::random::<f32>() - 0.5) * 2000.0; let y = (rand::random::<f32>() - 0.5) * 1000.0; let s = (rand::random::<f32>() - 0.5) * s_mul + s_base; Transform::from_translation(Vec3::new(x, y, 0.0)).with_scale(Vec3::new(s, s, 1.0)) } fn random_delta() -> Vec3 { let dx = (rand::random::<f32>() - 0.5) * 20.0; let dy = (rand::random::<f32>() - 0.5) * 20.0; Vec3::new(dx, dy, 0.0) } fn setup(mut commands: Commands, asset_server: Res<AssetServer>) { commands.spawn(Camera2dBundle::default()); let image = asset_server.load("map0.png"); let spritesheet0 = InstancedSpritesheet { image, width_tiles: 32, height_tiles: 32, }; let mut instancing_group0 = SpriteInstancingGroup { entities: HashSet::new(), }; let instancing_group0_id = commands.spawn_empty().id(); for _ in 0..ENTITY_COUNT { let id = commands .spawn(( random_transform(16.0, 10.0), InstancedSprite { group_id: instancing_group0_id, texture_index: 0, }, )) .id(); instancing_group0.entities.insert(id); } commands .entity(instancing_group0_id) .insert((instancing_group0, spritesheet0)); } fn move_entities(mut query: Query<&mut Transform, With<InstancedSprite>>) { for mut transform in query.iter_mut() { transform.translation += random_delta(); } } fn animate_entities(mut query: Query<&mut InstancedSprite>, time: Res<Time>) { let t = time.elapsed_seconds(); let animation_step = (t * 10.0) as u32 % 5; for mut instance in query.iter_mut() { instance.texture_index = animation_step; } } fn handle_clicks( mut commands: Commands, entities: Query<(Entity, &Transform, &InstancedSprite)>, mut instance_groups: Query<&mut SpriteInstancingGroup>, window: Query<&Window>, mouse_button: Res<Input<MouseButton>>, ) { if mouse_button.just_pressed(MouseButton::Left) { let window = window.single(); let position = window.cursor_position().unwrap() - Vec2::new(window.width() / 2.0, window.height() / 2.0); for (entity, transform, instance) in &entities { let pos = transform.translation.xy(); if pos.distance(position) < 10.0 { commands.entity(entity).despawn(); instance_groups .get_mut(instance.group_id) .unwrap() .entities .remove(&entity); } } } } pub fn main() { App::new() .add_plugins(DefaultPlugins) .add_plugin(InstancedSpriteRenderPlugin) .add_plugin(LogDiagnosticsPlugin::default()) .add_plugin(FrameTimeDiagnosticsPlugin::default()) .add_startup_system(setup) .add_system(move_entities) .add_system(animate_entities) .add_system(handle_clicks) .run(); }