Skip to content

Commit

Permalink
Added the accessing tiles example for the new API.
Browse files Browse the repository at this point in the history
  • Loading branch information
StarArawn committed Jul 4, 2022
1 parent 365740f commit 1d471ab
Show file tree
Hide file tree
Showing 6 changed files with 249 additions and 57 deletions.
161 changes: 161 additions & 0 deletions examples/accessing_tiles.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
use bevy::prelude::*;
use bevy_ecs_tilemap::{
map::{
Tilemap2dGridSize, Tilemap2dSize, Tilemap2dTextureSize, Tilemap2dTileSize, TilemapId,
TilemapTexture,
},
tiles::{Tile2dStorage, TileBundle, TilePos2d, TileTexture},
Tilemap2dPlugin, TilemapBundle,
};

mod helpers;

#[derive(Component)]
struct CurrentColor(u16);

#[derive(Component)]
struct LastUpdate(f64);

fn startup(mut commands: Commands, asset_server: Res<AssetServer>) {
commands.spawn_bundle(OrthographicCameraBundle::new_2d());

let texture_handle: Handle<Image> = asset_server.load("tiles.png");

// Size of the tile map in tiles.
let tilemap_size = Tilemap2dSize { x: 128, y: 128 };

// To create a map we use the Tile2dStorage component.
// This component is a grid of tile entities and is used to help keep track of individual
// tiles in the world. If you have multiple layers of tiles you would have a Tilemap2dStorage
// component per layer.
let mut tile_storage = Tile2dStorage::empty(tilemap_size);

// Create a tilemap entity a little early
// We want this entity early because we need to tell each tile which tilemap entity
// it is associated with. This is done with the TilemapId component on each tile.
let tilemap_entity = commands.spawn().id();

// Spawn a 32 by 32 tilemap.
for x in 0..tilemap_size.x {
for y in 0..tilemap_size.y {
let tile_pos = TilePos2d { x, y };
let tile_entity = commands
.spawn()
.insert_bundle(TileBundle {
position: tile_pos,
tilemap_id: TilemapId(tilemap_entity),
..Default::default()
})
.id();
// Here we let the tile storage component know what tiles we have.
tile_storage.set(&tile_pos, Some(tile_entity));
}
}

// We can grab a list of neighbors.
let neighbors = tile_storage.get_tile_neighbors(&TilePos2d { x: 0, y: 0 });

// We can access tiles using:
assert!(tile_storage.get(&TilePos2d { x: 0, y: 0 }).is_some());
assert!(neighbors.len() == 8);
let neighbor_count = neighbors.iter().filter(|n| n.is_some()).count();
assert!(neighbor_count == 3); // Only 3 neighbors since negative is outside of map.

// This changes some of our tiles by looking at neighbors.
let mut color = 0;
for x in (2..128).step_by(4) {
color += 1;
for y in (2..128).step_by(4) {
// Grabbing neighbors is easy.
let neighbors = tile_storage.get_neighboring_pos(&TilePos2d { x, y });
for pos in neighbors.iter().filter_map(|pos| pos.as_ref()) {
// We can replace the tile texture component like so:
commands
.entity(tile_storage.get(pos).unwrap())
.insert(TileTexture(color));
}
}
}

// This is the size of each individual tiles in pixels.
let tile_size = Tilemap2dTileSize { x: 16.0, y: 16.0 };

// Spawns a tilemap.
// Once the tile storage is inserted onto the tilemap entity it can no longer be accessed.
commands
.entity(tilemap_entity)
.insert_bundle(TilemapBundle {
grid_size: Tilemap2dGridSize { x: 16.0, y: 16.0 },
size: tilemap_size,
storage: tile_storage,
texture_size: Tilemap2dTextureSize { x: 96.0, y: 16.0 },
texture: TilemapTexture(texture_handle),
tile_size,
transform: bevy_ecs_tilemap::helpers::get_centered_transform_2d(
&tilemap_size,
&tile_size,
0.0,
),
..Default::default()
})
.insert(LastUpdate(0.0))
.insert(CurrentColor(1));
}

// A system that manipulates tile colors.
fn update_map(
time: Res<Time>,
mut tilemap_query: Query<(&mut CurrentColor, &mut LastUpdate, &Tile2dStorage)>,
mut tile_query: Query<&mut TileTexture>,
) {
let current_time = time.seconds_since_startup();
for (mut current_color, mut last_update, tile_storage) in tilemap_query.iter_mut() {
if current_time - last_update.0 > 0.1 {
current_color.0 += 1;
if current_color.0 > 5 {
current_color.0 = 1;
}

let mut color = current_color.0;

for x in (2..128).step_by(4) {
for y in (2..128).step_by(4) {
// Grab the neighboring tiles
let neighboring_entities = tile_storage.get_tile_neighbors(&TilePos2d { x, y });

// Iterate over neighbors
for i in 0..8 {
if let Some(neighbor) = neighboring_entities[i] {
// Query the tile entities to change the colors
if let Ok(mut tile_texture) = tile_query.get_mut(neighbor) {
tile_texture.0 = color as u32;
}
}
}
}
color += 1;
if color > 5 {
color = 1;
}
}
last_update.0 = current_time;
}
}
}

