Add lighting system

This commit is contained in:
Timothy Warren 2022-01-10 10:21:19 -05:00
parent f3ccf50b91
commit 6f9aa54896
8 changed files with 73 additions and 1 deletions

View File

@ -285,6 +285,12 @@ pub struct OtherLevelPosition {
pub depth: i32, pub depth: i32,
} }
#[derive(Component, Serialize, Deserialize, Clone)]
pub struct LightSource {
pub color: RGB,
pub range: i32,
}
// Serialization helper code. We need to implement ConvertSaveLoad for each type that contains an // Serialization helper code. We need to implement ConvertSaveLoad for each type that contains an
// Entity. // Entity.

45
src/lighting_system.rs Normal file
View File

@ -0,0 +1,45 @@
use ::rltk::{Point, RGB};
use ::specs::prelude::*;
use rltk::DistanceAlg;
use super::{LightSource, Map, Position, Viewshed};
pub struct LightingSystem {}
impl<'a> System<'a> for LightingSystem {
#[allow(clippy::type_complexity)]
type SystemData = (
WriteExpect<'a, Map>,
ReadStorage<'a, Viewshed>,
ReadStorage<'a, Position>,
ReadStorage<'a, LightSource>,
);
fn run(&mut self, data: Self::SystemData) {
let (mut map, viewshed, positions, lighting) = data;
if map.outdoors {
return;
}
let black = RGB::from_f32(0., 0., 0.);
for l in map.light.iter_mut() {
*l = black;
}
for (viewshed, pos, light) in (&viewshed, &positions, &lighting).join() {
let light_point = Point::from(*pos);
let range_f = light.range as f32;
for t in viewshed.visible_tiles.iter() {
if t.x > 0 && t.x < map.width && t.y > 0 && t.y < map.height {
let idx = map.xy_idx(t.x, t.y);
let distance = DistanceAlg::Pythagoras.distance2d(light_point, *t);
let intensity = (range_f - distance) / range_f;
map.light[idx] = map.light[idx] + (light.color * intensity);
}
}
}
}
}

View File

@ -8,6 +8,7 @@ mod gamesystem;
mod gui; mod gui;
mod hunger_system; mod hunger_system;
mod inventory_system; mod inventory_system;
mod lighting_system;
mod map; mod map;
pub mod map_builders; pub mod map_builders;
mod map_indexing_system; mod map_indexing_system;
@ -38,6 +39,7 @@ pub use game_log::GameLog;
use gui::{show_cheat_mode, CheatMenuResult}; use gui::{show_cheat_mode, CheatMenuResult};
use hunger_system::HungerSystem; use hunger_system::HungerSystem;
use inventory_system::{ItemCollectionSystem, ItemDropSystem, ItemRemoveSystem, ItemUseSystem}; use inventory_system::{ItemCollectionSystem, ItemDropSystem, ItemRemoveSystem, ItemUseSystem};
use lighting_system::LightingSystem;
pub use map::*; pub use map::*;
use map_indexing_system::MapIndexingSystem; use map_indexing_system::MapIndexingSystem;
use melee_combat_system::MeleeCombatSystem; use melee_combat_system::MeleeCombatSystem;
@ -152,6 +154,9 @@ impl State {
let mut particles = ParticleSpawnSystem {}; let mut particles = ParticleSpawnSystem {};
particles.run_now(&self.ecs); particles.run_now(&self.ecs);
let mut lighting = LightingSystem {};
lighting.run_now(&self.ecs);
self.ecs.maintain(); self.ecs.maintain();
} }
} }
@ -468,6 +473,7 @@ fn main() -> ::rltk::BError {
InBackpack, InBackpack,
InflictsDamage, InflictsDamage,
Item, Item,
LightSource,
LootTable, LootTable,
MagicMapper, MagicMapper,
MeleeWeapon, MeleeWeapon,

View File

@ -8,6 +8,7 @@ use ::rltk::{Algorithm2D, BaseMap, Point, SmallVec};
use ::serde::{Deserialize, Serialize}; use ::serde::{Deserialize, Serialize};
use ::specs::prelude::*; use ::specs::prelude::*;
pub use dungeon::*; pub use dungeon::*;
use rltk::RGB;
pub use themes::*; pub use themes::*;
pub use tiletype::{tile_opaque, tile_walkable, TileType}; pub use tiletype::{tile_opaque, tile_walkable, TileType};
@ -25,6 +26,8 @@ pub struct Map {
pub bloodstains: HashSet<usize>, pub bloodstains: HashSet<usize>,
pub view_blocked: HashSet<usize>, pub view_blocked: HashSet<usize>,
pub name: String, pub name: String,
pub outdoors: bool,
pub light: Vec<RGB>,
#[serde(skip_serializing)] #[serde(skip_serializing)]
#[serde(skip_deserializing)] #[serde(skip_deserializing)]
@ -74,6 +77,8 @@ impl Map {
bloodstains: HashSet::new(), bloodstains: HashSet::new(),
view_blocked: HashSet::new(), view_blocked: HashSet::new(),
name: name.to_string(), name: name.to_string(),
outdoors: true,
light: vec![RGB::from_f32(0., 0., 0.); map_tile_count],
} }
} }
} }

View File

@ -16,6 +16,9 @@ pub fn tile_glyph(idx: usize, map: &Map) -> (FontCharType, RGB, RGB) {
if !map.visible_tiles[idx] { if !map.visible_tiles[idx] {
fg = fg.to_greyscale(); fg = fg.to_greyscale();
bg = RGB::from_f32(0., 0., 0.); bg = RGB::from_f32(0., 0., 0.);
} else if !map.outdoors {
fg = fg * map.light[idx];
bg = bg * map.light[idx];
} }
(glyph, fg, bg) (glyph, fg, bg)

View File

@ -4,7 +4,7 @@ use super::{
AreaStartingPosition, BuilderChain, BuilderMap, CullUnreachable, DistantExit, AreaStartingPosition, BuilderChain, BuilderMap, CullUnreachable, DistantExit,
DrunkardsWalkBuilder, MetaMapBuilder, VoronoiSpawning, XStart, YStart, DrunkardsWalkBuilder, MetaMapBuilder, VoronoiSpawning, XStart, YStart,
}; };
use crate::map::{self, TileType}; use crate::map::TileType;
pub fn limestone_cavern_builder( pub fn limestone_cavern_builder(
new_depth: i32, new_depth: i32,
@ -82,5 +82,6 @@ impl CaveDecorator {
} }
build_data.take_snapshot(); build_data.take_snapshot();
build_data.map.outdoors = false;
} }
} }

View File

@ -80,6 +80,7 @@ pub fn save_game(ecs: &mut World) {
InBackpack, InBackpack,
InflictsDamage, InflictsDamage,
Item, Item,
LightSource,
LootTable, LootTable,
MagicMapper, MagicMapper,
MeleeWeapon, MeleeWeapon,
@ -184,6 +185,7 @@ pub fn load_game(ecs: &mut World) {
InBackpack, InBackpack,
InflictsDamage, InflictsDamage,
Item, Item,
LightSource,
LootTable, LootTable,
MagicMapper, MagicMapper,
MeleeWeapon, MeleeWeapon,

View File

@ -50,6 +50,10 @@ pub fn player(ecs: &mut World, player_x: i32, player_y: i32) -> Entity {
xp: 0, xp: 0,
level: 1, level: 1,
}) })
.with(LightSource {
color: RGB::from_f32(1.0, 1.0, 0.5),
range: 8,
})
.marked::<SimpleMarker<SerializeMe>>() .marked::<SimpleMarker<SerializeMe>>()
.build(); .build();