Некоторые полезные функции (Python) - TrueCat17/Ren-Engine GitHub Wiki

Вывод сообщений и ошибок в окне

out_msg("from", "error_description")

Для удобства также выводится весь python-стек и идёт запись всего выведенного текста в лог-файл (../var/log.txt).


Моды

Получить кортёж (tuple) модов в виде ((name1, dir_name1), (name2, dir_name2), ...), где name - название мода, а dir_name - название директории, в которой находится мод:
get_mods()

Запуск мода в директории mod_name:
start_mod("mod_name")
Аналогично переход в основное меню:
start_mod("main_menu")
Немедленный выход из игры (не в меню, а вообще):
exit_from_game()


Размеры окна

Ширина окна игры:
get_stage_width()
Высота:
get_stage_height()
Ширина и высота окна:
get_stage_size()
Установить размер окна в 1366x768:
set_stage_size(1366, 768)

Внимание, переменные config.width и config.height нужны совсем для других целей, см. Авто-масштабирование спрайтов.


Полноэкранный режим

Развернуть окно на весь экран:
set_fullscreen(True)
Выйти из полноэкранного режима:
set_fullscreen(False)


Изображения

Загрузить изображение (и обработать im-функциями, если есть) асинхронно, т. е. в отдельном потоке:
load_image("image_path")
Ширина изображения:
get_image_width("image_path")
Высота:
get_image_height("image_path")
Ширина и высота:
get_image_size("image_path")
Получить пиксель в точке (x, y) изображения "image_path" (число в формате RGBA, т. е. 0xRRGGBBAA):
get_image_pixel("image_path", x, y)


Мышь

Получить координаты мыши:
get_mouse()
Получить координаты мыши относительно кнопки, на которую наведена мышь:
get_local_mouse()
Узнать, нажата ли левая кнопка мыши:
get_mouse_down()


Параметр из params.conf

Получить параметр "param" из файла params.conf как тип some_type (один из str, float, int или bool):
get_from_hard_config("param", some_type)


FPS

Получить максимальное значение фпс (FPS, Frame Per Second, количество кадров в секунду):
get_fps()
Установить максимальное значение фпс в 30 (можно поставить любое число от 1 до 60 включительно):
set_fps(30)


ATL

Получить ATL изображения ("список действий"), зарегистрированного командой image (см. начало главы Изображения):
get_image("image name")

Например, если изображение было зарегистрировано так:

image bg room = "images/bg/room.jpg"

Или так:

image bg room:
	"images/bg/room.jpg"

То get_image("bg room") вернёт в обоих случаях ["images/bg/room.jpg"] (конечно, если default_decl_at пуст, см. статью про ATL)


Проверка существования спрайта

Узнать, было ли зарегистрировано изображение командой image:
image_was_registered("bg room")


Скрины

Показать скрин с именем screen_name:
show_screen("screen_name") # или renpy.show_screen
Скрыть:
hide_screen("screen_name") # или renpy.hide_screen
Узнать, отображается ли:
has_screen("screen_name") # или renpy.has_screen


Метки

Узнать, существует ли метка (label) some_label:
renpy.has_label("some_label")
Прыгнуть (jump) на метку some_label:
renpy.jump("some_label")
Вызвать (call) метку some_label:
renpy.call("some_label")
Последние 2 функции действуют не сразу, а после окончания работы всего питон-кода, в котором они находятся, пример:

python:
	print(123)
	renpy.jump("some_label") # отмечает, что после этого блока будет выполнен jump на some_label
	print(234) # выхода из питон-блока после renpy.[jump/call] нет, поэтому эта строка тоже отработает

Screenshot

Сделать скриншот (по умолчанию вызывается при нажатии на P (англ.)):
make_screenshot(width = None, height = None)
Где width и height - размеры к которым масштабируется скриншот до сохранения (None - не масштабировать).
Скриншот сохраняется в var/screenshots/ под именем screenshotNNNN.png.


Скрытие курсора мыши

Разрешить/запретить скрывать курсор при бездействии в текущем моде:
set_can_mouse_hide(False) # False - не скрывать, по умолчанию - True
Используется, например, в главном меню.
Время устанавливается в resources/params.conf.


