Skip to content

Сигналы и таймауты

TrueCat17 edited this page May 6, 2024 · 2 revisions

С помощью сигналов можно реагировать на определённые события (и/или запускать их самостоятельно).
Таймауты позволяют вызвать какую-либо функцию через определённое время.
Интервалы позволяют вызывать функцию через определённые промежутки времени.

Всё это работает на уровне питона, т. е. должно быть либо в блоке python, либо в команде $.


Сигналы

Добавить реакцию на сигнал "event" - выполнить функцию function:
signals.add("event", function, priority = 0, times = -1)
Если на одно событие повешено несколько функций, то сначала выполнится та, что с меньшим приоритетом. Если 2 функции имеют одинаковый приоритет, то первой будет первая добавленная.
times определяет число вызовов, после которого эта функция будет удалена из реакций на данное событие (-1 - никогда не удалять).

Пример:

def my_function(arg = "world"):
	out_msg("Hello, %s!" % arg)

signals.add("my_super_event", my_function)

Удалить реакцию на событие "event":
signals.remove("event", function)
Здесь function - функция, указанная ранее в signals.add.

Отправить сигнал (вызвать все функции, подписанные на "event"):
signals.send("event", *args, **kwargs)
2 последние аргумента обозначают, что вы можете добавлять какие-угодно аргументы, и они будут переданы вызываемым функциям.

Например: signals.send("my_super_event", "My Super World")
Или даже с именованым параметром: signals.send("my_super_event", arg="another world")

При отправке сигнала все функции, реагирующие на этот сигнал, вызываются сразу же.
Список стандартных сигналов - в конце.


Таймауты

Таймауты и интервалы работают примерно также, как и в JS (javascript в вашем браузере).

Вызвать function через time_sec секунд (может быть нецелым числом):
my_id = set_timeout(function, time_sec)
Результат - идентификатор таймаута (его номер), через который его можно отменить (и это единственный способ сделать это).

Отменить вышеуказанную операцию:
clear_timeout(my_id)
Если вызвать эту функцию несколько раз для одного и того же идентификатора, то это не будет считаться ошибкой.


Интервалы

Интервалы очень похожи на таймауты, но указанная функция вызывается не 1 раз, а постоянно через указанные промежутки времени:
my_id = set_interval(function, time_sec)
Отмена:
clear_interval(my_id)


Дополнительные пояснения

Вместо функций могут приниматься вызываемые (callable) объекты, в том числе такие как Function, AddVariable, SetDict и т. д.
Однако следует помнить, что все эти функции должны где-то храниться, а значит и уметь сохраняться и восстанавливаться с помощью pickle.
Причём проверка на это занимает какое-то время, так что делать это по тысяче раз за кадр - плохая идея.

Впрочем, проверку можно временно отключить, вызвав
signals.set_check_picklable(False)
Тогда после включения (True вместо False в примере выше) будут проверены все новые объекты сразу, что будет в десятки раз быстрее.

Функции таймаутов никогда не выполнятся сразу же - только в следующем кадре, даже если указано выполнить их через 0 секунд. Таймауты и интервалы реализованы через сигналы, конкретно - через "enter_frame". Поэтому их точность зависит от текущего FPS (кол-ва кадров в секунду). При максимальном FPS (60) можно рассчитывать на максимальную точность в 16.7 милисекунды (если не будет зависаний по каким-либо причинам).

Таким образом, нельзя рассчитывать на то, что нужные функции будут вызваны милисекунда в милисекунду (или даже в нужный десяток милисекунд). Также интервал будет вызван между 2 соседними кадрами не более одного раза.

Непонятно зачем, но если вдруг есть реальная причина, то можно создать собственный экземпляр сигналов, полностью независимый от стандартного: my_signals = Signals()
Разумеется, при отправке событий в стандартные сигналы, ваши не будут их получать (на то он и полностью независимый).


Список стандартных сигналов

Общие:

  • "enter_frame" - "вход" в кадр (перед отрисовкой скринов),
  • "exit_frame" - "выход" из кадра (после отрисовки всех скринов),
  • "show_screen" - на экран добавлен какой-то скрин (функция должна принимать 1 аргумент - название скрина),
  • "hide_screen" - с экрана был скрыт какой-то скрин (функция должна принимать 1 аргумент - название скрина),
  • "resized_stage" - размер окна был изменён (см. функцию get_stage_size).

РПГ-часть:

  • "rpg-location" - игрок перешёл из одной локации в другую (см. переменные cur_location и cur_location_name),
  • "rpg-place" - игрок вошёл в определённое место на локации (см. cur_place и cur_place_name),
  • "rpg-no_exit" - игрок попытался перейти туда, куда у него нет доступа (см. систему запретов в РПГ),
  • "rpg-stand_up" - игрок встал,
  • "rpg-sit_down" - игрок сел,
  • "rpg-action" - нажата "кнопка действия".

Инвентарь РПГ-части (функция должна принимать 1 аргумент - название объекта):

  • "inventory-remove" - выбрасывание предмета из инвентаря,
  • "inventory-use" - использование предмета в инвентаре,
  • "inventory-take" - взятие предмета в инвентарь.

Прочее:

Основы
Если вы новичок, то будет достаточно прочитать лишь это, пока ваш энтузиазм не исчерпан.
Остальное можно будет прочесть по мере надобности.

  1. Быстрый старт!
  2. Основы команд и блоков.
  3. Простейшие примеры.
  4. Изображения.
  5. Музыка и звуки.

Документация по RPG-части находится здесь.


Более сложные вещи
Через некоторое время вам, возможно, потребуются более продвинутые возможности.

  1. Функции для изображений (im-функции).
  2. Эффекты.
  3. Времена суток.
  4. ATL (анимации и трансформации).
  5. Ввод с клавиатуры.
  6. Введение в ScreenLang (GUI, интерфейс).
  7. Конфигурирование игры.

Дополнительно


Перед самым началом
Советы для новичков и не только.


Оффтоп.

Clone this wiki locally