use bevy::prelude::*; use bevy::window::{CursorGrabMode, CursorOptions}; use common::block::Blocks; // TODO: Use picking system instead of manually raycasting. pub fn place_break_blocks( mut commands: Commands, mut blocks: Blocks, mut ray_cast: MeshRayCast, mouse_button_input: Res>, window: Single<(&Window, &CursorOptions)>, camera: Single<(&GlobalTransform, &Camera)>, ) { let (window, cursor) = window.into_inner(); let (cam_transform, camera) = camera.into_inner(); let ray = if cursor.grab_mode == CursorGrabMode::Locked { Ray3d::new(cam_transform.translation(), cam_transform.forward()) } else if let Some(cursor_pos) = window.cursor_position() { camera.viewport_to_world(cam_transform, cursor_pos).unwrap() } else { return; // cursor outside window area }; let settings = &MeshRayCastSettings::default(); let Some((block, hit)) = ray_cast.cast_ray(ray, settings).first() else { return; // ray didn't hit anything }; let Some(block_pos) = blocks.position(*block) else { return; // entity hit is not a block }; if mouse_button_input.just_pressed(MouseButton::Left) { // Destroy the block clicked. commands.entity(*block).despawn(); } else if mouse_button_input.just_pressed(MouseButton::Right) { // Create a new block next to the one that was just clicked. // FIXME: This only works for axis-aligned normals. let offset = hit.normal.normalize().round().as_ivec3(); blocks.spawn(block_pos + offset); } }