use bevy::{
input::mouse::{MouseScrollUnit, MouseWheel},
prelude::*,
};
use crate::client::components::{MainCamera, Me};
use crate::client::starfield::{parallax_layer_translation, StarfieldSize, BACK_STARFIELD_SIZE, FRONT_STARFIELD_SIZE, MID_STARFIELD_SIZE};
use crate::client::starguide::components::{StarfieldBack, StarfieldFront, StarfieldMid, StarguideCamera};
use crate::shared::ecs::GameplayState;
const STARGUIDE_ZOOM_LEVEL: f32 = 20.0;
fn restore_tiled(sprite: &mut Sprite, size: Option<&StarfieldSize>) {
if let Some(size) = size {
sprite.image_mode = SpriteImageMode::Tiled {
tile_x: true,
tile_y: true,
stretch_value: size.0,
};
}
}
pub fn zoom_plugin(app: &mut App) {
app.add_systems(Update, on_scroll);
}
fn on_scroll(
mut scroll_events: MessageReader<MouseWheel>,
gameplay_state: Res<State<GameplayState>>,
mut gameplay_next_state: ResMut<NextState<GameplayState>>,
window: Single<&Window>,
starfield_back: Single<
(&mut Sprite, &mut Transform, &mut Visibility, Option<&StarfieldSize>),
(
With<StarfieldBack>,
Without<StarfieldMid>,
Without<StarfieldFront>,
),
>,
starfield_mid: Single<
(&mut Sprite, &mut Transform, &mut Visibility, Option<&StarfieldSize>),
(
With<StarfieldMid>,
Without<StarfieldBack>,
Without<StarfieldFront>,
),
>,
starfield_front: Single<
(&mut Sprite, &mut Transform, &mut Visibility, Option<&StarfieldSize>),
(
With<StarfieldFront>,
Without<StarfieldBack>,
Without<StarfieldMid>,
),
>,
mut starguide_camera: Single<
(&mut Camera, &mut Projection, &mut Transform),
(
With<StarguideCamera>,
Without<MainCamera>,
Without<Me>,
Without<StarfieldFront>,
Without<StarfieldMid>,
Without<StarfieldBack>,
),
>,
mut camera: Single<
(&mut Camera, &mut Projection),
(
With<MainCamera>,
Without<StarguideCamera>,
Without<Me>,
Without<StarfieldFront>,
Without<StarfieldMid>,
Without<StarfieldBack>,
),
>,
player: Single<
&Transform,
(
With<Me>,
Without<StarfieldFront>,
Without<StarfieldMid>,
Without<StarfieldBack>,
Without<MainCamera>,
),
>,
) {
let (mut starfield_back, mut starfield_back_pos, mut visibility_back, size_back) =
starfield_back.into_inner();
let (mut starfield_mid, mut starfield_mid_pos, mut visibility_mid, size_mid) = starfield_mid.into_inner();
let (mut starfield_front, mut starfield_front_pos, mut visibility_front, size_front) =
starfield_front.into_inner();
let Projection::Orthographic(ref mut camera_projection) = camera.1.clone() else { return };
let Projection::Orthographic(ref mut starguide_projection) = starguide_camera.1.clone() else { return };
for event in scroll_events.read() {
match event.unit {
MouseScrollUnit::Line | MouseScrollUnit::Pixel => {
if event.y > 0.0 {
camera_projection.scale *= 0.97;
starguide_projection.scale *= 0.97;
} else {
camera_projection.scale *= 1.03;
starguide_projection.scale *= 1.03;
}
if camera_projection.scale > STARGUIDE_ZOOM_LEVEL && matches!(gameplay_state.get(), GameplayState::Main) {
camera.0.is_active = false;
starguide_camera.0.is_active = true;
starguide_camera.2.translation = player.translation;
gameplay_next_state.set(GameplayState::Starguide);
starfield_back.image_mode = SpriteImageMode::Auto;
starfield_mid.image_mode = SpriteImageMode::Auto;
starfield_front.image_mode = SpriteImageMode::Auto;
*visibility_back = Visibility::Hidden;
*visibility_mid = Visibility::Hidden;
*visibility_front = Visibility::Hidden;
} else if camera_projection.scale <= STARGUIDE_ZOOM_LEVEL && matches!(gameplay_state.get(), GameplayState::Starguide) {
camera.0.is_active = true;
gameplay_next_state.set(GameplayState::Main);
starguide_camera.0.is_active = false;
if matches!(*visibility_back, Visibility::Hidden) {
restore_tiled(&mut starfield_back, size_back);
restore_tiled(&mut starfield_mid, size_mid);
restore_tiled(&mut starfield_front, size_front);
}
*visibility_back = Visibility::Inherited;
*visibility_mid = Visibility::Inherited;
*visibility_front = Visibility::Inherited;
}
starfield_back.custom_size =
Some(window.size() * camera_projection.scale + Vec2::splat(BACK_STARFIELD_SIZE * 2.0));
starfield_mid.custom_size =
Some(window.size() * camera_projection.scale + Vec2::splat(MID_STARFIELD_SIZE * 2.0));
starfield_front.custom_size =
Some(window.size() * camera_projection.scale + Vec2::splat(FRONT_STARFIELD_SIZE * 2.0));
let win = window.size();
starfield_back_pos.translation = parallax_layer_translation(player.translation, win, camera_projection.scale, 3.0, BACK_STARFIELD_SIZE, 5.0);
starfield_mid_pos.translation = parallax_layer_translation(player.translation, win, camera_projection.scale, 2.5, MID_STARFIELD_SIZE, 4.5);
starfield_front_pos.translation = parallax_layer_translation(player.translation, win, camera_projection.scale, 2.0, FRONT_STARFIELD_SIZE, 4.0);
}
}
}
*camera.1 = Projection::Orthographic(camera_projection.clone());
*starguide_camera.1 = Projection::Orthographic(starguide_projection.clone());
}