From 6b5ddca26b99f8fa0bfc6cbca21b6a24badd8393 Mon Sep 17 00:00:00 2001 From: Alice Cecile Date: Fri, 5 May 2023 17:59:52 -0400 Subject: [PATCH] Swap to a static sun (#844) * Simplify TimeOfDay and vary sky color with weather * Don't move sun and moon * Remove dead shadows code * Don't add the light from hidden bodies --- emergence_lib/src/graphics/atmosphere.rs | 24 +++++++- emergence_lib/src/graphics/lighting.rs | 48 +++------------ emergence_lib/src/graphics/palette.rs | 15 ++--- emergence_lib/src/light/mod.rs | 14 +++-- emergence_lib/src/simulation/time.rs | 77 ++++++++---------------- 5 files changed, 71 insertions(+), 107 deletions(-) diff --git a/emergence_lib/src/graphics/atmosphere.rs b/emergence_lib/src/graphics/atmosphere.rs index ca90f6ebd..1f14d4f70 100644 --- a/emergence_lib/src/graphics/atmosphere.rs +++ b/emergence_lib/src/graphics/atmosphere.rs @@ -2,7 +2,10 @@ use bevy::prelude::*; -use crate::simulation::time::InGameTime; +use crate::simulation::{ + time::{InGameTime, TimeOfDay}, + weather::CurrentWeather, +}; /// Logic and resources to modify the sky and atmosphere. pub(super) struct AtmospherePlugin; @@ -14,6 +17,21 @@ impl Plugin for AtmospherePlugin { } /// Changes the `ClearColor` resource which drives the sky color based on the time of day. -fn animate_sky_color(mut clear_color: ResMut, in_game_time: Res) { - clear_color.0 = in_game_time.time_of_day().sky_color(); +fn animate_sky_color( + mut clear_color: ResMut, + weather: Res, + in_game_time: Res, +) { + clear_color.0 = match in_game_time.time_of_day() { + TimeOfDay::Day => weather.get().sky_color(), + TimeOfDay::Night => { + let Color::Hsla { hue, saturation, lightness, alpha } = weather.get().sky_color() else { panic!("Expected HSL color") }; + Color::Hsla { + hue, + saturation, + lightness: lightness * 0.5, + alpha, + } + } + }; } diff --git a/emergence_lib/src/graphics/lighting.rs b/emergence_lib/src/graphics/lighting.rs index 8c3c34855..a2f03308a 100644 --- a/emergence_lib/src/graphics/lighting.rs +++ b/emergence_lib/src/graphics/lighting.rs @@ -25,10 +25,7 @@ impl Plugin for LightingPlugin { //.insert_resource(DirectionalLightShadowMap { size: 8192 }) // Need to wait for the player camera to spawn .add_startup_system(spawn_celestial_bodies.in_base_set(StartupSet::PostStartup)) - .add_systems(( - animate_celestial_body_transform, - animate_celestial_body_brightness, - )); + .add_systems((animate_celestial_body_transform,)); } } @@ -56,8 +53,6 @@ pub(crate) struct CelestialBody { /// /// This defaults to 1.0, and is multiplied by the base illuminance. light_level: f32, - /// The number of in-game days required to complete a full cycle. - pub(crate) days_per_cycle: f32, } impl CelestialBody { @@ -117,7 +112,6 @@ impl CelestialBody { travel_axis: 0., illuminance: 8e4, light_level: 1.0, - days_per_cycle: 1.0, } } @@ -130,35 +124,21 @@ impl CelestialBody { travel_axis: PI / 6., illuminance: 3e4, light_level: 1.0, - days_per_cycle: 29.53, } } } /// This component signals that this Entity is the primary celestial body for lighting. #[derive(Component, Debug)] -pub(crate) struct PrimaryCelestialBody; +pub(crate) struct Sun; + +/// This component signals that this Entity is the secondary celestial body for lighting. +#[derive(Component, Debug)] +pub(crate) struct Moon; /// Spawns a directional light source to illuminate the scene #[allow(dead_code)] fn spawn_celestial_bodies(mut commands: Commands) { - /* Shadows are currently disabled for perf reasons: - Tracked in https://github.com/Leafwing-Studios/Emergence/issues/726 - - let camera_settings = camera_query.single(); - let cascade_shadow_config = CascadeShadowConfigBuilder { - // Max is 4, as of Bevy 0.10 - num_cascades: 4, - // Shadows must be visible even when fully zoomed in - minimum_distance: camera_settings.min_zoom, - // Shadows must be visible even when fully zoomed out - maximum_distance: 4. * camera_settings.max_zoom, - first_cascade_far_bound: 2. * camera_settings.min_zoom, - overlap_proportion: 0.3, - } - .build(); - */ - let sun = CelestialBody::sun(); commands .spawn(DirectionalLightBundle { @@ -171,7 +151,7 @@ fn spawn_celestial_bodies(mut commands: Commands) { ..default() }) .insert(sun) - .insert(PrimaryCelestialBody); + .insert(Sun); let moon = CelestialBody::moon(); commands @@ -184,10 +164,12 @@ fn spawn_celestial_bodies(mut commands: Commands) { }, ..default() }) - .insert(moon); + .insert(moon) + .insert(Moon); } /// Moves celestial bodies to the correct position and orientation +// PERF: this doesn't need to run constantly if we're not moving the sun and moon fn animate_celestial_body_transform( mut query: Query<(&mut Transform, &CelestialBody), Changed>, ) { @@ -210,13 +192,3 @@ fn animate_celestial_body_transform( transform.look_at(Vec3::ZERO, Vec3::Y); } } - -/// Adjusts the brightness of celestial bodies based on their position in the sky -fn animate_celestial_body_brightness( - mut query: Query<(&CelestialBody, &mut DirectionalLight), Changed>, -) { - for (celestial_body, mut directional_light) in query.iter_mut() { - let current_illuminance = celestial_body.compute_light(); - directional_light.illuminance = current_illuminance.0; - } -} diff --git a/emergence_lib/src/graphics/palette.rs b/emergence_lib/src/graphics/palette.rs index ee181d9ee..506017137 100644 --- a/emergence_lib/src/graphics/palette.rs +++ b/emergence_lib/src/graphics/palette.rs @@ -160,21 +160,18 @@ pub(crate) mod infovis { pub(crate) mod environment { use bevy::prelude::Color; - use crate::simulation::time::TimeOfDay; + use crate::simulation::weather::Weather; /// The color used for columns of dirt underneath tiles pub(crate) const COLUMN_COLOR: Color = Color::hsl(21., 0.6, 0.15); - impl TimeOfDay { - /// The color of the sky at the given time of day. + impl Weather { + /// The color of the sky for this weather. pub(crate) const fn sky_color(&self) -> Color { match self { - TimeOfDay::Dawn => Color::hsl(180., 0.3, 0.6), - TimeOfDay::Morning => Color::hsl(190., 0.3, 0.7), - TimeOfDay::Noon => Color::hsl(209., 0.7, 0.8), - TimeOfDay::Afternoon => Color::hsl(212., 0.55, 0.7), - TimeOfDay::Evening => Color::hsl(220., 0.4, 0.3), - TimeOfDay::Midnight => Color::hsl(232., 0.2, 0.1), + Weather::Clear => Color::hsl(209., 0.7, 0.8), + Weather::Cloudy => Color::hsl(209., 0.3, 0.6), + Weather::Rainy => Color::hsl(209., 0.3, 0.5), } } } diff --git a/emergence_lib/src/light/mod.rs b/emergence_lib/src/light/mod.rs index dd09b32ea..9b0d86409 100644 --- a/emergence_lib/src/light/mod.rs +++ b/emergence_lib/src/light/mod.rs @@ -7,7 +7,7 @@ use serde::{Deserialize, Serialize}; use std::ops::Mul; use crate::{ - graphics::lighting::{CelestialBody, PrimaryCelestialBody}, + graphics::lighting::{CelestialBody, Sun}, simulation::SimulationSet, }; @@ -106,8 +106,8 @@ impl Mul for f32 { /// Computes the amount of light available from each celestial body based on its position in the sky and luminous intensity. fn compute_light( - mut query: Query<&CelestialBody>, - primary_body_query: Query<&CelestialBody, With>, + mut query: Query<(&CelestialBody, &Visibility)>, + primary_body_query: Query<&CelestialBody, With>, mut total_light: ResMut, ) { if total_light.max_illuminance == Illuminance(0.0) { @@ -117,9 +117,11 @@ fn compute_light( } let mut sum = Illuminance(0.0); - for body in query.iter_mut() { - let light = body.compute_light(); - sum += light; + for (body, visibility) in query.iter_mut() { + if visibility == Visibility::Visible { + let light = body.compute_light(); + sum += light; + } } total_light.illuminance = sum; } diff --git a/emergence_lib/src/simulation/time.rs b/emergence_lib/src/simulation/time.rs index f19ce2f1b..2e8345702 100644 --- a/emergence_lib/src/simulation/time.rs +++ b/emergence_lib/src/simulation/time.rs @@ -1,6 +1,5 @@ //! Controls in-game time: day-night cycles, weather and the passing of seasons -use core::f32::consts::{PI, TAU}; use core::fmt::Display; use std::ops::{Div, Mul}; @@ -11,7 +10,7 @@ use leafwing_abilities::prelude::Pool; use leafwing_input_manager::prelude::ActionState; use serde::{Deserialize, Serialize}; -use crate::graphics::lighting::CelestialBody; +use crate::graphics::lighting::{Moon, Sun}; use crate::organisms::lifecycle::Lifecycle; use crate::player_interaction::PlayerAction; @@ -90,53 +89,21 @@ impl Mul for Days { /// These are evenly spaced throughout the 24 hour day. #[derive(Debug, Display, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)] pub enum TimeOfDay { - /// The beginning part of the day. - Morning, - /// The peak hour of sun. - Noon, - /// The latter part of the day. - Afternoon, - /// The beginning of the ngiht. - Evening, - /// The peak hour of darkness. - Midnight, - /// The latter part of the night. - Dawn, + /// The sun is out + Day, + /// The sun is down + Night, } impl TimeOfDay { - /// Is this time of day during the day? - pub fn is_day(&self) -> bool { - matches!( - self, - TimeOfDay::Morning | TimeOfDay::Noon | TimeOfDay::Afternoon - ) - } - - /// Is this time of day during the night? - pub fn is_night(&self) -> bool { - matches!( - self, - TimeOfDay::Evening | TimeOfDay::Midnight | TimeOfDay::Dawn - ) - } - /// Returns the time of day that is closest to the given fraction of a day. /// /// Values outside of [0.0, 1.0] are modulo'd to fit the range. pub fn from_fraction_of_day(fraction: f32) -> Self { - let cleaned_fraction = fraction.rem_euclid(1.0); - let scaled_fraction = cleaned_fraction * 6.0; - // We want to ensure that noon is centered at 0.5. - let shifted_fraction = scaled_fraction + 0.5; - match shifted_fraction.round() as u32 { - 0 => TimeOfDay::Dawn, - 1 => TimeOfDay::Morning, - 2 => TimeOfDay::Noon, - 3 => TimeOfDay::Afternoon, - 4 => TimeOfDay::Evening, - 5 => TimeOfDay::Midnight, - _ => TimeOfDay::Dawn, + if fraction < 0.7 { + TimeOfDay::Day + } else { + TimeOfDay::Night } } } @@ -204,15 +171,23 @@ pub fn advance_in_game_time(time: Res, mut in_game_time: ResMut, in_game_time: Res) { - for mut celestial_body in query.iter_mut() { - // Take the modulo with respect to the period to get the revolution period correct - let cycle_normalized_time = (in_game_time.elapsed_time.0 % celestial_body.days_per_cycle) - / celestial_body.days_per_cycle; - - // Scale the progress by TAU to get a full rotation. - // Offset by PI / 2 to compensate for the fact that 0 represents the noon sun - celestial_body.hour_angle = cycle_normalized_time * TAU - PI / 2.; +fn move_celestial_bodies( + mut sun_query: Query<&mut Visibility, (With, Without)>, + mut moon_query: Query<&mut Visibility, With>, + in_game_time: Res, +) { + let mut sun_visibility = sun_query.single_mut(); + let mut moon_visibility = moon_query.single_mut(); + + match in_game_time.time_of_day() { + TimeOfDay::Day => { + *sun_visibility = Visibility::Visible; + *moon_visibility = Visibility::Hidden; + } + TimeOfDay::Night => { + *sun_visibility = Visibility::Hidden; + *moon_visibility = Visibility::Visible; + } } }