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

View File

@ -8,6 +8,7 @@ use ::rltk::{Algorithm2D, BaseMap, Point, SmallVec};
use ::serde::{Deserialize, Serialize};
use ::specs::prelude::*;
pub use dungeon::*;
use rltk::RGB;
pub use themes::*;
pub use tiletype::{tile_opaque, tile_walkable, TileType};
@ -25,6 +26,8 @@ pub struct Map {
pub bloodstains: HashSet<usize>,
pub view_blocked: HashSet<usize>,
pub name: String,
pub outdoors: bool,
pub light: Vec<RGB>,
#[serde(skip_serializing)]
#[serde(skip_deserializing)]
@ -74,6 +77,8 @@ impl Map {
bloodstains: HashSet::new(),
view_blocked: HashSet::new(),
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] {
fg = fg.to_greyscale();
bg = RGB::from_f32(0., 0., 0.);
} else if !map.outdoors {
fg = fg * map.light[idx];
bg = bg * map.light[idx];
}
(glyph, fg, bg)

View File

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

View File

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

View File

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