tgoop.com/logofalprog/76
Last Update:
Скрипты в Encased 1.1
#код
Что-то у меня одновременно много людей заказали размещения, поэтому чтобы канал не превращался в сплошную рекламу, придётся делать посты почаще на этой неделе.
А давайте поговорим, например, про скрипты. С прошлого раза, когда я про них рассказывал, они претерпели некоторые изменения и это должно быть интересно. Напомню, что у нас скрипты — это экземпляры классов, унаследованных от Script, которые имеют функции Start() и Update(), могут содержать сериализуемые поля, которые выполняют роль эдаких «локальных переменных», а также скрипты умеют подписываться на различные события от сущностей в мире.
Предполагалось, что на события можно как подписываться, так и отписываться в реалтайме, а текущее состояние подписок также бы попадало в файл сохранения. И всё было бы хорошо, если бы не одно «но». Судя по вопросам и фиче-реквестам, которые я получал, оказалось, что скриптеры не понимают концепт подписок на интуитивном уровне.
Их основная идея была в том, что мы подписываемся на нужные события в Start и потом, по мере обработки событий, отписываемся от них или подписываемся на новые. При этом функция Start, разумеется, больше никогда не вызовется. Даже после нажатия Сохранить/Загрузить мы получим абсолютно то же состояние подписок, которое было до этого. Но скриптеры ожидают, что они могут сохраниться, добавить подписку в функции Start, загрузиться и обработать свежедобавленый эвент. Этой ситуации у нас пока не случилось, но я предвосхищаю, что мне бы пришёл вопрос «а нельзя ли сделать, чтобы после загрузки Start() отрабатывал ещё раз?». То, что тогда получится по 2 подписки и это вообще ломает всю концепцию скриптов, никого бы не смутило.
Такое поведение скриптеров может показаться глупым, но дело в том, что если что-то может быть понято неправильно, оно обязательно будет понято не так, а я не смогу со свечкой стоять над каждым скриптом в игре. Моя задача в первую очередь не в том, чтобы сделать крутую вещь в себе, а в том, чтобы поддержать удобный пайплайн для скриптеров. Поэтому от подписок в реалтайме пришлось отказаться. Все подписки теперь статичны и устанавливаются при инициализации скрипта. Причём ручное навешивание делегатов возможно теперь только в специально отведённой для этого функции и является запасным способом. А рекомендуемым способом теперь является простая пометка функций атрибутами.
Например, мы помечаем функцию атрибутом
[OnUsed(Guids.Levels.MagicBalls.LeverSwitch)]
что означает, что функция отработает, когда мы нажмём на рубильник в игре. LeverSwitch — это константа, содержащая уникальный guid рубильника, который доступен из скриптов, потому что у нас сделана кодогенерация констант (с поддержкой последующего переименования, разумеется).
Реальной отписки от этой функции причём не существует, но она эмулируется через проверку глобальной переменной внутри тела функции или с помощью атрибутов. Вроде таких:
[If(BunkerVariables.LiftEnabled)]
или ещё проще
[OnlyOnce(0)]
Последний вариант означает, что функция выполнится только один раз, а 0 нужен для уникальной пометки этой функции (чтобы можно было безопасно переименовать функцию и ничего не сломать). В пределах одного файла у других функций, соответственно будет OnlyOnce(1), OnlyOnce(2) и так далее.
На поверку оказывается, что если функция не вызывается по причине того, что на её запуске стоит тест переменной, которая в данный момент не включена, то это намного проще воспринимается скриптерами, чем функция, которая не вызывается, потому что на неё никто не подписывался в истории этого сейва. Так что такая модель выглядит более перспективной в плане поддержки игры и накатывания апдейтов. Посмотрим, как она покажет себя в бою, а пока всем счастливого рождества!
Обсудить
BY Log of Alprog
Share with your friend now:
tgoop.com/logofalprog/76