Здесь показаны различия между двумя версиями данной страницы.
Both sides previous revision Предыдущая версия Следущая версия | Предыдущая версия | ||
help:principle [2013/11/02 13:28] newsash |
help:principle [2024/10/14 07:28] (текущий) aleks_versus проба обновления до 5.9.0 |
||
---|---|---|---|
Строка 1: | Строка 1: | ||
- | [[help:jump|Назад: Переходы внутри локации, циклы]] | + | [[help:objs|Назад: Предметы]] |
- | =====Порядок работы интерпретатора===== | + | |
- | При обработке новой локации (например, при переходе с помощью операторов "GOTO, XGOTO, GOSUB") выполняются следующие действия: | + | ====== Порядок работы интерпретатора ====== |
- | - Очистка списка действий предыдущей локации, если был осуществлен непосредственный переход на локацию (например, с помощью операторов "GOTO, XGOTO"); | + | |
- | - Обновление поля описания локации (замена существующего основного описания, либо добавление к нему текста базового описания новой локации - в зависимости от того, каким образом был произведён переход); | + | |
- | - Добавление базовых действий новой локации; | + | |
- | - Последовательное выполнение операторов, находящихся в поле "Выполнить при посещении"; | + | |
- | - При непосредственном переходе на локацию выполняется обработка локации-обработчика перехода на новую локацию, если таковая указана; | + | |
- | - Если переменная локации-счётчика не пуста, то происходит обработка соответствующей локации (по умолчанию, 2 раза в секунду); | + | |
- | - Обновление интерфейса (шрифт, цвета, заданные с помощью системных переменных) - также, по умолчанию, 2 раза в секунду; | + | |
- | - При выборе действия или предмета пользователем, происходит обработка локаций-обработчиков выбора действий и предметов; | + | |
- | - При загрузке или сохранении состояния игры, происходит обработка локаций-обработчиков загрузки и сохранения игры; | + | |
- | - Если пользователь щёлкает на действии, то выполняются операторы, определённые для этого действия; | + | |
- | - Если пользователь нажимает "Enter" в строке ввода, то происходит обработка локации-обработчика строки ввода. | + | |
+ | **Несмотря на то, что эта статья обросла некоторыми подробностями, она всё ещё требует серьёзной редактуры, упрощения и расширения. Так что пока что это всё ещё черновой вариант.** | ||
+ | Эта статья подробно рассказывает о порядке работы интерпретатора (плеера) **QSP**. Она может показаться вам довольно сложной, но читать её всю не обязательно. Вернитесь к ней, когда у вас возникнут сложности в понимании того, как ведёт себя плеер. А пока достаточно ознакомиться с общими принципами: | ||
- | Системные переменные | + | * При запуске игры автоматически воспроизводится только самая первая в игре локация. На остальные локации нужно осуществлять переходы с помощью **''GOTO''** или **''XGOTO''**, или вызывать их с помощью **''GOSUB''**, **''FUNC''**, или иным предусмотренным плеером способом. |
- | Системные переменные - переменные, значения которых обрабатываются интерпретатором специальным образом. Системные переменные используются как обычные переменные, т.е. в них можно заносить и считывать из них значения (правда стоит помнить, что в результате вы можете получить, например, чёрный цвет текста на чёрном же фоне - и ничего не будет видно). | + | * Код действий "прикрепляется" к действию и не выполняется, пока игрок не нажмёт на действие. |
+ | * Все команды выполняются последовательно одна за другой, и никогда не выполняются одновременно. | ||
+ | Ниже по тексту будут использоваться следующие определения: | ||
- | Базовые системные переменные - основные переменные. | + | * **Переход на локацию** — это событие в игре, которое происходит при обращении к локации с помощью операторов **''GOTO''** или **''XGOTO''**. При этом локация становится "активной", или "текущей". Функция **''$CURLOC''** возвращает название локации, на которую был совершён переход, а массив **''ARGS[]''** этой локации сохраняет свои значения, пока снова не будет осуществлён переход на локацию (другую, или ту же самую). После добавления текста из поля "Базовое описание" в Окно основного описания, действий из поля "**Базовые действия**" в **Окно действий**, и выполнения кода из поля "**Выполнить при посещении**", плеер "останавливается" и ожидает участия игрока, при этом локация, на которую был осуществлён переход, остаётся "активной" ("текущей"), т.е. функция **''$CURLOC''** в любой момент может вернуть название этой локации, а массив ''ARGS[]'' сохраняет значения.\\ Для переходов существуют только два оператора (подробнее см. статью [[help:goto|"Переходы"]]): |
- | Переменные, задающие обработчики событий - позволяют обрабатывать такие события, как выбор предмета, переход на новую локацию, ввод строки в поле ввода... | + | * **''GOTO''** — осуществляет переход на указанную локацию с автоматической очисткой **Окна основного описания** и **Окна действий**. |
- | Переменные настройки интерфейса - позволяют настраивать цвета, шрифт, а также использовать в описаниях HTML. | + | * **''XGOTO''** — осуществляет переход на указанную локацию с автоматической очисткой **Окна действий**. **Окно основного описания** НЕ очищается. |
+ | * **Вызов локации** — это событие в игре, которое происходит при обращении к локации с помощью оператора **''GOSUB''**, функции **''FUNC''**, или в связи с выполнением другого события (например, "**Выделение предмета**", "**Загрузка сохранения**", "**Ввод в поле ввода**", "**Выбор пункта меню**"). В отличие от **перехода на локацию**, при **вызове** локация не становится "активной" ("текущей"), т.е. функция **''$CURLOC''** не возвращает название этой локации, а массив **''ARGS[]''** сохраняет свои значения только пока выполняется код локации. После выполнения кода локации, продолжается выполнение того блока кода, который выполнялся до вызова. Например, если локация была **вызвана** из действия, то после выполнения её кода, продолжится выполнение кода действия, при этом в массив **''ARGS[]''** внутри действия не попадут значения массива **''ARGS[]''** из вызванной локации. При вызове локации в **Окно основного описания** добавляется текст из поля "**Базовое описание**" локации, в **Окно действий** добавляются действия из поля "**Базовые действия**" локации, и выполняется код из поля "**Выполнить при посещении**" локации. Очистка окон при вызове локации НЕ ПРОИСХОДИТ. <sxh qsp> | ||
+ | act "Действие с вызовом локации": | ||
+ | *pl "Выводим текст до вызова" | ||
+ | gosub 'foo' & ! вызываем локацию foo | ||
+ | *pl "Продолжаем выполнять код после вызова локации foo" | ||
+ | end | ||
+ | </sxh> Вызвать локацию можно разными способами: | ||
+ | * Оператор **''GOSUB''** вызывает локацию без возвращения результата (подробнее в статье [[help:organizing|"Пользовательские функции и процедуры"]]). | ||
+ | * Оператор **FUNC** вызывает локацию с возвращением результата (подробнее в статье [[help:organizing|"Пользовательские функции и процедуры"]]). | ||
+ | * Нажатием пункта всплывающего меню (см. статью [[help:menu|"Всплывающее меню"]]) | ||
+ | * Выполнением какого-либо события в игре, как то: "Выделение предмета", "Выделение действия", "Загрузка сохранения", "Ввод текста в поле ввода" и т.д. (подробнее в статье [[help:service_locations|"Служебные локации"]]). | ||
+ | * **Блок кода** — это выделенный в отдельное целое фрагмент кода игры. Отдельными блоками кода в **QSP** являются: | ||
+ | * Локации сами со себе. | ||
+ | * Код, передаваемый оператору **''DYNAMIC''** или функции **''DYNEVAL''** в виде текста. | ||
+ | * Код, выполняемый при нажатии на гиперссылку. | ||
+ | * Код каждого отдельного Действия (**[[help:acts|ACT]]**). | ||
+ | * Код каждого отдельного Цикла (**[[help:cycle|LOOP]]**) | ||
+ | |||
+ | ===== Запуск игры ===== | ||
+ | |||
+ | Каждая игра на **QSP** структурно представляет собой набор локаций, последовательно записанных в файл. | ||
+ | |||
+ | Когда мы открываем игру в плеере (интерпретаторе), автоматически запускается чтение самой первой локации в файле (далее **Стартовая локация**), как если бы на неё был совершён переход с помощью оператора **''GOTO''**. То есть: | ||
+ | |||
+ | * В Окно основного описания добавляется текст из поля "**Базовое описание**" локации (поле "**Описание**" в **Quest Generator**). | ||
+ | * В Окно действий добавляются действия из поля "**Базовые действия**" локации (поле "**Базовые действия**" в **Quest Generator**). | ||
+ | * Выполняется код из поля "**Выполнить при посещении**" локации. | ||
+ | * Если на Стартовой локации в переменную **''$ONNEWLOC''** было помещено название локации-обработчика события "**Переход на новую локацию**", произойдёт автоматический вызов этой самой локации-обработчика события "**Переход на новую локацию**" (см. [[help:service_locations|"Служебные локации"]]). | ||
+ | * После того, как Стартовая локация была прочитана, плеер "останавливается" и ожидает действий от игрока. При этом локация остаётся "активной", т.е. функция **''$CURLOC''** в любой момент может вернуть её название, а в массиве **''ARGS[]''** данной локации сохраняются значения, которые на ней были выставлены, и эти значения могут использоваться, например, в действиях, выведенных в **Окно действий**. | ||
+ | |||
+ | Если на Стартовой локации в переменную **''$COUNTER''** было помещено название локации-счётчика, примерно через равные промежутки времени (по умолчанию раз в пол секунды) плеер будет вызывать локацию-счётчик (см. [[help:service_locations|"Служебные локации"]]). | ||
+ | |||
+ | ===== Выполнение кода ===== | ||
+ | |||
+ | Код в **QSP** всегда выполняется последовательно, команда за командой. Чтение команд происходит сверху вниз и справа налево: | ||
+ | |||
+ | <sxh qsp> | ||
+ | *pl "Первая команда" | ||
+ | *pl "Вторая команда" | ||
+ | *pl "Третья команда" | ||
+ | |||
+ | *pl "Четвёртая команда" & *pl "Пятая команда" & *pl "Шестая команда" | ||
+ | </sxh> | ||
+ | |||
+ | **QSP** не способен выполнить две команды одновременно, или случайно выполнить вторую команду раньше первой. Поэтому в большинстве случаев, если вам кажется, что плеер "забывает" выполнить какую-либо команду, скорее всего эта команда написана в таком месте, где плеер просто не может до неё добраться. | ||
+ | |||
+ | Например, если написано невыполнимое условие, команда никогда не будет выполнена: | ||
+ | |||
+ | <sxh qsp> | ||
+ | if 5>6: | ||
+ | *pl "Данная команда никогда не будет выполнена" | ||
+ | end | ||
+ | </sxh> | ||
+ | |||
+ | Команды, стоящие после **''GOTO''** или **''XGOTO''**, так же никогда не будут выполнены: | ||
+ | |||
+ | <sxh qsp> | ||
+ | *pl "Текст на локации" & ! этот текст будет виден на локации всегда | ||
+ | act "Переход по XGOTO": | ||
+ | *pl "Этот текст виден благодаря тому, что вы перешли с помощью XGOTO" | ||
+ | xgoto $curloc & ! переходим на текущую локацию | ||
+ | *pl "А эта команда никогда не будет выполнена" | ||
+ | end | ||
+ | |||
+ | act "Переход по GOTO": | ||
+ | *pl "Эта команда будет выполнена" | ||
+ | ! но при переходе по GOTO Окно основного описания очистится, | ||
+ | ! так что эту строчку вы всё равно не увидите. | ||
+ | goto $curloc & ! переходим на текущую локацию | ||
+ | *pl "А эта команда никогда не будет выполнена" | ||
+ | end | ||
+ | </sxh> | ||
+ | |||
+ | Код действий (**''ACT''**) не выполняется сразу, а "прикрепляется" к этим действиям. Он будет выполнен только тогда, когда игрок нажмёт на соответствующее действие. | ||
+ | |||
+ | <sxh qsp> | ||
+ | example=12 & ! присваиваем переменной число 12 | ||
+ | ! создаём действие | ||
+ | act "Вывести значение переменной example": | ||
+ | *pl example | ||
+ | end | ||
+ | example=37 & ! меняем значение в переменной | ||
+ | </sxh> | ||
+ | |||
+ | То же самое происходит с кодом в гиперссылках. Он не выполняется сразу, когда мы создаём гиперссылку, он выполняется только тогда, когда мы на гиперссылку нажимаем: | ||
+ | |||
+ | <sxh qsp> | ||
+ | usehtml=1 & ! включаем режим распознавание HTML | ||
+ | example=12 | ||
+ | ! выводим на экран гиперссылку с кодом | ||
+ | *pl "<a href='EXEC:*pl example'>Вывести значение переменной example</a>" | ||
+ | example=37 | ||
+ | </sxh> | ||
+ | |||
+ | При выполнении команды, которая содержит строки с вложенными выражениями, сначала раскрываются вложенные выражения, и только затем происходит работа со строкой, например, передача её оператору для вывода на экран: | ||
+ | |||
+ | <sxh qsp> | ||
+ | яблоки = 23 | ||
+ | ! Сначала в строку подставится значение, | ||
+ | ! потом строка выведется на экран: | ||
+ | *pl "Яблок в кармане: <<яблоки>>." | ||
+ | </sxh> | ||
+ | |||
+ | ===== Переход на новую локацию ===== | ||
+ | |||
+ | Переход на новую локацию может осуществляться с помощью двух операторов **''GOTO''** и **''XGOTO''**. Различие в их работе заключается в следующем: | ||
+ | |||
+ | * При переходе с помощью оператора **''GOTO''** очищаются Окно основного описания и Окно действий. | ||
+ | * При переходе с помощью оператора **''XGOTO''** очищается только Окно действий. Окно основного описания не очищается. | ||
+ | |||
+ | В остальном работа этих операторов схожа: | ||
+ | |||
+ | * В Окно основного описания добавляется текст из поля "Базовое описание" локации (поле "Описание" в **Quest Generator**). | ||
+ | * В Окно действий добавляются действия из поля "Базовые действия" локации (поле "Базовые действия" в **Quest Generator**). | ||
+ | * Выполняется код из поля "Выполнить при посещении" локации. | ||
+ | * Если в переменную **''$ONNEWLOC''** было помещено название локации-обработчика события "Переход на новую локацию", произойдёт автоматический вызов этой самой локации-обработчика события "Переход на новую локацию" (см. [[help:service_locations|"Служебные локации"]]). | ||
+ | * После этого плеер "останавливается" и ожидает действий от игрока. При этом локация остаётся "активной", т.е. функция **''$CURLOC''** в любой момент может вернуть её название, а в массиве **''ARGS[]''** данной локации сохраняются значения, которые на ней были выставлены, и эти значения могут использоваться, например, в действиях, выведенных в **Окно действий**. | ||
+ | |||
+ | Если в переменную **''$COUNTER''** было помещено название локации-счётчика, примерно через равные промежутки времени (по умолчанию раз в пол секунды) плеер будет вызывать локацию-счётчик (см. [[help:service_locations|"Служебные локации"]]). | ||
+ | |||
+ | P.S.: "Переход на новую локацию" — это устоявшееся название события. Технически более правильно называть такие переходы просто "Переход на локацию", поскольку мы можем переходить не только на новые, но и на текущую локацию: | ||
+ | |||
+ | <sxh qsp> | ||
+ | "Счёт: <<count>>" | ||
+ | act "Обновить": | ||
+ | count+=1 | ||
+ | goto $curloc & ! перезаходим на текущую локацию | ||
+ | end | ||
+ | </sxh> | ||
+ | |||
+ | Поэтому, столкнувшись с выражением "Переход на новую локацию" помните, что оно может значить в том числе и переход на текущую локацию. | ||
+ | |||
+ | ===== Вызов локации ===== | ||
+ | |||
+ | Вызов локации может быть выполнен напрямую через оператор [[help:organizing|**GOSUB**]] или функцию [[help:organizing|**FUNC**]] или в привязке к какому-либо [[help:service_locations|событию]]. | ||
+ | |||
+ | При вызове: | ||
+ | |||
+ | * В Окно основного описания добавляется текст из поля "Базовое описание" локации (поле "Описание" в **Quest Generator**). | ||
+ | * В Окно действий добавляются действия из поля "Базовые действия" локации (поле "Базовые действия" в **Quest Generator**). | ||
+ | * Выполняется код из поля "Выполнить при посещении" локации. | ||
+ | |||
+ | Дополнительно, при вызове с помощью оператора **''GOSUB''**, или функции **''FUNC''**, а так же с помощью оператора [[help:menu|**MENU**]], осуществляется возврат к тому коду, из которого был осуществлён вызов, и продолжается выполнение этого кода. Например, если локация была вызвана из действия, то произойдёт возврат к выполнению кода действия. | ||
+ | |||
+ | <sxh qsp> | ||
+ | act "Действие с вызовом локации": | ||
+ | *pl "Выводим текст до вызова" | ||
+ | gosub 'foo' & ! вызываем локацию foo | ||
+ | *pl "Продолжаем выполнять код после вызова локации foo" | ||
+ | end | ||
+ | </sxh> | ||
+ | |||
+ | Более подробно работа оператора **''GOSUB''** и функции **''FUNC''** освещена в разделе [[help:organizing|"Пользовтальские функции и процедуры"]]. | ||
+ | |||
+ | О работе оператора **''MENU''** более подробно можно почитать в разделе [[help:menu|"Меню"]]. | ||
+ | |||
+ | ===== Обработка событий ===== | ||
+ | |||
+ | События, если смотреть на это понятие с точки зрения работы плеера, — это некое изменение состояния в написанной нами игре. Например, у нас все предметы были не выделены, и вот игрок щёлкает мышью по одному из предметов, и предмет оказывается выделен. То есть предмет изменил своё состояние с "не выделен", на "выделен". Это и есть **событие выделения предмета**. | ||
+ | |||
+ | Конечно, мы могли бы и сами отслеживать некоторые события, например, с помощью локации-счётчика постоянно проверять, какое значение возвращает нам функция **''$SELOBJ''**, и в момент, когда функция изменяет своё значение с одного на другое, мы точно знаем, что произошло выделение нового предмета, или иными словами: событие "Выделение предмета". Однако, для нас это, во-первых, лишний код, а, во-вторых, очень неудобный и неточный инструмент по отслеживанию событий, поскольку локация-счётчик имеет ряд ограничений и на скорость выполнения, и на очерёдность. Мы хотим, чтобы миллисекунда в миллисекунду мы знали, что какое-то событие произошло, и чтобы при этом мы могли выполнить какой-либо код. | ||
+ | |||
+ | Именно для этого в **QSP** введены специальные служебные локации: локации-обработчики событий (и локация-счётчик). | ||
+ | |||
+ | Любая локация, названная как угодно, и написанная каким угодно образом, может быть назначена обработчиком-события или локацией-счётчиком. Для этого название этой локации нужно прописать в специальную системную переменную. Например: | ||
+ | |||
+ | <sxh qsp> | ||
+ | $counter = 'счётчик' & ! назначаем локацию-счётчик | ||
+ | $onobjsel = 'onClick' & ! назначаем локацию-обработчик события "Выделение предмета" | ||
+ | $usercom = 'debugger' & ! назначаем локацию-обработчик события "Нажатие клавиши ввода в Поле ввода" | ||
+ | </sxh> | ||
+ | |||
+ | Как видите, название локации может быть совершенно любым, главное, чтобы она была прописана в нужную системную переменную. И как только это происходит, как только мы прописываем имя локации в нужную переменную, эта локация становится **связана** с указанным событием. Это значит, что как только это событие случится, будет выполнен код на указанной локации. | ||
+ | |||
+ | Подробнее о том, какая системная переменная за **связку** с каким событием отвечает, вы можете прочитать в статье [[help:service_locations|"Служебные локации"]]. | ||
+ | |||
+ | Чтобы отвязать локацию от события, достаточно в нужную системную переменную прописать пустое значение: | ||
+ | |||
+ | <sxh qsp> | ||
+ | $counter = '' & ! отключаем локацию-счётчик | ||
+ | $onobjsel = '' & ! отключаем локацию-обработчик события "Выделение предмета" | ||
+ | </sxh> | ||
+ | |||
+ | ===== Процессы в настоящем времени ===== | ||
+ | |||
+ | Если была назначена локация-счётчик, то с приблизительно равной периодичностью будет происходить вызов указанной локации-счётчика. По умолчанию локация-счётчик вызывается 2 раза в секунду, то есть каждые 500 миллисекунд — это значение можно изменять с помощью оператора **''SETTIMER''**. | ||
+ | |||
+ | <sxh qsp> | ||
+ | settimer 100 & ! устанавливаем период обращения к локации-счётчику в 100 мс | ||
+ | $counter = 'отсчёт_времени' & ! плеер будет вызывать локацию **отсчёт времени** примерно 10 раз в секунду | ||
+ | </sxh> | ||
+ | |||
+ | Так же с заданной периодичностью (по умолчанию 2 раза в секунду) происходит полное обновление интерфейса: шрифт и цвета, заданные с помощью системных переменных. | ||
+ | |||
+ | Подробнее о локации-счётчике и создании игровых событий в реальном времени читайте в статье [[help:realtime|"Реальное время"]]. | ||
+ | |||
+ | [[help:variables|Вперёд: Переменные]] | ||
- | PS: | ||
- | При использовании операторов "KILLALL, KILLVAR" удаляются также все системные переменные. |