time-related brightness controlled by light-map

main
Norman Köhring 1 year ago
parent 3b7ee96f62
commit d75f862380

@ -11,13 +11,13 @@ import useInput from './util/useInput'
import usePlayer from './util/usePlayer'
import useLightMap from './util/useLightMap'
const { updateTime, time, clock } = useTime()
const { updateTime, time, timeOfDay, clock } = useTime()
const { player, direction, dx, dy } = usePlayer()
const { inputX, inputY, running, paused, help, inventory } = useInput()
const level = createLevel(STAGE_WIDTH + 2, STAGE_HEIGHT + 2)
const lightMapEl = ref<HTMLCanvasElement | undefined>(undefined)
let lightMap: ReturnType<typeof useLightMap>
let updateLightMap: ReturnType<typeof useLightMap>
player.inventory.push(
{ name: 'Shovel', type: 'tool', icon: 'shovel', quality: 'bronze', amount: 1 },
@ -144,7 +144,7 @@ const move = (thisTick: number): void => {
y.value += dy_ * fallMultiplier
}
lightMap.draw(floorX.value, floorY.value, tx.value, ty.value, time.value)
updateLightMap()
lastTick = thisTick
}
@ -171,14 +171,14 @@ onMounted(() => {
canvas.width = (BLOCK_SIZE + 2) * STAGE_WIDTH
const ctx = canvas.getContext('2d')!
lightMap = useLightMap(ctx)
updateLightMap = useLightMap(ctx, floorX, floorY, tx, ty, time, lightBarrier)
lastTick = performance.now()
move(lastTick)
})
</script>
<template>
<div id="field">
<div id="field" :class="timeOfDay">
<div id="blocks" :style="{transform: `translate(${tx}px, ${ty}px)`}">
<template v-for="(row, y) in rows">

