17 KiB
Поселение
Здания и развитие города: Ратуша, участки, свободная стройка на сетке, постройка зданий, восстановление города из сохранения. Люди города — отдельный модуль Население, связь только через контракты ядра.
- Ответственность: совместная.
- Сборка:
Bogatyri.Settlement. - Папка:
Assets/Scripts/Modules/Settlement. - Зависит от: ядра. Ресурсы на стройку берёт через
IEconomy.
Стройка на сетке
Игрок сам выбирает, где строить. Участки (BuildSlot) больше не нужны: они и площадки «Застройка» прячутся при запуске, сцену менять не надо.
- Сетка (
BuildGrid). Клетка — 1 единица мира, сетка прямоугольная. Область стройки — прямоугольник вокруг старых участков и Ратуши с запасомpadding(3 клетки). Можно задать руками: поставитьBuildGridна сцену,autoArea = false,areaMin/areaMax. Объект создаётся сам, если его нет. - Занятые клетки: под Ратушей и под каждым построенным зданием. Пересчёт раз в 0.3 с, пока сетка видна, и перед каждой постройкой.
- Размер здания:
BuildingData.footprint(ширина × высота в клетках).0 × 0— посчитать поBoxCollider2Dпрефаба (иначе по картинке), округлив до клеток. Размер здания задаётся там же, в карточке здания. - Призрак (
BuildGhost): полупрозрачная копия картинки здания и пятно клеток под ней — зелёное (свободно) или красное (занято / за границей). Только картинка: скриптов и коллайдеров нет, экономика его не видит. - Постройка:
BuildManager.BuildAt(data, cell)— проверяет клетки и ресурсы, списывает цену, ставит префаб так, чтобы его коллайдер лёг на клетки призрака, публикуетBuildingPlacedEvent.CanBuildAt(data, cell)— та же проверка без постройки. - Старые сохранения: здания встают на свои позиции, занятость считается по тому, какие клетки здание накрывает. Ничего переносить не нужно.
Управление — Meta/Build/BuildModeController (слой приложения):
- «СТРОЙКА» — сетка на земле, подсказка сверху, список зданий (размер в клетках, цена; закрытые по уровню Ратуши — серые).
- «Выбрать» — призрак встаёт в центр экрана или на ближайшее свободное место.
- Тащить призрак пальцем (за пятно) или тапнуть по земле — призрак прыгает туда. Камера в это время стоит (
UIBlocker.WorldInputCaptured). - Нижняя панель: «Поставить» (место свободно и хватает ресурсов), «Другое», «Отмена».
- После постройки режим остаётся; «Здания» сверху — строить дальше, «Выйти» — сетка прячется.
Стройка по времени, лимиты, перенос (01.11.2026, решения 04.11; числа — ТЕСТ)
- Время реальное (решение 04.11): 60 с стройки — 60 реальных секунд, «игровой час» к стройке не относится. Развитие долгосрочное: позже — тиры T1/T2/T3 и внутри них уровни с растущим временем (шкалу согласуют отдельно).
- Стройка и улучшение идут по времени (
BuildTimer). Постройка —buildSeconds(60 с), улучшение до уровня N —upgradeSecondsToLevel(60 с … 2 ч), Ратуша ×2. Время — часы игры (GameClock.UnixNowMs): идёт и в офлайне, и при перемотке DEV. - Пока здание строится, оно полупрозрачное и не работает: его скрипты выключены,
App/CitySyncего не считает (нет мест, жилья, лимитов; Казармы не учат, Терем без героя). При улучшении здание работает на старом уровне, новый — когда время выйдет. - Строители: одновременно не больше
builders(2) строек и улучшений, Ратуша тоже занимает строителя. - Ускорение: 1 кристалл за
secondsPerGem(30) секунд оставшегося времени — кнопка в окне здания. - Лимит зданий по уровню Ратуши (
EconomyConfig.buildingLimits): в списке стройки «построено 2 / 3», сверх лимита — «Лимит: больше на Ратуше N ур.». Здания не из таблицы — без лимита. В окне Ратуши — каких зданий станет больше на следующем уровне. - Перенос: кнопка «Перенести» в окне здания — режим стройки с призраком на месте здания, «Сюда» — здание переезжает бесплатно (
BuildModeController.StartMove,BuildGrid.IgnoredBuilding). Стройка или улучшение продолжаются. - Сноса нет (решение 04.11): удалить здание и вернуть ресурсы нельзя. Перенос — бесплатно, в пределах поселения, уровень и текущие стройка или улучшение сохраняются. Ратушу не переносят.
- Офлайн по временным меткам (решение 04.11): в сохранении хранится момент конца стройки. После входа стройка вступает в силу в тот момент офлайн-расчёта добычи, когда время дошло до её конца (
App/ConstructionClock, событиеGameTimeSimulatedEventот Населения,BuildTimer.MayComplete). Добыча нового здания или уровня идёт с момента завершения (точность — шаг расчёта 10 минут, никогда не раньше конца стройки). - Проверки: таймер из файла принимается, только если он осмыслен (постройка — у здания 1 уровня, улучшение — до уровня выше текущего); завершение только повышает уровень, повторное ничего не даёт; перенос не тратит и не возвращает ресурсы.
Контракт ISettlement
| Свойство | Что значит |
|---|---|
TownHallLevel |
Уровень Ратуши (если город не открыт — из сохранения). |
BuildingCount |
Сколько построек. |
IsCityLoaded |
Открыта ли сейчас сцена города. |
Получить: GameServices.Get<ISettlement>().
События
Публикует:
BuildingPlacedEvent— здание построено (имя здания);TownHallLevelChangedEvent— Ратуша улучшена (новый уровень);SettlementRestoringEvent— город начинает восстанавливаться из сохранения. На негоApp/GameModulesдобавляет Казармы в список стройки.
Слушает: ничего.
Сохранение
Секция "settlement": { "townHallLevel", "townHallTimerStartMs", "townHallTimerEndMs", "townHallTimerTargetLevel", "placedBuildings": [ { "buildingName", "posX", "posY", "level", "timerKind", "timerStartMs", "timerEndMs", "timerTargetLevel" } ] }. Поля таймера (01.11) — стройка или улучшение, которое ещё идёт (timerKind: 0 — нет, 1 — постройка, 2 — улучшение). В старых сохранениях их нет — значит, ничего не строится.
Сброс (ResetState): Ратуша 1 уровня, постройки убраны, участки освобождены, память модуля очищена. Иначе при следующем входе в город вернулись бы старые здания.
Модуль помнит последнее состояние города, поэтому сохранение на карте мира не стирает постройки. При каждом входе в город (BuildManager.Start) здания восстанавливаются один раз. Уровень здания берётся у любого компонента с ILeveledBuilding.
Файлы
| Файл | Что это |
|---|---|
SettlementModule.cs |
Точка входа: ISettlement, сохранение города, восстановление на сцене. |
BuildManager.cs |
Список зданий, постройка на сетке (BuildAt), поиск данных здания по имени. |
BuildGrid.cs |
Сетка стройки: область, занятые клетки, рисунок сетки. Там же BuildFootprint — размер здания в клетках. |
BuildGhost.cs |
Призрак здания в режиме стройки. |
BuildingData.cs |
Описание здания (ScriptableObject): префаб, размер на сетке, цена, нужный уровень Ратуши. |
TownHall.cs |
Ратуша и её улучшение. Раньше файл назывался NewEmptyCSharpScript.cs. |
BuildSlot.cs |
Участок под здание (старая схема, участки прячутся) и связь здания с участком. |
PlacedBuildingId.cs |
Метка построенного здания. Раньше файл назывался PlaceBuilding.cs. |
В слое приложения остаются BuildMenuUi.cs, Meta/Build/* (Казармы, BuildModeController).
Решения и план
- Решение команды от 19.10.2026 (этап 2): Ратуша даёт базовую вместимость жителей, новое здание «Дом» — дополнительные места.
- Лимит населения = база Ратуши + сумма Домов + бонусы, значения из
EconomyConfig. - Уровень поселения задаёт доступные уровни и количество жилья, а также минимальный гражданский резерв.
- Лимит населения = база Ратуши + сумма Домов + бонусы, значения из
- Этап 3: рабочие места в зданиях (
BuildingData), экран распределения рабочих. - Стройка на сетке (27.10.2026, по просьбе Володи): вернулись к свободной стройке — игрок сам выбирает место, сетка показывает границы и красные занятые клетки, у зданий разный размер.
- Этап 4 (утверждён без изменений): доступность зданий зависит от месторождений позиции.
Журнал изменений
| Дата | Кто | Что |
|---|---|---|
| 04.11.2026 | Claude | Решения 04.11: снос убран, остался бесплатный перенос; офлайн по временным меткам — стройка, закончившаяся офлайн, вступает в силу в момент завершения внутри расчёта добычи (ConstructionClock, GameTimeSimulatedEvent, BuildTimer.MayComplete); проверки таймеров из сохранения; уровень при завершении только растёт. |
| 01.11.2026 | Claude | Стройка и улучшение по времени (BuildTimer), 2 строителя, ускорение за кристаллы, офлайн; лимит зданий по уровню Ратуши; перенос и снос зданий из окна. Сохранение: поля таймера у зданий и Ратуши (старые сохранения читаются). Терем богатыря (HeroCastle) и гуляющий герой. Числа — ТЕСТ, EconomyConfig. |
| 01.11.2026 | Claude (Саша) | Новое здание «Госпиталь» в списке стройки (Meta/Build/HospitalBootstrap.cs, как Казармы): уровни I–V сохраняются как у остальных (ILeveledBuilding), тап — окно госпиталя. Места — в HospitalConfig. Арта нет: копия обычного здания светло-голубого цвета. |
| 01.11.2026 | Claude (Саша) | Для госпиталя (решения 31.10, п. 7) в ядре есть контракт IHospital.Beds — его будет регистрировать здание госпиталя (уровни I–V, 20–60 мест). Здания пока нет. |
| 31.10.2026 | Claude | Ратуша: тап больше не улучшает сразу, а открывает окно Ратуши (событие TownHall.Tapped, окно — App/BuildingWindow). Улучшение — кнопкой в окне, с ценой и тем, что откроется. |
| 31.10.2026 | Claude | Казармы стали уровневым зданием (ILeveledBuilding, уровень сохраняется как у остальных). Тап открывает окно Казарм: очередь обучения, какие войска открыты и что нужно для остальных, улучшение, кнопка «Нанять войска». Войско открывается, когда хватает и уровня Ратуши, и уровня Казарм; считаются самые прокачанные Казармы, каждые Казармы по-прежнему дают +1 место в очереди. Уровни Казарм: пехота 1, лучники 2, конница 3, осадные 5 (EconomyConfig, soldier.requiredBarracksLevel) — ТЕСТ, согласовать с Димой; цена улучшения общая, тоже не утверждена. |
| 31.10.2026 | Claude | Откат: Население снова самостоятельный модуль (Modules/Population), из Поселения убрано. |
| 28.10.2026 | Claude | Население стало частью Поселения (Settlement/Population, сборка Bogatyri.Settlement.Population) — как на схеме Димы. Подробности — Population.md. |
| 27.10.2026 | Claude | Свободная стройка на сетке: BuildGrid, BuildGhost, BuildingData.footprint, BuildManager.BuildAt / CanBuildAt / FindData. Участки и площадки «Застройка» прячутся. Новый BuildModeController (призрак, «Поставить / Другое / Отмена»), камера не двигается, пока тащат призрак. |
| 19.10.2026 | Claude | ResetState() для сброса сохранений. Убранные здания помечаются, чтобы запись в том же кадре их не сохранила. |
| 19.10.2026 | Claude | Модуль выделен. Стройка и Ратуша платят через IEconomy. Сохранение города перенесено из SaveManager в SettlementModule (секция "settlement"). Восстановление защищено от двойного запуска и от освобождения занятого участка. Файлы переименованы под имена классов. |