[[help:principle|Назад: Порядок работы интерпретатора]]
====== Переменные ======
Иногда в процессе игры нам требуется на время сохранить какую-либо информацию. Например, герой срывает с дерева яблоки, и нам нужно куда-то "записать", сколько яблок он сорвал. Или же в результате битвы погибает злодей, и нам нужно, чтобы плеер "запомнил", что злодей погиб. Для таких вот "записей", "запоминаний", и существуют переменные.
**Переменная** - это именованная "ячейка памяти". То есть это некий кусочек памяти в программе, которому мы назначаем имя.
Для удобства можно представлять переменную, как коробку, в которую мы что-нибудь "складываем", например число, или фрагмент текста (или даже несколько значений одновременно - кортеж).
===== Типы переменных =====
Память программ работает совсем не так, как наша, и "запоминать" они могут только определённого типа значения. **QSP** умеет "запоминать" только **целочисленные** (числовые) и **строковые** значения. Особняком можно отметить **кортежи**, которые позволяют упаковать в одну переменную сразу группу значений.
Поэтому и переменные в **QSP** делятся на три типа:
* Целочисленные
* Строковые
* Кортежи
**В целочисленных переменных** (иногда для краткости их называют просто числовыми) мы можем хранить только **целые** числа в пределах от -2147483648 до 2147483647.
Если мы не поместили никакого значения в целочисленную переменную, то считается, что она хранит значение **''0''**. Это **значение по умолчанию** для числовых переменных.
**В строковых переменных** (иногда их называют текстовыми переменными) мы можем хранить целые строки текста, и длина таких строк может доходить до двух Гигабайт. Строка не может превысить объём оперативной памяти.
Если мы не поместили никакого значения в строковую переменную, то считается, что она хранит пустую строку, т.е. строку совсем без символов. Это **значение по умолчанию** для строковых переменных.
**В кортежах** мы можем хранить сразу группу значений, причём это могут быть значения любого из трёх типов: числовые, строковые и другие кортежи. **Не рекомендуется** создавать очень большие кортежи, хотя теоретически кортежи могут быть //очень// большими. Если вам и правда понадобится //настолько// большой кортеж, примите во внимание, что как и со строкой, объём занимаемых кортежем данных не может превысить двух Гигабайт, или объёма оперативной памяти.
**В переменной можно хранить значение только одного типа!** Переменные **''%яблоко''**, **''$яблоко''** и **''яблоко''** — это одна и та же переменная, но с разным типом значения, которое в ней хранится.
===== Создание переменных и изменение их значений =====
Чтобы создать переменную, мы должны задать ей значение. Это называется операцией **присваивания**.
Операция присваивания в **QSP** записывается так:
* сначала пишется имя переменной
* затем ставится знак **равно** (**=**)
* после знака **равно** пишется значение, которое мы хотим "записать" в переменную.
Примеры:
! переменной яблоко присваивается число 23
яблоко=23
! переменной $скороговорка присваивается строка Ехал Грека Через Реку
$скороговорка = 'Ехал Грека Через Реку'
! переменной %unit присваивается кортеж значений
%unit = [187, 94, 'steel', [0, 2]]
Как видите, во всех трёх случаях сначала ставится имя переменной, потом знак равенства, а потом значение. Вместо значения можно написать название другой переменной, название функции, или даже целое выражение. Плеер автоматически вычислит **значение** из выражения, функции или переменной, и присвоит это **значение** переменной, стоящей слева от знака **равно**. Примеры:
! присваиваем переменной значение другой переменной
$скороговорка_про_Греку = $скороговорка
! присваиваем переменной значение выражения
яблоко = яблоки_в_кармане + яблоки_в_лукошке + яблоки_у_Лёшки
! присваиваем переменной значение функции
случайное_число = rnd
$текущая_локация = $curloc
Не путайте операцию присваивания, и операцию сравнения. Их запись похожа, но операция сравнения обычно следует за ключевыми словами **''IF''**, **''ELSEIF''** или **''WHILE''** и позволяет сравнивать одно значение с другим.
==== Множественное присваивание ====
Вы можете одной командой присвоить значения сразу нескольким переменным (множественное присваивание). Для этого:
* сначала перечисляете через запятую несколько имён переменных
* затем ставите знак **равно** (**=**)
* после знака **равно** так же через запятую перечисляете значения, которые хотите назначить переменным.
Примеры:
яблоки_в_кармане, яблоки_в_лукошке, яблоки_у_Лёшки = 58, 11, 19
$строка_1, $строка_2 = 'Ехал Грека Через Реку', 'Видит Грека В Реке Рак'
$name, count = 'Старый меч', 2
Во всех трёх командах слева от знака **равно** через запятую перечисляются переменные, которым мы присваиваем значения, а справа через запятую перечисляются значения, которые мы присваиваем переменным.
Вместо прямого указания значений можно присваивать значения других переменных, выражений, функций:
! три переменные = три значения
red, green, blue = rand(0,255), rand(0,255), rand(0,255)
! две переменные = два значения
яблоки_в_кармане, яблоки_в_лукошке = яблоки_у_Лёшки, яблоки_на_дереве+15
Присваивать значения одной командой очень удобно, если переменные близки по своему смыслу или назначению. Например, одной строкой можно задавать значения сразу нескольким системным переменным в начале игры:
usehtml, debug, nosave = 1, 1, 1
bcolor, lcolor, fcolor = rgb(255,255,255), rgb(0,90,90), rgb(0,0,0)
Благодаря возможности одновременно присваивать значения сразу нескольким переменным, можно менять местами данные в двух переменных, не прибегая к помощи третьей:
! присваиваем пременным x и y значения 12 и 99
x, y = 12, 99
! меняем местами значения. Теперь в x находится число 99, а в y — 12
x, y = y, x
**Важно помнить!** Слева от знака равенства должно быть столько же переменных, сколько справа значений. Число переменных, и число присваиваемых значений — должны совпадать. Такие записи неверны:
! три переменные, а значения только два
raz, dva, tri = 24, 67
! одна переменная, и два значения
chetyre = 89, 21
Так же в одной команде можно использовать лишь один оператор присваивания:
! так неправильно:
raz = 24, dva = 67, tri = 89
! а вот так правильно
raz, dva, tri = 24, 67, 89
! и вот так правильно, потому что здесь три команды записаны в одну строку
raz = 24 & dva = 67 & tri = 89
==== Присваивание из кортежа (распаковка) ====
Поскольку кортежи содержат в себе сразу несколько значений, запись присваивания значений переменным из кортежа может показаться необычной:
! %unit = [187, 94, 'steel', [0, 2]]
рост, вес, $материал, %координаты = %unit
Как видите, здесь у нас слева четыре имени переменной, а справа только одно имя переменной-кортежа. Такое присваивание называется **распаковкой** — значения извлекаются из кортежа и помещаются в указанные переменные.
Точно так же распаковывается кортеж, даже не помещённый в переменную:
рост, вес, $материал, %координаты = [187, 94, 'steel', [0, 2]]
Такая запись мало чем отличается от множественного присваивания, поэтому внешние квадратные скобки не обязательны:
рост, вес, $материал, %координаты = 187, 94, 'steel', [0, 2]
Подробнее о работе с кортежами, читайте в [[help:tuples|соответствующем разделе]].
==== Операторы SET и LET ====
Из старых версий плеера перекочевали операторы **''SET''** и **''LET''**. Эти операторы явно указывают, что данная команда производит присваивание. Любой из этих операторов может быть поставлен перед операцией присваивания, это никак не влияет на работу переменных. В примере ниже все три варианта присваивания значения переменным равнозначны:
SET golden_axe_damage = 120
LET golden_axe_damage = 120
golden_axe_damage = 120
Точно так же, как и в операции присваивания без операторов **''SET''** и **''LET''**, можно присваивать значения сразу нескольким переменным одной командой и с использованием операторов:
set яблоки_в_кармане, яблоки_в_лукошке, яблоки_у_Лёшки = 58, 11, 19
set $строка_1, $строка_2 = 'Ехал Грека Через Реку', 'Видит Грека В Реке Рак'
let $name, count = 'Старый меч', 2
Для улучшения читаемости кода можно использовать оператор **''SET''** только для команд с множественным присваиванием.
Оператор **''LET''** использовать не рекомендуется.
==== Изменение типа переменной ====
Изменить тип переменной в **QSP** можно, просто присвоив ей значение другого типа. Например:
! присваиваем переменной строковое значение
$яблоко = 'Антоновка'
! если мы попытаемся вывести на экран числовое значение этой переменной,
! то увидим значение по умолчанию, то есть ноль:
*pl яблоко & ! выведет 0 на экран
! но мы можем изменить тип переменной, записав в неё число
яблоко = 19
! теперь, если мы попытаемся вывести на экран то же числовое значение
! мы увидим число 19
*pl яблоко & ! выведет 19 на экран
! а если мы попытаемся вывести на экран текстовое значение,
! то ничего не увидим, потому что числовое значение затёрло текстовое
*pl $яблоко
===== Наименование переменных =====
Чтобы не сбивать плеер с толку, названия переменных должны соответствовать следующим условиям:
* Название переменной **не** должно **начинаться с цифры**.
* Оно не должно совпадать с ключевыми словами (cм. [[help:keywords|список ключевых слов]]).
* В названии не должны использоваться пробелы, символы табуляции и следующие символы:
! : & = < > + - * / , ' " ( ) [ ] { } @ ? ;
* Названия строковых переменных должны начинаться с символа **''$''**.
* Названия кортежей должны начинаться с символа **''%''**.
* Регистр в названии переменной не важен: **''деньги''** и **''ДеНьГи''** - одна и та же переменная.
А вот несколько рекомендаций по тому, как правильно подбирать названия переменных
* Вместо пробела в названиях можно использовать символ подчеркивания - "**''_''**".
* Не рекомендуется делать названия длиннее 10-15 символов, это усложняет читаемость кода.
* Не стоит использовать в названии переменной **одновременно** символы разных алфавитов, это может запутать вас, и вы допустите ошибку.
Используйте краткие и ёмкие названия, указывающие на назначение переменной. При этом **QSP** разрешает пользоваться символами любого алфавита:
яблоки_в_кармане = 3
$АмулетНаШее = "Ожерелье Гроз"
money_count = 1037
$money_name = "RUB"
我_拿_钥匙 = 1
%饭碗 = ["Rice Bowl", 'Cat-wife ']
===== Удаление переменных =====
Удалить переменную можно с помощью оператора **''KILLVAR''**.
KILLVAR 'имя_переменной'
Имя переменной при этом должно помещаться в кавычки:
killvar 'яблоки_в_кармане'
killvar "$АмулетНаШее"
Более подробное описание оператора **''KILLVAR''** находится в статье про [[help:arrays|массивы]].
===== Проверка существования переменной =====
В **QSP** нет специальной команды для проверки существования переменных, однако в силу особенностей движка можно использовать функцию получения размера [[help:arrays|массива]] **''ARRSIZE''**. Если функция вернёт единицу **1**, значит переменная существует; если вернёт **0**, значит переменная не существует.
яблоко = 19 & ! создана переменная яблоко
! увидим на экране Переменная "яблоко" существует
if arrsize('яблоко') = 1:
*pl 'Переменная "яблоко" существует'
else
*pl 'Переменная "яблоко" не существует'
end
! переменную груша мы не создавали
! увидим на экране Переменная "груша" не существует
if arrsize('груша')=1:
*pl 'Переменная "груша" существует'
else
*pl 'Переменная "груша" не существует'
end
Название переменной для функции **''ARRSIZE''** указывается внутри кавычек и помещается в круглые скобки. Указывать символ ''$'' или ''%'' перед названием переменной не обязательно. Вне зависимости от типа значения, которое в этой переменной хранится, **''ARRSIZE''** вернёт единицу, если переменная существует:
яблоко = 19 & ! в переменную записано число
! обе команды ниже вернут единицу, потому что
! яблоко, $яблоко и %яблоко - это одна и та же переменная
*pl arrsize('яблоко')
*pl arrsize('$яблоко')
*pl arrsize('%яблоко')
О функции **''ARRSIZE''** так же можно подробнее почитать в разделе [[help:arrays|"Массивы"]].
===== Получение значений из переменных =====
Чтобы получить значение переменной, достаточно написать её имя в выражении.
При этом, чтобы получить кортеж, нужно поставить перед именем переменной ''%'', а чтобы получить строковое значение, нужно поставить перед именем переменной ''$''.
Примеры:
! присваиваем значение одной переменной - другой
num = int & ! выражение здесь состоит из одной переменной
! выводим значение переменной на экран
*pl $text &! выражение состоит из одной переменной
! вычисляем куб числа, записанного в переменную и выводим на экран
d * d * d &! выражение состоит из двух операций умножения
**Важно!** Если мы пытаемся получить значение переменной, которая не была создана, то такая переменная вернёт значение по умолчанию:
* для числовых переменных значение по умолчанию ''0'' (ноль);
* для текстовых переменных значение по умолчанию ''""'' (пустая строка);
* для кортежей значение по умолчанию ''%%[]%%'' (пустой кортеж).
===== Локальные переменные =====
В **QSP** есть возможность сделать переменные локальными, то есть их значения будут сохраняться в пределах определённого //блока кода//, например, только на определённой локации или в отдельном действии.
Чтобы объявить переменную локальной, нужно использовать ключевое слово **''LOCAL''**. В общем виде объявление локальной переменной выглядит так:
LOCAL имя_переменной = [значение]
Здесь **''имя_переменной''** — это имя переменной, которую мы объявляем, а **''[значение]''** — это любое значение, которое мы этой переменной присваиваем. Пример:
! объявляем локальную переменную **tempora** со значением **12**
local tempora = 12
Эта запись очень похожа на объявление переменной через оператор **''SET''**, и точно так же, как для оператора **''SET''**, для оператора **''LOCAL''** существует возможность объявить сразу несколько локальных переменных:
! множественное объявление локальных переменных
local x, y, $item = 11, 19, "Старый меч"
Как видите, сразу после оператора **''LOCAL''** через запятую перечислены имена объявляемых переменных, затем стоит знак равенства и после него перчислены значения, которые мы присваиваем этим переменным. Число переменных слева от знака **''=''** и число значений справа должны совпадать.
Однако, в отличие от оператора **''SET''** оператор **''LOCAL''** позволяет нам назначить локальные переменные без присвоения им значений. Для этого достаточно просто перечислить после оператора **''LOCAL''** через запятую названия переменных:
local $название_предмета, количество, цена
Здесь оператор **''LOCAL''** работает без операции присваивания. Локальные переменные создаются, но **''arrsize''** для них покажет **''0''**.
Собственные локальные переменные можно создавать для таких блоков кода как:
* Локации сами со себе.
* Код, передаваемый оператору **''DYNAMIC''** или функции **''DYNEVAL''** в виде текста.
* Код, выполняемый при нажатии на гиперссылку.
* Код каждого отдельного Действия (**[[help:acts|ACT]]**).
* Код каждого отдельного Цикла (**[[help:cycle|LOOP]]**)
**Внимание!** У локальных переменных есть одна особенность, которую нужно очень чётко понимать. Значение объявленной в данном блоке кода локальной переменной транслируется и во все вложенные, или вызванные из данного, блоки кода. Например, если на локации объявлена локальная переменная, то её значение транслируется во все вызываемые с помощью **''GOSUB''** или **''FUNC''** локации, в блоки кода для **''DYNAMIC''**/**''DYNEVAL''**, в блоки циклов и так далее. Пример:
# start
! из этой локации мы будем вызывать локацию foo
i=99 & ! объявляем глобальную переменную
gosub 'foo'
*nl i & ! на экране увидим число 99
- start -
# foo
! на этой локации объявляем локальную переменную
local i=0
! локальная переменная транслируется в цикл
loop while i<10 step i+=1:
! в цикле мы вызываем локацию undo
gosub 'undo'
! и так же в цикле мы работаем с переменной,
! объявленной на локации foo
end
*nl i & ! на экране увидим число 10
- foo -
# undo
! в эту локацию из цикла с локации foo
! транслируется всё та же локальная переменная
! объявленная на локации foo
i+=1 & ! увеличиваем значение переменной, влияя на значение в foo
*p 'undo:<>, ' & ! на экране появятся числа 1,3,5,7,9 с припиской undo:
- undo -
**Однако!** Значения локальных переменных не транслируются в действия (в отличие от значений массива **''ARGS''** на текущей локации):
$args[0] = 'текущая локация'
local $var = 'локальная переменная'
*pl $args[0]
*pl $var
act "Вывести значения":
*pl $args[0]
*pl $var
end
**Важно.** Значения локальных переменных не передаются в локации-обработчики событий, однако передаются на локации-обработчики пунктов меню. Будьте внимательны.
==== Примеры назначения локальных переменных ====
Две локации, на каждой из которых собственная переменная **''i''**:
# локация 1
if i=0: i=99 & ! значение переменной i задаётся лишь раз
*pl "Глобальное i = <>"
act "На локацию 2": goto 'локация 2'
- локация 1 -
# локация 2
*pl "Глобальное i = <>"
local i=137 & ! значение переменной i задаётся лишь раз
*pl "Локальное i = <>"
act "На локацию 1": goto 'локация 1'
- локация 2 -
Ещё пример с двумя локациями:
! этот код последовательно выведет на экран числа 12, 549 и 99, 549
# start
x=99
z=4608
gosub 'foo'
*pl x & *pl z & ! на экран выведутся числа 99 и 549
- start -
# foo
local x & ! объявляем переменную x локальной для данной локации
x=12 & ! изменяем значение переменной x
z=549
*pl x & *pl z & ! на экран выведутся числа 12 и 549
- foo -
Пример объявления локальных переменных в коде для **''DYNEVAL''** и в цикле:
$chkObjWord = {
! это код, записанный в виде текста в переменную $chkObjWord
! в локальную переменную $word записываем слово,
! по которому производим поиск
local $word = $args[0]
loop local i = 1 while no i > countobj step i += 1:
! используем локальную переменную i внутри цикла
! цикл выполняется пока счётчик не превысит число предметов
if instr($getobj(i), $word) <> 0:
! как только в названии очередного предмета
! встречается рассматриваемое слово
result = i & ! возвращаем позицию
exit & ! закрываем функцию
end
end
}
object_position = dyneval($chkObjWord, 'граната')
Локальные переменные можно объявлять и внутри действий:
i=99
act "Действие с локальной i":
local i = 449933
*pl i
end
act "Действие с глобальной i":
*pl i
end
[[help:expressions|Вперёд: Выражения]]