//! Shows a tilemap chunk rendered with a single draw call. use bevy::{ color::palettes::tailwind::RED_400, image::{ImageArrayLayout, ImageLoaderSettings}, prelude::*, sprite_render::{TileData, TilemapChunk, TilemapChunkTileData}, }; use chacha20::ChaCha8Rng; use rand::{RngExt, SeedableRng}; fn main() { App::new() .add_plugins(DefaultPlugins.set(ImagePlugin::default_nearest())) .add_systems(Startup, (setup, spawn_fake_player).chain()) .add_systems(Update, (update_tilemap, move_player, log_tile)) .run(); } #[derive(Component, Deref, DerefMut)] struct UpdateTimer(Timer); #[derive(Resource, Deref, DerefMut)] struct SeededRng(ChaCha8Rng); fn setup(mut commands: Commands, assets: Res) { // We're seeding the PRNG here to make this example deterministic for testing purposes. // This isn't strictly required in practical use unless you need your app to be deterministic. let mut rng = ChaCha8Rng::seed_from_u64(42); let chunk_size = UVec2::splat(64); let tile_display_size = UVec2::splat(8); let tile_data: Vec> = (0..chunk_size.element_product()) .map(|_| rng.random_range(0..5)) .map(|i| { if i == 0 { None } else { Some(TileData::from_tileset_index(i - 1)) } }) .collect(); commands.spawn(( TilemapChunk { chunk_size, tile_display_size, tileset: assets .load_builder() .with_settings(|settings: &mut ImageLoaderSettings| { // The tileset texture is expected to be an array of tile textures, so we tell the // `ImageLoader` that our texture is composed of 4 stacked tile images. settings.array_layout = Some(ImageArrayLayout::RowCount { rows: 4 }); }) .load("textures/array_texture.png"), ..default() }, TilemapChunkTileData(tile_data), UpdateTimer(Timer::from_seconds(0.1, TimerMode::Repeating)), )); commands.spawn(Camera2d); commands.insert_resource(SeededRng(rng)); } #[derive(Component)] struct MovePlayer; fn spawn_fake_player( mut commands: Commands, mut meshes: ResMut>, mut materials: ResMut>, chunk: Single<&TilemapChunk>, ) { let mut transform = chunk.calculate_tile_transform(UVec2::new(0, 0)); transform.translation.z = 1.; commands.spawn(( Mesh2d(meshes.add(Rectangle::new(8., 8.))), MeshMaterial2d(materials.add(Color::from(RED_400))), transform, MovePlayer, )); let mut transform = chunk.calculate_tile_transform(UVec2::new(5, 6)); transform.translation.z = 1.; // second "player" to visually test a non-zero position commands.spawn(( Mesh2d(meshes.add(Rectangle::new(8., 8.))), MeshMaterial2d(materials.add(Color::from(RED_400))), transform, )); } fn move_player( mut player: Single<&mut Transform, With>, time: Res