Практически не дав вам времени отдышаться, друзья из Mojon Twins снова вернулись со своим семинаром по созданию игр на Чуррере. Эту главу мы посвятим скриптам. Целая Вселенная возможностей, которая требует от нас максимальной собранности. Работа будет тяжелая, и мы все это знаем, так что заточите поострее ваши ножи. Ножи – в зубы, и начинаем главу, которую многие так ждали.
Глава 8: Начинаем работу со скриптами
Прежде всего, скачайте соответствующие материалы для этой главы, нажав на ссылку ниже:
http://www.mojontwins.com/churrera/churreratut-capitulo8.zip (скачать локально: churreratut-capitulo8)
Чувак, ну наконец-то!
Ага, уже. Только ты еще об этом пожалеешь. Потому что все будет настолько неприятно и болезненно, насколько тебе хватит воображения. Нет, серьезно все не так страшно: немножко вазелина, и ты почти ничего не почувствуешь. В этой первой части объясним, как собирается система, чтобы ты понимал, что тут есть, для чего служит и как работает – и в конце рассмотрим примеры детсадовского уровня, правда очень-очень легкие. В следующей части мы закончим скрипт Dogmole Tuppowski, и с этого момента начнем изучать, что можно вытворять с помощью скрипта. Потому что натворить можно много разного.
Ну что ж, приступим!
Давай. Что такое скрипт Чурреры? Это просто набор проверок с соответствующими действиями, организованными по секциям, которые позволяют определить сценарий твоей игры. Или, проще говоря, то, что происходит, и то, что должно произойти, чтобы все было хорошо – или плохо.
То есть без скрипта у тебя есть примитивная базовая версия игры. Собрать Х предметов, чтобы выиграть, убить N врагов… Чтобы выйти на новый уровень крутости, необходимо включить в сценарий игры проверки и связанные с этими проверками действия: если мы находимся там-то и сделали то-то, то дверь и откроется. Если зайдем на такой-то экран и поговорим с тем-то персонажем, появится текст «ПРИВЕТ, ЧЁ ТВОРИШЬ», и ты услышишь определенный звук. Вот мы о чем тут вещаем.
Скрипт тебе нужен для всех действий начиная с размещения красивого тайла в четвертом окне и текста «ТЫ ДОМА» до реагирования на твои действия в одном окне, проверки того, что ты уже сделал, подтверждения, что ты сдвинул такой-то тайл, а еще после этого включается таймер – или чтобы поменять сценарий или что тебе взбредет в голову.
Так как ты уже знаком с твоими рабочими инструментами, ты уже готов к тому, что тебе придется проделать тысячу операций. Мы часто обнаруживаем штуки, которые мы считали невозможными, когда мы начинали разрабатывать систему, так что, как видишь, всяко бывает.
И это не шутка!
Но это программирование.
Правда, чуваки, одно дело, это запрограммировать сценарий на языке Си и прошить его в движок, и совсем другое дело – иметь язык, специально созданный для описания сценария, и который так просто выучить и освоить. Потому что я уверен, что многим будет знакомо то, о чем мы будем говорить, особенно если вы когда-то сталкивались с PAWS или GAC или выпивали с каким-нибудь разработчиком игр. Потому что нам, мохонам, очень в кайф заново изобретать колесо, и в результате у нас есть супер система, наиболее используемая для этих функций, из всех, когда-либо существовавших в истории. Ты сам увидишь.
Давай, расскажи мне, как это работает.
Договорились. Посмотрим, смогу ли я это сказать на одном дыхании, а потом мы разберемся во всем по отдельности: скрипт состоит из секций. Каждая секция – это просто набор условий. Каждое условие состоит из списка проверок и списка команд. Если каждое из условий из этого списка выполняется, то каждая команда также выполняется в определенном порядке. Движок игры будет обращаться к движку скриптов при определенных условиях, выполняя одну из этих секций. Выполнить условие – значит выполнить проверки каждого условия из списка проверок и, если они выполняются, выполнить по порядку команды из списка команд. Это важный концепт, который надо четко понимать.
Чтобы понимать, в какие моменты движок игры будет обращаться к движку скриптов, мы должны разобраться, что такое секции, и какие их типы существуют:
ENTERING SCREEN n, где n – номер экрана. Эта команда выполняется при входе на экран, когда создается сценарий, инициализируются враги и размещаются хотспоты. Можем его использовать, чтобы изменять сценарий или вносить вариативные варианты. Например, в окне 3 можно разместить скрипт, который проверит, убили ли мы всех врагов и, если нет, ставит препятствие, через которое не можем пройти.
ENTERING ANY: выполняется для всех окон, сразу перед ENTERING SCREEN n. То есть, когда ты заходишь на третий экран, сначала выполняется секция ENTERING ANY (если она прописана в скрипте), и только потом выполняется секция ENTERING SCREEN 3 (если она прописана в скрипте).
ENTERING GAME: выполняется только один раз в начале игры. Это первый выполняемый скрипт. Можешь его использовать, чтобы, например, изменять величины изменяемых значений. Скоро мы увидим, как.
PRESS_FIRE AT SCREEN n, где n – номер экрана. Выполняется при различных вариантах в окне n: если игрок нажимает на кнопку действия при передвижении блока, при активированной команде PUSHING_ACTION, или при входе в специальную зону, определенную скриптом под названием “fire zone” (это мы тоже объясним), если активна команда ENABLE_FIRE_ZONE. Обычно эти секции используются, чтобы реагировать на действия игрока.
PRESS_FIRE AT ANY: выполняется при всех предыдущих ситуациях для любого окна, сразу перед нажатием PRESS_FIRE AT SCREEN n. То есть, если нажимаем кнопку действия на 7 экране, сначала выполняются условия PRESS_FIRE AT ANY, а сразу за этим – PRESS_FIRE AT SCREEN 7.
ON_TIMER_OFF: выполняется, когда таймер обнуляется, если он активирован, и мы прописали это командой TIMER_SCRIPT_0.
Для версии 3.99.2 это все возможные секции, но мы добавим еще больше в следующих версиях. Например, при уничтожении врага. Но пока такого скрипта нет.
Конечно, необязательно использовать все возможные секции. Движок будет выполнять секцию, только если она существует. Например, если на экране 8 нечего делать, то для окна 8 можно не прописывать секций. Если нет никаких общих для всех окон действий при входе на экран, то не будет и секции ENTERING ANY. И так далее. Если нечего выполнять, то движок ничего и не выполнит.
Так, давайте вспомним: зачем нам такая куча секций и прочей фигни? Все просто: с одной стороны, чтобы проверки и действия менялись от окна к окну. Но это детали. Самое важное, это что у нас 8-битный экран, и мы не можем себе позволить постоянно делать все проверки. У нас нет лишних фреймов, поэтому мы оставим проверки только для отдельных моментов: никто не умрет, если смена экрана задержится на несколько миллисекунд, или если действие произойдет не сразу после нажатия кнопки действия.
Сохраняем значения: флаги
Перед тем как продолжать, нам надо объяснить еще одно понятие: флаги, которые являются ничем иным, как изменяемыми, которые могут сохранять значения – как раз для этого у нас и есть флаги. Изначально имеется 16 флагов под номерами от 0 до 15, но этот номер можно легко изменить, поменяв определение в definitions.h (ищи #define MAX_FLAGS и поменяй 16 на другое значение).
Каждый флаг сохраняет значение от 0 до 255, что нам дает гораздо больше возможностей. Большую часть времени мы сохраняем только двоичные значения (0 или 1).
В скрипте бОльшая часть проверок и команд имеют цифровые значения. Например, IF PLAYER_TOUCHES 4, 5 оценит с точностью, дотронулся ли игрок до координат (4, 5). Если перед номером поставить #, то это будет относиться к значению соответствующего флага, чтобы IF PLAYER_TOUCHES #4, #5 с точностью оценил, дотронулся ли игрок до ячейки координат, сохраненных во флагах 4 и 5, какое бы это ни было значение.
Этот уровень опосредованности (выучи это слово, чтобы использовать его на дискотеках: тёлочки обожают программистов, знакомых с этим понятием) действительно полезен, потому что таким образом ты можешь сэкономить объем кода. Например, в Cadàveriön это позволяет соединить в одной секции связь между количеством размещенных колонн и исчезновением решетки, блокирующей выход из каждого окна: все координаты сохранены во флагах, и мы используем знак #, чтобы добраться до этих значений в проверках.
Не волнуйся, если ты сейчас не до всего допёр, скоро мы все разжуём.
Фух.
Много информации? Я понимаю. Но когда увидишь, как это работает, до тебя сразу дойдет. Мы начнем с самых простых примеров скрипта, рассмотрев некоторые из секций, необходимых для нашего Dogmole, которые мы будем потихоньку собирать. Мы посвятим этому эту и следующую главу. Потом мы объясним в тематическом виде все возможные проверки и команды.
Как активировать скрипт? Куда его вносить?
Чтобы активировать скрипт, нам надо выполнить 2 вещи: сначала его активировать и отконфигурировать в config.h, а затем изменить наш make.bat, чтобы включить его в проект. Начнем с config.h. Вот соответствующие команды для активации и конфигурации:
#define ACTIVATE_SCRIPTING // Активирует возможность скриптинга и штуки, связанные с флагами.
#define SCRIPTING_DOWN // Использовать ВНИЗ как кнопку действия.
//#define SCRIPTING_KEY_M // Использовать M как кнопку действия.
//#define SCRIPTING_KEY_FIRE // Использовать ОГОНЬ как кнопку действия.
//#define ENABLE_EXTERN_CODE // Разрешает расширенный режим с EXTERN n
//#define ENABLE_FIRE_ZONE // Позволяет определить зону, которая автонажимает “ОГОНЬ”
Первая команда, ACTIVATE_SCRIPTING, как раз и активирует движок скрипта и добавит необходимый дополнительный код, чтобы выполнялась нужная секция скрипта в нужный момент. Эта как раз то, что нам нужно активировать, и без размышлений.
Из трех следующих команд мы должны активировать только одну. Они определяют, какая кнопка будет кнопкой действия, т.е. которая будет запускать скрипты PRESS_FIRE AT ANY и PRESS_FIRE AT SCREEN n. Первая, SCRIPTING_DOWN, конфигурирует кнопку «вниз». Это отлично работает в играх с боковым видом, т.к. эта кнопка больше ни для чего не используется. Вторая, SCRIPTING_KEY_M, привязывает клавишу «М» к скрипту. Третья, SCRIPTING_KEY_FIRE, конфигурирует для этого кнопку выстрела (или кнопку джойстика). Конечно, если в твоей игре есть выстрелы, ты не можешь использовать эту опцию. А если можешь, то сам виноват.
Следующая команда – ENABLE_EXTERN_CODE. Обычно оставляем ее дезактивированной, только если ты не магистр Чурреры. Есть специальная команда скрипта, EXTERN n, где n – номер. Этот скрипт вызывает функцию системы Си, расположенную во внешнем архиве extern.h, используя этот номер. Благодаря этой функции можно добавить код системы Си, если тебе не терпится добавить различные штуки. Например, D_Skywalk использовал это в Justin and the Lost Abbey для добавления кода, который рисует собранные части меча в экране маркировки. Если тебе не нужно программировать дополнительное поведение в системе Си, оставь эту функцию дезактивированной – это сэкономит тебе пару байтов.
Наконец, ENABLE_FIRE_ZONE служит для определения специального прямоугольника внутри игровой зоны текущего экрана. Обычно используем ENTERING SCREEN n, чтобы определить зону, использующую команду SET_FIRE_ZONE x1, y1, x2, y2. Когда игрок находится в этой зоне, выполняются скрипты PRESS_FIRE AT ANY и PRESS_FIRE AT SCREEN n текущего экрана. Это действительно удобно для выполнения действий – и игроку не приходится нажимать на кнопку действия. Мы используем эту функцию в Sgt. Helmet, чтобы устанавливать бомбы в финальном окне или показывать сообщение «ПРОДАЮ ПОДЕРЖАННЫЙ МОТОЦИКЛ». Если ты считаешь, что тебе это нужно, активируй эту команду. Если нет, не активируй ее и сэкономь место. Не волнуйся, мы еще раз объясним это. Следующее действие – это отконфигурировать make.bat, активировав компиляцию и добавление скрипта. Если откроешь make.bat, увидишь, что в начале есть отсылка к msc. Это компилятор скриптов, который получает название архива скрипта, название выхода (msc.h) и общее количество окон в игре:
echo ### COMPILANDO SCRIPT ###
cd ..script
msc cadaver.spt msc.h 20
copy *.h ..dev
Название твоего скрипта – такое же, как название твоей игры с расширением .spt. Архив находится в script. Если зайдешь в script, увидишь churromain.spt. Переименуй его, чтобы название совпадало с названием твоей игры (такое же как у твоего архива .c в dev). Не ошибись в количестве окон, это очень важно. Если перепутаешь, код выполнения скриптов будет неправильно сгенерирован. Для нашего Dogmole архив будет devdogmole.spt, и в make.bat прописываем:
echo ### COMPILANDO SCRIPT ###
cd ..script
msc dogmole.spt msc.h 24
copy *.h ..dev
Потому что в нашем Dogmole 24 окна.
Если теперь перейдешь в script и откроешь архив со скриптом (который раньше назывался churromain.spt и которому ты дал называние своей игры) увидишь, что он пустой, ну или почти. В нем только скелет одной секции. Выглядит примерно так:
# Título tonto
# Copyleft 201X tu grupo roneón soft.
# Churrera 3.1
# flags:
# 1 –
ENTERING GAME
IF TRUE
THEN
SET FLAG 1 = 0
END
END
Вот здесь-то мы и начинаем писать наш скрипт. Посмотри, как он выглядит: это секция ENTERING GAME, которая выполняется при начале игры. В этой секции только одно условие. Это условие имеет только одну проверку: IF TRUE, которая всегда будет выполняться. Затем идет THEN – отсюда и до слова END идет список команд. В нашем случае команда только одна: SET FLAG 1 = 0, которая устанавливает флаг 1 в 0.
Этот скрипт абсолютно ничего не делает. И более того, из-за него система с самого начала ставит все флаги на 0, так что тебе не надо их обнулять. И зачем нам это? Блин, не знаю, просто чтобы было. Поэтому первое, что ты сделаешь, это УДАЛИШЬ ЕГО.
Интересно будет поменять эту часть. Строчки, начинающиеся с # (это может быть и не #, можешь поставить, например ; или ‘ или // или все, что тебе взбредет в голову), – это комментарии. Привыкай ставить комментарии в твоих строчках. Не ставь комментарии после проверки или команды, потому что компилятор может запутаться и увидеть то, чего там нет. И прежде всего привыкай оставлять комментарии. Так ты сможешь вспомнить, что делал 3 дня назад, до попойки и бурной ночи с этой брюнеточкой с ресепшена.
Так как пока изменяемые величины (флаги) определяются номером (я хочу доработать компилятор, чтобы давать им другие значения, как предложил D_Skywalk), было бы здорово сделать список, что делает каждый из них, чтобы нам потом не мучиться. И я это сделал, глянь:
# Cadàveriön
# Copyleft 2013 Mojon Twins
# Churrera 3.99.2
# flags:
# 1 – Тайл для передвигаемого блока
# 2, 3 – координаты X и Y
# 4, 5 – координаты X и Y тайла “retry”
# 6, 7 – координаты X и Y тайла двери
# 8 – количество завершенных окон
# 9 – количество статуй, которые нужно разместить
# 10 – количество размещенных статуй
# 11 – Уже покинули подъезд
# 12 – Окно, в которое мы возвращаемся по завершении отведенного времени
# 13, 14 – Координаты, в которые возвращаемся… бла-бла-бла
# 15 – Пол
# 0 – сохранено значение 8
# 16 – Продаю подержанный мотоцикл
Видишь? Классно знать, с чем имеешь дело.
Мои первые условия
Теперь, когда мы знаем, что есть в нашем арсенале, начинаем наш скрипт. Видим базовый синтаксис. Именно отсюда начинаем рисовать наш скрипт:
СЕКЦИЯ
ПРОВЕРКИ
THEN
КОМАНДЫ
END
…
END
…
Как мы видим, каждая секция начинается с названия секции и заканчивается END. Между названием секции и END находятся условия, которые ее составляют, которых может быть одно или несколько. Каждое условие состоит из списка проверок, по одной на строчку, слова THEN, списка команд, по одной на строчку, и слова END. После этого не может стоять дополнительных условий.
Вспомни, как это работает: выполнение секции соответствует выполнению каждого условия, по порядку. Выполнить условие – это выполнить все проверки из списка. Если ни одно не выпадает, то есть, все выполняются, выполняются все команды из списка.
Чтобы посмотреть как это выглядит, создадим простой скрипт, который добавляет декорации в некоторые окна. Расширим тайлсет Dogmole, включив новые тайлы, которые мы не расположили на карте (потому что мы уже использовали 16 тайлов, т.е. максимальное количество), – добавим их через скрипт. Это наш новый расширенный скрипт:
(ты уже знаешь, что делать: расположи их в нужном порядке, отправь их на страницу кода, загрузи в SevenuP, сгенерируй код и перенеси его в /dev/tileset.h).
Здесь у нас куча вещей, которые мы будем размещать через скрипт. Идеальное место, чтобы это сделать, это секции ENTERING SCREEN n окон, которые мы хотим украсить, и которые выполняются, когда все остальное уже на месте: фон уже нарисован, чтобы мы могли поверх нарисовать наши тайлы. Начнем украшать окно под номером 0, куда надо доставлять ящики. Нам надо разместить подиум из тайлов 22 и 23 и добавим еще кое-какие декорации: сосуды (29), несколько полок (20 и 21), несколько коробок (27 и 28), доспехи (32 и 33), лампочку на проводе (30 и 31). Начнем создавать секцию ENTERING SCREEN 0 в нашем scriptdogmole.spt:
# Вестибюль университета
ENTERING SCREEN 0
END
Прорисовка дополнительных тайлов выполняется из списка команд условия. Так как нам надо, чтобы условие всегда выполнялось, пропишем самое простое условие: которое всегда выполняется и которое видим ниже:
# Вестибюль университета
ENTERING SCREEN 0
# Декорации и подиум
IF TRUE
THEN
END
END
Это значит, что всегда, когда входим на экран 0, выполняются команды из списка команд этого условия, и единственное условие ВСЕГДА будет выполняться.
Команда для добавления тайла в окно выглядит так:
SET TILE (x, y) = t
Где (x, y) – координата (помнишь, у нас 15 x 10 тайлов в окне, так что х может быть от 0 до 14, а у – от 0 до 9), а t – номер тайла, который мы хотим нарисовать. Открываем карту в mappy, чтобы считать ячейки и определить, где будем дорисовывать тайлы, и размещаем сначала подиум, а потом все остальные декорации:
# Вестибюль университета
ENTERING SCREEN 0
# Декорации и подиум
IF TRUE
THEN
# Подиум
SET TILE (3, 7) = 22
SET TILE (4, 7) = 23
# Декорации
SET TILE (1, 5) = 29
SET TILE (1, 6) = 20
SET TILE (1, 7) = 21
SET TILE (6, 6) = 20
SET TILE (6, 7) = 21
SET TILE (7, 7) = 28
SET TILE (1, 2) = 27
SET TILE (1, 3) = 28
SET TILE (2, 2) = 29
SET TILE (2, 3) = 27
SET TILE (3, 2) = 32
SET TILE (3, 3) = 33
SET TILE (9, 1) = 30
SET TILE (9, 2) = 30
SET TILE (9, 3) = 31
END
END
Отлично, ты написал свое первое условие. Пока не слишком сложно, правда? Я так полагаю, что, чтобы удовольствие было полным, ты хочешь еще и посмотреть, как это работает. Хорошо: добавим еще несколько кодов, которые потом уберем из финальной версии, и которые будем использовать, чтобы перейти сразу в нужное окно при начале игры, – и проверим, все ли мы сделали правильно.
Если помнишь, одна из возможных секций, которую можем добавить к скрипту, выполняется сразу в начале игры: ENTERING GAME, которая сначала показывается пустой, и которую мы удалили, потому что она нам не нужна. Ну что, давайте тогда сделаем ENTERING GAME, который позволит нам сразу перейти сразу на экран под номером 0 и проверить, что мы расположили все тайлы в командах условия секции ENTERING SCREEN 0. Так что добавим этот код (можешь добавить его куда хочешь, но я обычно оставляю его в начале. Все равно, куда его поставишь, но всегда удобно соблюдать порядок).
ENTERING GAME
IF TRUE
THEN
WARP_TO 0, 12, 2
END
END
Что это нам дает? Благодаря этому в начале игры выполняется список условий из одного единственного условия, которое всегда будет выполняться (потому что имеет IF TRUE) и которое переносит нас в координаты (12, 2) окна 0 – это роль команды WARP:
WARP_TO n, x, y
Она нас переносит в окно n, в координаты (х, у).
Что произойдет? Ого! Это просто: когда игрок начинает игру, выполняется секция ENTERING GAME. Единственное, что выполняет эта секция – это переносит игрока в позицию (2, 2) и меняет окно на окно под номером 0. Так что при входе на экран 0 выполняется секция ENTERING SCREEN 0, которая дорисовывает дополнительные тайлы. Попробуем! Скомпилируй игру и запусти ее. Если все работает, то персонаж должен появиться в украшенном окне 0:
Вах! Черт, все отлично! Ещё, ещё! Нарисуем еще тайлы, чтобы украсить и остальные окна. Таким же образом, как мы украсили окно 0, украсим и окно 1, установив табличку Университета Мискатоник (тайлы 24, 25 и 26) и доспехи (тайлы 32 и 33):
# Коридор университета
ENTERING SCREEN 1
# Табличка “Мискатоник” и т.д.
IF TRUE
THEN
SET TILE (7, 2) = 24
SET TILE (8, 2) = 25
SET TILE (9, 2) = 26
SET TILE (1, 6) = 32
SET TILE (1, 7) = 33
SET TILE (13, 6) = 32
SET TILE (13, 7) = 33
END
END
Ну что, посмотрим! Измени ENTERING_GAME, чтобы зайти в окно 1, вместо 0.
Компилируем, выполняем… и вуаля!
Таким же образом добавляем код, чтобы добавить еще декорации на карту. По правде говоря, нам скоро надоело, и мы добавили финтифлюшки только в 6 окне (лампу) и в 18 (якорь на пляже). Может тебе захочется побольше добавить? Вот что мы прописали в оригинальной игре:
ENTERING SCREEN 6
IF TRUE
THEN
SET TILE (10, 1) = 30
SET TILE (10, 2) = 31
SET TILE (10, 4) = 35
END
END
ENTERING SCREEN 18
IF TRUE
THEN
SET TILE (4, 8) = 34
END
END
По-моему, до меня дошло
Пора сделать перерыв. Постарайся впитать эти знания, запомни все. Если что-то тут не понял, не торопись и подожди продолжения, в конце концов, ты все поймёшь. И как всегда, если хочешь что-то спросить – спрашивай!
В следующей главе начнется самое месиво: мы будем определять, убиты ли все колдуны, чтобы убрать камень от входа в университет, и пропишем логику, чтобы оставлять ящики в вестибюле.
А пока развлекайся с тем, что мы тебе рассказали. В архиве с материалами к этой главе ты найдешь Dogmole с частично завершенным скриптом, с теми вещами, которые мы видели в этой главе.
[ Перевод на русский язык — сайт viva-games.ru. При перепечатке статьи или любой её части ссылка на viva-games.ru обязательна. Оригинал статьи тут. ]
Понравилась публикация? Поделись с друзьями