Быстро преобразовать float в int:
ftoi(3.14)
Работает заметно быстрее int(3.14).
Может быть использовано для быстрого отбрасывания дробной частипри отрисовке нескольких тысяч изображений в ScreenLang.


Получить имя папки текущего мода:
get_current_mod()


Получить время запуска текущего мода (в секундах, как и time.time()):
get_mod_start_time()


Функции для работы со временем.

Если вы попробуете засекать время между кадрами вызовами time.time() примерно таким образом:

prev_my_update_time = time.time()
def my_update():
	global prev_my_update_time
	dtime = time.time() - prev_my_update_time
	prev_my_update_time = time.time()
	
	# using <dtime>

То в случае перевода системных часов или в случае загрузки сохранения вы получите неадеватные результаты, ведь между кадрами здесь могут пройти минуты или даже месяцы.
Для решения этой проблемы у Ren-Engine есть 2 следующих функции.

Получить время между началом текущего и началом прошлого кадров (в секундах):
dtime = get_last_tick()
Возвращает 0 в init-блоках или в случае, если это первый кадр после запуска с нуля или загрузки сохранения.
Кроме решения проблемы, эта функция также избавляет нас от кучи рутинной возьни.

Получить сумму вызовов get_last_tick() для всех предыдущих кадров:
get_game_time()
Также возвращает 0 во время инициализации (выполнение init-блока).
В некотором роде это аналог для time.time() без его вышеописанных недостатков.

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


Текущие файл и строка

Получить путь до текущего файла:
get_filename(0)

Получить номер текущей строки:
get_numline(0)

Получить путь до текущего файла и номер текущей строки:
get_file_and_line(0)

Число 0 здесь означает именно текущее место (при 1 будет место, откуда вызвана текущая функция, и так далее).

Полученный путь может быть использован, к примеру, для построения пути к изображению, которое лежит рядом с текущим файлом.
Но вообще эти данные иногда требуются самому движку для более информативного сообщения об ошибке.


Сборка объекта из глобальных функций

build_object('name')

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

Пример создания:

def my_map__some_function():
	pass

def my_map__music__play(*args):
	pass

build_object('my_map')
my_map.my_prop = 'my value'

build_object в данном случае делает примерно следующее:

my_map = Object()
my_map.some_function = my_map__some_function
my_map.music = Object()
my_map.music.play = my_map__music__play

После этого доступен для использования объект my_map класса Object (не путать со стандартным python-классом object), который допускает (без выкидывания ошибок) обращение к любым свойствам.
Конечно, это можно делать и вручную, но зачем, если есть специальная функция, позволяющая делать это одной строчкой кода?

А вот и примеры использования полученного объекта, ничего неожиданного:

my_map.some_function()
my_map.music.play('some_music')

my_map.my_prop += '!'
what = 'prop'
my_map['my_' + what] += '!!' # в квадратных скобках можно "вычислить" название свойства

Ещё может возникнуть вопрос, почему бы не делать это с помощью классов или модулей?
Ну, у модулей в python есть свои недостатки (например: переусложнённость, циклические зависимости, сложности с сохранением данных).
С классами же есть 2 выхода, и оба весьма корявы:

  1. Создать экземпляр класса (всего 1, что само по себе нетипично и странно) и постоянно передавать ненужный self в методах,
  2. Добавить @staticmethod к каждому методу и дать классу имя с маленькой буквы (+cpickle отказывается сохранять staticmethod, что совсем катастрофично).

Вот и выходит, что одним из самых разумных методов становится создание таких объектов.


Буфер обмена

Получить текст (строка в utf-8) из буфера обмена:
s = get_clipboard_text()

Установить текст в буфер обмена:
res = set_clipboard_text("Your Text.")
Функция возвращает True, если всё прошло удачно и False в противном случае.
Этот результат можно просто проигнорировать, вовсе не записывая его ни в какую переменную.


UTF-8

Ren-Engine ведёт всю работу в кодировке utf-8.
В этой же кодировке работает и python3.

