Better lighting and a circle algorithm that works more reliably.
This commit is contained in:
parent
03fe9b3d01
commit
35f2defc11
9 changed files with 97 additions and 87 deletions
|
@ -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"
|
||||
}
|
||||
}
|
||||
|
|
40
lights.cpp
40
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<Point> 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) {
|
||||
|
|
19
lights.hpp
19
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<int, 10> 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; }
|
||||
};
|
||||
}
|
||||
|
|
4
main.cpp
4
main.cpp
|
@ -46,7 +46,7 @@ void configure_world(DinkyECS::World &world, Map &game_map) {
|
|||
world.set<Motion>(enemy2, {0,0});
|
||||
world.set<Combat>(enemy2, {20, 10});
|
||||
world.set<Tile>(enemy2, {"*"});
|
||||
world.set<LightSource>(enemy2, {7,1});
|
||||
world.set<LightSource>(enemy2, {7,0});
|
||||
|
||||
auto gold = world.entity();
|
||||
world.set<Position>(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<Position>(wall_torch, {game_map.place_entity(4)});
|
||||
world.set<LightSource>(wall_torch, {2,3});
|
||||
world.set<LightSource>(wall_torch, {3,4});
|
||||
world.set<Tile>(wall_torch, {"☀"});
|
||||
}
|
||||
|
||||
|
|
48
matrix.cpp
48
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;
|
||||
|
|
14
matrix.hpp
14
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();
|
||||
|
|
13
systems.cpp
13
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);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -226,22 +226,28 @@ TEST_CASE("prototype line algorithm", "[matrix:line]") {
|
|||
}
|
||||
|
||||
TEST_CASE("prototype circle algorithm", "[matrix:circle]") {
|
||||
size_t width = Random::uniform<size_t>(10, 13);
|
||||
size_t height = Random::uniform<size_t>(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<size_t>(10, 13);
|
||||
size_t height = Random::uniform<size_t>(10, 15);
|
||||
int pos_mod = Random::uniform<int>(-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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue