use bevy::{ app::{App, Startup, Update}, asset::{AssetEvent, AssetServer, Assets}, ecs::{ event::EventReader, query::{With, Without}, system::{Commands, Query, Res, Single}, }, image::Image, math::{Vec2, Vec3}, sprite::{Sprite, SpriteImageMode}, transform::components::Transform, window::{Window, WindowResized}, }; use crate::{ client::Me, ecs::{MainCamera, StarfieldBack, StarfieldFront, StarfieldMid}, }; pub const BACK_STARFIELD_SIZE: f32 = 256.0; pub const MID_STARFIELD_SIZE: f32 = 384.0; pub const FRONT_STARFIELD_SIZE: f32 = 512.0; pub fn starfield_plugin(app: &mut App) { app.add_systems(Startup, setup_starfield) .add_systems(Update, fix_starfield) .add_systems(Update, resize_starfield) .add_systems(Update, update_starfield); } pub fn setup_starfield( mut commands: Commands, asset_server: Res, window: Query<&Window>, ) { let starfield_handle = asset_server.load("textures/starfield.png"); let starfield_transp_handle = asset_server.load("textures/starfield_transp.png"); let window = window.iter().next().unwrap(); commands .spawn(Sprite { image: starfield_handle, custom_size: Some(window.size() + Vec2::splat(BACK_STARFIELD_SIZE)), image_mode: SpriteImageMode::Tiled { tile_x: true, tile_y: true, stretch_value: 1.0, }, ..Default::default() }) .insert(Transform::from_xyz(0.0, 0.0, 5.0)) .insert(StarfieldBack); commands .spawn(Sprite { image: starfield_transp_handle.clone(), custom_size: Some(window.size() + Vec2::splat(MID_STARFIELD_SIZE)), image_mode: SpriteImageMode::Tiled { tile_x: true, tile_y: true, stretch_value: 1.0, }, ..Default::default() }) .insert(Transform::from_xyz(0.0, 0.0, 4.5)) .insert(StarfieldMid); commands .spawn(Sprite { image: starfield_transp_handle, custom_size: Some(window.size() + Vec2::splat(FRONT_STARFIELD_SIZE)), image_mode: SpriteImageMode::Tiled { tile_x: true, tile_y: true, stretch_value: 1.0, }, ..Default::default() }) .insert(Transform::from_xyz(0.0, 0.0, 4.0)) .insert(StarfieldFront); } pub fn fix_starfield( mut starfield_back: Query< &mut Sprite, ( With, Without, Without, ), >, mut starfield_mid: Query< &mut Sprite, ( With, Without, Without, ), >, mut starfield_front: Query< &mut Sprite, ( With, Without, Without, ), >, assets: Res>, mut asset_events: EventReader>, ) { for event in asset_events.read() { if let AssetEvent::Added { id } = event { let mut starfield_back = starfield_back.single_mut().unwrap(); if *id == starfield_back.image.id() { let starfield_image = assets.get(*id).unwrap(); starfield_back.image_mode = SpriteImageMode::Tiled { tile_x: true, tile_y: true, stretch_value: BACK_STARFIELD_SIZE / (starfield_image.size().x as f32), }; } let mut starfield_mid = starfield_mid.single_mut().unwrap(); if *id == starfield_mid.image.id() { let starfield_image = assets.get(*id).unwrap(); starfield_mid.image_mode = SpriteImageMode::Tiled { tile_x: true, tile_y: true, stretch_value: MID_STARFIELD_SIZE / (starfield_image.size().x as f32), }; } let mut starfield_front = starfield_front.single_mut().unwrap(); if *id == starfield_front.image.id() { let starfield_image = assets.get(*id).unwrap(); starfield_front.image_mode = SpriteImageMode::Tiled { tile_x: true, tile_y: true, stretch_value: FRONT_STARFIELD_SIZE / (starfield_image.size().x as f32), }; } } } } pub fn resize_starfield( mut starfield_back: Query< &mut Sprite, ( With, Without, Without, ), >, mut starfield_mid: Query< &mut Sprite, ( With, Without, Without, ), >, mut starfield_front: Query< &mut Sprite, ( With, Without, Without, ), >, mut resize_event: EventReader, camera: Single<&Transform, With>, ) { for event in resize_event.read() { starfield_back.single_mut().unwrap().custom_size = Some( Vec2::new(event.width, event.height) * camera.scale.z + Vec2::splat(BACK_STARFIELD_SIZE * 2.0), ); starfield_mid.single_mut().unwrap().custom_size = Some( Vec2::new(event.width, event.height) * camera.scale.z + Vec2::splat(MID_STARFIELD_SIZE * 2.0), ); starfield_front.single_mut().unwrap().custom_size = Some( Vec2::new(event.width, event.height) * camera.scale.z + Vec2::splat(FRONT_STARFIELD_SIZE * 2.0), ); } } pub fn update_starfield( mut starfield_back: Query< &mut Transform, ( With, Without, Without, Without, ), >, mut starfield_mid: Query< &mut Transform, ( With, Without, Without, Without, ), >, mut starfield_front: Query< &mut Transform, ( With, Without, Without, Without, ), >, window: Single<&Window>, camera: Single< &Transform, ( With, Without, Without, Without, Without, ), >, player: Query<&Transform, (With, Without)>, ) { let Some(player) = player.iter().next() else { return; }; let mut starfield_back_pos = starfield_back.single_mut().unwrap(); let mut starfield_mid_pos = starfield_mid.single_mut().unwrap(); let mut starfield_front_pos = starfield_front.single_mut().unwrap(); //starfield_pos.translation = (player.translation / STARFIELD_SIZE).round() * STARFIELD_SIZE; starfield_back_pos.translation = player.translation + (-player.translation / 3.0) % BACK_STARFIELD_SIZE + (Vec3::new( window.resolution.width(), -window.resolution.height() + BACK_STARFIELD_SIZE, 0.0, ) * camera.scale.z / 2.0) % BACK_STARFIELD_SIZE + Vec3::new(0.0, BACK_STARFIELD_SIZE, 0.0) - Vec3::new(0.0, 0.0, 5.0); starfield_mid_pos.translation = player.translation + (-player.translation / 2.5) % MID_STARFIELD_SIZE + (Vec3::new( window.resolution.width(), -window.resolution.height() + MID_STARFIELD_SIZE, 0.0, ) * camera.scale.z / 2.0) % MID_STARFIELD_SIZE + Vec3::new(0.0, MID_STARFIELD_SIZE, 0.0) - Vec3::new(0.0, 0.0, 4.5); starfield_front_pos.translation = player.translation + (-player.translation / 2.0) % FRONT_STARFIELD_SIZE + (Vec3::new( window.resolution.width(), -window.resolution.height() + FRONT_STARFIELD_SIZE, 0.0, ) * camera.scale.z / 2.0) % FRONT_STARFIELD_SIZE + Vec3::new(0.0, FRONT_STARFIELD_SIZE, 0.0) - Vec3::new(0.0, 0.0, 4.0); }