🎉 initial commit

This commit is contained in:
2026-03-20 08:11:31 +00:00
commit fe389a9856
25 changed files with 3621 additions and 0 deletions

77
src/utils/noise.ts Normal file
View File

@@ -0,0 +1,77 @@
import { createNoise2D } from 'simplex-noise'
import { WORLD_TILES } from '../config'
import { TileType } from '../types'
/** Simple seeded PRNG (mulberry32) */
function mulberry32(seed: number): () => number {
return () => {
seed |= 0
seed = (seed + 0x6D2B79F5) | 0
let t = Math.imul(seed ^ (seed >>> 15), 1 | seed)
t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t
return ((t ^ (t >>> 14)) >>> 0) / 4294967296
}
}
function classify(e: number, m: number): TileType {
if (e < 0.22) return TileType.DEEP_WATER
if (e < 0.30) return TileType.SHALLOW_WATER
if (e < 0.38) return TileType.SAND
if (e > 0.82) return TileType.ROCK
// land split by moisture
if (m > 0.62 && e > 0.48) return TileType.FOREST
if (m > 0.38) return TileType.DARK_GRASS
return TileType.GRASS
}
export function generateTerrain(seed: number): number[] {
const prng1 = mulberry32(seed)
const prng2 = mulberry32(seed ^ 0xDEADBEEF)
const elevNoise = createNoise2D(prng1)
const moistNoise = createNoise2D(prng2)
const size = WORLD_TILES
const tiles = new Array<number>(size * size)
for (let y = 0; y < size; y++) {
for (let x = 0; x < size; x++) {
// Multi-octave elevation
const nx = x / size
const ny = y / size
const e =
(elevNoise(nx * 4, ny * 4) * 1.0 +
elevNoise(nx * 8, ny * 8) * 0.5 +
elevNoise(nx * 16, ny * 16) * 0.25) / 1.75
const eNorm = (e + 1) / 2 // -1..1 → 0..1
const m = moistNoise(nx * 6 + 10, ny * 6 + 10)
const mNorm = (m + 1) / 2
tiles[y * size + x] = classify(eNorm, mNorm)
}
}
return tiles
}
/** Find a walkable spawn tile near the world center */
export function findSpawn(tiles: number[]): { tileX: number; tileY: number } {
const center = Math.floor(WORLD_TILES / 2)
const walkable = new Set([TileType.GRASS, TileType.DARK_GRASS, TileType.SAND])
for (let r = 0; r < center; r++) {
for (let dy = -r; dy <= r; dy++) {
for (let dx = -r; dx <= r; dx++) {
if (Math.abs(dx) !== r && Math.abs(dy) !== r) continue
const tx = center + dx
const ty = center + dy
if (tx < 0 || ty < 0 || tx >= WORLD_TILES || ty >= WORLD_TILES) continue
if (walkable.has(tiles[ty * WORLD_TILES + tx])) {
return { tileX: tx, tileY: ty }
}
}
}
}
return { tileX: center, tileY: center }
}