@ -1,3 +1,6 @@
.block, #player {
transition: filter .5s linear;
}
.block {
flex: 0 0 auto;
width: var(--block-size);
@ -42,44 +45,15 @@
.block.cave { background-color: #000; }
#field .block:hover { outline: 1px solid white; z-index: 10; }
.block.sun-3 { filter: brightness(1.0); }
.block.sun-2 { filter: brightness(0.4); }
.block.sun-1 { filter: brightness(0.2); }
.block.sun-0 { filter: brightness(0.0); }
.morning0 .block, .morning0 #player {filter: saturate(50%) brightness(0.6) hue-rotate(-10deg); }
.morning1 .block, .morning1 #player { filter: saturate(100%) brightness(0.8) hue-rotate(-20deg); }
.morning2 .block, .morning2 #player { filter: saturate(200%) hue-rotate(-30deg); }
.morning0 .block.sun-2 { filter: brightness(0); }
.morning1 .block.sun-2 { filter: saturate(100%) brightness(0.2) hue-rotate(-20deg); }
.morning2 .block.sun-2 { filter: saturate(200%) brightness(0.4) hue-rotate(-30deg); }
.morning0 .block.sun-1,
.morning1 .block.sun-1 { filter: brightness(0); }
.morning2 .block.sun-1 { filter: saturate(200%) brightness(0.2) hue-rotate(-30deg); }
.evening0 .block, .evening0 #player { filter: brightness(0.8) hue-rotate(-10deg); }
.evening1 .block, .evening1 #player { filter: brightness(0.6) hue-rotate(-20deg); }
.evening2 .block, .evening2 #player { filter: brightness(0.4) hue-rotate(-10deg) saturate(50%); }
.evening0 .block.sun-2 { filter: brightness(0.3) hue-rotate(-10deg); }
.evening1 .block.sun-2 { filter: brightness(0.2) hue-rotate(-20deg); }
.evening2 .block.sun-2 { filter: brightness(0); }
.evening0 .block.sun-1 { filter: brightness(0.2) hue-rotate(-10deg); }
.evening1 .block.sun-1, .evening2 .block.sun-1 { filter: brightness(0); }
.morning0 .block, .morning0 #player {filter: saturate(50%); }
.morning1 .block, .morning1 #player { filter: saturate(100%); }
.morning2 .block, .morning2 #player { filter: saturate(120%); }
.night .block, .night #player { filter: brightness(0.3) saturate(30%); }
.evening0 .block, .evening0 #player { filter: saturate(90%); }
.evening1 .block, .evening1 #player { filter: saturate(70%); }
.evening2 .block, .evening2 #player { filter: saturate(50%); }
.block.sun-0,
.morning0 .block.sun-0,
.morning1 .block.sun-0,
.morning2 .block.sun-0,
.evening0 .block.sun-0,
.evening1 .block.sun-0,
.evening2 .block.sun-0,
.night .block.sun-0 { filter: brightness(0); }
.night .block, .night #player { filter: saturate(30%); }
#blocks {
position: absolute;
@ -98,4 +72,5 @@
width: calc(100% + var(--block-size) * 2);
height: calc(100% + var(--block-size) * 2);
mix-blend-mode: multiply;
pointer-events: none;
}

@ -13,6 +13,7 @@ export type Block = {
walkable: boolean,
climbable?: boolean,
transparent?: boolean,
illuminated?: boolean,
}
export type BlockType =
@ -22,7 +23,7 @@ export type BlockType =
| 'bedrock' | 'cave'
export const blockTypes: Record<BlockType, Block> = {
air: { type: 'air', hp: Infinity, walkable: true, transparent: true },
air: { type: 'air', hp: Infinity, walkable: true, transparent: true, illuminated: true },
grass: { type: 'grass', hp: 5, walkable: false },
treeCrown: { type: 'treeCrown', hp: 1, walkable: true, transparent: true },

@ -1,6 +1,15 @@
import type { ComputedRef } from 'vue'
import { BLOCK_SIZE, STAGE_WIDTH, STAGE_HEIGHT } from '../level/def'
export default function useLightMap(ctx: CanvasRenderingContext2D) {
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)
@ -8,15 +17,15 @@ export default function useLightMap(ctx: CanvasRenderingContext2D) {
const playerY = H / 2 - BLOCK_SIZE / 2
const playerLightSize = BLOCK_SIZE * 1.8
function drawPlayerLight(tx: number, ty: number) {
function drawPlayerLight(sizeMul:number) {
const playerLight = ctx.createRadialGradient(
playerX - tx, playerY - ty, 0,
playerX - tx, playerY - ty, playerLightSize
playerX - tx.value, playerY - ty.value, 0,
playerX - tx.value, playerY - ty.value, playerLightSize * sizeMul
)
// Add three color stops
playerLight.addColorStop(0.0, "#FFCF");
playerLight.addColorStop(1, "#FFC0");
playerLight.addColorStop(0.0, "#FFFF");
playerLight.addColorStop(1, "#FFF0");
// Set the fill style and draw a rectangle
ctx.fillStyle = playerLight;
@ -24,21 +33,22 @@ export default function useLightMap(ctx: CanvasRenderingContext2D) {
}
// TODO: support light barrier
function draw(x:number, y:number, tx:number, ty:number, time:number) {
if (time > 900 || time < 100) {
return function update() {
const t = time.value
if (t > 900 || t < 100) {
ctx.fillStyle = `hsl(0, 0%, 20%)`
} else if (time < 250) {
const s = Math.round((time - 100) / 1.5) // 0-100%
const l = Math.round((time - 100) / 1.875) + 20 // 20-100%
} else if (t < 250) {
const s = Math.round((t - 100) / 1.5) // 0-100%
const l = Math.round((t - 100) / 1.875) + 20 // 20-100%
ctx.fillStyle = `hsl(0, ${s}%, ${l}%)`
// } else if (t < 700) {
// ctx.fillStyle = `hsl(0, ${}%, ${}%)`
} else if (t > 700) {
const s = 100 - Math.round((t - 700) / 2.5) // 100-20%
ctx.fillStyle = `hsl(245, ${s}%, ${s}%)`
} else {
ctx.fillStyle = `hsl(0, 0%, 100%)`
}
ctx.fillRect(0, 0, W, H)
drawPlayerLight(tx, ty)
drawPlayerLight(1)
}
return { draw }
}

@ -2,7 +2,7 @@ import { ref, computed } from 'vue'
export default function useTime() {
// the day is split in 1000 parts, so we start in the morning
const time = ref(250)
const time = ref(230)
function updateTime() {
time.value = (time.value + 0.1) % 1000

Loading…
Cancel
Save