bevy cursor to world
代码
//! bevy version: 0.11
//! Spawn a ball on the plane when you click on it.
use bevy::prelude::*;
use bevy::input::common_conditions::input_just_pressed;
use bevy::window::{PrimaryWindow, close_on_esc};
const PLANE_SIZE: f32 = 5.0;
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_systems(Startup, setup)
.add_systems(Update, close_on_esc)
.add_systems(
Update,
cursor_to_world
.run_if(input_just_pressed(MouseButton::Left)),
)
.run();
}
fn setup(
mut commands: Commands,
mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<StandardMaterial>>,
) {
// plane
commands
.spawn(PbrBundle {
mesh: meshes.add(shape::Plane::from_size(PLANE_SIZE).into()),
material: materials.add(Color::rgb(0.3, 0.5, 0.3).into()),
..default()
});
// light
commands
.spawn(PointLightBundle {
point_light: PointLight {
intensity: 1500.0,
shadows_enabled: true,
..default()
},
transform: Transform::from_xyz(4.0, 8.0, 4.0),
..default()
});
// camera
commands.spawn(Camera3dBundle {
transform: Transform::from_translation(Vec3::new(2., 2., 4.))
.looking_at(Vec3::ZERO, Vec3::Y),
..default()
});
}
fn cursor_to_world(
window: Query<&Window, With<PrimaryWindow>>,
camera: Query<(&Camera, &GlobalTransform)>,
mut commands: Commands,
mut meshes: ResMut<Assets<Mesh>>,
) {
let window = window.single();
let Some(cursor_position) = window.cursor_position() else { return; };
let (camera, camera_transform) = camera.single();
let Some(ray) = camera.viewport_to_world(camera_transform, cursor_position) else { return; };
let Some(distance) = ray.intersect_plane(Vec3::ZERO, Vec3::Y) else { return; };
let world_position = ray.get_point(distance);
if world_position.x.abs() > PLANE_SIZE/2. || world_position.z.abs() > PLANE_SIZE/2. { return; }
let radius = 0.1;
commands.spawn(PbrBundle {
mesh: meshes.add(shape::UVSphere { radius, ..default() }.into()),
transform: Transform::from_translation(world_position + Vec3::new(0., radius, 0.)),
..default()
});
}
+V why_null 请备注:from博客园