Phase A: wire climate + day/night into the world; design doc
Bump the engine submodule to a684c23 (Climate + day/night ambient). The world scene now registers UseClimate and UseDayNight, so it darkens at night and the HUD shows the season and temperature alongside the date. Add docs/растения.md capturing the whole plant-ecosystem design (growth as a suitability product, hybrid Mendelian genome, climate, lighting with shadows, reproduction, persistence) and the A-D phase plan. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
147ab203f1
commit
aff5a947c5
@@ -1,6 +1,11 @@
|
|||||||
{
|
{
|
||||||
"hud.world": "LittleSim | seed {0} | {1} | {2} FPS",
|
"hud.world": "LittleSim | seed {0} | {1} | {2} FPS",
|
||||||
"hud.datetime": "day {0}, {1:00}:{2:00}",
|
"hud.datetime": "day {0}, {1:00}:{2:00}",
|
||||||
|
"hud.climate": "{0} {1}°C",
|
||||||
|
"season.spring": "spring",
|
||||||
|
"season.summer": "summer",
|
||||||
|
"season.autumn": "autumn",
|
||||||
|
"season.winter": "winter",
|
||||||
"hud.controls": "WASD — camera, wheel — zoom, ` — console, F1 — inspector",
|
"hud.controls": "WASD — camera, wheel — zoom, ` — console, F1 — inspector",
|
||||||
"hud.paused": "PAUSED",
|
"hud.paused": "PAUSED",
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,11 @@
|
|||||||
{
|
{
|
||||||
"hud.world": "LittleSim | сид {0} | {1} | {2} FPS",
|
"hud.world": "LittleSim | сид {0} | {1} | {2} FPS",
|
||||||
"hud.datetime": "день {0}, {1:00}:{2:00}",
|
"hud.datetime": "день {0}, {1:00}:{2:00}",
|
||||||
|
"hud.climate": "{0} {1}°C",
|
||||||
|
"season.spring": "весна",
|
||||||
|
"season.summer": "лето",
|
||||||
|
"season.autumn": "осень",
|
||||||
|
"season.winter": "зима",
|
||||||
"hud.controls": "WASD — камера, колесо — зум, ` — консоль, F1 — инспектор",
|
"hud.controls": "WASD — камера, колесо — зум, ` — консоль, F1 — инспектор",
|
||||||
"hud.paused": "ПАУЗА",
|
"hud.paused": "ПАУЗА",
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,84 @@
|
|||||||
|
# Растения как экосистема
|
||||||
|
|
||||||
|
Дизайн системы растений: рост зависит от среды, среда описана факторами, реакция растения на
|
||||||
|
факторы задаётся **генами**, а размножение передаёт гены потомкам с мутацией — появляется
|
||||||
|
естественный отбор. Документ — единый ориентир для фаз A–D; детали каждой фазы уточняются её
|
||||||
|
отдельным планом.
|
||||||
|
|
||||||
|
## Модель роста
|
||||||
|
|
||||||
|
Скорость роста растения в данный момент:
|
||||||
|
|
||||||
|
```
|
||||||
|
скорость = база × пригодность(свет) × пригодность(температура) × пригодность(плодородность)
|
||||||
|
```
|
||||||
|
|
||||||
|
Каждая «пригодность» — число в [0..1] из кривой отклика (движковый `ResponseCurve`, модуль
|
||||||
|
`MrGameEng.AI`) с **оптимумом** и **шириной толерантности**, которые берутся из генов растения.
|
||||||
|
Растение вне своих оптимумов растёт медленно или стоит; в своих — быстро. Так все факторы среды
|
||||||
|
сводятся к одному механизму, а различие видов/особей — целиком в генах.
|
||||||
|
|
||||||
|
Фактор «возраст/стадия» остаётся как сейчас (`PlantGrowthStage` в дефах): пригодности умножают
|
||||||
|
прирост `AgeDays`, стадии переключают спрайт/размер по накопленному возрасту.
|
||||||
|
|
||||||
|
## Факторы среды
|
||||||
|
|
||||||
|
- **Свет** — амбиент день/ночь (`MrGameEng.Lighting.DayNight`), сэмплируемый в точке
|
||||||
|
(`SampleAt(world)`); глобальный в фазе A, локальный (с тенями) в фазе D.
|
||||||
|
- **Температура** — непрерывная, из климата (`MrGameEng.Core.Climate`): сезонный синус по дню года
|
||||||
|
+ суточные колебания (холоднее ночью).
|
||||||
|
- **Плодородность** — пока константа типа террейна (`TerrainDef.Fertility`); позже возможна
|
||||||
|
по-клеточная почва с истощением/восстановлением.
|
||||||
|
|
||||||
|
## Гены (диплоидный геном, гибридная экспрессия)
|
||||||
|
|
||||||
|
Каждое растение несёт **геном**: по паре аллелей на ген. Экспрессия гибридная:
|
||||||
|
|
||||||
|
- **Числовые гены** (оптимум света, толерантность к свету, оптимум температуры, толерантность,
|
||||||
|
потребность в плодородности, макс. размер, базовая скорость, продолжительность жизни, дальность
|
||||||
|
расселения, плодовитость, темп мутаций, способность к самоопылению) — фенотип = **смешение**
|
||||||
|
(среднее двух аллелей). Реализм отбора: промежуточные значения, плавный дрейф.
|
||||||
|
- **Дискретные гены** (например, цвет/морфа, наличие признака) — **доминант/рецессив**: рецессивный
|
||||||
|
фенотип виден только в гомозиготе (aa).
|
||||||
|
|
||||||
|
Наследование (мейоз): каждый родитель отдаёт по одному случайному аллелю на ген; потомок получает
|
||||||
|
по одному от каждого. Затем — мутация (с вероятностью из гена темпа мутаций сдвигаем числовой
|
||||||
|
аллель/переключаем дискретный). Всё детерминировано сидом мира.
|
||||||
|
|
||||||
|
Стартовая популяция: геномы генерируются из сида (вид задаёт базовый геном и разброс аллелей в
|
||||||
|
дефе; особи отклоняются).
|
||||||
|
|
||||||
|
## Размножение (полуреалистичное)
|
||||||
|
|
||||||
|
- **Перекрёстное опыление (приоритет):** зрелое растение ищет зрелого соседа того же вида в радиусе
|
||||||
|
(ген дальности; запрос через spatial-hash движка). Есть партнёр → семя с геномом от двух
|
||||||
|
родителей (Мендель + мутация).
|
||||||
|
- **Самоопыление (запас):** нет партнёра и ген «способность к самоопылению» позволяет → семя из
|
||||||
|
одного родителя (само-скрещивание аллелей + мутация).
|
||||||
|
- **Расселение:** семя падает в клетку в радиусе расселения; прорастает, если клетка подходит
|
||||||
|
(суша, не занято сверх лимита, пригодность не нулевая).
|
||||||
|
- **Лимит плотности:** не больше N растений на клетку/площадь — иначе взрыв численности.
|
||||||
|
- **Старение/смерть:** возраст превышает ген жизни → смерть; или длительный стресс (пригодность
|
||||||
|
около нуля) → гибель. Смерть освобождает место — баланс с размножением и основа отбора.
|
||||||
|
|
||||||
|
## Производительность и сейв
|
||||||
|
|
||||||
|
- Представление — **по сущности на растение** (видно в рендере и ECS-инспекторе, индивидуальные
|
||||||
|
гены). Защита от взрыва: лимит плотности, смерть, разумные радиусы, проверки размножения по
|
||||||
|
таймеру/сезону (не каждый кадр на каждое растение), spatial-hash для соседей.
|
||||||
|
- **Персист:** геномы, позиции, возраст и стадия растений сохраняются в `WorldSave` (мир больше не
|
||||||
|
воспроизводится только из сида — эволюция переживает загрузку).
|
||||||
|
- **Детерминизм:** мутации/расселение/опыление — на сидированном `Random`, как в остальной симуляции.
|
||||||
|
|
||||||
|
## Фазы реализации
|
||||||
|
|
||||||
|
- **A — климат и день/ночь (движок).** `Climate` (температура/сезон поверх `Calendar`),
|
||||||
|
`DayNight` (амбиент, `Renderer2D.AmbientLight` на World-слоях, сэмплируемый `SampleAt`),
|
||||||
|
затемнение мира ночью, HUD: сезон/температура/время. Фундамент для влияния среды на рост.
|
||||||
|
- **B — гены и рост по пригодностям (игра).** Компонент `PlantGenome`, расчёт пригодностей
|
||||||
|
(свет из `DayNight.SampleAt`, температура из `Climate`, плодородность из террейна), замена
|
||||||
|
плоского `GrowthRate`. Геном виден/правится в инспекторе.
|
||||||
|
- **C — размножение и смерть (игра).** Перекрёстное/самоопыление, расселение, лимит плотности,
|
||||||
|
старение/стресс-смерть, персист популяции в сейв.
|
||||||
|
- **D — полноценное 2D-освещение (движок).** Точечные источники + тени (окклюзия от препятствий);
|
||||||
|
`DayNight.SampleAt` начинает возвращать локальную освещённость, и затенённые растения растут хуже.
|
||||||
+1
-1
Submodule engine updated: f39ee9e787...a684c23cd9
@@ -13,6 +13,7 @@ using MrGameEng.DevConsole;
|
|||||||
using MrGameEng.Graphics;
|
using MrGameEng.Graphics;
|
||||||
using MrGameEng.Input;
|
using MrGameEng.Input;
|
||||||
using MrGameEng.Inspector;
|
using MrGameEng.Inspector;
|
||||||
|
using MrGameEng.Lighting;
|
||||||
using MrGameEng.Tilemaps;
|
using MrGameEng.Tilemaps;
|
||||||
using MrGameEng.UI;
|
using MrGameEng.UI;
|
||||||
using Myra.Graphics2D;
|
using Myra.Graphics2D;
|
||||||
@@ -74,6 +75,8 @@ public sealed class WorldScene : Scene
|
|||||||
this.UseTilemaps();
|
this.UseTilemaps();
|
||||||
|
|
||||||
var calendar = Context.UseCalendar(SecondsPerDay);
|
var calendar = Context.UseCalendar(SecondsPerDay);
|
||||||
|
var climate = Context.UseClimate(ClimateSettings.Default);
|
||||||
|
this.UseDayNight(renderer); // мир темнеет ночью — амбиент идёт в рендер
|
||||||
|
|
||||||
// Рельеф и расстановка растений детерминированы сидом мира (независимые потоки seed).
|
// Рельеф и расстановка растений детерминированы сидом мира (независимые потоки seed).
|
||||||
var plants = new PlantSet(content, atlases, device);
|
var plants = new PlantSet(content, atlases, device);
|
||||||
@@ -105,7 +108,15 @@ public sealed class WorldScene : Scene
|
|||||||
new GodCameraSystem(camera, input, renderer, console, () => _pause.IsOpen)
|
new GodCameraSystem(camera, input, renderer, console, () => _pause.IsOpen)
|
||||||
);
|
);
|
||||||
UpdateSystems.Add(
|
UpdateSystems.Add(
|
||||||
new HudSystem(Context, content.Languages, hudLabel, "hud.world", _config.Seed, calendar)
|
new HudSystem(
|
||||||
|
Context,
|
||||||
|
content.Languages,
|
||||||
|
hudLabel,
|
||||||
|
"hud.world",
|
||||||
|
_config.Seed,
|
||||||
|
calendar,
|
||||||
|
climate
|
||||||
|
)
|
||||||
);
|
);
|
||||||
UpdateSystems.Add(new CallbackSystem(() => Hotkeys(input)));
|
UpdateSystems.Add(new CallbackSystem(() => Hotkeys(input)));
|
||||||
|
|
||||||
|
|||||||
@@ -185,7 +185,8 @@ public sealed class HudSystem(
|
|||||||
Myra.Graphics2D.UI.Label label,
|
Myra.Graphics2D.UI.Label label,
|
||||||
string titleKey,
|
string titleKey,
|
||||||
int seed,
|
int seed,
|
||||||
MrGameEng.Core.Calendar? calendar = null
|
MrGameEng.Core.Calendar? calendar = null,
|
||||||
|
MrGameEng.Core.Climate? climate = null
|
||||||
) : BaseSystem
|
) : BaseSystem
|
||||||
{
|
{
|
||||||
private float _accumulated;
|
private float _accumulated;
|
||||||
@@ -206,6 +207,14 @@ public sealed class HudSystem(
|
|||||||
var when = calendar is null
|
var when = calendar is null
|
||||||
? ""
|
? ""
|
||||||
: languages.Format("hud.datetime", calendar.Day, calendar.Hour, calendar.Minute);
|
: languages.Format("hud.datetime", calendar.Day, calendar.Hour, calendar.Minute);
|
||||||
|
if (climate is not null)
|
||||||
|
{
|
||||||
|
var season = languages.Get("season." + climate.Season.ToString().ToLowerInvariant());
|
||||||
|
when +=
|
||||||
|
" | "
|
||||||
|
+ languages.Format("hud.climate", season, (int)MathF.Round(climate.Temperature));
|
||||||
|
}
|
||||||
|
|
||||||
label.Text =
|
label.Text =
|
||||||
languages.Format(titleKey, seed, when, fps) + "\n" + languages.Get("hud.controls");
|
languages.Format(titleKey, seed, when, fps) + "\n" + languages.Get("hud.controls");
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user