From f46b5f15eff4eba40e9484282df779a2c55b8df5 Mon Sep 17 00:00:00 2001 From: "Zed A. Shaw" Date: Thu, 26 Dec 2024 04:39:07 -0500 Subject: [PATCH] Lighting now uses pathing to determine where it can go, but _distance_ to determin strength. Looks way better. --- lights.cpp | 37 +++++++------------------------------ lights.hpp | 2 +- main.cpp | 4 ++-- matrix.cpp | 16 +++++++++++++--- matrix.hpp | 3 +++ systems.cpp | 4 ++-- tests/lighting.cpp | 46 ++++++++++++++++++++++------------------------ tests/matrix.cpp | 23 ++++++++++++++++++++++- 8 files changed, 72 insertions(+), 63 deletions(-) diff --git a/lights.cpp b/lights.cpp index 9110a99..91986ab 100644 --- a/lights.cpp +++ b/lights.cpp @@ -5,29 +5,10 @@ using std::vector; namespace lighting { - - void LightRender::render_circle_light(LightSource source, Point at, PointList &has_light) { - for(matrix::circle it{$lightmap, at, source.radius}; it.next();) { - for(int x = it.left; x < it.right; x++) { - $lightmap[it.y][x] = light_level(source.strength, x, it.y); - has_light.push_back({(size_t)x, (size_t)it.y}); - } - } - } - - void LightRender::render_compass_light(LightSource source, Point at, PointList &has_light) { - for(matrix::compass it{$lightmap, at.x, at.y}; it.next();) { - if($paths.$paths[it.y][it.x] != WALL_PATH_LIMIT) { - $lightmap[it.y][it.x] = light_level(source.strength, it.x, it.y); - has_light.push_back({it.x, it.y}); - } - } - } - void LightRender::render_square_light(LightSource source, Point at, PointList &has_light) { for(matrix::in_box it{$lightmap, at.x, at.y, (size_t)floor(source.radius)}; it.next();) { if($paths.$paths[it.y][it.x] != WALL_PATH_LIMIT) { - $lightmap[it.y][it.x] = light_level(source.strength, it.x, it.y); + $lightmap[it.y][it.x] = light_level(source.strength, it.distance(), it.x, it.y); has_light.push_back({it.x, it.y}); } } @@ -38,26 +19,22 @@ namespace lighting { clear_light_target(at); PointList has_light; - if(source.radius < 1.5f) { - render_compass_light(source, at, has_light); - } else if(source.radius < 2.0f) { - render_square_light(source, at, has_light); - } else { - render_circle_light(source, at, has_light); - } + render_square_light(source, at, has_light); const int wall_light = source.strength + WALL_LIGHT_LEVEL; for(auto point : has_light) { for(matrix::compass it{$lightmap, point.x, point.y}; it.next();) { if($paths.$paths[it.y][it.x] == WALL_PATH_LIMIT) { - $lightmap[it.y][it.x] = light_level(wall_light, point.x, point.y); + // BUG: include the distance in the list of walls to light + // so that they will be closer to the light level at that point + $lightmap[it.y][it.x] = light_level(wall_light, 1.0f, point.x, point.y); } } } } - int LightRender::light_level(int level, size_t x, size_t y) { - size_t at = level + $paths.$paths[y][x]; + int LightRender::light_level(int level, float distance, size_t x, size_t y) { + size_t at = level + ceil(distance); int cur_level = $lightmap[y][x]; int new_level = at < lighting::LEVELS.size() ? lighting::LEVELS[at] : lighting::MIN; return cur_level < new_level ? new_level : cur_level; diff --git a/lights.hpp b/lights.hpp index a7c9572..9a018ef 100644 --- a/lights.hpp +++ b/lights.hpp @@ -49,7 +49,7 @@ namespace lighting { void clear_light_target(const Point &at); void path_light(Matrix &walls); void light_box(LightSource source, Point from, Point &min_out, Point &max_out); - int light_level(int level, size_t x, size_t y); + int light_level(int level, float distance, size_t x, size_t y); void render_light(LightSource source, Point at); void render_square_light(LightSource source, Point at, PointList &has_light); void render_compass_light(LightSource source, Point at, PointList &has_light); diff --git a/main.cpp b/main.cpp index 2d138fd..d5af73a 100644 --- a/main.cpp +++ b/main.cpp @@ -33,7 +33,7 @@ void configure_world(DinkyECS::World &world, Map &game_map) { world.set(player.entity, {100, 10}); world.set(player.entity, {config.PLAYER_TILE}); world.set(player.entity, {5}); - world.set(player.entity, {6,2.1}); + world.set(player.entity, {6,1.0}); auto enemy = world.entity(); world.set(enemy, {game_map.place_entity(1)}); @@ -55,7 +55,7 @@ void configure_world(DinkyECS::World &world, Map &game_map) { auto wall_torch = world.entity(); world.set(wall_torch, {game_map.place_entity(4)}); - world.set(wall_torch, {3,2.4}); + world.set(wall_torch, {4,3}); world.set(wall_torch, {"☀"}); } diff --git a/matrix.cpp b/matrix.cpp index f79df5e..1e9a748 100644 --- a/matrix.cpp +++ b/matrix.cpp @@ -53,9 +53,11 @@ namespace matrix { return at_end(y, height); } - in_box::in_box(Matrix &mat, size_t from_x, size_t from_y, size_t size) { - size_t h = mat.size(); - size_t w = mat[0].size(); + in_box::in_box(Matrix &mat, size_t at_x, size_t at_y, size_t size) : + from_x(at_x), from_y(at_y) + { + size_t h = matrix::height(mat); + size_t w = matrix::width(mat); // keeps it from going below zero // need extra -1 to compensate for the first next() @@ -78,9 +80,17 @@ namespace matrix { // if x==0 then this moves it to min_x x = max(x, left); // and done + return at_end(y, bottom); } + float in_box::distance() { + int dx = from_x - x; + int dy = from_y - y; + + return sqrt((dx * dx) + (dy * dy)); + } + void in_box::dump() { println("BOX: x={},y={}; left={},right={}; top={},bottom={}", x, y, left, right, top, bottom); diff --git a/matrix.hpp b/matrix.hpp index 9482f1f..66335d6 100644 --- a/matrix.hpp +++ b/matrix.hpp @@ -37,6 +37,8 @@ namespace matrix { }; struct in_box { + size_t from_x; + size_t from_y; size_t x = 0; // these are set in constructor size_t y = 0; // again, no fancy ~ trick needed size_t left = 0; @@ -45,6 +47,7 @@ namespace matrix { size_t bottom = 0; in_box(Matrix &mat, size_t x, size_t y, size_t size); + float distance(); bool next(); void dump(); }; diff --git a/systems.cpp b/systems.cpp index 96b7db3..6ee4796 100644 --- a/systems.cpp +++ b/systems.cpp @@ -143,8 +143,8 @@ void System::collision(DinkyECS::World &world, Player &player) { world.send(Events::GUI::LOOT, entity, loot); inventory.gold += loot.amount; - light.strength = 4; - light.radius = 2.3; + light.strength = 5; + light.radius = 2; collider.remove(loot_pos.location); } else { println("UNKNOWN COLLISION TYPE {}", entity); diff --git a/tests/lighting.cpp b/tests/lighting.cpp index f150d21..e08ea9f 100644 --- a/tests/lighting.cpp +++ b/tests/lighting.cpp @@ -10,38 +10,36 @@ using namespace lighting; TEST_CASE("lighting a map works", "[lighting]") { - for(int i = 0; i < 5; i++) { - Map map(20+i,23+i); - WorldBuilder builder(map); - builder.generate(); + Map map(20,23); + WorldBuilder builder(map); + builder.generate(); - Point light1 = map.place_entity(0); - Point light2 = map.place_entity(1); - LightSource source1{7,1}; - LightSource source2{3,2}; + Point light1 = map.place_entity(0); + Point light2 = map.place_entity(1); + LightSource source1{0,2}; + LightSource source2{1,3}; - LightRender lr(map.width(), map.height()); + LightRender lr(map.width(), map.height()); - lr.reset_light(); + lr.reset_light(); - lr.set_light_target(light1); - lr.set_light_target(light2); + lr.set_light_target(light1); + lr.set_light_target(light2); - lr.path_light(map.walls()); + lr.path_light(map.walls()); - lr.render_light(source1, light1); - lr.render_light(source2, light2); + lr.render_light(source1, light1); + lr.render_light(source2, light2); - lr.clear_light_target(light1); - lr.clear_light_target(light2); + lr.clear_light_target(light1); + lr.clear_light_target(light2); - Matrix &lighting = lr.lighting(); + Matrix &lighting = lr.lighting(); - //matrix::dump("WALLS=====", map.walls()); - //matrix::dump("LIGHT PATHS======", lr.$paths.$paths); + matrix::dump("WALLS=====", map.walls(), light1.x, light1.y); + matrix::dump("LIGHTING======", lighting, light1.x, light1.y); - // confirm light is set at least at and around the two points - REQUIRE(lighting[light1.y][light1.x] == lighting::LEVELS[source1.strength]); - REQUIRE(lighting[light2.y][light2.x] == lighting::LEVELS[source2.strength]); - } + // confirm light is set at least at and around the two points + REQUIRE(lighting[light1.y][light1.x] == lighting::LEVELS[source1.strength]); + REQUIRE(lighting[light2.y][light2.x] == lighting::LEVELS[source2.strength]); } diff --git a/tests/matrix.cpp b/tests/matrix.cpp index 360651f..4d57e67 100644 --- a/tests/matrix.cpp +++ b/tests/matrix.cpp @@ -101,6 +101,27 @@ TEST_CASE("thash matrix iterators", "[matrix]") { } } +TEST_CASE("thrash box distance iterators", "[matrix:distance]") { + size_t width = Random::uniform(10, 21); + size_t height = Random::uniform(10, 25); + + Matrix result(height, matrix::Row(width)); + matrix::assign(result, 0); + + size_t size = Random::uniform(4, 10); + + Point target{width/2, height/2}; + matrix::in_box box{result, target.x, target.y, size}; + while(box.next()) { + result[box.y][box.x] = box.distance(); + } + + matrix::dump(format("MAP {}x{} @ {},{}; BOX {}x{}; size: {}", + matrix::width(result), matrix::height(result), + target.x, target.y, box.right - box.left, box.bottom - box.top, size), + result, target.x, target.y); +} + TEST_CASE("thrash box iterators", "[matrix]") { for(int count = 0; count < 20; count++) { size_t width = Random::uniform(1, 25); @@ -250,7 +271,7 @@ TEST_CASE("prototype circle algorithm", "[matrix:circle]") { } } - matrix::dump(format("RESULT AFTER CIRCLE radius {}", radius), result, start.x, start.y); + // matrix::dump(format("RESULT AFTER CIRCLE radius {}", radius), result, start.x, start.y); } } }