fn main() {
App::new()
.insert_resource(WindowDescriptor {
width: 1270.0,
height: 720.0,
title: String::from("Basic Example"),
..Default::default()
})
.add_plugins(DefaultPlugins)
.add_plugin(Tilemap2dPlugin)
.add_startup_system(startup)
.add_system(helpers::camera::movement)
.add_system(helpers::texture::set_texture_filters_to_nearest)
.add_system(update_map)
.run();
}
17 changes: 9 additions & 8 deletions examples/random_map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use bevy_ecs_tilemap::{
Tilemap2dGridSize, Tilemap2dSize, Tilemap2dTextureSize, Tilemap2dTileSize, TilemapId,
TilemapTexture,
},
tiles::{Tile2dStorage, TilePos2d, TileTexture, TileVisible},
tiles::{Tile2dStorage, TileBundle, TilePos2d, TileTexture},
Tilemap2dPlugin, TilemapBundle,
};
use rand::{thread_rng, Rng};
Expand All @@ -19,20 +19,21 @@ fn startup(mut commands: Commands, asset_server: Res<AssetServer>) {

let texture_handle: Handle<Image> = asset_server.load("tiles.png");

let tilemap_size = Tilemap2dSize { x: 640, y: 640 };
let tilemap_size = Tilemap2dSize { x: 320, y: 320 };
let mut tile_storage = Tile2dStorage::empty(tilemap_size);
let tilemap_entity = commands.spawn().id();

for x in 0..640u32 {
for y in 0..640u32 {
for x in 0..320u32 {
for y in 0..320u32 {
let tile_pos = TilePos2d { x, y };
let tile_entity = commands
.spawn()
.insert(tile_pos)
.insert(TileTexture(0))
.insert(TilemapId(tilemap_entity))
.insert_bundle(TileBundle {
position: tile_pos,
tilemap_id: TilemapId(tilemap_entity),
..Default::default()
})
.insert(LastUpdate::default())
.insert(TileVisible(true))
.id();
tile_storage.set(&tile_pos, Some(tile_entity));
}
Expand Down
12 changes: 7 additions & 5 deletions src/helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use bevy::{

use crate::{
map::{Tilemap2dSize, Tilemap2dTileSize, TilemapId, TilemapMeshType},
tiles::{Tile2dStorage, TilePos2d, TileTexture, TileVisible},
tiles::{Tile2dStorage, TileBundle, TilePos2d, TileTexture},
};

pub fn pos_2d_to_index(tile_pos: &TilePos2d, size: &Tilemap2dSize) -> usize {
Expand Down Expand Up @@ -42,10 +42,12 @@ pub fn fill_tilemap(
let tile_pos = TilePos2d { x, y };
let tile_entity = commands
.spawn()
.insert(tile_pos)
.insert(tile_texture)
.insert(tilemap_id)
.insert(TileVisible(true))
.insert_bundle(TileBundle {
position: tile_pos,
tilemap_id: tilemap_id,
texture: tile_texture,
..Default::default()
})
.id();
tile_storage.set(&tile_pos, Some(tile_entity));
}
Expand Down
9 changes: 9 additions & 0 deletions src/map/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use bevy::{
prelude::{Component, Entity, Handle, Image},
};

// A component which stores a reference to the tilemap entity.
#[derive(Component, Clone, Copy, Debug)]
pub struct TilemapId(pub Entity);

Expand All @@ -12,6 +13,7 @@ impl Default for TilemapId {
}
}

/// Size of the tilemap in tiles.
#[derive(Component, Default, Clone, Copy, Debug)]
pub struct Tilemap2dSize {
pub x: u32,
Expand Down Expand Up @@ -45,6 +47,7 @@ impl From<UVec2> for Tilemap2dSize {
#[derive(Component, Clone, Default, Debug)]
pub struct TilemapTexture(pub Handle<Image>);

/// Size of the tiles in pixels
#[derive(Component, Default, Clone, Copy, Debug)]
pub struct Tilemap2dTileSize {
pub x: f32,
Expand All @@ -57,6 +60,10 @@ impl Into<Vec2> for Tilemap2dTileSize {
}
}

/// Size of the tiles on the grid in pixels.
/// This can be used to overlay tiles on top of each other.
/// Ex. A 16x16 pixel tile can be overlapped by 8 pixels by using
/// a grid size of 16x8.
#[derive(Component, Default, Clone, Copy, Debug)]
pub struct Tilemap2dGridSize {
pub x: f32,
Expand All @@ -69,6 +76,7 @@ impl Into<Vec2> for Tilemap2dGridSize {
}
}

/// Spacing between tiles inside of the texture atlas.
#[derive(Component, Default, Clone, Copy, Debug)]
pub struct Tilemap2dSpacing {
pub x: f32,
Expand All @@ -87,6 +95,7 @@ impl Tilemap2dSpacing {
}
}

/// Size of the atlas texture in pixels.
#[derive(Component, Default, Clone, Copy, Debug)]
pub struct Tilemap2dTextureSize {
pub x: f32,
Expand Down
2 changes: 1 addition & 1 deletion src/render/pipeline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ impl FromWorld for TilemapPipeline {
let uniform_layout = render_device.create_bind_group_layout(&BindGroupLayoutDescriptor {
entries: &[BindGroupLayoutEntry {
binding: 0,
visibility: ShaderStages::VERTEX,
visibility: ShaderStages::VERTEX_FRAGMENT,
ty: BindingType::Buffer {
ty: BufferBindingType::Uniform,
has_dynamic_offset: true,
Expand Down
Loading

0 comments on commit 1d471ab

Please sign in to comment.