use bevy::prelude::*;
use bevy_ecs_tilemap::prelude::*;
mod helpers;
use helpers::camera::movement as camera_movement;
const MAP_SIDE_LENGTH: u32 = 8;
const TILE_SIZE_HEX_ROW: TilemapTileSize = TilemapTileSize { x: 50.0, y: 58.0 };
const TILE_SIZE_HEX_COL: TilemapTileSize = TilemapTileSize { x: 58.0, y: 50.0 };
const GRID_SIZE_HEX_ROW: TilemapGridSize = TilemapGridSize { x: 50.0, y: 58.0 };
const GRID_SIZE_HEX_COL: TilemapGridSize = TilemapGridSize { x: 58.0, y: 50.0 };
#[derive(Deref, Resource)]
pub struct TileHandleHexRow(Handle<Image>);
#[derive(Deref, Resource)]
pub struct TileHandleHexCol(Handle<Image>);
impl FromWorld for TileHandleHexCol {
fn from_world(world: &mut World) -> Self {
let asset_server = world.resource::<AssetServer>();
Self(asset_server.load("bw-tile-hex-col.png"))
}
}
impl FromWorld for TileHandleHexRow {
fn from_world(world: &mut World) -> Self {
let asset_server = world.resource::<AssetServer>();
Self(asset_server.load("bw-tile-hex-row.png"))
}
}
fn spawn_tilemap(mut commands: Commands, tile_handle_hex_row: Res<TileHandleHexRow>) {
commands.spawn(Camera2d);
let map_size = TilemapSize {
x: MAP_SIDE_LENGTH,
y: MAP_SIDE_LENGTH,
};
let mut tile_storage = TileStorage::empty(map_size);
let tilemap_entity = commands.spawn_empty().id();
let tilemap_id = TilemapId(tilemap_entity);
let hex_coord_system = HexCoordSystem::Row;
fill_tilemap_hexagon(
TileTextureIndex(0),
TilePos {
x: MAP_SIDE_LENGTH / 2,
y: MAP_SIDE_LENGTH / 2,
},
MAP_SIDE_LENGTH / 2,
hex_coord_system,
tilemap_id,
&mut commands,
&mut tile_storage,
);
let tile_size = TILE_SIZE_HEX_ROW;
let grid_size = GRID_SIZE_HEX_ROW;
let map_type = TilemapType::Hexagon(hex_coord_system);
commands.entity(tilemap_entity).insert(TilemapBundle {
grid_size,
size: map_size,
storage: tile_storage,
texture: TilemapTexture::Single(tile_handle_hex_row.clone()),
tile_size,
map_type,
anchor: TilemapAnchor::Center,
..Default::default()
});
}
#[derive(Component)]
pub struct MapTypeLabel;
fn spawn_map_type_label(
mut commands: Commands,
windows: Query<&Window>,
map_type_q: Query<&TilemapType>,
) {
for window in windows.iter() {
for map_type in map_type_q.iter() {
let transform = Transform {
translation: Vec2::new(-0.5 * window.width() / 2.0, 0.8 * window.height() / 2.0)
.extend(1.0),
..Default::default()
};
commands.spawn((
Text2d::new(format!("{map_type:?}")),
TextFont {
font_size: 20.0,
..default()
},
TextColor(Color::BLACK),
TextLayout::new_with_justify(Justify::Center),
transform,
MapTypeLabel,
));
}
}
}
#[allow(clippy::too_many_arguments)]
fn swap_map_type(
mut commands: Commands,
mut tilemap_query: Query<(
Entity,
&mut TilemapType,
&mut TilemapGridSize,
&mut TilemapTexture,
&mut TilemapTileSize,
&mut TileStorage,
)>,
keyboard_input: Res<ButtonInput<KeyCode>>,
mut map_type_label_q: Query<&mut Text2d, With<MapTypeLabel>>,
tile_handle_hex_row: Res<TileHandleHexRow>,
tile_handle_hex_col: Res<TileHandleHexCol>,
) {
if keyboard_input.just_pressed(KeyCode::Space) {
for (
map_id,
mut map_type,
mut grid_size,
mut map_texture,
mut tile_size,
mut tile_storage,
) in tilemap_query.iter_mut()
{
for possible_entity in tile_storage.iter_mut() {
if let Some(entity) = possible_entity.take() {
commands.entity(entity).despawn();
}
}
let new_coord_sys = match map_type.as_ref() {
TilemapType::Hexagon(HexCoordSystem::Row) => HexCoordSystem::Column,
TilemapType::Hexagon(HexCoordSystem::Column) => HexCoordSystem::Row,
_ => unreachable!(),
};
*map_type = TilemapType::Hexagon(new_coord_sys);
if new_coord_sys == HexCoordSystem::Column {
*map_texture = TilemapTexture::Single((*tile_handle_hex_col).clone());
*tile_size = TILE_SIZE_HEX_COL;
*grid_size = GRID_SIZE_HEX_COL;
} else if new_coord_sys == HexCoordSystem::Row {
*map_texture = TilemapTexture::Single((*tile_handle_hex_row).clone());
*tile_size = TILE_SIZE_HEX_ROW;
*grid_size = GRID_SIZE_HEX_ROW;
}
fill_tilemap_hexagon(
TileTextureIndex(0),
TilePos {
x: MAP_SIDE_LENGTH / 2,
y: MAP_SIDE_LENGTH / 2,
},
MAP_SIDE_LENGTH / 2,
new_coord_sys,
TilemapId(map_id),
&mut commands,
&mut tile_storage,
);
for mut label_text in map_type_label_q.iter_mut() {
label_text.0 = format!("{:?}", map_type.as_ref());
}
}
}
}
fn main() {
App::new()
.add_plugins(
DefaultPlugins
.set(WindowPlugin {
primary_window: Some(Window {
title: String::from("Generating a hexagonal hex map"),
..Default::default()
}),
..default()
})
.set(ImagePlugin::default_nearest()),
)
.add_plugins(TilemapPlugin)
.init_resource::<TileHandleHexCol>()
.init_resource::<TileHandleHexRow>()
.add_systems(
Startup,
(spawn_tilemap, ApplyDeferred, spawn_map_type_label).chain(),
)
.add_systems(Update, camera_movement)
.add_systems(Update, swap_map_type)
.run();
}