use bevy::{
input::mouse::{MouseMotion, MouseWheel},
prelude::*,
};
use bevy_2d_grid::{InfiniteGrid2DBundle, InfiniteGrid2DPlugin};
fn main() {
App::new()
.add_plugins((DefaultPlugins, InfiniteGrid2DPlugin))
.add_systems(Startup, setup_system)
.add_systems(Update, (camera_movement, camera_zoom))
.run();
}
fn setup_system(mut commands: Commands) {
commands.spawn(InfiniteGrid2DBundle::default());
commands.spawn((
Camera2d::default(),
Transform::from_xyz(0.0, 0.0, 10.0),
CameraMovement::default(),
));
commands.spawn((
Sprite {
color: Color::srgb(1., 1., 1.),
custom_size: Some(Vec2::new(300.0, 300.0)),
..default()
},
Transform::from_xyz(-250.0, -250.0, -1.0), ));
commands.spawn((
Sprite {
color: Color::srgb(0.8, 0.2, 0.2),
custom_size: Some(Vec2::new(100.0, 100.0)),
..default()
},
Transform::from_xyz(150.0, 150.0, 1.0), ));
commands.spawn((
Sprite {
color: Color::srgb(0.2, 0.8, 0.2),
custom_size: Some(Vec2::new(200.0, 200.0)),
..default()
},
Transform::from_xyz(-200.0, 200.0, 1.0), ));
commands.spawn((
Sprite {
color: Color::srgb(0.2, 0.2, 0.8),
custom_size: Some(Vec2::new(100.0, 100.0)),
..default()
},
Transform::from_xyz(30.0, -230.0, 1.0), ));
}
#[derive(Component)]
struct CameraMovement {
speed: f32,
}
impl Default for CameraMovement {
fn default() -> Self {
Self { speed: 200.0 }
}
}
fn camera_movement(
time: Res<Time>,
key_input: Res<ButtonInput<KeyCode>>,
mouse_input: Res<ButtonInput<MouseButton>>,
mut mouse_motion: MessageReader<MouseMotion>,
mut camera_query: Query<(&mut Transform, &CameraMovement, &Projection), With<Camera2d>>,
) {
let Ok((mut transform, movement, projection)) = camera_query.single_mut() else {
return;
};
let dt = time.delta_secs();
if mouse_input.pressed(MouseButton::Left) {
for motion in mouse_motion.read() {
let mouse_delta = motion.delta;
let scale = if let Projection::Orthographic(ortho) = projection {
ortho.scale
} else {
1.0
};
transform.translation.x -= mouse_delta.x * scale;
transform.translation.y += mouse_delta.y * scale; }
}
let mut direction = Vec2::ZERO;
if key_input.pressed(KeyCode::KeyW) || key_input.pressed(KeyCode::ArrowUp) {
direction.y += 1.0;
}
if key_input.pressed(KeyCode::KeyS) || key_input.pressed(KeyCode::ArrowDown) {
direction.y -= 1.0;
}
if key_input.pressed(KeyCode::KeyA) || key_input.pressed(KeyCode::ArrowLeft) {
direction.x -= 1.0;
}
if key_input.pressed(KeyCode::KeyD) || key_input.pressed(KeyCode::ArrowRight) {
direction.x += 1.0;
}
if direction != Vec2::ZERO {
direction = direction.normalize();
let movement_delta = direction * movement.speed * dt;
transform.translation.x += movement_delta.x;
transform.translation.y += movement_delta.y;
}
}
fn camera_zoom(
key_input: Res<ButtonInput<KeyCode>>,
mut scroll_events: MessageReader<MouseWheel>,
mut camera_query: Query<&mut Projection, With<Camera2d>>,
) {
if let Ok(mut projection) = camera_query.single_mut() {
if let Projection::Orthographic(ortho) = projection.as_mut() {
let zoom_speed = 0.1;
if key_input.just_pressed(KeyCode::Equal) || key_input.just_pressed(KeyCode::NumpadAdd)
{
ortho.scale *= 1.0 - zoom_speed;
ortho.scale = ortho.scale.max(0.1); }
if key_input.just_pressed(KeyCode::Minus)
|| key_input.just_pressed(KeyCode::NumpadSubtract)
{
ortho.scale *= 1.0 + zoom_speed;
ortho.scale = ortho.scale.min(10.0); }
for scroll in scroll_events.read() {
let scroll_zoom_speed = 0.05;
if scroll.y > 0.0 {
ortho.scale *= 1.0 - scroll_zoom_speed;
ortho.scale = ortho.scale.max(0.1);
} else if scroll.y < 0.0 {
ortho.scale *= 1.0 + scroll_zoom_speed;
ortho.scale = ortho.scale.min(10.0);
}
}
}
}
}