Use Perlin noise for surfaces
Эта ссылка описывает как можно сгенерировать различные поверхности с помощью всего одной функции Перлина. Нам нужно получить что-то похожее и тоже с формой архипелага. А именно: вода, суша, пустыня, горы, лед, вулканы. Основная идея здесь следующая - находясь на каком-то элементе, организм испытывает его влияние на каждой итерации. Например, находясь во льду, его инструкции будут выполняться медленнее (за один проход их выполнится меньше), что увеличит его продолжительность жизни, но уменьшит скорость ее течения. Должны быть области, где жить наиболее выгодно и те, где жить очень сложно. В конфигурации должен быть раздел surfaces с массивом поверхностей и значениями коэффициентов для траты энергии, скорости старения, скорости выполнения команд и т.д.
Список новшеств:
- Нужно чтобы мир рисовался слоями: сначала поверхность, потом организмы и молекулы
- Все поверхности должны быть динамическими (конфиг - со скоростью изменения). Это можно сделать введя параметр времени в функцию Перлина.
- Поверхности должны быть закешированы в одномерном массиве мира, состоящем из 6 битных (тип поверхности) + 26 битных значений (индекс организма/молекулы). Кеш обновляется тогда, когда изменяется параметр времени и пересчитывается весь кеш (должно быть редко). Сейчас это массив
World._data.
Дополнительную информацию для размышления можно взять отсюда и отсюда.
Вот какие параметры организма могут изменяться в зависимости от поверхности:
- количество затрачиваемой энергии (равен коэффициенту из конфигурации). Энергия уменьшается каждую итерацию.
- скорость старения (подумать над этим)
- скорость движения (сколько выполнится операторов
stepперед тем, как произойдет сдвиг на 1 пиксель) - количество мутаций
- количество выполняемых инструкций за итерацию (по сути - приоритет)
- количество помех в команде
see(вплоть до полного ее отказа. тогда она всегда возвращает 0. Зависит от освещенности. связано с #33) - количество помех в команде
listen, вплоть до ее отказа - скорость поедания (
join). Сколько команд выполняется до фактического присоединения молекулы
Продумать этот список Вот список поверхностей и их действий на организм
- вода - меньше скорость движения, трата энергии повышена, повышенные помехи в команде
listen, замедленное выполнение инструкций - земля - самая благоприятная. высокая скорость, минимальная трата энергии, жизни и старения. минимальная скорость мутаций.
- пустыня
- горы - так же, как лед, но чуть меньше.
- лед - замедленное выполнение инструкций должно соответствовать высоте. Оно должно быть ниже, чем в горах. Скорость старения должна быть тоже замедлена. Движение должно быть тоже замедленно.
- вулкан - максимум забирания энергии, замедленное движение. увеличенное количество мутаций
Реализация этого таска сложная. По этому, нужно разбить ее на этапы:
- сделать отрисовку поверхностей и занесение ее в массив мира с учётом битности
- последовательно реализововать трату энергии, замедление/ускорение выполнения кода, ухудшения видимости, слышимости и т.д. Каждый из этих пунктов влечёт за собой изменение одной или нескольких команд. Они и могут быть отдельными тасками.
var inc = 0;
var simplex = new SimplexNoise(() => inc+=0.12357241),
canvas = document.getElementById('c'),
ctx = canvas.getContext('2d'),
imgdata = ctx.getImageData(0, 0, canvas.width, canvas.height),
data = imgdata.data,
t = 0;
var scale = 160;
var speed = 1000;
var height = .8;
var shift = .3;
var SEA = [65,105,225];
var GROUND = [238,214,175];
var FOREST = [34,139,34];
var SNOW = [255,250,250];
var ROCKS = [139,137,137];
var width = 1000;
var radius = width / 2 - 10;
var r2 = radius**2;
var radius10 = radius + 10;
var radius90 = r2 * .5;
window.setInterval(() => {
for (var x = 0; x < width; x++) {
for (var y = 0; y < width; y++) {
let red = 1;
let green = 1;
let blue = 1;
let color = SEA;
const xy2 = (x - radius10)**2 + (y - radius10)**2;
if (xy2 <= r2) {
let r = simplex.noise3D(x / scale, y / scale, t / speed) * height + shift;
r = r * (xy2 > radius90 ? r2 / xy2 - 1 : 1);
if (r < 0.2) {color = SEA; blue = 1 - r / .2}
else if (r >= .2 && r < .4) {color = GROUND; red = green = (r / .4) / 4 + 0.75}
else if (r >= .4 && r < .6) {color = FOREST}
else if (r >= .6 && r < .8) {color = ROCKS}
else if (r >= .8) {color = SNOW}
}
data[(x + y * width) * 4 + 0] = color[0] * red;
data[(x + y * width) * 4 + 1] = color[1] * green;
data[(x + y * width) * 4 + 2] = color[2] * blue;
data[(x + y * width) * 4 + 3] = 255;
}
}
t++;
ctx.putImageData(imgdata, 0, 0);
}, 1000/60);
Связано с #28