dig blocks, finally

This commit is contained in:
Norman Köhring 2023-02-15 16:16:17 +01:00
parent 811b6e5b78
commit b2a4d2e547
4 changed files with 92 additions and 40 deletions

View file

@ -3,7 +3,7 @@ import { ref, computed, onMounted } from 'vue'
import Help from './screens/help.vue'
import Inventory from './screens/inventory.vue'
import { BLOCK_SIZE, STAGE_WIDTH, STAGE_HEIGHT, type Block } from './level/def'
import { BLOCK_SIZE, STAGE_WIDTH, STAGE_HEIGHT, type Block, blockTypes } from './level/def'
import createLevel from './level'
import useTime from './util/useTime'
@ -12,7 +12,7 @@ import usePlayer from './util/usePlayer'
const { updateTime, timeOfDay, clock } = useTime()
const { player, direction, dx, dy } = usePlayer()
const { inputX, inputY, running, digging, paused, help, inventory } = useInput()
const { inputX, inputY, running, paused, help, inventory } = useInput()
const level = createLevel(STAGE_WIDTH + 2, STAGE_HEIGHT + 2)
player.inventory.push(
@ -67,8 +67,24 @@ const blocked = computed(() => {
}
})
function dig() {
console.warn('digging not yet implemented')
function dig(blockX: number, blockY: number, oldBlockType: BlockType) {
// § 4 ArbZG
if (paused.value) return
// TODO: temporary filter
if (oldBlockType === 'air' || oldBlockType === 'cave') return
level.change({
type: 'exchange',
x: floorX.value + blockX,
y: floorY.value + blockY,
newType: 'air'
})
// This feels like cheating, but it makes Vue recalculate floorX
// which then recalculates the blocks, so that the changes are
// applied. Otherwise, they wouldn't be visible before moving
x.value = x.value + 0.01
x.value = x.value - 0.01
}
let lastTimeUpdate = 0
@ -107,13 +123,9 @@ const move = (thisTick: number): void => {
if (dy_ > 0 && blocked.value.down) dy_ = 0
else if (dy_ < 0 && blocked.value.up) dy_ = 0
if (!inputY.value && digging.value) {
dx_ = 0
dig()
}
const optimal = 16 // 16ms per tick => 60 FPS
const movementMultiplier = (tickDelta / optimal) * 2
const fallMultiplier = movementMultiplier * 2 // TODO: accelerated fall?
if (arriving.value && dy_ === 0) {
arriving.value = false
@ -122,7 +134,12 @@ const move = (thisTick: number): void => {
walking.value = !!dx_
x.value += dx_ * movementMultiplier
y.value += dy_ * movementMultiplier
if (dy_ < 0 || arriving.value) {
y.value += dy_ * movementMultiplier
} else {
y.value += dy_ * fallMultiplier
}
lastTick = thisTick
}
@ -140,10 +157,6 @@ onMounted(() => {
lastTick = performance.now()
move(lastTick)
})
function log(...args: any[]) {
console.log(...args)
}
</script>
<template>
@ -153,7 +166,7 @@ function log(...args: any[]) {
<template v-for="(row, y) in rows">
<div v-for="(block, x) in row"
:class="['block', block.type, calcBrightness(y, x)]"
@click="log('block', x, y, block.type)"
@click="dig(x, y, block.type)"
/>
</template>
</div>

View file

@ -15,18 +15,24 @@ export type Block = {
transparent?: boolean,
}
export const blockTypes: Record<string, Block> = {
export type BlockType =
| 'air' | 'grass'
| 'treeCrown' | 'treeLeaves' | 'treeTrunk' | 'treeRoot'
| 'soil' | 'soilGravel' | 'stone' | 'stoneGravel'
| 'bedrock' | 'cave'
export const blockTypes: Record<BlockType, Block> = {
air: { type: 'air', hp: Infinity, walkable: true, transparent: true },
grass: { type: 'grass', hp: 1, walkable: false },
grass: { type: 'grass', hp: 5, walkable: false },
treeCrown: { type: 'treeCrown', hp: 5, walkable: true, transparent: true },
treeLeaves: { type: 'treeLeaves', hp: 5, walkable: true, transparent: true },
treeTrunk: { type: 'treeTrunk', hp: 15, walkable: true, climbable: true, transparent: true },
treeRoot: { type: 'treeRoot', hp: 15, walkable: true, climbable: true },
treeCrown: { type: 'treeCrown', hp: 1, walkable: true, transparent: true },
treeLeaves: { type: 'treeLeaves', hp: 1, walkable: true, transparent: true },
treeTrunk: { type: 'treeTrunk', hp: 10, walkable: true, climbable: true, transparent: true },
treeRoot: { type: 'treeRoot', hp: 10, walkable: true, climbable: true },
soil: { type: 'soil', hp: 2, walkable: false },
soil: { type: 'soil', hp: 5, walkable: false },
soilGravel: { type: 'soilGravel', hp: 5, walkable: false },
stoneGravel: { type: 'stoneGravel', hp: 5, walkable: false },
stoneGravel: { type: 'stoneGravel', hp: 10, walkable: false },
stone: { type: 'stone', hp: 10, walkable: false },
bedrock: { type: 'bedrock', hp: 25, walkable: false },
cave: { type: 'cave', hp: Infinity, walkable: true, transparent: true },

View file

@ -3,7 +3,22 @@ import { createNoise2D, type NoiseFunction2D } from 'simplex-noise'
import createBlockGenerator from './blockGen'
import createBlockExtender from './blockExt'
import {blockTypes as T, level as L, type Block} from './def'
import {blockTypes, blockTypes as T, level as L, type Block, type BlockType} from './def'
// describes a changed block, eg digged or placed by the player
type DamagedBlock = {
type: 'damage'
x: number
y: number
damage: number
}
type ChangedBlock = {
type: 'exchange'
x: number
y: number
newType: BlockType
}
type Change = DamagedBlock | ChangedBlock
const MAX_LIGHT = 100 // maximum level where light shines
@ -17,15 +32,34 @@ export default function createLevel(width: number, height: number, seed = 'extre
// stores the limit to where light still shines,
// for each column currently visible on the screen
const _lightBarrier: number[] = [...new Array(width)].map(() => MAX_LIGHT)
const _changes: Change[] = []
const blockGen = createBlockGenerator(rand)
const blockExt = createBlockExtender(rand)
// Apply changes, coming from the player (tocktocktock-plopp!)
function change (level: number, column: number, newBlock: Block) {
// TODO
function change(change: Change) {
_changes.push(change)
console.log(_changes)
}
function applyPlayerChanges(columnOffset: number, levelOffset: number) {
for (const change of _changes) {
// ignore all changes outside of the current view
if (change.x < columnOffset || change.x > columnOffset + width) continue
if (change.y < levelOffset || change.y > levelOffset + height) continue
if (change.type === 'exchange') {
_grid[change.y - levelOffset][change.x - columnOffset] = blockTypes[change.newType]
} else if (change.type === 'damage') {
console.warn('damaging blocks not yet supported')
}
}
}
// takes the current columnOffset and generates all blocks from the very top
// until a block is generated that blocks light. The height of that block is
// stored in the lightBarrier list
function calcLightBarrier(columnOffset: number) {
let previousBlock: Block = T.air
@ -33,6 +67,12 @@ export default function createLevel(width: number, height: number, seed = 'extre
for (let level = 0; level < MAX_LIGHT; level++) {
let block = blockGen.generateBlock(level, col + columnOffset)
block = blockExt.extendBlock(level, col, columnOffset, block, previousBlock)
const change = _changes.find(change => {
return change.x === columnOffset + col && change.y === level
})
if (change && change.type === 'exchange') block = blockTypes[change.newType]
previousBlock = block
if (!block.transparent) {
@ -43,21 +83,22 @@ export default function createLevel(width: number, height: number, seed = 'extre
}
}
function generate(column: number, y: number) {
function generate(columnOffset: number, levelOffset: number) {
for (let i = 0; i < height; i++) {
const level = y+i
const level = levelOffset + i
const row: Block[] = Array(width)
const previousRow = i ? _grid[i-1] : [] as Block[]
blockGen.fillRow(level, column, row)
blockExt.extendRow(level, column, row, previousRow)
blockGen.fillRow(level, columnOffset, row)
blockExt.extendRow(level, columnOffset, row, previousRow)
_grid[i] = row
}
applyPlayerChanges(columnOffset, levelOffset)
}
function sunLight(x: number, y: number) {
calcLightBarrier(x)
function sunLight(columnOffset: number) {
calcLightBarrier(columnOffset)
return _lightBarrier
}

View file

@ -4,7 +4,6 @@ export default function useInput() {
let inputX = ref(0)
let inputY = ref(1)
let running = ref(false)
let digging = ref(false)
let paused = ref(false)
let help = ref(false)
let inventory = ref(false)
@ -32,9 +31,6 @@ export default function useInput() {
if (!help.value) paused.value = !paused.value
if (wasPaused && !paused.value) wasPaused = false
break
case ' ':
digging.value = true
break
case '?':
if (paused.value && !help.value) wasPaused = true
help.value = !help.value
@ -64,9 +60,6 @@ export default function useInput() {
case 'ArrowLeft':
inputX.value = inputX.value === -1 ? 0 : 1
break
case ' ':
digging.value = false
break
}
}
@ -80,7 +73,6 @@ export default function useInput() {
inputX,
inputY,
running,
digging,
paused,
help,
inventory,