use crate::{actor, nature, settings, hud}; use bevy::prelude::*; use bevy::render::render_resource::{AsBindGroup, ShaderRef}; use bevy::math::{DVec3, I64Vec3}; use bevy_xpbd_3d::prelude::*; use bevy_xpbd_3d::plugins::sync::SyncConfig; use std::collections::HashMap; use std::f32::consts::PI; use fastrand; const ASTEROID_UPDATE_INTERVAL: f32 = 0.1; // seconds const ASTEROID_SIZE_FACTOR: f32 = 3.0; const STARS_MAX_MAGNITUDE: f32 = 5.5; const CENTER_WORLD_ON_PLAYER: bool = true; const ASTEROID_SPAWN_STEP: f64 = 500.0; const ASTEROID_VIEW_RADIUS: f64 = 3000.0; const ASSET_ASTEROID1: &str = "models/asteroid.glb#Scene0"; const ASSET_ASTEROID2: &str = "models/asteroid2.glb#Scene0"; pub fn asset_name_to_path(name: &str) -> &'static str { match name { "suit" => "models/suit.glb#Scene0", "asteroid1" => ASSET_ASTEROID1, "asteroid2" => ASSET_ASTEROID2, "moonlet" => "models/moonlet.glb#Scene0", "monolith" => "models/monolith_neon.glb#Scene0", "lightorb" => "models/lightorb.glb#Scene0", "MeteorAceGT" => "models/MeteorAceGT.glb#Scene0", "pizzeria" => "models/pizzeria2.glb#Scene0", "pizzasign" => "models/pizzasign.glb#Scene0", _ => "models/error.glb#Scene0", } } pub struct WorldPlugin; impl Plugin for WorldPlugin { fn build(&self, app: &mut App) { app.add_systems(Startup, setup); app.add_systems(Update, handle_cheats); app.add_systems(PostUpdate, handle_despawn); app.add_systems(Update, spawn_despawn_asteroids); app.add_plugins(PhysicsPlugins::default()); app.add_plugins(MaterialPlugin::::default()); //app.add_plugins(PhysicsDebugPlugin::default()); app.insert_resource(Gravity(DVec3::splat(0.0))); app.insert_resource(AsteroidUpdateTimer( Timer::from_seconds(ASTEROID_UPDATE_INTERVAL, TimerMode::Repeating))); app.insert_resource(AsteroidDatabase(Vec::new())); app.insert_resource(ActiveAsteroids(HashMap::new())); app.add_event::(); if CENTER_WORLD_ON_PLAYER { // Disable bevy_xpbd's position->transform sync function app.insert_resource(SyncConfig { position_to_transform: false, transform_to_position: false, }); // Add own position->transform sync function app.add_systems(PreUpdate, position_to_transform); } } } #[derive(Resource)] struct AsteroidUpdateTimer(Timer); #[derive(Resource)] struct AsteroidDatabase(Vec); #[derive(Resource)] struct ActiveAsteroids(HashMap); #[derive(Component)] struct Asteroid; struct AsteroidData { entity: Entity, //viewdistance: f64, } #[derive(Event)] pub struct DespawnEvent { entity: Entity, origin: I64Vec3, } #[derive(Asset, TypePath, AsBindGroup, Debug, Clone)] pub struct RingMaterial { alpha_mode: AlphaMode, #[uniform(0)] ring_radius: f32, #[uniform(1)] jupiter_radius: f32, } impl Material for RingMaterial { fn fragment_shader() -> ShaderRef { "shaders/jupiters_rings.wgsl".into() } fn alpha_mode(&self) -> AlphaMode { self.alpha_mode } } #[derive(Component)] pub struct Star; pub fn setup( mut commands: Commands, mut meshes: ResMut>, mut materials: ResMut>, mut materials_custom: ResMut>, ) { // Generate starmap let sphere_handle = meshes.add(Sphere::new(1.0)); let mut starcount = 0; for star in nature::STARS { let mag = star[3]; if mag > STARS_MAX_MAGNITUDE { continue; } let scale_color = {|color: f32| if mag < -20.0 { color * 13.0f32 // Sun } else { color * (0.0659663 * mag * mag - 1.09862 * mag + 4.3) } }; let scale_size = {|mag: f32| if mag < -20.0 { 40000.0f32 // Sun } else { 1000.0 * (0.230299 * mag * mag - 3.09013 * mag + 15.1782) } * 100.0 }; let (r, g, b) = nature::star_color_index_to_rgb(star[4]); let star_color_handle = materials.add(StandardMaterial { base_color: Color::rgb(scale_color(r), scale_color(g), scale_color(b)), unlit: true, ..default() }); let dist = 1e9; commands.spawn(( Star, PbrBundle { mesh: sphere_handle.clone(), material: star_color_handle.clone(), transform: Transform::from_xyz( dist * star[0], dist * star[1], dist * star[2], ) .with_scale(Vec3::splat(scale_size(mag))), ..default() } )); starcount += 1; } info!("Generated {starcount} stars"); // Add shaded ring let ring_radius = 229_000_000.0; let jupiter_radius = 71_492_000.0; commands.spawn(( MaterialMeshBundle { mesh: meshes.add(Mesh::from(Cylinder::new(ring_radius, 1.0))), material: materials_custom.add(RingMaterial { alpha_mode: AlphaMode::Blend, ring_radius: ring_radius, jupiter_radius: jupiter_radius, }), ..default() }, Position::from_xyz(0.0, -10000.0, 0.0), //Rotation::from(Quat::IDENTITY), Rotation::from(Quat::from_rotation_x(-0.3f32.to_radians())), )); } fn spawn_despawn_asteroids( time: Res