Bloxel sandbox game similar to Minecraft "Classic" (2009) written in Rust with Bevy
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

46 lines
1.6 KiB

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<ButtonInput<MouseButton>>,
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);
}
}