diff --git a/app/routes/gen/route.jsx b/app/routes/gen/route.jsx new file mode 100644 index 0000000..05acee0 --- /dev/null +++ b/app/routes/gen/route.jsx @@ -0,0 +1,186 @@ +import {Container, Sprite, Stage} from '@pixi/react'; +import {useState} from 'react'; + +import TileLayer from '@/react/components/pixi/tile-layer.jsx'; +import AssetsContext from '@/react/context/assets.js'; +import {CHUNK_SIZE} from '@/util/constants.js'; + +import alea from 'alea'; +import {createNoise2D} from 'simplex-noise'; + +// const seed = 3; + +const dirt = [342, 456]; +const grass = [1, 3, 4, 10, 11, 12]; +// const stone = [407, 408, 423, 424]; +// const water = [103, 104]; + +class Generator { + constructor({ + area, + passes, + seed, + }) { + const prng = alea(seed); + const rawNoise = createNoise2D(prng); + this.noise = (x, y) => (1 + rawNoise(x, y)) / 2; + this.area = area; + this.passes = passes; + } + generate(fn) { + for (let y = 0; y < this.area.y; ++y) { + for (let x = 0; x < this.area.x; ++x) { + for (let j = this.passes.length - 1; j >=0; --j) { + if (this.passes[j].test(x, y, this.noise)) { + fn(this.passes[j].compute(x, y, this.noise), x, y); + break; + } + } + } + } + } +} + +function Gen() { + const area = {x: 80, y: 80}; + const assetsTuple = useState({}); + const [seed, setSeed] = useState(0); + const [dirtClump, setDirtClump] = useState(30); + const [dirtPer, setDirtPer] = useState(0.3); + + const dirtCheck = (x, y, noise) => noise(x / dirtClump, y / dirtClump) < dirtPer; + + const tilePasses = [ + { + test: () => 1, + compute: (x, y, noise) => grass[Math.floor(noise(x, y) * grass.length)], + }, + { + test: dirtCheck, + compute: (x, y, noise) => dirt[Math.floor(noise(x, y) * dirt.length)], + }, + { + test: (x, y, noise) => noise(x / 60, y / 60) < 0.25, + compute: () => 103, + }, + { + test: (x, y, noise) => noise(x / 60, y / 60) < 0.14, + compute: () => 104, + }, + ]; + + const entityPasses = [ + { + test: (x, y, noise) => ( + dirtCheck(x, y, noise) + && !(noise(x / 60, y / 60) < 0.25) + && noise(x, y) < 0.2 + ), + compute: (x, y) => ({ + anchor:{x: 0.5, y: 0.875}, + image: '/assets/ambient/tree.png', + x: x * 16, + y: y * 16, + }), + }, + { + test: (x, y, noise) => ( + !dirtCheck(x, y, noise) + && !(noise(x / 60, y / 60) < 0.25) + && noise(x / 5, y / 5) < 0.15 + ), + compute: (x, y, noise) => ({ + anchor:{x: 0.5, y: 0.7}, + image: '/assets/ambient/flower.png', + x: x * 16 + (noise(x, y) * 8 - 4), + y: y * 16 + (noise(y, x) * 8 - 4), + }), + }, + { + test: (x, y, noise) => ( + !dirtCheck(x, y, noise) + && !(noise(x / 60, y / 60) < 0.25) + && noise(x / 10, y / 10) < 0.2 + ), + compute: (x, y, noise) => ({ + anchor:{x: 0.5, y: 0.7}, + image: '/assets/ambient/shrub.png', + x: x * 16 + (noise(x, y) * 8 - 4), + y: y * 16 + (noise(y, x) * 8 - 4), + }), + }, + ]; + + const layer = { + area, + $$chunks: Array( + Math.ceil(area.x / CHUNK_SIZE) * Math.ceil(area.y / CHUNK_SIZE) + ).fill(0).map(() => ({})), + data: Array(area.x * area.y).fill(1), + source: '/assets/tileset.json', + tileSize: {x: 16, y: 16}, + }; + const tileGenerator = new Generator({ + area, + passes: tilePasses, + seed, + }); + tileGenerator.generate((tile, x, y) => { + layer.data[y * area.x + x] = tile; + }); + const entities = []; + const entityGenerator = new Generator({ + area, + passes: entityPasses, + seed, + }); + entityGenerator.generate((entity) => { + entities.push(entity); + }); + return ( + <> + + + + + {entities.map((entity, i) => ( + + ))} + + + + setSeed(value || 0)} value={seed} /> + setDirtPer(value)} + /> + setDirtClump(value)} + /> + + ); +} + +export default Gen;