75 lines
1.7 KiB
Rust
75 lines
1.7 KiB
Rust
use bevy::{prelude::*, window::PrimaryWindow};
|
|
use bevy_rapier3d::{plugin::ReadRapierContext, prelude::QueryFilter};
|
|
use shared::{
|
|
resources::{TileContact, TileUnderCursor},
|
|
tags::MainCamera,
|
|
};
|
|
use world_generation::{hex_utils::HexCoord, prelude::Map, states::GeneratorState};
|
|
pub struct TileSelectionPlugin;
|
|
|
|
impl Plugin for TileSelectionPlugin
|
|
{
|
|
fn build(&self, app: &mut App)
|
|
{
|
|
app.init_resource::<TileUnderCursor>();
|
|
app.add_systems(
|
|
PreUpdate,
|
|
update_tile_under_cursor.run_if(in_state(GeneratorState::Idle)),
|
|
);
|
|
}
|
|
}
|
|
|
|
fn update_tile_under_cursor(
|
|
cam_query: Single<(&GlobalTransform, &Camera), With<MainCamera>>,
|
|
window: Single<&Window, With<PrimaryWindow>>,
|
|
rapier: ReadRapierContext,
|
|
map: Res<Map>,
|
|
mut tile_under_cursor: ResMut<TileUnderCursor>,
|
|
)
|
|
{
|
|
let (cam_transform, camera) = cam_query.into_inner();
|
|
let Some(cursor_pos) = window.cursor_position()
|
|
else
|
|
{
|
|
return;
|
|
};
|
|
|
|
let Ok(cam_ray) = camera.viewport_to_world(cam_transform, cursor_pos)
|
|
else
|
|
{
|
|
return;
|
|
};
|
|
|
|
let ctx = rapier.single().expect("Failed to get rapier read context");
|
|
|
|
let collision = ctx.cast_ray(
|
|
cam_ray.origin,
|
|
cam_ray.direction.into(),
|
|
500.,
|
|
true,
|
|
QueryFilter::only_fixed(),
|
|
);
|
|
|
|
if let Some((_e, dist)) = collision
|
|
{
|
|
let contact_point = cam_ray.get_point(dist);
|
|
let contact_coord = HexCoord::from_world_pos(contact_point);
|
|
//todo: handle correct tile detection when contacting a tile from the side
|
|
if !map.is_in_bounds(&contact_coord)
|
|
{
|
|
tile_under_cursor.0 = None;
|
|
return;
|
|
}
|
|
let surface = map.sample_height(&contact_coord);
|
|
tile_under_cursor.0 = Some(TileContact::new(
|
|
contact_coord,
|
|
contact_point,
|
|
contact_coord.to_world(surface),
|
|
));
|
|
}
|
|
else
|
|
{
|
|
tile_under_cursor.0 = None;
|
|
}
|
|
}
|