Files
phos-neo/game/main/src/utlis/tile_selection_plugin.rs
2026-03-14 19:55:53 -04:00

77 lines
1.7 KiB
Rust

use bevy::{prelude::*, window::PrimaryWindow};
use bevy_rapier3d::{plugin::ReadRapierContext, prelude::QueryFilter};
use hex::prelude::*;
use shared::{
resources::{TileContact, TileUnderCursor},
tags::MainCamera,
};
use world_generation::{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;
}
}