fix types

This commit is contained in:
Norman Köhring 2025-03-16 00:10:04 +01:00
parent b8335d9392
commit be68f73721
13 changed files with 108 additions and 130 deletions

View file

@ -1,15 +1,16 @@
<script setup lang="ts">
import type { Block, Direction, Item, InventoryItem } from './types.d'
import { ref, computed, watch, 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 } from './level/def'
import { getItem, getItemClass } from './level/items'
import createLevel from './level'
import usePlayer from './util/usePlayer'
import useTime from './util/useTime'
import useInput from './util/useInput'
import usePlayer, { type InventoryItem } from './util/usePlayer'
import useLightMap from './util/useLightMap'
const { updateTime, time, timeOfDay, clock } = useTime()
@ -20,9 +21,9 @@ const level = createLevel(STAGE_WIDTH + 2, STAGE_HEIGHT + 2)
const lightMapEl = ref<HTMLCanvasElement | undefined>(undefined)
let updateLightMap: ReturnType<typeof useLightMap>
pocket({ name: 'Shovel', type: 'tool', icon: 'shovel', quality: 'wood' })
pocket({ name: 'Sword', type: 'weapon', icon: 'sword', quality: 'wood' })
pocket({ name: 'Pick Axe', type: 'tool', icon: 'pick', quality: 'wood' })
pocket({ name: 'Wooden Shovel', type: 'tool', icon: 'shovel', quality: 'wood' })
pocket({ name: 'Wooden Sword', type: 'tool', icon: 'sword', quality: 'wood' })
pocket({ name: 'Wooden Pick Axe', type: 'tool', icon: 'pick', quality: 'wood' })
let animationFrame = 0
let lastTick = 0
@ -54,14 +55,7 @@ const arriving = ref(true)
const walking = ref(false)
const inventorySelection = ref<InventoryItem>(player.inventory[0])
type Surroundings = {
at: Block,
left: Block,
right: Block,
up: Block,
down: Block,
}
const surroundings = computed<Surroundings>(() => {
const surroundings = computed<Record<Direction, Block>>(() => {
const _update = mapUpdateCount.value // reactivity trigger
const x = px.value
const y = py.value
@ -100,7 +94,7 @@ function dig(blockX: number, blockY: number, block: Block) {
// finally dig that block
// TODO: damage blocks first
level.change({
type: 'exchange',
change: 'exchange',
x: floorX.value + blockX,
y: floorY.value + blockY,
newType: 'air'
@ -120,14 +114,14 @@ function build(blockX: number, blockY: number, block: InventoryItem) {
if (!blockToBuild) return
level.change({
type: 'exchange',
change: 'exchange',
x: floorX.value + blockX,
y: floorY.value + blockY,
newType: blockToBuild
})
mapUpdateCount.value = mapUpdateCount.value + 1
const newAmount = unpocket(block)
const newAmount = unpocket(block as Item)
if (newAmount < 1) inventorySelection.value = player.inventory[0]
}
@ -268,8 +262,6 @@ onMounted(() => {
x:{{ floorX }}, y:{{ floorY }}
<template v-if="paused">(PAUSED)</template>
<template v-else>({{ clock }})</template>
<br/>
Map Changes: {{ mapUpdateCount }}
</div>
<Inventory :shown="inventory"

View file

@ -1,7 +1,15 @@
.item.tool-shovel-wood { background-image: url("/Items/shovel_bronze.png"); }
.item.weapon-sword-wood { background-image: url("/Items/sword_bronze.png"); }
.item.tool-sword-wood { background-image: url("/Items/sword_bronze.png"); }
.item.tool-pick-wood { background-image: url("/Items/pick_bronze.png"); }
.item.tool-shovel-iron { background-image: url("/Items/shovel_iron.png"); }
.item.tool-sword-iron { background-image: url("/Items/sword_iron.png"); }
.item.tool-pick-iron { background-image: url("/Items/pick_iron.png"); }
.item.tool-shovel-diamond { background-image: url("/Items/shovel_diamond.png"); }
.item.tool-sword-diamond { background-image: url("/Items/sword_diamond.png"); }
.item.tool-pick-diamond { background-image: url("/Items/pick_diamond.png"); }
.item.block-wood { background-image: url("/Tiles/wood.png"); }
.item.block-dirt { background-image: url("/Tiles/dirt.png"); }
.item.block-stone { background-image: url("/Tiles/stone.png"); }

View file

@ -1,5 +1,6 @@
import type { NoiseFunction2D } from 'simplex-noise'
import {blockTypes as T, level as L, probability as P, type Block} from './def'
import { blockTypes as T, level as L, probability as P } from './def'
import type { Block } from '../types.d'
const TREE_ROOT = [T.treeRootLeft, T.treeRootMiddle, T.treeRootRight]

View file

@ -1,5 +1,6 @@
import type { NoiseFunction2D } from 'simplex-noise'
import {blockTypes as T, level as L, probability as P, type Block} from './def'
import { blockTypes as T, level as L, probability as P } from './def'
import type { Block } from '../types.d'
export default function createBlockGenerator(rand: NoiseFunction2D) {
// randomly generate a block

View file

@ -1,6 +1,6 @@
import type { DropItem } from './items'
import type { Block, BlockType } from '../types.d'
export const BLOCK_SIZE = 64 // each block is 64̨̣̌̇x64 pixel in size and equals 1m
export const BLOCK_SIZE = 64 // each block is 64x64 px in size and equals 1m
export const RECIPROCAL = 1 / BLOCK_SIZE
export const STAGE_WIDTH = 20 // 20*64 = 1280 pixel wide stage
@ -9,23 +9,6 @@ export const STAGE_HEIGHT = 12 // 12*64 = 768 pixel high stage
export const GRAVITY = 10 // blocks per second
export type Block = {
type: string, // 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?: DropItem, // what do I get, when loot it?
}
export type BlockType =
| 'air' | 'grass'
| 'treeCrown' | 'treeLeaves' | 'treeTrunk' | 'treeRoot'
| 'soil' | 'soilGravel' | 'stone' | 'stoneGravel'
| 'bedrock' | 'cave'
| 'brickWall'
export const blockTypes: Record<BlockType, Block> = {
// Transparent Blocks
air: { type: 'air', hp: Infinity, walkable: true, transparent: true },
@ -35,6 +18,9 @@ export const blockTypes: Record<BlockType, Block> = {
treeLeaves: { type: 'treeLeaves', hp: 1, walkable: true, transparent: true, drops: 'leaves' },
treeTrunk: { type: 'treeTrunk', hp: 10, walkable: true, climbable: true, transparent: true, drops: 'wood' },
treeRoot: { type: 'treeRoot', hp: 10, walkable: true, climbable: true, drops: 'wood' },
treeRootLeft: { type: 'treeRootLeft', hp: 10, walkable: true, climbable: true, drops: 'wood' },
treeRootMiddle: { type: 'treeRootMiddle', hp: 10, walkable: true, climbable: true, drops: 'wood' },
treeRootRight: { type: 'treeRootRight', hp: 10, walkable: true, climbable: true, drops: 'wood' },
// Opaque Natural Blocks
grass: { type: 'grass', hp: 5, walkable: false, drops: 'dirt' },
soil: { type: 'soil', hp: 5, walkable: false, drops: 'dirt' },

View file

@ -3,22 +3,8 @@ import { createNoise2D, type NoiseFunction2D } from 'simplex-noise'
import createBlockGenerator from './blockGen'
import createBlockExtender from './blockExt'
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
import { blockTypes, blockTypes as T } from './def'
import type { Block, Change } from '../types.d'
const MAX_LIGHT = 100 // maximum level where light shines
@ -50,7 +36,7 @@ export default function createLevel(width: number, height: number, seed = 'extre
if (changes) {
const maxLevel = levelOffset + height
changes.forEach(c => {
if (c.type !== 'exchange' || c.y < levelOffset || c.y >= maxLevel) return
if (c.change !== 'exchange' || c.y < levelOffset || c.y >= maxLevel) return
_grid[c.y - levelOffset][c.x - columnOffset] = blockTypes[c.newType]
})
}
@ -71,7 +57,7 @@ export default function createLevel(width: number, height: number, seed = 'extre
const changes = _changes[columnOffset + col]
if (changes) {
const change = changes.find(c => c.y === level)
if (change && change.type === 'exchange') block = blockTypes[change.newType]
if (change && change.change === 'exchange') block = blockTypes[change.newType]
}
previousBlock = block
@ -107,7 +93,7 @@ export default function createLevel(width: number, height: number, seed = 'extre
let lastGenY = 0
generate(0, 0)
function grid(x: number, y: number, force: false): Block[][] {
function grid(x: number, y: number, force = false): Block[][] {
if (force || lastGenX !== x || lastGenY !== y) {
generate(x, y)
lastGenX = x

View file

@ -1,26 +1,21 @@
import type { BlockType } from './def'
import type { InventoryItem } from '../util/usePlayer'
export type ItemQuality = 'wood' | 'iron' | 'silver' | 'gold' | 'diamond'
export type ItemType = 'tool' | 'weapon' | 'block' | 'ore'
export type DropItem =
| 'Shovel' | 'Pick Axe' | 'Sword'
| 'leaves' | 'dirt' | 'wood' | 'stone' | 'gravel'
| 'coal' | 'iron' | 'silver' | 'gold' | 'ruby' | 'diamond' | 'emerald'
export interface Item {
name: DropItem
type: ItemType
icon: string
hasQuality?: boolean
builds?: BlockType
}
import type { ItemQuality, Item, InventoryItem } from '../types.d'
export const items: Item[] = [
{ name: 'Shovel', type: 'tool', icon: 'shovel', hasQuality: true },
{ name: 'Pick Axe', type: 'tool', icon: 'pick', hasQuality: true },
{ name: 'Sword', type: 'weapon', icon: 'sword', hasQuality: true },
{ name: 'Wooden Shovel', type: 'tool', icon: 'shovel', quality: 'wood' },
{ name: 'Wooden Pick Axe', type: 'tool', icon: 'pick', quality: 'wood' },
{ name: 'Wooden Sword', type: 'tool', icon: 'sword', quality: 'wood' },
{ name: 'Iron Shovel', type: 'tool', icon: 'shovel', quality: 'iron' },
{ name: 'Iron Pick Axe', type: 'tool', icon: 'pick', quality: 'iron' },
{ name: 'Iron Sword', type: 'tool', icon: 'sword', quality: 'iron' },
{ name: 'Diamond Shovel', type: 'tool', icon: 'shovel', quality: 'diamond' },
{ name: 'Diamond Pick Axe', type: 'tool', icon: 'pick', quality: 'diamond' },
{ name: 'Diamond Sword', type: 'tool', icon: 'sword', quality: 'diamond' },
{ name: 'Wooden Shovel', type: 'tool', icon: 'shovel', quality: 'wood' },
{ name: 'Wooden Pick Axe', type: 'tool', icon: 'pick', quality: 'wood' },
{ name: 'Wooden Sword', type: 'tool', icon: 'sword', quality: 'wood' },
{ name: 'leaves', type: 'block', icon: 'leaves', builds: 'treeLeaves' },
{ name: 'dirt', type: 'block', icon: 'dirt', builds: 'soil' },
@ -39,13 +34,11 @@ export const items: Item[] = [
export const damage: Record<ItemQuality, number> = {
wood: 1,
iron: 2,
silver: 3,
gold: 5,
diamond: 8,
iron: 3,
diamond: 5,
}
export function getItem(name: string, quality = null) {
export function getItem(name: string, quality?: ItemQuality) {
const item = items.find(i => i.name === name)
if (item) {
return {

View file

@ -1,7 +1,7 @@
<script setup lang="ts">
import { ref, computed, onUnmounted } from 'vue'
import { getItemClass } from '../level/items'
import type { InventoryItem } from '../util/usePlayer'
import type { InventoryItem } from '../types.d'
export interface Props {
items: InventoryItem[]
@ -10,7 +10,7 @@ export interface Props {
const props = defineProps<Props>()
const emit = defineEmits<{
(event: 'selection', value: InventoryItem | null): void
(event: 'selection', value: InventoryItem): void
}>()
// inventory size is 15

52
src/types.d.ts vendored
View file

@ -1,8 +1,10 @@
export type ItemQuality = 'wood' | 'iron' | 'silver' | 'gold' | 'diamond'
export type ItemType = 'tool' | 'weapon' | 'block' | 'ore'
export type ItemQuality = 'wood' | 'iron' | 'diamond'
export type ItemType = 'tool' | 'block' | 'ore'
export type DropItem =
| 'Shovel' | 'Pick Axe' | 'Sword'
| 'Wooden Shovel' | 'Iron Shovel' | 'Diamond Shovel'
| 'Wooden Pick Axe' | 'Iron Pick Axe' | 'Diamond Pick Axe'
| 'Wooden Sword' | 'Iron Sword' | 'Diamond Sword'
| 'leaves' | 'dirt' | 'wood' | 'stone' | 'gravel'
| 'coal' | 'iron' | 'silver' | 'gold' | 'ruby' | 'diamond' | 'emerald'
@ -10,12 +12,29 @@ export interface Item {
name: DropItem
type: ItemType
icon: string
hasQuality?: boolean
quality?: ItemQuality
builds?: BlockType
}
export interface ToolItem extends Item {
type: 'tool'
quality: ItemQuality
}
export interface BlockItem extends Item {
type: 'block'
builds: BlockType
}
export type BlockType =
| 'air' | 'grass'
| 'treeCrown' | 'treeLeaves' | 'treeTrunk' | 'treeRoot' | 'treeRootRight' | 'treeRootMiddle' | 'treeRootLeft'
| 'soil' | 'soilGravel' | 'stone' | 'stoneGravel'
| 'bedrock' | 'cave'
| 'brickWall'
export type Block = {
type: string, // what is 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?
@ -24,12 +43,20 @@ export type Block = {
drops?: DropItem, // what do I get, when loot it?
}
export type BlockType =
| 'air' | 'grass'
| 'treeCrown' | 'treeLeaves' | 'treeTrunk' | 'treeRoot'
| 'soil' | 'soilGravel' | 'stone' | 'stoneGravel'
| 'bedrock' | 'cave'
| 'brickWall'
// describes a changed block, eg digged or placed by the player
type DamagedBlock = {
change: 'damage'
x: number
y: number
damage: number
}
type ChangedBlock = {
change: 'exchange'
x: number
y: number
newType: BlockType
}
type Change = DamagedBlock | ChangedBlock
export interface InventoryItem extends Item {
amount: number
@ -52,3 +79,6 @@ export interface Npc extends Moveable {
export interface Player extends Moveable {
inventory: InventoryItem[]
}
export type Direction = 'at' | 'left' | 'right' | 'up' | 'down'

View file

@ -135,11 +135,11 @@ export default function useBackground (canvasEl: HTMLCanvasElement, w: number, h
const grH = h / rayQuality
const ctx = canvasEl.getContext('2d')
if (ctx === null) return // like, how old is your browser?
if (ctx === null) return () => {} // like, how old is your browser?
const grCanvasEl = document.createElement('canvas')
const grCtx = grCanvasEl.getContext('2d')
if (grCtx === null) return // like, how old is your browser?
if (grCtx === null) return () => {} // for real, how old is it?
grCanvasEl.width = grW
grCanvasEl.height = grH

View file

@ -1,14 +1,16 @@
import type { ComputedRef } from 'vue'
import type { Ref, ComputedRef } from 'vue'
import { BLOCK_SIZE, STAGE_WIDTH, STAGE_HEIGHT } from '../level/def'
type RefOrComputed<T> = Ref<T> | ComputedRef<T>
export default function useLightMap(
ctx: CanvasRenderingContext2D,
x: ComputedRef<number>,
y: ComputedRef<number>,
tx: ComputedRef<number>,
ty: ComputedRef<number>,
time: ComputedRef<number>,
lightBarrier: ComputedRef<number[]>,
x: RefOrComputed<number>,
y: RefOrComputed<number>,
tx: RefOrComputed<number>,
ty: RefOrComputed<number>,
time: RefOrComputed<number>,
lightBarrier: RefOrComputed<number[]>,
) {
const W = ((STAGE_WIDTH + 2) * BLOCK_SIZE)
const H = ((STAGE_HEIGHT + 2) * BLOCK_SIZE)

View file

@ -1,15 +1,6 @@
import { computed, reactive } from 'vue'
import { RECIPROCAL, STAGE_WIDTH, STAGE_HEIGHT } from '../level/def'
import type { Item, ItemQuality } from '../level/items'
export interface InventoryItem extends Item {
amount: number
quality: ItemQuality | null
}
export interface Player extends Moveable {
inventory: InventoryItem[]
}
import type { Item, Player } from '../types.d'
const player = reactive<Player>({
x: Math.round((STAGE_WIDTH + 2) / 2),
@ -17,7 +8,7 @@ const player = reactive<Player>({
lastDir: 0,
vx: 0,
vy: 1, // always falling, because of gravity
inventory: [], // not yet in use
inventory: [],
})
const pocket = (newItem: Item) => {

12
src/vite-env.d.ts vendored
View file

@ -1,18 +1,6 @@
/// <reference types="vite/client" />
declare global {
interface Moveable {
x: number // position on x-axis (fixed for the player)
y: number // position on y-axis (fixed for the player)
lastDir: number // store last face direction
vx: number // velocity on the x-axis
vy: number // velocity on the y-axis
}
interface Npc extends Moveable {
hostile: boolean
inventory: InventoryItem[]
}
}
export {}