time-related brightness controlled by light-map
This commit is contained in:
parent
3b7ee96f62
commit
d75f862380
5 changed files with 45 additions and 59 deletions
10
src/App.vue
10
src/App.vue
|
@ -11,13 +11,13 @@ import useInput from './util/useInput'
|
||||||
import usePlayer from './util/usePlayer'
|
import usePlayer from './util/usePlayer'
|
||||||
import useLightMap from './util/useLightMap'
|
import useLightMap from './util/useLightMap'
|
||||||
|
|
||||||
const { updateTime, time, clock } = useTime()
|
const { updateTime, time, timeOfDay, clock } = useTime()
|
||||||
const { player, direction, dx, dy } = usePlayer()
|
const { player, direction, dx, dy } = usePlayer()
|
||||||
const { inputX, inputY, running, paused, help, inventory } = useInput()
|
const { inputX, inputY, running, paused, help, inventory } = useInput()
|
||||||
const level = createLevel(STAGE_WIDTH + 2, STAGE_HEIGHT + 2)
|
const level = createLevel(STAGE_WIDTH + 2, STAGE_HEIGHT + 2)
|
||||||
|
|
||||||
const lightMapEl = ref<HTMLCanvasElement | undefined>(undefined)
|
const lightMapEl = ref<HTMLCanvasElement | undefined>(undefined)
|
||||||
let lightMap: ReturnType<typeof useLightMap>
|
let updateLightMap: ReturnType<typeof useLightMap>
|
||||||
|
|
||||||
player.inventory.push(
|
player.inventory.push(
|
||||||
{ name: 'Shovel', type: 'tool', icon: 'shovel', quality: 'bronze', amount: 1 },
|
{ name: 'Shovel', type: 'tool', icon: 'shovel', quality: 'bronze', amount: 1 },
|
||||||
|
@ -144,7 +144,7 @@ const move = (thisTick: number): void => {
|
||||||
y.value += dy_ * fallMultiplier
|
y.value += dy_ * fallMultiplier
|
||||||
}
|
}
|
||||||
|
|
||||||
lightMap.draw(floorX.value, floorY.value, tx.value, ty.value, time.value)
|
updateLightMap()
|
||||||
lastTick = thisTick
|
lastTick = thisTick
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -171,14 +171,14 @@ onMounted(() => {
|
||||||
canvas.width = (BLOCK_SIZE + 2) * STAGE_WIDTH
|
canvas.width = (BLOCK_SIZE + 2) * STAGE_WIDTH
|
||||||
const ctx = canvas.getContext('2d')!
|
const ctx = canvas.getContext('2d')!
|
||||||
|
|
||||||
lightMap = useLightMap(ctx)
|
updateLightMap = useLightMap(ctx, floorX, floorY, tx, ty, time, lightBarrier)
|
||||||
lastTick = performance.now()
|
lastTick = performance.now()
|
||||||
move(lastTick)
|
move(lastTick)
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div id="field">
|
<div id="field" :class="timeOfDay">
|
||||||
|
|
||||||
<div id="blocks" :style="{transform: `translate(${tx}px, ${ty}px)`}">
|
<div id="blocks" :style="{transform: `translate(${tx}px, ${ty}px)`}">
|
||||||
<template v-for="(row, y) in rows">
|
<template v-for="(row, y) in rows">
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
.block, #player {
|
||||||
|
transition: filter .5s linear;
|
||||||
|
}
|
||||||
.block {
|
.block {
|
||||||
flex: 0 0 auto;
|
flex: 0 0 auto;
|
||||||
width: var(--block-size);
|
width: var(--block-size);
|
||||||
|
@ -42,44 +45,15 @@
|
||||||
.block.cave { background-color: #000; }
|
.block.cave { background-color: #000; }
|
||||||
#field .block:hover { outline: 1px solid white; z-index: 10; }
|
#field .block:hover { outline: 1px solid white; z-index: 10; }
|
||||||
|
|
||||||
.block.sun-3 { filter: brightness(1.0); }
|
.morning0 .block, .morning0 #player {filter: saturate(50%); }
|
||||||
.block.sun-2 { filter: brightness(0.4); }
|
.morning1 .block, .morning1 #player { filter: saturate(100%); }
|
||||||
.block.sun-1 { filter: brightness(0.2); }
|
.morning2 .block, .morning2 #player { filter: saturate(120%); }
|
||||||
.block.sun-0 { filter: brightness(0.0); }
|
|
||||||
|
|
||||||
.morning0 .block, .morning0 #player {filter: saturate(50%) brightness(0.6) hue-rotate(-10deg); }
|
.evening0 .block, .evening0 #player { filter: saturate(90%); }
|
||||||
.morning1 .block, .morning1 #player { filter: saturate(100%) brightness(0.8) hue-rotate(-20deg); }
|
.evening1 .block, .evening1 #player { filter: saturate(70%); }
|
||||||
.morning2 .block, .morning2 #player { filter: saturate(200%) hue-rotate(-30deg); }
|
.evening2 .block, .evening2 #player { filter: saturate(50%); }
|
||||||
|
|
||||||
.morning0 .block.sun-2 { filter: brightness(0); }
|
.night .block, .night #player { filter: saturate(30%); }
|
||||||
.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); }
|
|
||||||
|
|
||||||
.night .block, .night #player { filter: brightness(0.3) saturate(30%); }
|
|
||||||
|
|
||||||
.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); }
|
|
||||||
|
|
||||||
#blocks {
|
#blocks {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
@ -98,4 +72,5 @@
|
||||||
width: calc(100% + var(--block-size) * 2);
|
width: calc(100% + var(--block-size) * 2);
|
||||||
height: calc(100% + var(--block-size) * 2);
|
height: calc(100% + var(--block-size) * 2);
|
||||||
mix-blend-mode: multiply;
|
mix-blend-mode: multiply;
|
||||||
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@ export type Block = {
|
||||||
walkable: boolean,
|
walkable: boolean,
|
||||||
climbable?: boolean,
|
climbable?: boolean,
|
||||||
transparent?: boolean,
|
transparent?: boolean,
|
||||||
|
illuminated?: boolean,
|
||||||
}
|
}
|
||||||
|
|
||||||
export type BlockType =
|
export type BlockType =
|
||||||
|
@ -22,7 +23,7 @@ export type BlockType =
|
||||||
| 'bedrock' | 'cave'
|
| 'bedrock' | 'cave'
|
||||||
|
|
||||||
export const blockTypes: Record<BlockType, Block> = {
|
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 },
|
grass: { type: 'grass', hp: 5, walkable: false },
|
||||||
|
|
||||||
treeCrown: { type: 'treeCrown', hp: 1, walkable: true, transparent: true },
|
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'
|
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 W = ((STAGE_WIDTH + 2) * BLOCK_SIZE)
|
||||||
const H = ((STAGE_HEIGHT + 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 playerY = H / 2 - BLOCK_SIZE / 2
|
||||||
const playerLightSize = BLOCK_SIZE * 1.8
|
const playerLightSize = BLOCK_SIZE * 1.8
|
||||||
|
|
||||||
function drawPlayerLight(tx: number, ty: number) {
|
function drawPlayerLight(sizeMul:number) {
|
||||||
const playerLight = ctx.createRadialGradient(
|
const playerLight = ctx.createRadialGradient(
|
||||||
playerX - tx, playerY - ty, 0,
|
playerX - tx.value, playerY - ty.value, 0,
|
||||||
playerX - tx, playerY - ty, playerLightSize
|
playerX - tx.value, playerY - ty.value, playerLightSize * sizeMul
|
||||||
)
|
)
|
||||||
|
|
||||||
// Add three color stops
|
// Add three color stops
|
||||||
playerLight.addColorStop(0.0, "#FFCF");
|
playerLight.addColorStop(0.0, "#FFFF");
|
||||||
playerLight.addColorStop(1, "#FFC0");
|
playerLight.addColorStop(1, "#FFF0");
|
||||||
|
|
||||||
// Set the fill style and draw a rectangle
|
// Set the fill style and draw a rectangle
|
||||||
ctx.fillStyle = playerLight;
|
ctx.fillStyle = playerLight;
|
||||||
|
@ -24,21 +33,22 @@ export default function useLightMap(ctx: CanvasRenderingContext2D) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: support light barrier
|
// TODO: support light barrier
|
||||||
function draw(x:number, y:number, tx:number, ty:number, time:number) {
|
return function update() {
|
||||||
if (time > 900 || time < 100) {
|
const t = time.value
|
||||||
|
|
||||||
|
if (t > 900 || t < 100) {
|
||||||
ctx.fillStyle = `hsl(0, 0%, 20%)`
|
ctx.fillStyle = `hsl(0, 0%, 20%)`
|
||||||
} else if (time < 250) {
|
} else if (t < 250) {
|
||||||
const s = Math.round((time - 100) / 1.5) // 0-100%
|
const s = Math.round((t - 100) / 1.5) // 0-100%
|
||||||
const l = Math.round((time - 100) / 1.875) + 20 // 20-100%
|
const l = Math.round((t - 100) / 1.875) + 20 // 20-100%
|
||||||
ctx.fillStyle = `hsl(0, ${s}%, ${l}%)`
|
ctx.fillStyle = `hsl(0, ${s}%, ${l}%)`
|
||||||
// } else if (t < 700) {
|
} else if (t > 700) {
|
||||||
// ctx.fillStyle = `hsl(0, ${}%, ${}%)`
|
const s = 100 - Math.round((t - 700) / 2.5) // 100-20%
|
||||||
|
ctx.fillStyle = `hsl(245, ${s}%, ${s}%)`
|
||||||
} else {
|
} else {
|
||||||
ctx.fillStyle = `hsl(0, 0%, 100%)`
|
ctx.fillStyle = `hsl(0, 0%, 100%)`
|
||||||
}
|
}
|
||||||
ctx.fillRect(0, 0, W, H)
|
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() {
|
export default function useTime() {
|
||||||
// the day is split in 1000 parts, so we start in the morning
|
// the day is split in 1000 parts, so we start in the morning
|
||||||
const time = ref(250)
|
const time = ref(230)
|
||||||
|
|
||||||
function updateTime() {
|
function updateTime() {
|
||||||
time.value = (time.value + 0.1) % 1000
|
time.value = (time.value + 0.1) % 1000
|
||||||
|
|
Loading…
Add table
Reference in a new issue