silphius/app/create-forest.js
2024-07-10 14:59:07 -05:00

148 lines
3.7 KiB
JavaScript

import alea from 'alea';
import {createNoise2D} from 'simplex-noise';
import {createRandom, Generator} from '@/util/math.js';
import createEcs from './create-ecs.js';
const seed = 42069;
const prng = alea(seed);
const rawNoise = createNoise2D(prng);
const noise = (x, y) => (1 + rawNoise(x, y)) / 2;
const random = createRandom(seed);
const indexComputer = (indices, randomizer) => (
(position) => indices[Math.floor(indices.length * randomizer(position))]
);
const [w, h] = [256, 256];
const Forest = new Generator({
calculate: indexComputer(
[1, 3, 4, 10, 11, 12], // grass
({x, y}) => noise(x * 30, y * 30),
),
covers: () => true,
size: {w, h},
children: [
new Generator({
calculate: indexComputer(
[342, 456], // dirt
({x, y}) => noise(x * 30, y * 30),
),
covers: ({x, y}) => noise(x * (1 / 16), y * (1 / 16)) < 0.5,
size: {w, h},
children: [
new Generator({
calculate: indexComputer(
[407, 408, 423, 424], // stone path
({x, y}) => noise(x * 30, y * 30),
),
covers: ({x, y}) => noise(x * (1 / 16), y * (1 / 16)) < 0.1625,
size: {w, h},
}),
],
}),
new Generator({
calculate: indexComputer(
[103, 104], // water
({x, y}) => noise(x * 30, y * 30),
),
covers: ({x, y}) => noise(x * (1 / 32), y * (1 / 32)) < 0.3,
size: {w, h},
}),
],
});
export default async function createForest(Ecs) {
const ecs = createEcs(Ecs);
const area = {x: w, y: h};
const master = ecs.get(await ecs.create({
AreaSize: {x: area.x * 16, y: area.y * 16},
Ticking: {},
TileLayers: {
layers: [
{
area,
data: Array(w * h).fill(0),
source: '/assets/tileset.json',
tileSize: {x: 16, y: 16},
},
{
area,
data: Array(w * h).fill(0),
source: '/assets/tileset.json',
tileSize: {x: 16, y: 16},
},
],
},
Time: {},
}));
Forest.generate();
const layer0 = master.TileLayers.layers[0];
layer0.data = Forest.matrix;
for (let y = 0; y < h; ++y) {
for (let x = 0; x < w; ++x) {
const dirt = Forest.children[0].matrix[y * w + x];
if (dirt) {
layer0.data[y * w + x] = dirt;
}
const stone = Forest.children[0].children[0].matrix[y * w + x];
if (stone) {
layer0.data[y * w + x] = stone;
}
const water = Forest.children[1].matrix[y * w + x];
if (water) {
layer0.data[y * w + x] = water;
}
}
}
const entityPosition = (x, y) => ({
x: (8 + (x * 16) + random() * 8 - 4),
y: (8 + (y * 16) + random() * 8 - 4),
});
for (let y = 0; y < h; ++y) {
for (let x = 0; x < w; ++x) {
let v = noise(x * (1 / 24), y * (1 / 24));
if (v > 0.2) {
v = noise(x * (1 / 7), y * (1 / 7));
if (v < 0.15) {
await ecs.create({
Position: entityPosition(x, y),
Sprite: {
anchorY: 0.7,
source: '/assets/ambient/shrub.json',
},
VisibleAabb: {},
});
}
else if (v < 0.17) {
await ecs.create({
Position: entityPosition(x, y),
Sprite: {
anchorY: 0.875,
source: '/assets/ambient/tree.json',
},
VisibleAabb: {},
});
}
v = noise(x * (1 / 12), y * (1 / 12));
if (v < 0.08) {
await ecs.create({
Position: entityPosition(x, y),
Sprite: {
anchorY: 0.7,
source: '/assets/ambient/flower.json',
},
VisibleAabb: {},
});
}
}
}
}
return ecs;
}