You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
106 lines
3.1 KiB
TypeScript
106 lines
3.1 KiB
TypeScript
import type { ComputedRef } from 'vue'
|
|
import { BLOCK_SIZE, STAGE_WIDTH, STAGE_HEIGHT } from '../level/def'
|
|
|
|
export default function useLightMap(
|
|
ctx: CanvasRenderingContext2D,
|
|
x: ComputedRef<number>,
|
|
y: ComputedRef<number>,
|
|
tx: ComputedRef<number>,
|
|
ty: ComputedRef<number>,
|
|
time: ComputedRef<number>,
|
|
lightBarrier: ComputedRef<number[]>,
|
|
) {
|
|
const W = ((STAGE_WIDTH + 2) * BLOCK_SIZE)
|
|
const H = ((STAGE_HEIGHT + 2) * BLOCK_SIZE)
|
|
const B = BLOCK_SIZE - 4 // no idea why there is a difference, but it is 4px
|
|
|
|
const playerX = (W - B) / 2 + B / 4
|
|
const playerY = H / 2 - B / 2
|
|
const playerLightSize = B * 1.8
|
|
|
|
function getAmbientLightColor() {
|
|
const t = time.value
|
|
|
|
// Night time (pale bluish dark: hslpicker.com/#2b293d )
|
|
if (t > 900 || t < 100) {
|
|
return `hsl(245, 20%, 20%)`
|
|
}
|
|
// Morning hours (gradually more reddish hue)
|
|
if (t < 250) {
|
|
const s = Math.round((t - 100) / 1.5) // 0-100%
|
|
const l = Math.round((t - 100) / 1.875) + 20 // 20-100%
|
|
return `hsl(0, ${s}%, ${l}%)`
|
|
}
|
|
// Evening hours (from neutral white to bluish hue with low saturation)
|
|
if (t > 700) {
|
|
const s = 100 - Math.round((t - 700) / 2.5) // 100-20%
|
|
return `hsl(245, ${s}%, ${s}%)`
|
|
}
|
|
// day (neutral white)
|
|
return `hsl(0, 0%, 100%)`
|
|
}
|
|
|
|
function drawPlayerLight(sizeMul:number) {
|
|
const playerLight = ctx.createRadialGradient(
|
|
playerX - tx.value, playerY - ty.value, 0,
|
|
playerX - tx.value, playerY - ty.value, playerLightSize * sizeMul
|
|
)
|
|
|
|
// Add color stops: white in the center to transparent white
|
|
playerLight.addColorStop(0.0, "#FFFF");
|
|
playerLight.addColorStop(1, "#FFF0");
|
|
|
|
// Set the fill style and draw a rectangle
|
|
ctx.fillStyle = playerLight;
|
|
ctx.fillRect(0, 0, W, H)
|
|
}
|
|
|
|
function drawLights() {
|
|
// used for everything above ground
|
|
const ambientLight = getAmbientLightColor()
|
|
const surroundingLight = ambientLight.slice(-2)
|
|
const barrier = lightBarrier.value
|
|
|
|
ctx.fillStyle = ambientLight
|
|
for (let col = 0; col < W / B; col++) {
|
|
const level = (barrier[col] - y.value) * B
|
|
const sw = B
|
|
const sh = level
|
|
const sx = col * sw
|
|
const sy = 0
|
|
|
|
ctx.fillRect(sx, sy, sw, sh)
|
|
}
|
|
|
|
// make light columns wider to illuminate surrounding blocks
|
|
const extra = Math.floor(B / 2)
|
|
const reflectedLight = ambientLight.slice(0, -1) + ', 50%)'
|
|
ctx.fillStyle = reflectedLight
|
|
for (let col = 0; col < W / B; col++) {
|
|
const level = (barrier[col] - y.value) * B
|
|
const sw = B
|
|
const sh = level
|
|
const sx = col * sw
|
|
const sy = 0
|
|
|
|
ctx.fillRect(sx - extra, sy - extra, sw + extra * 2, sh + extra * 2)
|
|
}
|
|
|
|
// TODO: draw light for candles and torches
|
|
}
|
|
|
|
return function update() {
|
|
// first, throw the world in complete darkness
|
|
ctx.fillStyle = '#000'
|
|
ctx.fillRect(0, 0, W, H)
|
|
|
|
// second, find and bring light into the world
|
|
drawLights()
|
|
|
|
// finally, draw the players light
|
|
// with a size multiplicator which might be later used to
|
|
// simulate greater illumination with candles or torches
|
|
drawPlayerLight(1)
|
|
}
|
|
}
|