use bevy::{
color::palettes::{
basic::WHITE,
css::{GREEN, RED},
},
math::ops::powf,
prelude::*,
render::camera::Viewport,
};
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_systems(Startup, setup)
.add_systems(FixedUpdate, controls)
.add_systems(
PostUpdate,
draw_cursor.after(TransformSystem::TransformPropagate),
)
.run();
}
fn draw_cursor(
camera_query: Single<(&Camera, &GlobalTransform)>,
window: Query<&Window>,
mut gizmos: Gizmos,
) {
let (camera, camera_transform) = *camera_query;
let Ok(window) = window.single() else {
return;
};
let Some(cursor_position) = window.cursor_position() else {
return;
};
let Ok(world_pos) = camera.viewport_to_world_2d(camera_transform, cursor_position) else {
return;
};
let Ok(viewport_check) = camera.world_to_viewport(camera_transform, world_pos.extend(0.0))
else {
return;
};
let Ok(world_check) = camera.viewport_to_world_2d(camera_transform, viewport_check.xy()) else {
return;
};
gizmos.circle_2d(world_pos, 10., WHITE);
gizmos.circle_2d(world_check, 8., RED);
}
fn controls(
mut camera_query: Query<(&mut Camera, &mut Transform, &mut Projection)>,
window: Query<&Window>,
input: Res<ButtonInput<KeyCode>>,
time: Res<Time<Fixed>>,
) {
let Ok(window) = window.single() else {
return;
};
let Ok((mut camera, mut transform, mut projection)) = camera_query.single_mut() else {
return;
};
let fspeed = 600.0 * time.delta_secs();
let uspeed = fspeed as u32;
let window_size = window.resolution.physical_size();
if input.pressed(KeyCode::ArrowUp) {
transform.translation.y += fspeed;
}
if input.pressed(KeyCode::ArrowDown) {
transform.translation.y -= fspeed;
}
if input.pressed(KeyCode::ArrowLeft) {
transform.translation.x -= fspeed;
}
if input.pressed(KeyCode::ArrowRight) {
transform.translation.x += fspeed;
}
if let Projection::Orthographic(projection2d) = &mut *projection {
if input.pressed(KeyCode::Comma) {
projection2d.scale *= powf(4.0f32, time.delta_secs());
}
if input.pressed(KeyCode::Period) {
projection2d.scale *= powf(0.25f32, time.delta_secs());
}
}
if let Some(viewport) = camera.viewport.as_mut() {
if input.pressed(KeyCode::KeyW) {
viewport.physical_position.y = viewport.physical_position.y.saturating_sub(uspeed);
}
if input.pressed(KeyCode::KeyS) {
viewport.physical_position.y += uspeed;
}
if input.pressed(KeyCode::KeyA) {
viewport.physical_position.x = viewport.physical_position.x.saturating_sub(uspeed);
}
if input.pressed(KeyCode::KeyD) {
viewport.physical_position.x += uspeed;
}
viewport.physical_position = viewport
.physical_position
.min(window_size - viewport.physical_size);
if input.pressed(KeyCode::KeyI) {
viewport.physical_size.y = viewport.physical_size.y.saturating_sub(uspeed);
}
if input.pressed(KeyCode::KeyK) {
viewport.physical_size.y += uspeed;
}
if input.pressed(KeyCode::KeyJ) {
viewport.physical_size.x = viewport.physical_size.x.saturating_sub(uspeed);
}
if input.pressed(KeyCode::KeyL) {
viewport.physical_size.x += uspeed;
}
viewport.physical_size = viewport
.physical_size
.min(window_size - viewport.physical_position)
.max(UVec2::new(20, 20));
}
}
fn setup(
mut commands: Commands,
mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<ColorMaterial>>,
window: Single<&Window>,
) {
let window_size = window.resolution.physical_size().as_vec2();
commands.spawn((
Camera2d,
Camera {
viewport: Some(Viewport {
physical_position: (window_size * 0.125).as_uvec2(),
physical_size: (window_size * 0.75).as_uvec2(),
..default()
}),
..default()
},
));
commands.spawn((
Text::new(
"Move the mouse to see the circle follow your cursor.\n\
Use the arrow keys to move the camera.\n\
Use the comma and period keys to zoom in and out.\n\
Use the WASD keys to move the viewport.\n\
Use the IJKL keys to resize the viewport.",
),
Node {
position_type: PositionType::Absolute,
top: Val::Px(12.0),
left: Val::Px(12.0),
..default()
},
));
commands.spawn((
Mesh2d(meshes.add(Rectangle::new(40.0, 20.0))),
MeshMaterial2d(materials.add(Color::from(GREEN))),
));
commands.spawn((
Mesh2d(meshes.add(Rectangle::new(50000.0, 50000.0))),
MeshMaterial2d(materials.add(Color::linear_rgb(0.01, 0.01, 0.01))),
Transform::from_translation(Vec3::new(0.0, 0.0, -200.0)),
));
}