silphius/app/create-forest.js

148 lines
3.7 KiB
JavaScript
Raw Normal View History

2024-07-10 14:59:07 -05:00
import alea from 'alea';
import {createNoise2D} from 'simplex-noise';
import {createRandom, Generator} from '@/util/math.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},
}),
],
});
2024-07-11 16:01:16 -05:00
export default async function createForest() {
2024-07-10 14:59:07 -05:00
const area = {x: w, y: h};
2024-07-11 16:01:16 -05:00
const entities = [];
entities.push({
2024-07-10 14:59:07 -05:00
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: {},
2024-07-11 03:09:15 -05:00
Water: {},
2024-07-11 16:01:16 -05:00
});
2024-07-10 14:59:07 -05:00
Forest.generate();
2024-07-11 16:01:16 -05:00
const master = entities[0];
2024-07-10 14:59:07 -05:00
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) {
2024-07-11 16:01:16 -05:00
entities.push({
2024-07-10 14:59:07 -05:00
Position: entityPosition(x, y),
Sprite: {
anchorY: 0.7,
source: '/assets/ambient/shrub.json',
},
VisibleAabb: {},
});
}
else if (v < 0.17) {
2024-07-11 16:01:16 -05:00
entities.push({
2024-07-10 14:59:07 -05:00
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) {
2024-07-11 16:01:16 -05:00
entities.push({
2024-07-10 14:59:07 -05:00
Position: entityPosition(x, y),
Sprite: {
anchorY: 0.7,
source: '/assets/ambient/flower.json',
},
VisibleAabb: {},
});
}
}
}
}
2024-07-11 16:01:16 -05:00
return entities;
2024-07-10 14:59:07 -05:00
}