This commit is like Batman, It has no parents.
This commit is contained in:
268
src/helpers/grid.rs
Normal file
268
src/helpers/grid.rs
Normal file
@@ -0,0 +1,268 @@
|
||||
use bevy::prelude::*;
|
||||
use bevy_ecs_tilemap::prelude::*;
|
||||
|
||||
use super::camera;
|
||||
|
||||
pub struct GridPlugin;
|
||||
|
||||
#[derive(Debug, Component, Reflect)]
|
||||
#[reflect(Component)]
|
||||
pub struct Tile {
|
||||
pub x: isize,
|
||||
pub y: isize,
|
||||
}
|
||||
|
||||
#[derive(Debug, Component, Reflect)]
|
||||
#[reflect(Component)]
|
||||
pub struct Flag;
|
||||
|
||||
#[derive(Debug, Component, Reflect)]
|
||||
#[reflect(Component)]
|
||||
pub struct Revealed;
|
||||
|
||||
#[derive(Debug, Component, Reflect, Copy, Clone, PartialEq, Eq)]
|
||||
#[reflect(Component)]
|
||||
pub enum TileType {
|
||||
Empty,
|
||||
One,
|
||||
Two,
|
||||
Three,
|
||||
Four,
|
||||
Five,
|
||||
Six,
|
||||
Seven,
|
||||
Eight,
|
||||
Mine,
|
||||
}
|
||||
|
||||
impl From<i32> for TileType {
|
||||
fn from(value: i32) -> Self {
|
||||
match value {
|
||||
1 => TileType::One,
|
||||
2 => TileType::Two,
|
||||
3 => TileType::Three,
|
||||
4 => TileType::Four,
|
||||
5 => TileType::Five,
|
||||
6 => TileType::Six,
|
||||
7 => TileType::Seven,
|
||||
8 => TileType::Eight,
|
||||
_ => TileType::Empty,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Component)]
|
||||
pub struct TileOffset {
|
||||
pub translation: Vec3,
|
||||
pub x: isize,
|
||||
pub y: isize,
|
||||
}
|
||||
|
||||
#[derive(Resource)]
|
||||
pub struct CursorPos(Vec2);
|
||||
impl Default for CursorPos {
|
||||
fn default() -> Self {
|
||||
Self(Vec2::new(-1000.0, -1000.0))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Event)]
|
||||
pub struct TileClickEvent {
|
||||
pub x: isize,
|
||||
pub y: isize,
|
||||
pub button: MouseButton,
|
||||
}
|
||||
|
||||
impl Plugin for GridPlugin {
|
||||
fn build(&self, app: &mut App) {
|
||||
app.register_type::<Tile>();
|
||||
app.register_type::<Flag>();
|
||||
app.register_type::<Revealed>();
|
||||
app.register_type::<TileType>();
|
||||
|
||||
app.add_plugins(TilemapPlugin);
|
||||
app.init_resource::<CursorPos>();
|
||||
app.add_event::<TileClickEvent>();
|
||||
app.add_systems(Startup, generate_grid);
|
||||
app.add_systems(
|
||||
First,
|
||||
(camera::movement, update_cursor_pos, click_tile).chain(),
|
||||
);
|
||||
app.add_systems(Update, update_tiles);
|
||||
}
|
||||
}
|
||||
|
||||
fn generate_grid(mut commands: Commands, asset_server: Res<AssetServer>) {
|
||||
let texture_handle: Handle<Image> = asset_server.load("tiles.png");
|
||||
|
||||
let map_size = TilemapSize { x: 82, y: 47 };
|
||||
let mut tile_storage = TileStorage::empty(map_size);
|
||||
let tilemap_entity = commands.spawn_empty().id();
|
||||
|
||||
for x in 0..map_size.x {
|
||||
for y in 0..map_size.y {
|
||||
let tile_pos = TilePos { x, y };
|
||||
let tile_entity = commands
|
||||
.spawn(TileBundle {
|
||||
position: tile_pos,
|
||||
tilemap_id: TilemapId(tilemap_entity),
|
||||
visible: TileVisible(true),
|
||||
texture_index: TileTextureIndex(1),
|
||||
..Default::default()
|
||||
})
|
||||
.id();
|
||||
tile_storage.set(&tile_pos, tile_entity);
|
||||
}
|
||||
}
|
||||
|
||||
let tile_size = TilemapTileSize { x: 16.0, y: 16.0 };
|
||||
let grid_size = TilemapTileSize { x: 16.0, y: 16.0 }.into();
|
||||
let map_type = TilemapType::Square;
|
||||
|
||||
commands.entity(tilemap_entity).insert(TilemapBundle {
|
||||
grid_size,
|
||||
map_type,
|
||||
size: map_size,
|
||||
storage: tile_storage,
|
||||
texture: TilemapTexture::Single(texture_handle),
|
||||
tile_size,
|
||||
transform: get_tilemap_center_transform(&map_size, &grid_size, &map_type, 0.0),
|
||||
..Default::default()
|
||||
});
|
||||
}
|
||||
|
||||
// This is where we check which tile the cursor is hovered over.
|
||||
fn click_tile(
|
||||
buttons: Res<ButtonInput<MouseButton>>,
|
||||
cursor_pos: Res<CursorPos>,
|
||||
tilemap_q: Query<(&TilemapSize, &TilemapGridSize, &TileStorage, &Transform)>,
|
||||
offset: Query<&TileOffset, With<Camera>>,
|
||||
mut ev_tile_click: EventWriter<TileClickEvent>,
|
||||
) {
|
||||
if !buttons.just_pressed(MouseButton::Left) && !buttons.just_pressed(MouseButton::Right) {
|
||||
return;
|
||||
}
|
||||
|
||||
let offset = offset.single();
|
||||
|
||||
for (map_size, grid_size, tile_storage, map_transform) in tilemap_q.iter() {
|
||||
// Grab the cursor position from the `Res<CursorPos>`
|
||||
let cursor_pos: Vec2 = cursor_pos.0;
|
||||
// We need to make sure that the cursor's world position is correct relative to the map
|
||||
// due to any map transformation.
|
||||
let cursor_in_map_pos: Vec2 = {
|
||||
// Extend the cursor_pos vec3 by 0.0 and 1.0
|
||||
let cursor_pos = Vec4::from((cursor_pos, 0.0, 1.0));
|
||||
let cursor_in_map_pos = map_transform.compute_matrix().inverse() * cursor_pos;
|
||||
cursor_in_map_pos.xy()
|
||||
};
|
||||
|
||||
// Once we have a world position we can transform it into a possible tile position.
|
||||
let Some(tile_pos) = TilePos::from_world_pos(
|
||||
&cursor_in_map_pos,
|
||||
map_size,
|
||||
grid_size,
|
||||
&TilemapType::Square,
|
||||
) else {
|
||||
continue;
|
||||
};
|
||||
|
||||
if tile_storage.get(&tile_pos).is_none() {
|
||||
continue;
|
||||
};
|
||||
|
||||
ev_tile_click.send(TileClickEvent {
|
||||
x: tile_pos.x as isize + offset.x,
|
||||
y: tile_pos.y as isize + offset.y,
|
||||
button: if buttons.just_pressed(MouseButton::Left) {
|
||||
MouseButton::Left
|
||||
} else {
|
||||
MouseButton::Right
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
fn update_tiles(
|
||||
tiles: Query<(Entity, &Tile, &TileType)>,
|
||||
tile_flag: Query<&Flag>,
|
||||
tile_revealed: Query<&Revealed>,
|
||||
tilemap_q: Query<&TileStorage>,
|
||||
mut texture_index: Query<&mut TileTextureIndex>,
|
||||
offset: Query<&TileOffset, With<Camera>>,
|
||||
) {
|
||||
let offset = offset.single();
|
||||
|
||||
for mut index in texture_index.iter_mut() {
|
||||
*index = TileTextureIndex(1);
|
||||
}
|
||||
|
||||
for (ent, tile, kind) in tiles.iter() {
|
||||
if (tile.x - offset.x) < 0 || (tile.y - offset.y) < 0 {
|
||||
continue;
|
||||
}
|
||||
|
||||
let x = tile.x - offset.x;
|
||||
let y = tile.y - offset.y;
|
||||
|
||||
if x < 0 || y < 0 {
|
||||
continue;
|
||||
}
|
||||
|
||||
if x > 81 || y > 46 {
|
||||
continue;
|
||||
}
|
||||
|
||||
let tile_pos = TilePos {
|
||||
x: x as u32,
|
||||
y: y as u32,
|
||||
};
|
||||
|
||||
for tile_storage in tilemap_q.iter() {
|
||||
let Some(tile_entity) = tile_storage.get(&tile_pos) else {
|
||||
continue;
|
||||
};
|
||||
|
||||
let Ok(mut index) = texture_index.get_mut(tile_entity) else {
|
||||
continue;
|
||||
};
|
||||
|
||||
if tile_flag.get(ent).is_ok() {
|
||||
*index = TileTextureIndex(11);
|
||||
continue;
|
||||
}
|
||||
|
||||
if tile_revealed.get(ent).is_err() {
|
||||
*index = TileTextureIndex(1);
|
||||
continue;
|
||||
}
|
||||
|
||||
*index = TileTextureIndex(match kind {
|
||||
TileType::One => 2,
|
||||
TileType::Empty => 0,
|
||||
TileType::Two => 3,
|
||||
TileType::Three => 4,
|
||||
TileType::Four => 5,
|
||||
TileType::Five => 6,
|
||||
TileType::Six => 7,
|
||||
TileType::Seven => 8,
|
||||
TileType::Eight => 9,
|
||||
TileType::Mine => 10,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update_cursor_pos(
|
||||
camera_q: Query<(&GlobalTransform, &Camera)>,
|
||||
mut cursor_moved_events: EventReader<CursorMoved>,
|
||||
mut cursor_pos: ResMut<CursorPos>,
|
||||
) {
|
||||
for cursor_moved in cursor_moved_events.read() {
|
||||
for (cam_t, cam) in camera_q.iter() {
|
||||
if let Some(pos) = cam.viewport_to_world_2d(cam_t, cursor_moved.position) {
|
||||
*cursor_pos = CursorPos(pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user