Compare commits
2 commits
8f281fbdf9
...
3266ddb217
Author | SHA1 | Date | |
---|---|---|---|
![]() |
3266ddb217 | ||
![]() |
72c5cd1d19 |
15 changed files with 186 additions and 123 deletions
BIN
public/Items/torchCeiling.png
Normal file
BIN
public/Items/torchCeiling.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.1 KiB |
BIN
public/Items/torchFloor.png
Normal file
BIN
public/Items/torchFloor.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.8 KiB |
BIN
public/Items/torchLeft.png
Normal file
BIN
public/Items/torchLeft.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.4 KiB |
BIN
public/Items/torchRight.png
Normal file
BIN
public/Items/torchRight.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.2 KiB |
105
src/App.vue
105
src/App.vue
|
@ -1,11 +1,11 @@
|
|||
<script setup lang="ts">
|
||||
import type { Block, Direction, Item, InventoryItem } from './types.d'
|
||||
import type { Block, BlockType, Direction, Item, InventoryItem, LightSource } from './types.d'
|
||||
import { ref, computed, watch, onMounted, useTemplateRef } from 'vue'
|
||||
import Help from './screens/help.vue'
|
||||
import Inventory from './screens/inventory.vue'
|
||||
import Background from './Background.vue'
|
||||
|
||||
import { BLOCK_SIZE, STAGE_WIDTH, STAGE_HEIGHT } from './level/def'
|
||||
import { BLOCK_SIZE, STAGE_WIDTH, STAGE_HEIGHT, softTerrain, hardTerrain } from './level/def'
|
||||
import { getItem, getItemClass } from './level/items'
|
||||
import createLevel from './level'
|
||||
|
||||
|
@ -25,11 +25,12 @@ let updateLightMap = (() => {}) as ReturnType<typeof useLightMask>
|
|||
pocket(getItem('tool_shovel_wood'))
|
||||
pocket(getItem('tool_sword_wood'))
|
||||
pocket(getItem('tool_pickaxe_wood'))
|
||||
pocket(getItem('fixture_torch'), 5)
|
||||
|
||||
let animationFrame = 0
|
||||
let lastTick = 0
|
||||
|
||||
const debug = ref(false)
|
||||
const debug = ref(true)
|
||||
const x = ref(0)
|
||||
const y = ref(0)
|
||||
const floorX = computed(() => Math.floor(x.value))
|
||||
|
@ -51,15 +52,35 @@ const mapGrid = computed<Block[][]>(() => {
|
|||
const _update = mapUpdateCount.value // reactivity trigger
|
||||
return level.grid(floorX.value, floorY.value, true)
|
||||
})
|
||||
const lightSources = computed(() => {
|
||||
const _update = mapUpdateCount.value // reactivity trigger
|
||||
const _floorX = floorX.value // reactivity trigger
|
||||
const _floorY = floorY.value // reactivity trigger
|
||||
|
||||
const lightSources: LightSource[] = []
|
||||
const grid = mapGrid.value
|
||||
|
||||
for (let y = 0; y < grid.length; y++) {
|
||||
const row = grid[y]
|
||||
for (let x = 0; x < row.length; x++) {
|
||||
const block = row[x]
|
||||
if (block.illumination) {
|
||||
lightSources.push({
|
||||
x, y,
|
||||
strength: block.illumination,
|
||||
color: block.color ?? '#FFE'
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
return lightSources
|
||||
})
|
||||
|
||||
const arriving = ref(true)
|
||||
const walking = ref(false)
|
||||
const inventorySelection = ref<InventoryItem>(player.inventory[0])
|
||||
|
||||
const surroundings = computed<Record<Direction, Block>>(() => {
|
||||
const _update = mapUpdateCount.value // reactivity trigger
|
||||
const x = px.value
|
||||
const y = py.value
|
||||
const getSurroundings = (x: number, y: number) => {
|
||||
const rows = mapGrid.value
|
||||
|
||||
const rowY = rows[y]
|
||||
|
@ -73,6 +94,11 @@ const surroundings = computed<Record<Direction, Block>>(() => {
|
|||
up: rowYp[x],
|
||||
down: rowYn[x],
|
||||
}
|
||||
}
|
||||
|
||||
const surroundings = computed<Record<Direction, Block>>(() => {
|
||||
const _update = mapUpdateCount.value // reactivity trigger
|
||||
return getSurroundings(px.value, py.value)
|
||||
})
|
||||
const blocked = computed(() => {
|
||||
const { left, right, up, down } = surroundings.value
|
||||
|
@ -110,15 +136,26 @@ function dig(blockX: number, blockY: number, block: Block) {
|
|||
}
|
||||
|
||||
function build(blockX: number, blockY: number, block: InventoryItem) {
|
||||
const blockToBuild = block.builds
|
||||
// the block doesn't do anything
|
||||
if (!blockToBuild) return
|
||||
let blockToBuild = block.builds
|
||||
if (!blockToBuild) return // the block doesn't do anything?!
|
||||
|
||||
// While blocks are just filling the space completely, fixtures are attached
|
||||
// to the closest surface. We check the surroundings, starting at with left
|
||||
// and right, then bottom and top.
|
||||
if (block.type === 'fixture') {
|
||||
const { left, right, up, down } = getSurroundings(blockX, blockY)
|
||||
|
||||
if (!left.transparent) blockToBuild = `${blockToBuild}Left`
|
||||
else if (!right.transparent) blockToBuild = `${blockToBuild}Right`
|
||||
else if (!up.transparent) blockToBuild = `${blockToBuild}Ceiling`
|
||||
else if (!down.transparent) blockToBuild = `${blockToBuild}Floor`
|
||||
}
|
||||
|
||||
level.change({
|
||||
change: 'exchange',
|
||||
x: floorX.value + blockX,
|
||||
y: floorY.value + blockY,
|
||||
newType: blockToBuild
|
||||
newType: blockToBuild as BlockType
|
||||
})
|
||||
mapUpdateCount.value = mapUpdateCount.value + 1
|
||||
|
||||
|
@ -127,20 +164,37 @@ function build(blockX: number, blockY: number, block: InventoryItem) {
|
|||
}
|
||||
|
||||
function interactWith(blockX: number, blockY: number, block: Block) {
|
||||
if (debug) console.debug('interact with', blockX, blockY, block.type)
|
||||
if (debug) {
|
||||
console.debug(
|
||||
`interact with ${block.type} at ${blockX},${blockY},`,
|
||||
`with a ${inventorySelection.value.id} in hand`
|
||||
)
|
||||
}
|
||||
// § 4 ArbZG
|
||||
if (paused.value) return
|
||||
|
||||
const blockInHand = inventorySelection.value.type === 'block'
|
||||
const toolInHand = inventorySelection.value.type === 'tool'
|
||||
const emptyBlock = block.type === 'air' || block.type === 'cave'
|
||||
// no spooky interaction at a distance
|
||||
const distanceX = ~~(px.value - blockX)
|
||||
const distanceY = ~~(py.value - blockY)
|
||||
if (distanceX > 1 || distanceY > 1) return
|
||||
|
||||
const blockInHand = inventorySelection.value
|
||||
const shovelInHand = blockInHand.id.indexOf('shovel') >= 0
|
||||
const pickaxeInHand = blockInHand.id.indexOf('pickaxe') >= 0
|
||||
|
||||
const canBuild = !!blockInHand.builds
|
||||
const hasTool = blockInHand.type === 'tool'
|
||||
const hasSpace = block.type === 'air' || block.type === 'cave'
|
||||
const canUseShovel = softTerrain.indexOf(block.type) >= 0
|
||||
const canUsePickaxe = hardTerrain.indexOf(block.type) >= 0
|
||||
|
||||
// put the selected block
|
||||
if (blockInHand && emptyBlock) {
|
||||
build(blockX, blockY, inventorySelection.value)
|
||||
if (canBuild && hasSpace) {
|
||||
build(blockX, blockY, blockInHand)
|
||||
// dig a block with shovel or pick axe
|
||||
} else if (toolInHand && !emptyBlock) {
|
||||
dig(blockX, blockY, block)
|
||||
} else if (hasTool && !hasSpace) {
|
||||
if (shovelInHand && canUseShovel) dig(blockX, blockY, block)
|
||||
else if (pickaxeInHand && canUsePickaxe) dig(blockX, blockY, block)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -214,7 +268,10 @@ onMounted(() => {
|
|||
canvas.height = (BLOCK_SIZE + 2) * STAGE_HEIGHT
|
||||
canvas.width = (BLOCK_SIZE + 2) * STAGE_WIDTH
|
||||
const ctx = canvas.getContext('2d')!
|
||||
updateLightMap = useLightMask(ctx, floorX, floorY, tx, ty, time, lightBarrier)
|
||||
updateLightMap = useLightMask(
|
||||
ctx, floorY, tx, ty,
|
||||
lightBarrier, lightSources,
|
||||
)
|
||||
} else {
|
||||
console.warn('lightmap deactivated')
|
||||
}
|
||||
|
@ -265,7 +322,13 @@ onMounted(() => {
|
|||
<div id="beam" v-if="arriving"></div>
|
||||
<div id="level-indicator">
|
||||
x:{{ floorX }}, y:{{ floorY }}
|
||||
<template v-if="paused">(PAUSED)</template>
|
||||
<template v-if="paused">
|
||||
<template v-if="debug">
|
||||
({{ clock }})<br/>
|
||||
time: <input type="number" max="0" min="1000" v-model="time" />
|
||||
</template>
|
||||
<template v-else>(PAUSED)</template>
|
||||
</template>
|
||||
<template v-else>({{ clock }})</template>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -21,18 +21,15 @@ onMounted(() => {
|
|||
|
||||
const drawBackground = useBackground(
|
||||
canvasEl,
|
||||
~~(STAGE_WIDTH * BLOCK_SIZE / 2.0),
|
||||
~~(STAGE_HEIGHT * BLOCK_SIZE / 2.0),
|
||||
~~(STAGE_WIDTH * BLOCK_SIZE / 1.0),
|
||||
~~(STAGE_HEIGHT * BLOCK_SIZE / 1.0),
|
||||
)
|
||||
|
||||
watch(props, () => {
|
||||
console.log('drawing background', sunY.value)
|
||||
drawBackground(props.x, sunY.value)
|
||||
}, { immediate: true })
|
||||
watch(props, () => drawBackground(props.x, sunY.value), { immediate: true })
|
||||
})
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<canvas ref="canvas" id="background"></canvas>
|
||||
<canvas ref="canvas" id="background" />
|
||||
</template>
|
||||
|
|
|
@ -98,6 +98,10 @@
|
|||
.block.brickWall {
|
||||
background-image: url(/Tiles/brick_grey.png);
|
||||
}
|
||||
.block.torchLeft { background-image: url("/Items/torchLeft.png"); }
|
||||
.block.torchRight { background-image: url("/Items/torchRight.png"); }
|
||||
.block.torchFloor { background-image: url("/Items/torchFloor.png"); }
|
||||
.block.torchCeiling { background-image: url("/Items/torchCeiling.png"); }
|
||||
|
||||
#field {
|
||||
user-select: none;
|
||||
|
@ -112,17 +116,17 @@
|
|||
|
||||
.morning0 .block,
|
||||
.morning0 #player {
|
||||
filter: saturate(50%);
|
||||
filter: saturate(50%) brightness(0.6);
|
||||
}
|
||||
|
||||
.morning1 .block,
|
||||
.morning1 #player {
|
||||
filter: saturate(100%);
|
||||
filter: saturate(100%) brightness(0.8);
|
||||
}
|
||||
|
||||
.morning2 .block,
|
||||
.morning2 #player {
|
||||
filter: saturate(120%);
|
||||
filter: saturate(120%) brightness(0.9);
|
||||
}
|
||||
|
||||
.evening0 .block,
|
||||
|
@ -132,17 +136,17 @@
|
|||
|
||||
.evening1 .block,
|
||||
.evening1 #player {
|
||||
filter: saturate(70%);
|
||||
filter: saturate(70%) brightness(0.8);
|
||||
}
|
||||
|
||||
.evening2 .block,
|
||||
.evening2 #player {
|
||||
filter: saturate(50%);
|
||||
filter: saturate(50%) brightness(0.6);
|
||||
}
|
||||
|
||||
.night .block,
|
||||
.night #player {
|
||||
filter: saturate(30%);
|
||||
filter: saturate(30%) brightness(0.4);
|
||||
}
|
||||
|
||||
#blocks {
|
||||
|
|
|
@ -14,3 +14,5 @@
|
|||
.item.block-dirt { background-image: url("/Tiles/dirt.png"); }
|
||||
.item.block-stone { background-image: url("/Tiles/stone.png"); }
|
||||
.item.block-gravel { background-image: url("/Tiles/gravel_stone.png"); }
|
||||
|
||||
.item.fixture-torch { background-image: url("/Items/torchFloor.png"); }
|
||||
|
|
|
@ -27,8 +27,19 @@ export const blockTypes: Record<BlockType, Block> = {
|
|||
bedrock: { type: 'bedrock', hp: 25, walkable: false, drops: 'block_stone' },
|
||||
// Built Blocks
|
||||
brickWall: { type: 'brickWall', hp: 25, walkable: false, drops: 'block_gravel' },
|
||||
|
||||
torchLeft: { type: 'torchLeft', hp: 1, walkable: true, transparent: true, drops: 'fixture_torch', illumination: 1.0, color: '#FFE', fixture: true },
|
||||
torchRight: { type: 'torchRight', hp: 1, walkable: true, transparent: true, drops: 'fixture_torch', illumination: 1.0, color: '#FFE', fixture: true },
|
||||
torchCeiling: { type: 'torchCeiling', hp: 1, walkable: true, transparent: true, drops: 'fixture_torch', illumination: 1.0, color: '#FFE', fixture: true },
|
||||
torchFloor: { type: 'torchFloor', hp: 1, walkable: true, transparent: true, drops: 'fixture_torch', illumination: 1.0, color: '#FEB', fixture: true },
|
||||
}
|
||||
|
||||
export const softTerrain: BlockType[] = [
|
||||
'grass', 'soil', 'soilGravel',
|
||||
'torchLeft', 'torchRight', 'torchCeiling', 'torchFloor',
|
||||
]
|
||||
export const hardTerrain: BlockType[] = ['stone', 'stoneGravel', 'bedrock', 'brickWall']
|
||||
|
||||
export const level = {
|
||||
treeTop: 9,
|
||||
ground: 14,
|
||||
|
|
|
@ -3,10 +3,10 @@ import { createNoise2D, type NoiseFunction2D } from 'simplex-noise'
|
|||
import createBlockGenerator from './blockGen'
|
||||
import createBlockExtender from './blockExt'
|
||||
|
||||
import { blockTypes, blockTypes as T } from './def'
|
||||
import { level as L, blockTypes, blockTypes as T } from './def'
|
||||
import type { Block, Change } from '../types.d'
|
||||
|
||||
const MAX_LIGHT = 100 // maximum level where light shines
|
||||
const MAX_LIGHT = L.underground // maximum level where light shines
|
||||
|
||||
export default function createLevel(width: number, height: number, seed = 'extremely random seed') {
|
||||
const prng = alea(seed)
|
||||
|
|
|
@ -26,6 +26,8 @@ export const items = {
|
|||
ore_ruby: { id: 'ore_ruby', name: 'ruby', type: 'ore', icon: 'ore_ruby' } as Item,
|
||||
ore_diamond: { id: 'ore_diamond', name: 'diamond', type: 'ore', icon: 'ore_diamond' } as Item,
|
||||
ore_emerald: { id: 'ore_emerald', name: 'emerald', type: 'ore', icon: 'ore_emerald' } as Item,
|
||||
|
||||
fixture_torch: { id: 'fixture_torch', name: 'Torch', type: 'fixture', icon: 'torch', builds: 'torch' } as Item,
|
||||
} as const
|
||||
|
||||
export type ItemId = keyof typeof items
|
||||
|
|
36
src/types.d.ts
vendored
36
src/types.d.ts
vendored
|
@ -1,6 +1,7 @@
|
|||
import type { ItemId } from './level/items'
|
||||
export type { ItemId } from './level/items'
|
||||
export type ItemQuality = 'wood' | 'iron' | 'diamond'
|
||||
export type ItemType = 'tool' | 'block' | 'ore'
|
||||
export type ItemType = 'tool' | 'block' | 'ore' | 'fixture'
|
||||
|
||||
export interface Item {
|
||||
id: string
|
||||
|
@ -8,7 +9,9 @@ export interface Item {
|
|||
type: ItemType
|
||||
icon: string
|
||||
quality?: ItemQuality
|
||||
builds?: BlockType
|
||||
// this should be ItemId | BlockType, but has to be string to avoid
|
||||
// a circular type reference
|
||||
builds?: string
|
||||
}
|
||||
|
||||
export interface ToolItem extends Item {
|
||||
|
@ -21,6 +24,8 @@ export interface BlockItem extends Item {
|
|||
builds: BlockType
|
||||
}
|
||||
|
||||
type Fixture<T extends string> = `${T}Left` | `${T}Right` | `${T}Ceiling` | `${T}Floor`;
|
||||
|
||||
export type BlockType =
|
||||
| 'air' | 'grass'
|
||||
| 'treeCrown' | 'treeLeaves' | 'treeTrunk' | 'treeRoot'
|
||||
|
@ -28,15 +33,18 @@ export type BlockType =
|
|||
| 'stone' | 'stoneGravel'
|
||||
| 'bedrock' | 'cave'
|
||||
| 'brickWall'
|
||||
| Fixture<'torch'>
|
||||
|
||||
export type Block = {
|
||||
type: BlockType, // what is it?
|
||||
hp: number, // how long do I need to hit it?
|
||||
walkable: boolean, // can I walk through it?
|
||||
climbable?: boolean, // can I climb it?
|
||||
transparent?: boolean, // can I see through it?
|
||||
illuminated?: boolean, // is it glowing?
|
||||
drops?: ItemId, // what do I get, when loot it?
|
||||
type: BlockType // what is it?
|
||||
hp: number // how long do I need to hit it?
|
||||
walkable: boolean // can I walk through it?
|
||||
climbable?: boolean // can I climb it?
|
||||
transparent?: boolean // can I see through it?
|
||||
fixture?: boolean // is it built by the player?
|
||||
illumination?: number // How many blocks wide is it glowing?
|
||||
color?: string // How is it coloured?
|
||||
drops?: ItemId // what do I get, when loot it?
|
||||
}
|
||||
|
||||
// describes a changed block, eg digged or placed by the player
|
||||
|
@ -52,11 +60,10 @@ type ChangedBlock = {
|
|||
y: number
|
||||
newType: BlockType
|
||||
}
|
||||
type Change = DamagedBlock | ChangedBlock
|
||||
export type Change = DamagedBlock | ChangedBlock
|
||||
|
||||
export interface InventoryItem extends Item {
|
||||
amount: number
|
||||
quality: ItemQuality | null
|
||||
}
|
||||
|
||||
export interface Moveable {
|
||||
|
@ -78,3 +85,10 @@ export interface Player extends Moveable {
|
|||
|
||||
export type Direction = 'at' | 'left' | 'right' | 'up' | 'down'
|
||||
|
||||
|
||||
export interface LightSource {
|
||||
x: number
|
||||
y: number
|
||||
strength: number
|
||||
color: string
|
||||
}
|
||||
|
|
|
@ -1,116 +1,87 @@
|
|||
import type { Ref, ComputedRef } from 'vue'
|
||||
import type { LightSource } from '../types.d'
|
||||
import { BLOCK_SIZE, STAGE_WIDTH, STAGE_HEIGHT } from '../level/def'
|
||||
|
||||
type RefOrComputed<T> = Ref<T> | ComputedRef<T>
|
||||
|
||||
export default function useLightMask(
|
||||
ctx: CanvasRenderingContext2D,
|
||||
x: RefOrComputed<number>,
|
||||
y: RefOrComputed<number>,
|
||||
tx: RefOrComputed<number>,
|
||||
ty: RefOrComputed<number>,
|
||||
time: RefOrComputed<number>,
|
||||
lightBarrier: RefOrComputed<number[]>,
|
||||
lightSources: RefOrComputed<LightSource[]>,
|
||||
) {
|
||||
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 BHalf = B / 2
|
||||
|
||||
const playerX = (W - B) / 2 + B / 4
|
||||
const playerY = H / 2 - B / 2
|
||||
const playerY = H / 2 - BHalf
|
||||
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 t = time.value
|
||||
|
||||
const playerLight = ctx.createRadialGradient(
|
||||
playerX - tx.value, playerY - ty.value, 0,
|
||||
playerX - tx.value, playerY - ty.value, playerLightSize * sizeMul
|
||||
)
|
||||
|
||||
// Add color stops for a light around the player
|
||||
// Night time, lets tone down the light a bit
|
||||
if (t > 900 || t < 100) {
|
||||
playerLight.addColorStop(0.7, "#AA7A");
|
||||
playerLight.addColorStop(1, "#AA70");
|
||||
|
||||
// Morning
|
||||
} else if (t < 150) {
|
||||
playerLight.addColorStop(0.7, "#CCAA");
|
||||
playerLight.addColorStop(1, "#CCA0");
|
||||
|
||||
// Day (neutral white)
|
||||
} else {
|
||||
playerLight.addColorStop(0.7, "#FFFA");
|
||||
playerLight.addColorStop(1, "#FFF0");
|
||||
}
|
||||
playerLight.addColorStop(0.7, "#FFFA");
|
||||
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()
|
||||
function drawLightSources() {
|
||||
for (const src of lightSources.value) {
|
||||
const x = src.x * B
|
||||
const y = src.y * B
|
||||
const strength = src.strength + (src.strength * Math.random()) / 10
|
||||
const light = ctx.createRadialGradient(
|
||||
x + BHalf, y - BHalf, 0,
|
||||
x + BHalf, y - BHalf, strength * B,
|
||||
)
|
||||
const color = src.color
|
||||
|
||||
light.addColorStop(0.0, color)
|
||||
light.addColorStop(0.4, `${color}A`)
|
||||
light.addColorStop(1, `${color}0`)
|
||||
|
||||
ctx.fillStyle = light
|
||||
ctx.fillRect(0, 0, W, H)
|
||||
}
|
||||
}
|
||||
|
||||
function drawShadows() {
|
||||
const barrier = lightBarrier.value
|
||||
|
||||
ctx.fillStyle = ambientLight
|
||||
for (let col = 0; col < W / B; col++) {
|
||||
for (let col = 0; col < barrier.length; col++) {
|
||||
const level = (barrier[col] - y.value) * B
|
||||
const sw = B
|
||||
const sh = level
|
||||
const sx = col * sw
|
||||
const sy = 0
|
||||
const x = B*col
|
||||
|
||||
ctx.fillRect(sx, sy, sw, sh)
|
||||
// gradient for the shadow that is cast down from the surface
|
||||
const gradient = ctx.createLinearGradient(0, 0, 0, H)
|
||||
gradient.addColorStop(0, '#FFF')
|
||||
gradient.addColorStop(Math.min(level / H, 1), '#FFF')
|
||||
gradient.addColorStop(Math.min((level + B) / H, 1), '#000')
|
||||
ctx.fillStyle = gradient
|
||||
ctx.fillRect(x, 0, B, H)
|
||||
}
|
||||
|
||||
// make light columns wider to illuminate surrounding blocks
|
||||
const extra = Math.floor(B / 2)
|
||||
ctx.fillStyle = ambientLight.slice(0, -1) + ', 40%)'
|
||||
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 = '#000000'
|
||||
ctx.fillStyle = '#FFFFFF'
|
||||
ctx.fillRect(0, 0, W, H)
|
||||
|
||||
// second, find and bring light into the world
|
||||
drawLights()
|
||||
// second, hide what is beneath
|
||||
drawShadows()
|
||||
|
||||
// third, fight the darkness
|
||||
drawLightSources()
|
||||
|
||||
// finally, draw the players light
|
||||
// with a size multiplicator which might be later used to
|
||||
|
|
|
@ -11,7 +11,7 @@ const player = reactive<Player>({
|
|||
inventory: [],
|
||||
})
|
||||
|
||||
const pocket = (newItem: Item) => {
|
||||
const pocket = (newItem: Item, amount = 1) => {
|
||||
const existing = player.inventory.find(item => item.name === newItem.name)
|
||||
|
||||
if (existing) {
|
||||
|
@ -19,9 +19,8 @@ const pocket = (newItem: Item) => {
|
|||
return existing.amount
|
||||
}
|
||||
player.inventory.push({
|
||||
quality: null,
|
||||
amount: 1,
|
||||
...newItem
|
||||
...newItem,
|
||||
amount,
|
||||
})
|
||||
return 1
|
||||
}
|
||||
|
|
|
@ -46,7 +46,7 @@ export function calcSunAngle(tick: number): number {
|
|||
|
||||
export default function useTime() {
|
||||
// the day is split in 1000 parts, so we start in the morning
|
||||
const time = ref(250)
|
||||
const time = ref(240)
|
||||
|
||||
function updateTime() {
|
||||
time.value = (time.value + 0.1) % 1000
|
||||
|
|
Loading…
Add table
Reference in a new issue