Ранее вместо него использовался python2, а там с этим были некоторые проблемы, для обхода которых было написано несколько функций, о которых и рассказывалось в этом разделе, а также была дана ссылка на интересную статью про устройство utf-8.

Сейчас же (с переходом на python3) из тех функций сохранилась только 1 (да и та поменяла имя):

  • get_text_width(text, text_size) - посчитать примерную длину text, отрисованную шрифтом размера text_size.

Внимание - функция не учитывает тэги (вроде {b} - полужирности), разный размер разных символов и принципиальную неопределяемость размеров разных символов шрифта без самого шрифта. Рекомендуется на всякий случай к полученному значению добавлять число от 20 до 50 (в зависимости от ситуации).

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


Остановка и продолжение сценария

Добавить свою функцию, при возвращении которой значения False сценарий будет стоять на месте:
can_exec_next_check_funcs.append(your_func)

Добавить функцию, которая "перематывает" функцию из предыдущего абзаца:
can_exec_next_skip_funcs.append(your_func)

Не для каждой функции, которая "тормозит" сценарий должна быть аналогичная функция для пропуска.
Например, этим может заниматься связанный по смыслу скрин.
Однако, рекомендуется максимально избегать принципиальной невозможности пропуска.

Для отладочных целей иногда нужно узнавать: какая именно функция останавливает сейчас сценарий?
Эта функция записывается в переменную func_that_stopped_scenario.
Её можно посмотреть, просто вставив название в консоль движка (Shift+O).


Показывалось ли изображение

renpy.seen_image('rn happy')
Возвращает True если показывалось, иначе - False.
Изображение rn happy зарегистрировано командой image (вроде image rn happy = "images/sprites/rn/happy.png").


Проигрывался ли аудио-файл

renpy.seen_audio('sound/music/road.ogg')


Посещалась ли метка

renpy.seen_label('label_name')
Где label_name зарегистрирована так:

label label_name:
	# ...

Качество масштабирования

По умолчанию задаётся переменной scale_quality в файле resources/params.conf.

Если какой-то мод хочет поменять при своём запуске значение этой переменной, это можно сделать так:
set_scale_quality('1')

Значения (строки):

  • '0' - оставить видимые пиксели ("лесенку") при масштабировании - используется, например, в RPG;
  • '1' - включить сглаживание ("мыло") - используется, например, в Визуальных Новеллах;
  • '2' - на данный момент то же самое, что и '1' (поведение библиотеки SDL).

Получить текущее значение можно так:
get_scale_quality()


Версия движка

Узнать версию движка можно функцией get_engine_version(), которая возвращает строку вроде 0.9.6-2022.10.12.
Именно эта версия пишется в лог-файле (var/log.txt).

До знака - через точку идут номера версий: мажорная, минорная и микро (major, minor, micro).
После - дата последнего изменения в формате год, месяц и число месяца.

Предполагается, что:

  1. Мажорная версия меняется при добавлении значительной функциональности (вроде поддержки 3D), также именно с этими изменениями будут обычно идти и изменения, ломающие обратную совместимость.
  2. Минорная версия меняется при изменениях средней важности, обратная совместимость будет сохраняться почти полностью.
  3. Микро предназначена для мелких и незначительных изменений и исправлений.
  4. До релиза (версия 1.0) мажорная версия указывается на месте минорной, а минорная на месте микро; обратная совместимость же может быть сломана при абсолютно любом изменении.
  5. Движок берёт строку версии из файла Ren-Engine/version, если его нет или он пуст, то функция возвращает строку "None".

Работа с директориями

make_sure_dir(path) - возвращает path, гарантированно оканчивающийся на /.

get_directory_name(path)
Здесь path - путь относительно "корневой директории" проекта (содержит resources и var).
Возвращает "название" папки (по содержимому файла name, с учётом языка) или название игры (window_title из params.conf) для "корня" проекта.
Если файл name отсутствует - просто возвращает path.

get_root_dir() - возвращает путь к корню проекта.


Также много интересного можно найти в Ren-Engine/rpy/renpy_api.rpy.

⚠️ **GitHub.com Fallback** ⚠️