Skip to content

Instantly share code, notes, and snippets.

@anderoonies
Created November 15, 2020 04:19
Show Gist options
  • Save anderoonies/141a6991f2c0831f4a3f978cea788e07 to your computer and use it in GitHub Desktop.
Save anderoonies/141a6991f2c0831f4a3f978cea788e07 to your computer and use it in GitHub Desktop.
const lightDungeon = ({ dungeon, colors }) => {
// initialize an empty light map, which is mutated in `paintLight`
let lightMap = gridFromDimensions(HEIGHT, WIDTH, undefined);
for (let row = 0; row < HEIGHT; row++) {
for (let col = 0; col < WIDTH; col++) {
// if a cell is a light source, calculate the light data
// it creates and store it in `lightMap`
if (dungeon[row][col].glowLight) {
lightMap = paintLight({
lightSource: dungeon[row][col].glowLight,
dungeon,
row,
col,
lightMap
});
}
}
}
// map through the populated `lightMap`, updating the colors of every cell based
// on lighting data accumulated above
for (let row = 0; row < HEIGHT; row++) {
for (let col = 0; col < WIDTH; col++) {
if (lightMap[row][col]) {
colors[row][col].fg = Color({
r: colors[row][col].fg.red() + lightMap[row][col].r,
g: colors[row][col].fg.green() + lightMap[row][col].g,
b: colors[row][col].fg.blue() + lightMap[row][col].b
});
colors[row][col].bg = Color({
r: colors[row][col].bg.red() + lightMap[row][col].r,
g: colors[row][col].bg.green() + lightMap[row][col].g,
b: colors[row][col].bg.blue() + lightMap[row][col].b
});
}
}
}
return colors;
};
const paintLight = ({ lightSource, row, col, dungeon, lightMap }) => {
// calculate the radius of the light's effect
const radius = Math.floor(
randomRange(lightSource.minRadius, lightSource.maxRadius) / 100
);
// generate a light hyperspace, where calculations will be performed
let lightHyperspace = gridFromDimensions(HEIGHT, WIDTH, undefined);
// initialize an empty circle of light in hyperspace
for (
let i = Math.max(0, row - radius);
i < HEIGHT && i < row + radius;
i++
) {
for (
let j = Math.max(0, col - radius);
j < WIDTH && j < col + radius;
j++
) {
lightHyperspace[i][j] = 0;
}
}
// get a FOV mask, which zero's out any cells which cannot be reached
// by light
lightHyperspace = getFOVMask({
grid: lightHyperspace,
dungeon,
row,
col,
radius
});
// generate color components
const randComponent = randomRange(0, lightSource.color.variance.overall);
const colorComponents = {
r:
randComponent +
lightSource.color.baseColor.r +
randomRange(0, lightSource.color.variance.r),
g:
randComponent +
lightSource.color.baseColor.g +
randomRange(0, lightSource.color.variance.g),
b:
randComponent +
lightSource.color.baseColor.b +
randomRange(0, lightSource.color.variance.b)
};
let lightMultiplier;
const fadeToPercent = lightSource.fade;
for (
let i = Math.max(0, row - radius);
i < HEIGHT && i < row + radius;
i++
) {
for (
let j = Math.max(0, col - radius);
j < WIDTH && j < col + radius;
j++
) {
if (lightHyperspace[i][j]) {
// if the light hyperspace is non-zero (it's non-obstructed),
// then calculate the amount of light that reaches here
// based on the distance from the source and the fade %.
lightMultiplier =
100 -
((100 - fadeToPercent) *
Math.sqrt((i - row) ** 2 + (j - col) ** 2)) /
radius;
if (lightMap[i][j] === undefined) {
lightMap[i][j] = { r: 0, g: 0, b: 0 };
}
// for each color component, store lightMultiplier * component
Object.entries(colorComponents).forEach(
([component, value]) => {
lightMap[i][j][component] +=
(value * lightMultiplier) / 255;
}
);
}
}
}
if (lightMap[row][col] === undefined) {
lightMap[row][col] = { r: 0, g: 0, b: 0 };
}
// brighten the source of light itself!
lightMap[row][col].r += colorComponents.r;
lightMap[row][col].g += colorComponents.g;
lightMap[row][col].b += colorComponents.b;
return lightMap;
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment