Skip to content
AliceCyber edited this page Jan 24, 2022 · 1 revision

Дополнительная функциональность часто реализована в INSTEAD в виде модулей. Для использования модуля необходимо написать:

require "имя модуля"

Или:

loadmod "имя модуля"

Если модуль поставляется вместе с игрой.

Часть модулей входит в поставку INSTEAD, но есть и такие, которые вы можете скачать отдельно и положить в каталог с игрой. Вы можете заменить любой стандартный модуль своим, если положите его в каталог с игрой под тем-же именем файла, что и стандартный.

Модуль, это фактически 'lua' файл с именем: 'имя_модуля.lua'.

Ниже перечислены основные стандартные модули, с указанием функциональности, которые они предоставляют.

  • 'dbg' — модуль отладки;
  • 'click' — модуль перехвата кликов мыши по картинке сцены;
  • 'prefs' — модуль настроек (хранилище данных настроек);
  • 'snapshots' — модуль поддержки снапшотов (для откатов игровых ситуаций);
  • 'fmt' — модуль оформления вывода;
  • 'theme' — управление темой на лету;
  • 'noinv' - модуль работы с инвентарем;
  • 'key'' - модуль обработки событий срабатывания клавиш;
  • 'timer' - таймер;
  • 'sprite' — модуль для работы со спрайтами;
  • 'snd' — модуль работы со звуком;
  • 'nolife' – модуль блокировки методов life;

Пример загрузки модулей:

--$Name: Моя игра!$
require "fmt"
require "click"

Некоторые дополнительные модули, которые не входят в стандартную поставку, вы можете скачать из репозитория модулей. Просто скачайте нужный вам модуль и положите его в каталог с игрой. Включайте такой модуль с помощью loadmod().

Модуль keys

Вы можете перехватывать события клавиатуры с помощью модуля "keys".

Обычно, перехват клавиш имеет смысл использовать для организации текстового ввода.

Для задания того, какие именно клавиши необходимо отслеживать, определите функцию keys:filter(press, key). Эта функция должна возвращать true в том случае, если вы хотите отследить данное событие. Например:

require "keys"

function keys:filter(press, key)
	return press -- ловим нажатия любых клавиш
end

В примере мы просто возвращаем параметр press, который равен true для события нажатия клавиши и false -- отжатия. В key передается символическое название клавиши (в виде строки).

Обычно, нам нужно выбрать какие именно клавиши мы хотим перехватывать:

require "keys"

function keys:filter(press, key)
	if key == '0' or key == '1' or key == 'z' then
		return press -- ловим нажатия клавиш z, 1 и 0
	end
end

Итак, keys:filter позволяет выбрать нужные события клавиатуры. А сами события приходят в игру в виде вызова обработчика 'onkey' для текущей комнаты или (если он не задан в комнате) для объекта 'game'.

Обработчик onkey действует как обычный обработчик STEAD3. Он может вернуть false и тогда считается, что клавиша не была обработана игрой. Либо он может выполнить какое-нибудь действие.

Внимание: Если игра будет обрабатывать все события клавиш, то даже те комбинации, которые используются самим INSTEAD будут обрабатываться игрой, а не интерпретатором. Например, если игра будет перехватывать клавишу "escape" (и не возвращать false из обработчика), то клавиша "escape" перестанет обрабатываться интерпретатором INSTEAD (escape -- вызов меню).

Ниже приводится простой пример вывода на экран символических имен клавиш:

require "keys"

function keys:filter(press, key)
	return press -- ловим все нажатия
end

game.onkey = function(s, press, key)
	dprint("pressed: ", key)
	p("Нажата: ", key)
	return false -- давать обрабатывать клавиши интерпретатору INSTEAD
end

Этот пример можно использовать для того, чтобы выяснить символическое имя конкретной клавиши.

При написании аркадных игр бывает полезным не получать событие от клавиатуры, а опрашивать ее (как правило, в таймере). Для этого вы можете использовать функцию keys:state(имя клавиши).

Эта функция возвращает true для нажатой клавиши и false -- для отжатой, например:

require "timer"
require "keys"

game.timer = function(s) -- показываем состояние клавиши курсор вправо
	dprint("state of 'right' key: ", keys:state 'right')
	p("Состояние клавиши 'вправо':", keys:state 'right')
end

timer:set(30)

Модуль click

Вы можете отслеживать в своей игре клики по картинке сцены, а также по фону. Для этого, воспользуйтесь модулем "click". Также, вы можете отслеживать состояние мыши с помощью функции:

instead.mouse_pos([x, y])

Которая возвращает координаты курсора. Если задать параметры (x, y), то можно переместить курсор в указанную позицию (все координаты рассчитываются относительно левого верхнего угла окна INSTEAD).

require "click"
function click:filter(press, btn, x, y, px, py)
	dprint(press, btn, x, y, px, py)
	return press and px -- ловим только нажатия на картинку
end
room {
	nam = 'main';
	pic = "box:320x200,red";
	onclick = function(s, press, btn, x, y, px, py)
		pn("Вы нажали на картинку: ", px, ", ", py)
		pn("Абсолютные координаты: ", x, ", ", y)
		p("Кнопка: ", btn)
	end;
}

Внимание! В INSTEAD по умолчанию включен фильтр кликов мыши, который гасит быстрые клики. Это сделано для исключения эффекта дребезга клавиш мыши. В некоторых случаях фильтр может оказаться нежелательным. В таком случае, используйте функцию instead.mouse_filter(), которая может быть использована для определения текущего значения фильтра мыши и установки нового (в том числе - выключения), например:

function start()
	dprint("Mouse filter delay: ", instead.mouse_filter())
	instead.mouse_filter(0) -- выключили фильтр
end

Или так:

old_filter = instead.mouse_filter(0) -- выключили
...
instead.mouse_filter(old_filter) -- восстановили

Модуль theme

Модуль theme позволяет изменять параметры темы на лету.

Имейте в виду, что изменение параметров темы на лету для игр, которые не содержат собственную тему -- источник потенциальных проблем! Дело в том, что ваша игра в таком случае должна быть готова работать с любыми разрешениями и параметрами тем, что крайне сложно добиться. Поэтому, если вы собираетесь менять параметры темы из кода -- создайте свою тему и включите ее в игру!

При этом, сохранение изменений темы в файле сохранения не поддерживается. Автор игры должен сам восстановить параметры темы в функции start(), как это делается при работе с модулем спрайтов.

Для изменения параметров действующей темы, используются следующие функции:

-- настройка окна вывода
theme.win.geom(x, y, w, h)
theme.win.color(fg, link, alink)
theme.win.font(name, size, height)
theme.win.gfx.up(pic, x, y)
theme.win.gfx.down(pic, x, y)

-- настройка инвентаря
theme.inv.geom(x, y, w, h)
theme.inv.color(fg, link, alink)
theme.inv.font(name, size, height)
theme.inv.gfx.up(pic, x, y)
theme.inv.gfx.down(pic, x, y)
theme.inv.mode(mode)

-- настройка меню
theme.menu.bw(w)
theme.menu.color(fg, link, alink)
theme.menu.font(name, size, height)
theme.menu.gfx.button(pic, x, y)

-- настройка графики
theme.gfx.cursor(norm, use, x, y)
theme.gfx.mode(mode)
theme.gfx.pad(pad)
theme.gfx.bg(bg)

-- настройка звука
theme.snd.click(name);

Существует возможность чтения текущих параметров тем:

theme.get 'имя переменной темы';

Возвращаемое значение всегда в текстовой форме.

theme.set ('имя переменной темы', значение);

Вы можете сбросить значение параметра темы на то, которое было установлено во встроенной теме игры:

theme.reset 'имя переменной';
theme.win.reset();

Существует функция, для того, чтобы узнать текущую выбранную тему.

theme.name()

Функция возвращает строку -- имя каталога темы. Если игра использует собственный файл 'theme.ini', функция вернет точку. Это удобно, для определения того, включен ли механизм собственных тем игр:

if theme.name() ~= '.' then
	error "Please, enable own theme mode in menu!"
end

Если в игре используется механизм множественных тем, то имя темы начинается с точки, например:

if theme.name() == '.default' then
    -- наша встроенная тема default
elseif theme.name() == 'default' then
    -- стандартная тема default в INSTEAD
end

Пример использования:

theme.gfx.bg "dramatic_bg.png";
theme.win.geom (0,0, theme.get 'scr.w', theme.get 'scr.h');
theme.inv.mode 'disabled'

Получить размеры текущей темы:

theme.scr.w() -- ширина
theme.scr.w() -- высота

Модуль sprite

Модуль sprite позволяет работать с графическими изображениями. Для включения модуля напишите:

require "sprite"

Спрайты не могут попасть в файл сохранения, поэтому восстановление состояния спрайтов -- задача автора игры. Обычно, для этого используются функции init() и/или start(). start() вызывается после загрузки игры, поэтому в этой функции вы можете использовать переменные игры.

На самом деле в модуле спрайт реализованы два модуля: спрайты и пиксели. Но так как они используются совместно, они размещены в одном модуле. Начнем со спрайтов:

Спрайты

Для создания спрайта используйте метод sprite.new, например:

	declare 'my_spr' (sprite.new 'gfx/bird.png')
	local heart = sprite.new 'heart.png'
	local blank = sprite.new (320, 200) -- пустой спрайт 320x200

У созданного спрайтового объекта существуют следующие методы:

  • :alpha(alpha) - создает новый спрайт с заданной прозрачностью alpha (255 - не прозрачно). Это очень медленная функция;
  • :dup() - создает копию спрайта;
  • :scale(xs, ys, [smooth]) -- масштабирует спрайт, для отражений используйте масштаб -1.0 (медленно! не для реального времени). Создает новый спрайт.
  • :rotate(angle, [smooth]) -- поворот спрайта на заданный угол в градусах (медленно! не для реального времени). Создает новый спрайт.
  • :size() -- Возвращает ширину и высоту спрайта в пикселях.
  • :draw(fx, fy, fw, fh, dst_spr, x, y, [alpha]) -- Рисование области src спрайта в область dst спрайта (задание alpha сильно замедляет выполнение функции).
  • :draw(dst_spr, x, y, [alpha]) -- Рисование спрайта, укороченный вариант; (задание alpha замедляет выполнение функции).
  • :copy(fx, fy, fw, fh, dst_spr, x, y) -- Копирование прямоугольника fw-на-fh из спрайта в спрайт dst_spr по координатам [x,y] (рисование - замещение). Существует укороченный вариант (как :draw).
  • :compose(fx, fy, fw, fh, dst_spr, x, y) -- Рисование - с учетом прозрачности обоих спрайтов). Существует укороченный вариант (как :draw).
  • :fill(x, y, w, h, [col]) -- Заполнение спрайта цветом.
  • :fill([col]) -- Заполнение спрайта цветом.
  • :pixel(x, y, col, [alpha]) -- Заполнение пикселя спрайта.
  • :pixel(x, y) -- Взятие пикселя спрайта (возвращает четыре компонента цвета).
  • :colorkey(color) -- Задает в спрайте цвет, который выступает в роли прозрачного фона. При этом, при последующем выполнении операции :copy, из рассматриваемого спрайта будут скопированы только те пиксели, цвет которых не совпадает с цветом прозрачного фона.

В качестве "цвета" методы получают строки вида: 'green', 'red', 'yellow' или '#333333', '#2d80ff'...

Пример:

	local spr = sprite.new(320, 200)
	spr:fill 'blue'
	local spr2 = sprite.new 'fish.png'
	spr2:draw(spr, 0, 0)

Кроме того, существует возможность работы с шрифтами. Шрифт создается с помощью sprite.fnt(), например:

local font = sprite.fnt('sans.ttf', 32)

У созданного объекта определены следующие методы:

  • :height() -- высота шрифта в пикселях;
  • :text(text, col, [style]) -- создание спрайта из текста, col - здесь и далее - цвет в текстовом формате (в формате '#rrggbb' или 'текстовое название цвета').
  • :size(text) -- вычисляет размер, который будет занимать текстовый спрайт, без создания спрайта.

Вам также может пригодиться функция:

sprite.font_scaled_size(size)

Она возвращает размер шрифта с учетом масштабирование, которое выставил игрок в настройках INSTEAD. Если вы в своей игре хотите учитывать такую настройку, используйте эту функцию для определения размера шрифта.

Пример:

	local f = sprite.fnt('sans.ttf', 32)
	local spr = sprite.new('box:320x200,black')
	f:text("HELLO!", 'white'):draw(spr, 0, 0)

Теперь, рассмотрим варианты применения модуля sprite.

Функция pic

Функция pic может вернуть спрайт. Вы можете формировать каждый раз новый спрайт (что будет не очень эффективно), или можете возвращать заранее выделенный спрайт. Если в такой спрайт вносятся изменения, то эти изменения будут отражены в следующем кадре игры. Так, меняя спрайт по таймеру, можно делать анимацию:

require "sprite"
require "timer"
local spr = sprite.new(320, 200)

function game:timer()
	local col = { 'red', 'green', 'blue'}
	col = col[rnd(3)]
	spr:fill(col)
	return false -- Важно! Так, сцена не будет изменена
end

game.pic = function() return spr end -- функция: так как
-- спрайт это особый объект (не строка)

function start()
	timer:set(30)
end

room {
	nam = 'main';
	decor = [[ГИПНОЗ!]];
}

Отрисовка в фон

Функция sprite.scr() возвращает спрайт - фон. Вы можете выполнять отрисовку в этот спрайт в любом обработчике, например, в таймере. Тем самым добиваясь изменения фона на лету, без применения модуля theme. Например:

--$Author: Andrew Lobanov

require 'sprite'
require 'theme'
require 'timer'

declare {
   x = 0,
   y = 0,
   dx = 10,
   dy = 10,
}

const {
   w = theme.scr.w(),
   h = theme.scr.h(),
}

instead.fading = false

local bg, red, green

function init()
   theme.set('scr.col.bg', '#000000')
   theme.set('win.col.fg', '#aaaaaa')
   theme.set('win.col.link', '#ffaa00')
   theme.set('win.col.alink', '#ffffff')

   bg = sprite.new(w, h)
   bg:fill('black')
   red = sprite.new(w, h)
   red:fill('#ff0000')
   red = red:alpha(128)
   green = sprite.new(w, h)
   green:fill('#00ff00')
   green = green:alpha(64)
   bg:copy(sprite.scr())
   timer:set(25)
end

function game:timer()
   bg:copy(sprite.scr())
   red:draw(sprite.scr(), x, 0, 128)
   green:draw(sprite.scr(), 0, y, 64)
   x = x + dx
   if x >= w or x == 0 then
      dx = -dx
   end
   y = y + dy
   if y >= h or y == 0 then
      dy = -dy
   end
   return false -- Важно!
end

room {
   nam = 'main',
   disp = 'Test. Test? Test!',
   decor = 'Lorem ipsum';
}

Внимание! Интерпретатор INSTEAD в режиме использования предмета на предмет переводит себя в режим "паузы". Это значит, что в тот момент когда выбран предмет из инвентаря (курсор изменил вид на шестеренки) события таймера перестают обрабатываться до тех пор, пока игрок не применит предмет. Это сделано для того, чтобы не разрывать такт игры. Если для вашего творческого замысла такое поведение является помехой (например, вам не нравится тот факт, что анимация фона замирает), вы можете изменить его с помощью вызова:

instead.wait_use(false)

Как обычно, поместите вызов в init() или start() функцию.

Подстановки

Вы можете создать свой системный объект - подстановку, и формировать графику в выводе игры с помощью img, например:

require "sprite"
require "timer"
require "fmt"

obj {
	nam = '$spr';
	{
		["квадрат"] = sprite.new 'box:32x32,red';
	};
	act = function(s, w)
		return fmt.img(s[w])
	end
}

room {
	nam = 'main';
	decor = [[Сейчас мы вставим спрайт: {$spr|квадрат}.]];
}

direct режим

В INSTEAD существует режим прямого доступа к графике. В теме он задается с помощью параметра:

scr.gfx.mode = direct

Этот параметр можно заранее выставить в theme.ini, или воспользоваться модулем theme. Или (что лучше), специальной функцией:

sprite.direct(true)

Если режим удалось включить -- функция вернет true. sprite.direct() без параметра -- возвращает текущий режим (true -- если direct включен.)

В этом режиме игра имеет прямой доступ ко всему окну и может выполнять отрисовку в процедуре таймера. Экран представлен специальным спрайтом:

sprite.scr()

Например:

require "sprite"
require "timer"
require "theme"

sprite.direct(true)

local stars = {}
local w, h
local colors = {
	"red",
	"green",
	"blue",
	"white",
	"yellow",
	"cyan",
	"gray",
	"#002233",
}
function game:timer()
	local scr = sprite.scr()
	scr:fill 'black'
	for i = 1, #stars do
		local s = stars[i]
		scr:pixel(s.x, s.y, colors[s.dy])
		s.y = s.y + s.dy
		if s.y >= h then
			s.y = 0
			s.x = rnd(w) - 1
			s.dy = rnd(8)
		end
	end
end

function start()
	w, h = theme.scr.w(), theme.scr.h()

	w = std.tonum(w)
	h = std.tonum(h)

	for i = 1, 100 do
		table.insert(stars, { x = rnd(w) - 1, y = rnd(h) - 1, dy = rnd(8) })
	end
	timer:set(30)
end

Еще один пример:

require "timer"
require "sprite"
require "theme"

local spr = sprite

declare {
	fnt = false, ball = false, ballw = 0,
	ballh = 0, bg = false, line = false,
	G = false, by = false, bv = false,
	bx = false, t1 = false,
}

function init()
    fnt = spr.fnt(theme.get 'win.fnt.name', 32);
    ball = fnt:text("INSTEAD 3.0", 'white', 1);
    ballw, ballh = ball:size();
    bg = spr.new 'box:640x480,black';
    line = spr.new 'box:320x8,lightblue';
    spr.direct(true)
end

function start()
    timer:set(20)
    G = 9.81
    by = -ballh
    bv = 0
    bx = 320
    t1 = instead.ticks()
end

function phys()
    local t = timer:get() / 1000;
    bv = bv + G * t;
    by = by + bv * t;
    if by > 400 then
        bv = - bv
    end
end

function game:timer(s)
    local i
    for i = 1, 10 do
        phys()
    end
    if instead.ticks() - t1 >= 20 then
        bg:copy(spr.scr(), 0, 0);
        ball:draw(spr.scr(), (640 - ballw) / 2, by - ballh/2);
        line:draw(spr.scr(), 320/2, 400 + ballh / 2);
        t1 = instead.ticks()
    end
end

Внимание! direct режим может быть использован для создания простых аркадных игр. В некоторых случаях, вы можете захотеть убрать указатель мыши. Например, когда игра управляется только с клавиатуры.

Для этого воспользуйтесь функцией instead.mouse_show()

instead.mouse_show(false)

При этом в меню интерпретатора INSTEAD указатель мыши все еще будет виден.

Использование sprite совместно с модулем theme

В функции start и в обработчиках вы можете менять параметры темы, в том числе, используя в качестве графики спрайты, например:

require "sprite"
require "theme"

function start() -- заменим фон на спрайт
	local spr = sprite.new(800, 600)
	spr:fill 'blue'
	spr:fill (100, 100, 32, 60, 'red')
	theme.set('scr.gfx.bg', spr)
end

Используя эту технику, вы можете наносить на фоновое изображение статусы, элементы управления или просто менять подложку.

Обратите внимание, что при этом вызов theme.get('scr.gfx.bg') возвращает строку вида spr:xxxxxxxxxxx, а не объект спрайта. Если вы хотите изменять фон динамически, используйте sprite.scr() или многократные вызовы theme.set('scr.gfx.bg', spr) с новыми спрайтами.

Пиксели

Модуль спрайтов поддерживает также работу с пиксельной графикой. Вы можете создавать объекты -- наборы пикселей, модифицировать их и рисовать в спрайты.

Создание пикселей осуществляется функцией pixels.new().

Примеры:

local p1 = pixels.new(320, 200) -- создали пиксели 320x200
local p2 = pixels.new 'gfx/apple.png' -- создали пиксели из
-- изображения
local p3 = pixels.new(320, 200, 2) -- создали пиксели 320x200,
-- которые при отрисовке их в спрайт -- будут смасштабированы до
-- 640x400

Объект пиксели имеет следующие методы:

при описании использованы обозначения: r, g, b, a -- компоненты пикселя: красный, зеленый, синий, и прозрачность. Все значения от 0 до 255). x, y - координаты левого верхнего угла, w, h -- ширина и высота области.

  • :size() -- вернуть размер и масштаб (как 3 значения);
  • :clear(r, g, b, [a]) -- быстрая очистка пикселей;
  • :fill(r, g, b, [a]) -- заливка (с учетом прозрачности);
  • :fill(x, y, w, h, r, g, b, [a]) -- заливка области (с учетом прозрачности);
  • :val(x, y, r, g, b, a) - задать значение пикселя
  • :val(x, y) -- получить компоненты r, g, b, a
  • :pixel(x, y, r, g, b, a) -- нарисовать пиксель (с учетом прозрачности существующего пикселя);
  • :line(x1, y1, x2, y2, r, g, b, a) -- линия;
  • :lineAA(x1, y1, x2, y2, r, g, b, a) -- линия с AA;
  • :circle(x, y, radius, r, g, b, a) -- окружность;
  • :circleAA(x, y, radius, r, g, b, a) -- окружность с AA;
  • :poly({x1, y1, x2, y2, ...}, r, g, b, a) -- полигон;
  • :polyAA({x1, y1, x2, y2, ...}, r, g, b, a) -- полигон с AA;
  • :blend(x1, y1, w1, h1, pixels2, x, y) -- рисовать область пикселей в другой объект пиксели, полная форма;
  • :blend(pixels2, x, y) -- короткая форма;
  • :fill_circle(x, y, radius, r, g, b, a) -- залитый круг;
  • :fill_triangle(x1, y1, x2, y2, x3, y3, r, g, b, a) -- залитый треугольник;
  • :fill_poly({x1, y1, x2, y2, ...}, r, g, b, a) -- залитый полигон;
  • :copy(...) -- как blend, но не рисовать, а копировать (быстро);
  • :scale(xscale, yscale, [smooth]) -- масштабирование в новый объект pixels;
  • :rotate(angle, [smooth]) -- поворот в новый объект pixels;
  • :draw_spr(...) -- как draw, но в спрайт, а не пиксели;
  • :copy_spr(...) -- как copy, но в спрайт, а не пиксели;
  • :compose_spr(...) -- то же самое, но в режиме compose;
  • :dup() -- создать копию пикселей;
  • :sprite() -- создать спрайт из пикселей.

Также, есть возможность работы со шрифтами:

  • pixels.fnt(fnt(шрифт.ttf, размер) -- создать шрифт;

При этом, у созданного объекта "шрифт" существует метод text:

  • :text(текст, цвет(как в спрайтах), стиль) -- создать пиксели с текстом;

Например:

	local fnt = pixels.fnt("sans.ttf", 64)
	local t = fnt:text("HELLO, INSTEAD!", 'black')
	pxl:copy_spr(sprite.scr())
	pxl2:draw_spr(sprite.scr(), 100, 200);
	t:draw_spr(sprite.scr(), 200, 400)

Еще один пример (автор примера, Андрей Лобанов):

require "sprite"
require "timer"

sprite.direct(true)

declare 'pxl' (false)
declare 't' (0)

function game:timer()
   local x, y, i
   t = t + 1
   for x = 0, 199 do
       for y = 0, 149 do
           i = (x * x + y * y + t)
               pxl:val(x, y, 0, i, i / 2)
       end
   end
   pxl:copy_spr(sprite.scr())
end

function start(load)
   pxl = pixels.new(200, 150, 4)
   timer:set(20)
end

При процедурной генерации с помощью pixels удобно использовать шумы Перлина. В INSTEAD существуют функции:

  • instead.noise1(x) - 1D шум Перлина;
  • instead.noise2(x, y) - 2D шум Перлина;
  • instead.noise3(x, y, z) - 3D шум Перлина;
  • instead.noise4(x, y, z, w) - 4D шум Перлина;

Все эти функции возвращают значение в диапазоне [-1; 1] а на вход получают координаты с плавающей точкой.

Модуль snd

Мы уже рассматривали базовые возможности по работе со звуком. Модуль snd имеет еще некоторые функции по работе со звуком.

Вы можете подгрузить звук и держать его в памяти до тех пор, пока он вам нужен.

require 'snd'
local wav = snd.new 'bark.ogg'

Кроме подгрузки файлов, вы можете загрузить звук из массива lua:

local wav = {}
for i = 1, 10000 do
	table.insert(wav, rnd() * 2 - 1) -- случайные значения от -1 до 1
end

function start()
	local p = snd.new(22050, 1, wave) -- частота, число каналов и звук
	p:play()
end

Звук задается в нормированном формате: [-1 .. 1]

Звук можно проиграть методом :play([chan], [loop]), где chan -- канал (0 - 7), loop - циклы (0 - бесконечность).

Остальные функции модуля:

  • snd.stop([channel]) – остановить проигрывание выбранного канала или всех каналов. Вторым параметром можно задавать время затухания звука в мс. при его приглушении;

  • snd.playing([channel]) – узнать проигрывается ли звук на любом канале или на выбранном канале; если выбран конкретный канал, функция вернет хандл проигрываемого в данный момент звука или nil. Внимание! Звук клика не учитывается и обычно занимает 0 канал;

  • snd.pan(chan, l, r) – задание паннинга. Канал, громкость левого[0-255], громкость правого[0-255] каналов. Необходимо вызывать перед проигрыванием звука, чтобы имело эффект;

  • snd.vol(vol) – задание громкости звука (и музыки и эффектов) от 0 до 127.

Еще одна интересная возможность -- генерирование звука на лету (пока находится в экспериментальном статусе):

require "snd"

function cb(hz, len, data)
	for i = 1, len do
		data[i] = rnd() * 2 - 1
	end
end
function start()
	snd.music_callback(cb)
end

Модуль prefs

Этот модуль позволяет сохранять настройки игры. Другими словами, сохраненная информация не зависит от состояния игры. Такой механизм можно использовать, например, для реализации системы достижений или счетчика количества прохождений игры.

По своей сути prefs это объект, все переменные которого будут сохранены.

Cохранить настройки:

prefs:store()

Настройки сохраняются автоматически при сохранении игры, но вы можете контролировать этот процесс, вызывая prefs:store().

Уничтожить файл с настройками:

prefs:purge()

Загрузка настроек выполняется автоматически при запуске игры (перед вызовом функции start()), но вы можете инициировать загрузку и вручную:

prefs:load()

Пример использования:

-- $Name: Тест модуля prefs$
-- $Version: 0.1$
-- $Author: instead$

-- подключаем модуль click
require "click"
-- подключаем модуль prefs
require "prefs"

-- устанавливаем начальное значение счетчика
prefs.counter = 0;

-- определяем функцию отслеживания количества "кликов"
game.onclick = function(s)
    -- увеличиваем счетчик
    prefs.counter = prefs.counter + 1;
    -- сохраняем счетчик
    prefs:store();
    -- выводим сообщение
    p("На данный момент сделано ", prefs.counter ," кликов");
end;

-- добавляем изображение, по которому можно производить клики
game.pic = 'box:320x200,black';

room {
    nam = 'main',
    title = "Комната кликов",
    -- делаем фиксацию статичной части описания
    -- добавляем описание для сцены
    decor = [[ Этот тест был написан специально
            для проверки работы модуля <<prefs>>.
    ]];
};

Обратите внимание, что после запуска игры заново, число выполненных кликов не обнулится!

Модуль snapshots

Модуль snapshots предоставляет возможность восстанавливать предварительно сохраненные состояния игры. В качестве примера, можно привести ситуацию, когда игрок выполняет в игре действие, ведущее к проигрышу. Модуль позволяет автору игры написать код так, что игрок вернется к предварительно сохраненному состоянию игры.

Для создания снапшота используйте функцию: snapshots:make(). В качестве параметра может быть задано имя слота.

Внимание!!! Снапшот будет создан после завершения текущего такта игры, так как только в этом случае гарантирована непротиворечивость сохраненного состояния игры.

Загрузка снапшота осуществляется snapshots:restore(). В качестве параметра может быть задано имя слота.

Удаление снапшота делается с помощью snapshots:remove(). Следует удалять ненужные снапшоты, так как они занимают лишнее место в файлах сохранения.

Пример использования:

require "snapshots"

room {
	nam = 'main';
	title = 'Игра';
	onenter = function()
		snapshots:make() -- создали точку восстановления
	end;
	decor = [[{#red|Красное} или {#black|черное}?]];
}: with {
	obj {
		nam = '#red';
		act = function()
			p [[Вы выиграли!]]
		end;
	};
	obj {
		nam = '#black';
		act = function()
			walk 'end'
		end;
	}
}

room {
	nam = 'end';
	title = 'Конец';
}: with {
	obj {
		dsc = [[{Переиграть?}]];
		act = function()
			snapshots:restore() -- восстановились
		end;
	}
}