№3 Будуємо в’язницю мишею, і кімнати, що знаходяться самі
· Nick
Другий етап завершено, і вперше є на що подивитися. Клієнт на Godot тепер стоїть поверх ядра симуляції, і мишею можна побудувати одноповерхову в’язницю: класти підлоги, малювати стіни, ставити двері, позначати кімнати, зносити зайве. Усе це прості куби та плоскі кольори, людей у ній, як і раніше, немає. Але це місце, і по ньому можна рухати камеру.
Що можна робити зараз
Ви починаєте нову гру, обираєте розмір карти (64, 128 або 256 клітинок у стороні) і, за бажанням, сид, і отримуєте порожню сітку. Камера ортографічна з фіксованим нахилом. Вона повертається суворо кроками по 90°, наближається до курсора, переміщується клавішами або середньою кнопкою і має режим виду згори для будівництва. Стіни ховали б кімнати від камери, що вільно обертається, тому вона не обертається вільно.
Підлоги та знесення приймають прямокутник. Стіни йдуть за контуром (або по прямій, якщо тримати Shift). Двері ставляться кліком і обирають напрямок за сусідніми стінами, а повернути їх можна клавішею. Поки ви тягнете, ділянка під курсором показується привидом: зелені клітинки будуть побудовані, червоні – пропущені, а підпис повідомляє скільки і чому. До світу нічого не надсилається, доки ви не відпустите кнопку, а якщо ядро каже, що не зміниться жодна клітинка, не надсилається взагалі нічого. Правий клік або Escape скасовують.
У моделі світу кілька поверхів, тому є вибір поверху, а поверхи вище поточного приховано. У кімнат свій інструмент, про нього нижче. Налагоджувальний оверлей показує межі чанків, прохідні клітинки, клітинку під курсором і панель із таймінгами. Увесь інтерфейс англійською.
Попередній перегляд – це справжній результат
Привид, що розходиться з результатом, гірший за відсутність привида. Тому клієнт не вгадує, що зробить команда будівництва. Ядро вміє відповісти «що буде, якщо виконати це» для тієї самої ділянки, клітинка за клітинкою, з причиною для кожної клітинки, яку воно відхилить. Перевірка, що заповнює попередній перегляд, – те саме правило, яке команда застосовує під час справжнього виконання, тож вони не можуть розійтися. Клієнт лише малює відповідь. До ядра він звертається знову, лише коли змінилося щось, що впливає на відповідь: інструмент, протягнута ділянка, поверх або сама карта.
Той самий принцип визначає й решту клієнта: він читає стан світу й надсилає команди, а власної логіки симуляції в ньому немає. Поки що ядро тікає в головному потоці, а команда від кліка застосовується на початку наступного кадру, до тіка світу. Якщо час тіка почне підскакувати, коли світ наповниться людьми, план – винести ядро в окремий потік, із виміряним порогом, коли це робити.
Кімнати, що знаходяться самі
Я розглянув два способи зробити кімнати. У Prison Architect малюється зона, яка потім стає окремим об’єктом зі своїми клітинками. Це легко зрозуміти, але в в’язниці це не працює: цілий тюремний блок опинився б однією зоною, а після перебудови стіни її доводиться перефарбовувати. Інший спосіб – знаходити замкнені ділянки автоматично, але тоді не можна позначити двір, навколо якого немає стін.
Я обрав суміш. Зберігається лише тип кімнати на кожній клітинці: камера, їдальня, лазня, медпункт, кімната побачень, прогулянковий двір і так далі. Усе інше обчислюється за стінами. Простір – це група відкритих клітинок, з’єднаних сторонами, на одному рівні, і він замкнений, якщо не торкається краю карти чи порожнього урвища. Кімната – це всі клітинки одного типу всередині одного простору. Стіни та двері – межі, а тип, намальований під стіною, зберігається, але ігнорується, тому повертається, якщо стіну прибрати.
Так виходить поведінка, яка відчувається правильною без додаткових вказівок. Проведіть стіну крізь кімнату – вийде дві кімнати одного типу. Приберіть стіну – вони зіллються. Поставте двері на місце стіни – нічого не зміниться. Недопустима кімната не видаляється, адже це було б протилежністю «без болю»; вона показується червоним із причинами: не замкнена, ділиться з іншим типом, замала або немає дверей. Можна зафарбувати прямокутник, заповнити одним кліком увесь замкнений простір або очистити його.
Список кімнат – похідні дані, тому він не зберігається й не входить у хеш світу; зберігається лише тип на кожній клітинці. Він перебудовується після команд і після систем, а перевірка незміненого світу нічого не коштує. На цьому етапі змінений рівень перераховується цілком, що займає близько пів мілісекунди на карті 256×256; перерахунок по чанках може почекати, доки ті самі механізми не знадобляться регіонам для пошуку шляху. Правило, якому я його підпорядковую: інкрементальна перебудова має давати той самий результат, що й повна.
Перебудовуємо лише змінене, зріз поверхів задарма
Карта малюється однією сіткою на чанк на рівень, а не одним об’єктом на стіну. У кожного чанка в ядрі є лічильник версій, і рендерер пам’ятає, яку версію намалював востаннє. Коли світ змінюється, до черги потрапляють лише чанки з новішою версією, і черга обробляється з бюджетом часу на кадр, тож величезна зміна розтягується на кілька кадрів, а не заморожує один. Фарбування типу кімнати не збільшує версію карти, тому будівельник сіток воно взагалі не будить.
Зріз поверхів дотримується тієї самої ідеї «робити менше». Поверхи вище поточного просто ховаються. Стіни поточного поверху стискаються шейдером до одного метра: один спільний матеріал і одне значення висоти, тому перемикання поверхів чи повних стін нічого не перебудовує. Перемикання по чотирьох рівнях викликає нуль перебудов сіток.
Щілина в десять сантиметрів
Коли я спробував першу одноповерхову в’язницю на фінальній перевірці, на рівні вище була підлога, і збоку між верхом стіни та плитою над нею проходила тонка світла лінія. На розі було видно, як підлога висить у повітрі. Я підозрював зріз поверхів, потім z-fighting, потім згладжування.
Нічого з цього. Підлога була одним пласким квадом без товщини, намальованим на висоті свого рівня плюс десять сантиметрів. Стіни нижнього рівня доходили рівно до трьох метрів. Підлога наступного рівня починалася на трьох метрах десяти сантиметрах. Щілина завширшки десять сантиметрів, і крізь неї було видно освітлену верхню грань стіни. По горизонталі все збігалося ідеально, тому помітив я не одразу.
Виправлення: підлога тепер плита зі справжньою товщиною, що сягає вниз до початку свого рівня. Верх лишається на тій самій висоті, тож вибір клітинок мишею та всі оверлеї не змінилися. Бічні грані пропускаються там, де підлога чи стіна стикаються всередині одного чанка, і малюються на межах чанків, тож сітка чанка не залежить від сусідів. У підсумку на торці плити лишається темна кромка в десять сантиметрів. Я подивився скриншоти до і після й вирішив її залишити. Вона виглядає як край підлоги, чим і є.
Чи витримує це
Останнє завдання етапу – побудувати мишею одноповерхову в’язницю й подивитися, чи не боляче. Здебільшого не було. Окрім щілини, прогін виявив дрібні прикрі речі: кнопки інструментів не знімали підсвічування, коли ви обирали інший інструмент мишею, а з діалогу нової гри не можна було вийти за Escape. Обидва випадки виправлено. Меню паузи в списку ідей на потім.
Що далі
Далі M2, рух і розпорядок дня. У світі з’являться регіони та досяжність, пошук шляху між поверхами й поля потоків для натовпів. У ядра нарешті з’явиться справжня робота на кожному тіку, тож поріг бенчмарка перестане спати. Див. дорожню карту.