diff --git a/assets/shaders/darkness.wgsl b/assets/shaders/darkness.wgsl index 2b3a37a..376026a 100644 --- a/assets/shaders/darkness.wgsl +++ b/assets/shaders/darkness.wgsl @@ -52,7 +52,7 @@ fn fragment( if (point_lights[i].radius <= 0.0) { continue; } - let radius = point_lights[i].radius + sin(t * 5.0) * 0.2; + let radius = point_lights[i].radius - (sin(t * 5.0) * 0.5 + 0.5) * 0.2; let dist = distance(pos, point_lights[i].position); let edge_treshold = radius * light_edge_mult - light_edge; @@ -68,7 +68,7 @@ fn fragment( continue; } let spot = spot_lights[i]; - let radius = spot.radius + sin(t * 5.0) * 0.2; + let radius = spot.radius - (sin(t * 5.0) * 0.5 + 0.5) * 0.2; let diff = pos - spot.position; let dist = length(diff); let spot_dir = vec2(cos(spot.rotation), sin(spot.rotation)); diff --git a/src/debug.rs b/src/debug.rs index b799b87..71d7a34 100644 --- a/src/debug.rs +++ b/src/debug.rs @@ -1,5 +1,6 @@ use bevy::prelude::*; -use bevy_prototype_debug_lines::DebugLinesPlugin; + +use crate::game::darkness::LightAabb; pub struct DebugPlugin; @@ -11,12 +12,13 @@ impl Plugin for DebugPlugin { app.configure_set(Last, DebugSet.run_if(is_debug_enabled)); app.insert_resource(DebugMode::off()) + .add_plugins(bevy_prototype_debug_lines::DebugLinesPlugin::default()) .add_plugins(( bevy_inspector_egui::quick::WorldInspectorPlugin::new().run_if(is_debug_enabled), bevy_rapier2d::prelude::RapierDebugRenderPlugin::default(), )) - .add_plugins(DebugLinesPlugin::default()) - .add_systems(Update, debug_toggle); + .add_systems(Update, debug_toggle) + .add_systems(Last, (light_boundaries).in_set(DebugSet)); } } @@ -45,3 +47,66 @@ fn debug_toggle(input: Res>, mut debug_mode: ResMut) { debug_mode.enabled = !debug_mode.enabled } } + +fn light_boundaries( + mut debug_draw: ResMut, + point_query: Query<(&GlobalTransform, &crate::game::darkness::PointLight2D)>, + spot_query: Query<(&GlobalTransform, &crate::game::darkness::SpotLight2D)>, +) { + for (tranform, light) in &point_query { + let rect = light.aabb(); + draw_rect( + Rect::from_center_size( + rect.center() + tranform.translation().truncate(), + rect.size(), + ), + 0.0, + Color::RED, + &mut debug_draw, + ) + } + for (tranform, light) in &spot_query { + let rect = light.aabb(); + draw_rect( + Rect::from_center_size( + rect.center() + tranform.translation().truncate(), + rect.size(), + ), + 0.0, + Color::RED, + &mut debug_draw, + ) + } +} + +fn draw_rect( + rect: Rect, + duration: f32, + color: Color, + debug_draw: &mut ResMut, +) { + debug_draw.line_colored( + Vec3::new(rect.min.x, rect.min.y, 0.0), + Vec3::new(rect.max.x, rect.min.y, 0.0), + duration, + color, + ); + debug_draw.line_colored( + Vec3::new(rect.max.x, rect.min.y, 0.0), + Vec3::new(rect.max.x, rect.max.y, 0.0), + duration, + color, + ); + debug_draw.line_colored( + Vec3::new(rect.max.x, rect.max.y, 0.0), + Vec3::new(rect.min.x, rect.max.y, 0.0), + duration, + color, + ); + debug_draw.line_colored( + Vec3::new(rect.min.x, rect.max.y, 0.0), + Vec3::new(rect.min.x, rect.min.y, 0.0), + duration, + color, + ); +} diff --git a/src/game.rs b/src/game.rs index 4c5eaeb..85c4f3e 100644 --- a/src/game.rs +++ b/src/game.rs @@ -2,7 +2,7 @@ use crate::{debug, game_setup}; use bevy::prelude::*; use bevy_ecs_ldtk::{LdtkWorldBundle, LevelSelection}; -use self::darkness::SpotLight2D; +use self::darkness::{PointLight2D, SpotLight2D}; pub mod camera; pub mod darkness; @@ -36,5 +36,6 @@ fn setup(mut commands: Commands, assets: Res) { radius: 100.0, angle: 1.0, }, + PointLight2D { radius: 20.0 }, )); } diff --git a/src/game/darkness.rs b/src/game/darkness.rs index 35e8718..e0827c1 100644 --- a/src/game/darkness.rs +++ b/src/game/darkness.rs @@ -19,6 +19,7 @@ impl Plugin for DarknessPlugin { fn build(&self, app: &mut App) { app.register_type::() .register_type::() + .register_type::() .register_asset_reflect::() .add_plugins(Material2dPlugin::::default()) .add_systems(Update, add_to_level) @@ -26,12 +27,22 @@ impl Plugin for DarknessPlugin { } } +pub trait LightAabb { + fn aabb(&self) -> Rect; +} + #[derive(Component, Reflect, Default, Debug)] #[reflect(Component)] pub struct PointLight2D { pub radius: f32, } +impl LightAabb for PointLight2D { + fn aabb(&self) -> Rect { + Rect::from_center_half_size(Vec2::ZERO, Vec2::splat(self.radius + 2.0)) + } +} + #[derive(Copy, Clone, Debug, Default, Reflect, ShaderType)] pub(crate) struct GpuPointLight2D { pub(crate) position: Vec2, @@ -45,6 +56,12 @@ pub struct SpotLight2D { pub angle: f32, } +impl LightAabb for SpotLight2D { + fn aabb(&self) -> Rect { + Rect::from_center_half_size(Vec2::ZERO, Vec2::splat(self.radius + 2.0)) + } +} + #[derive(Copy, Clone, Debug, Default, Reflect, ShaderType)] pub(crate) struct GpuSpotLight2D { pub(crate) position: Vec2, @@ -56,6 +73,10 @@ pub(crate) struct GpuSpotLight2D { padding3: u32, } +#[derive(Component, Reflect, Default, Debug, Clone, Copy)] +#[reflect(Component)] +pub struct VisibilityBlocker; + fn add_to_level( mut commands: Commands, mut level_events: EventReader, diff --git a/src/game/ldtk.rs b/src/game/ldtk.rs index afc0e07..f8894b1 100644 --- a/src/game/ldtk.rs +++ b/src/game/ldtk.rs @@ -5,6 +5,7 @@ use bevy_ecs_ldtk::prelude::*; use bevy_rapier2d::prelude::*; use std::collections::HashSet; +use crate::game::darkness::VisibilityBlocker; use crate::util::Vector2I; pub struct LdtkHelperPlugin; @@ -31,7 +32,7 @@ impl Plugin for LdtkHelperPlugin { .add_event::() .register_ldtk_int_cell::(1) .insert_resource(WordlyInstances::default()) - .add_systems(Update, entity_instance_events) + .add_systems(Update, (wall_setup, entity_instance_events)) .add_systems(PostUpdate, (entity_namer, unique_handler)); } } @@ -153,7 +154,7 @@ impl FieldValueGetter for EntityInstance { /// 2. combine wall tiles into flat "plates" in each individual row /// 3. combine the plates into rectangles across multiple rows wherever possible /// 4. spawn colliders for each rectangle -pub fn wall_setup( +fn wall_setup( mut commands: Commands, wall_query: Query<(&GridCoords, &Parent), Added>, parent_query: Query<&Parent, Without>, @@ -277,26 +278,28 @@ pub fn wall_setup( // 1. Adjusts the transforms to be relative to the level for free // 2. the colliders will be despawned automatically when levels unload for wall_rect in wall_rects { - level - .spawn_empty() - .insert(Collider::cuboid( + level.spawn(( + Collider::cuboid( (wall_rect.right as f32 - wall_rect.left as f32 + 1.) * grid_size as f32 / 2., (wall_rect.top as f32 - wall_rect.bottom as f32 + 1.) * grid_size as f32 / 2., - )) - .insert(RigidBody::Fixed) - .insert(Friction::new(1.0)) - .insert(Transform::from_xyz( + ), + VisibilityBlocker, + RigidBody::Fixed, + Name::new("Collider"), + Friction::new(1.0), + Transform::from_xyz( (wall_rect.left + wall_rect.right + 1) as f32 * grid_size as f32 / 2., (wall_rect.bottom + wall_rect.top + 1) as f32 * grid_size as f32 / 2., 0., - )) - .insert(GlobalTransform::default()); + ), + GlobalTransform::default(), + )); } }); }