diff --git a/assets/tiles.json b/assets/tiles.json index f251855..462e312 100644 --- a/assets/tiles.json +++ b/assets/tiles.json @@ -1,32 +1,32 @@ { "WALL_TILE": { "foreground": [230, 20, 0], - "background": [230, 20, 0], + "background": [230, 20, 2], "display": "\ua5b8" }, "FLOOR_TILE": { "foreground": [80, 100, 0], - "background": [30, 20, 0], + "background": [30, 20, 2], "display":"\u2849" }, "PLAYER_TILE": { "foreground": [255, 200, 0], - "background": [30, 20, 0], + "background": [30, 20, 2], "display":"\ua66b" }, "ENEMY_TILE": { "foreground": [255, 200, 0], - "background": [30, 20, 0], + "background": [30, 20, 2], "display":"\u1d5c" }, "BG_TILE": { "foreground": [230, 20, 0], - "background": [230, 20, 0], + "background": [230, 20, 2], "display":"█" }, "WATER_TILE": { "foreground": [132, 200, 0], - "background": [147, 220, 0], + "background": [147, 220, 2], "display":"\u224b" } } diff --git a/lights.cpp b/lights.cpp index a77f6b4..6b86c62 100644 --- a/lights.cpp +++ b/lights.cpp @@ -5,18 +5,50 @@ using std::vector; namespace lighting { - void LightRender::render_light(LightSource source, Point at) { - Point min, max; - clear_light_target(at); - vector has_light; + void LightRender::render_circle_light(LightSource source, Point at, PointList &has_light) { + for(matrix::circle it{at, source.distance + 1}; it.next();) { + for(int x = it.left; x < it.right; x++) { + if(matrix::inbounds($paths.$paths, x, it.y) && + $paths.$paths[it.y][x] != WALL_PATH_LIMIT) + { + $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)source.distance}; 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_light(LightSource source, Point at) { + Point min, max; + clear_light_target(at); + PointList has_light; + + if(source.distance == 0) { + render_compass_light(source, at, has_light); + } else if(source.distance == 1) { + render_square_light(source, at, has_light); + } else { + render_circle_light(source, at, has_light); + } const int wall_light = source.strength + WALL_LIGHT_LEVEL; for(auto point : has_light) { diff --git a/lights.hpp b/lights.hpp index 7a4abe3..48e3ee8 100644 --- a/lights.hpp +++ b/lights.hpp @@ -13,20 +13,20 @@ namespace lighting { int distance = 1; // higher is farther, in squares }; - const int MIN = 40; - const int MAX = 220; - const int MID = 140; + const int MIN = 50; + const int MAX = 170; + const int MID = 130; const std::array LEVELS{ MAX, - 200, - 180, 160, + 150, + 140, MID, 120, - 100, - 80, - 60, + 110, + 90, + 70, MIN, }; @@ -51,6 +51,9 @@ namespace lighting { void light_box(LightSource source, Point from, Point &min_out, Point &max_out); int light_level(int level, 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); + void render_circle_light(LightSource source, Point at, PointList &has_light); Matrix &lighting() { return $lightmap; } }; } diff --git a/main.cpp b/main.cpp index 6e9af5e..b00c5a6 100644 --- a/main.cpp +++ b/main.cpp @@ -46,7 +46,7 @@ void configure_world(DinkyECS::World &world, Map &game_map) { world.set(enemy2, {0,0}); world.set(enemy2, {20, 10}); world.set(enemy2, {"*"}); - world.set(enemy2, {7,1}); + world.set(enemy2, {7,0}); auto gold = world.entity(); world.set(gold, {game_map.place_entity(3)}); @@ -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, {2,3}); + world.set(wall_torch, {3,4}); world.set(wall_torch, {"☀"}); } diff --git a/matrix.cpp b/matrix.cpp index eb6996a..0a4e6d6 100644 --- a/matrix.cpp +++ b/matrix.cpp @@ -183,48 +183,18 @@ namespace matrix { circle::circle(Point center, int radius) : center(center), radius(radius) { - xi = 0; - yi = radius; - m = 5 - 4 * radius; - step = 0; - } - - void circle::update() { - if(m > 0) { - yi--; - m -= 8 * yi; - } - xi++; - m += 8 * xi + 4; + top = max(center.y - radius, size_t(0)); + bottom = center.y + radius; + y = top; } bool circle::next() { - if(xi <= yi) { - switch(step % 4) { - case 0: - x0 = center.x - xi; - y = center.y - yi; - x1 = center.x + xi; - break; - case 1: - x0 = center.x - yi; - y = center.y - xi; - x1 = center.x + yi; - break; - case 2: - x0 = center.x - yi; - y = center.y + xi; - x1 = center.x + yi; - break; - case 3: - x0 = center.x - xi; - y = center.y + yi; - x1 = center.x + xi; - update(); - break; - } - - step++; + y++; + if(y <= bottom) { + dy = y - center.y; + dx = floor(sqrt(radius * radius - dy * dy)); + left = center.x - dx; + right = center.x + dx; return true; } else { return false; diff --git a/matrix.hpp b/matrix.hpp index c99d935..b1715bf 100644 --- a/matrix.hpp +++ b/matrix.hpp @@ -120,13 +120,13 @@ namespace matrix { struct circle { Point center; int radius = 0; - int xi = 0; - int yi = 0; - int m = 0; - int step = 0; - int x0; - int x1; - int y; + int y = 0; + int dx = 0; + int dy = 0; + int left = 0; + int right = 0; + int top = 0; + int bottom = 0; circle(Point center, int radius); void update(); diff --git a/systems.cpp b/systems.cpp index 77cdae2..0c93d80 100644 --- a/systems.cpp +++ b/systems.cpp @@ -189,20 +189,19 @@ void System::draw_map(DinkyECS::World &world, Map &game_map, const Matrix &light for(size_t x = 0; x < end_x; ++x) { const TileCell& tile = tiles.at(start.x+x, start.y+y); int light_value = debug.LIGHT ? 160 : lighting[start.y+y][start.x+x]; + int dnum = debug.PATHS ? paths[start.y+y][start.x+x] : WALL_PATH_LIMIT; - if(debug.PATHS) { - int dnum = paths[start.y+y][start.x+x]; - string num = format("{:x}", dnum); - num = num.size() > 2 ? "*" : num; + if(debug.PATHS && dnum != WALL_PATH_LIMIT) { + string num = dnum > 15 ? "*" : format("{:x}", dnum); canvas.DrawText(x * 2, y * 4, num, [dnum, light_value](auto &pixel) { pixel.foreground_color = Color::HSV(dnum * 20, 150, 200); - pixel.background_color = Color::HSV(30, 20, light_value / 5); + pixel.background_color = Color::HSV(30, 20, light_value / 2); }); } else { canvas.DrawText(x * 2, y * 4, tile.display, [tile, light_value](auto &pixel) { - pixel.foreground_color = Color::HSV(tile.fg_h, tile.fg_s, light_value); - pixel.background_color = Color::HSV(tile.bg_h, tile.bg_s, light_value / 2); + pixel.foreground_color = Color::HSV(tile.fg_h, tile.fg_s, light_value - tile.fg_v); + pixel.background_color = Color::HSV(tile.bg_h, tile.bg_s, light_value / tile.bg_v); }); } } diff --git a/tests/matrix.cpp b/tests/matrix.cpp index 10b20f7..1e2421b 100644 --- a/tests/matrix.cpp +++ b/tests/matrix.cpp @@ -226,22 +226,28 @@ TEST_CASE("prototype line algorithm", "[matrix:line]") { } TEST_CASE("prototype circle algorithm", "[matrix:circle]") { - size_t width = Random::uniform(10, 13); - size_t height = Random::uniform(10, 15); - Map map(width,height); - // create a target for the paths - Point start{.x=map.width() / 2, .y=map.height()/2}; + for(int count = 0; count < 20; count++) { + size_t width = Random::uniform(10, 13); + size_t height = Random::uniform(10, 15); + int pos_mod = Random::uniform(-3,3); + Map map(width,height); + // create a target for the paths + Point start{.x=map.width() / 2 + pos_mod, .y=map.height()/2 + pos_mod}; - for(int radius = 2; radius < 5; radius++) { - // use an empty map - Matrix result = map.walls(); + for(int radius = 2; radius < 10; radius++) { + // use an empty map + Matrix result = map.walls(); - for(matrix::circle it{start, radius}; it.next();) { - for(int i = it.x0; i < it.x1; i++) { - result[it.y][i] += 1; + for(matrix::circle it{start, radius}; it.next();) { + for(int x = it.left; x < it.right; x++) { + // println("top={}, bottom={}, center.y={}, dy={}, left={}, right={}, x={}, y={}", it.top, it.bottom, it.center.y, it.dy, it.left, it.right, x, it.y); + if(matrix::inbounds(result, x, it.y)) { + result[it.y][x] += 1; + } + } } - } - // matrix::dump("RESULT AFTER CIRCLE", result, start.x, start.y); + // matrix::dump("RESULT AFTER CIRCLE", result, start.x, start.y); + } } } diff --git a/worldbuilder.cpp b/worldbuilder.cpp index 81d0564..6c0d666 100644 --- a/worldbuilder.cpp +++ b/worldbuilder.cpp @@ -143,7 +143,7 @@ void WorldBuilder::generate() { Point center = $map.place_entity(1); for(matrix::circle it{center, 3}; it.next();) { - for(int x = it.x0; x < it.x1; x++) { + for(int x = it.left; x < it.right; x++) { if($map.inmap(x, it.y) && !$map.iswall(x, it.y)) { $map.$tiles.set_tile(x, it.y, "WATER_TILE"); }