Skip to content

Commit

Permalink
Swap to a static sun (Leafwing-Studios#844)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
alice-i-cecile authored May 5, 2023
1 parent 43943ce commit 6b5ddca
Show file tree
Hide file tree
Showing 5 changed files with 71 additions and 107 deletions.
24 changes: 21 additions & 3 deletions emergence_lib/src/graphics/atmosphere.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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<ClearColor>, in_game_time: Res<InGameTime>) {
clear_color.0 = in_game_time.time_of_day().sky_color();
fn animate_sky_color(
mut clear_color: ResMut<ClearColor>,
weather: Res<CurrentWeather>,
in_game_time: Res<InGameTime>,
) {
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,
}
}
};
}
48 changes: 10 additions & 38 deletions emergence_lib/src/graphics/lighting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,));
}
}

Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -117,7 +112,6 @@ impl CelestialBody {
travel_axis: 0.,
illuminance: 8e4,
light_level: 1.0,
days_per_cycle: 1.0,
}
}

Expand All @@ -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 {
Expand All @@ -171,7 +151,7 @@ fn spawn_celestial_bodies(mut commands: Commands) {
..default()
})
.insert(sun)
.insert(PrimaryCelestialBody);
.insert(Sun);

let moon = CelestialBody::moon();
commands
Expand All @@ -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<CelestialBody>>,
) {
Expand All @@ -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<CelestialBody>>,
) {
for (celestial_body, mut directional_light) in query.iter_mut() {
let current_illuminance = celestial_body.compute_light();
directional_light.illuminance = current_illuminance.0;
}
}
15 changes: 6 additions & 9 deletions emergence_lib/src/graphics/palette.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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),
}
}
}
Expand Down
14 changes: 8 additions & 6 deletions emergence_lib/src/light/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use serde::{Deserialize, Serialize};
use std::ops::Mul;

use crate::{
graphics::lighting::{CelestialBody, PrimaryCelestialBody},
graphics::lighting::{CelestialBody, Sun},
simulation::SimulationSet,
};

Expand Down Expand Up @@ -106,8 +106,8 @@ impl Mul<Illuminance> 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<PrimaryCelestialBody>>,
mut query: Query<(&CelestialBody, &Visibility)>,
primary_body_query: Query<&CelestialBody, With<Sun>>,
mut total_light: ResMut<TotalLight>,
) {
if total_light.max_illuminance == Illuminance(0.0) {
Expand All @@ -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;
}
77 changes: 26 additions & 51 deletions emergence_lib/src/simulation/time.rs
Original file line number Diff line number Diff line change
@@ -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};

Expand All @@ -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;

Expand Down Expand Up @@ -90,53 +89,21 @@ impl Mul<f32> 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
}
}
}
Expand Down Expand Up @@ -204,15 +171,23 @@ pub fn advance_in_game_time(time: Res<FixedTime>, mut in_game_time: ResMut<InGam
}

/// Moves the sun and moon based on the in-game time
fn move_celestial_bodies(mut query: Query<&mut CelestialBody>, in_game_time: Res<InGameTime>) {
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<Sun>, Without<Moon>)>,
mut moon_query: Query<&mut Visibility, With<Moon>>,
in_game_time: Res<InGameTime>,
) {
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;
}
}
}

Expand Down

0 comments on commit 6b5ddca

Please sign in to comment.