Конфигурация менеджера скриптов¶
В Nau Engine скрипты играют ключевую роль в реализации игровой логики. ScriptManager – это основной компонент, отвечающий за управление скриптами, их загрузку и выполнение. Данная статья описывает, как настроить ScriptManager, как выполнять скрипты, написанные на Lua и как использовать Typescript для разработки более сложных и поддерживаемых скриптов. В бета-версии Nau Engine функциональность ScriptManager может быть ограничена.
Настройка путей¶
Прежде всего, необходимо настроить пути поиска скриптов. Это можно сделать двумя способами:
Напрямую через код: Используйте метод ScriptManager::addScriptSearchPath , чтобы добавить путь к папке, где хранятся ваши скрипты.
Через файл конфигурации: Более удобный способ – указать пути поиска в файле конфигурации. Например, в JSON-файле конфигурации добавьте секцию
scripts
с массивомsearchPaths
, содержащим виртуальные пути к папкам со скриптами. Эти пути могут быть связаны с реальными папками на вашем диске через секциюvfs
(Virtual File System) в конфигурации.Пример конфигурации в JSON-формате:
{ "app":{ "vfs":{ "mounts":[ { "mountPoint":"/scriptsRoot", // Виртуальный путь "path":"${sampleProjectDir}/content/scripts/out.**Lua**" // Реальный путь на диске } ] } }, "scripts": { "searchPaths": [ "/scriptsRoot" // Виртуальный путь к скриптам ] } }
В этом примере виртуальный путь
/scriptsRoot
указывает на реальную папку${sampleProjectDir}/content/scripts/out.lua
на вашем диске. ScriptManager будет искать скрипты в папке, связанной с виртуальным путем/scriptsRoot
. Использование виртуальных путей позволяет абстрагироваться от физического расположения файлов и упрощает управление проектом.
Выполнение скрипта¶
Для выполнения скриптов в Nau Engine используется компонент ScriptManager. Доступны два основных способа запуска скриптов:
Из буфера памяти: ScriptManager::executeScriptFromBytes позволяет выполнить скрипт, загруженный в память. Этот подход полезен, если скрипт генерируется динамически или загружается из внешнего источника.
Напрямую из файла vfs: ScriptManager::executeScriptFromFile выполняет скрипт непосредственно из файла, расположенного в виртуальной файловой системе (VFS). Этот метод использует пути поиска, указанные в конфигурации ScriptManager. Движок найдет первый файл с указанным именем в путях поиска и выполнит его.
Оба метода возвращают объект Result
, который содержит информацию об успешности выполнения скрипта. В случае ошибки, Result
будет содержать ее описание
(например, синтаксическая ошибка или ошибка выполнения). Скрипт потенциально может возвращать значение, однако
в текущей бета-версии обработка возвращаемого значения не реализована. Загрузка и выполнение скрипта трактуются как вызов функции без аргументов.
Пример выполнения скрипта на C++:
1Result<> startupApplication()
2{
3using namespace nau::scripts;
4
5ScriptManager& scriptManager = getServiceProvider().get<ScriptManager>();
6
7// Поиск файла осуществляется во всех путях, указанных для поиска (будет использован первый найденный файл).
8NauCheckResult(scriptManager.executeScriptFromFile("MyScript1"));
9
10// ...
11}
В данном примере executeScriptFromFile
ищет файл MyScript1
(например, MyScript1.lua
) во всех указанных путях поиска скриптов
и выполняет его. NauCheckResult
проверяет результат выполнения и обрабатывает возможные ошибки.
Отображение C++ классов в скрипт¶
Nau Engine позволяет использовать C++ классы в скриптах. Для этого необходимо предоставить движку метаинформацию о типе, которая впоследствии доступна через Runtime API. Эта метаинформация позволяет скриптам взаимодействовать с C++ объектами и вызывать их методы.
Декларация/экспорт методов¶
Для экспорта методов C++ класса в скрипты используются макросы NAU_CLASS_METHODS
и CLASS_METHOD
. Макрос NAU_CLASS_METHODS
перечисляет все методы, которые должны быть доступны из скриптов. Макрос CLASS_METHOD
связывает имя метода в скрипте с соответствующим методом C++ класса.
class MyNativeBinding : public IRefCounted
{
NAU_CLASS_(MyNativeBinding, IRefCounted)
NAU_CLASS_METHODS(
CLASS_METHOD(MyNativeBinding, getKeyboardButtonPressed),
CLASS_METHOD(MyNativeBinding, spawnItem))
public:
bool getKeyboardButtonPressed(input::Key key) const;
void spawnItem(float x, float y, float z) const;
};
В этом примере методы getKeyboardButtonPressed
и spawnItem
класса MyNativeBinding
будут доступны для вызова из скриптов.
Параметры и возвращаемые значения экспортируемых методов должны быть совместимы с системой RuntimeValue
, которая используется
для передачи данных между C++ и скриптами.
Декларация/экспорта свойств (properties)¶
Экспорт свойств (properties) C++ классов в скрипты в текущей бета-версии Nau Engine не поддерживается.
Регистрация класса и создание экземпляра¶
Для того чтобы C++ класс стал доступен в скриптах, его необходимо зарегистрировать в ScriptManager. Это делается с помощью метода ScriptManager::registerClass или ScriptManager::registerNativeClass<Class> .
void startupApplication()
{
using namespace nau::scripts;
ScriptManager& scriptManager = getServiceProvider().get<ScriptManager>();
scriptManager.registerNativeClass<MyNativeBinding>();
}
После регистрации класса вы можете создавать экземпляры объекта-обертки над C++ типом в ваших скриптах. Способ создания экземпляра зависит от используемого языка скриптов.
Пример на Lua:
binding = MyNativeBinding:New()
function globalFunction(dt)
if binding:getKeyboardButtonPressed("A") then
binding:spawnItem(10, 20, 30)
print("Key pressed")
end
return ("no press (" .. tostring(dt)) .. ")"
end
Пример на Typescript:
/**
* Native (C++) Api
*/
declare class MyNativeBinding {
public static New(): MyNativeBinding;
public getKeyboardButtonPressed(key: string): boolean;
public spawnItem(x: number, y: number, z: number): void;
}
const binding = MyNativeBinding.New();
function globalFunction(dt: number): String {
if (binding.getKeyboardButtonPressed("A")) {
binding.spawnItem(10, 20, 30);
print("Key pressed");
}
return `no press (${dt})`
}
В обоих примерах создается экземпляр класса MyNativeBinding
и вызываются его методы.
Доступ к скриптам из C++¶
Nau Engine позволяет вызывать функции, определенные в скриптах, непосредственно из C++ кода. Это обеспечивает гибкость и позволяет использовать скрипты для реализации игровой логики, взаимодействуя с ними из C++.
Вызов глобальной функции¶
Для вызова глобальной функции, определенной в скрипте, используется метод ScriptManager::invokeGlobal или типизированная обёртка над invokeGlobal: GlobalFunction<R (P…)>, где R — тип возвращаемого значения, а P… — типы параметров функции.
scripts::GlobalFunction<std::string(float)> globalFunction{"globalFunction"};
// ...
Result<std::string> invokeRes = globalFunction(0.1f);
// ...
В этом примере объявляется глобальная функция globalFunction
, которая принимает один параметр типа float
и возвращает значение типа std::string
.
Затем функция вызывается с параметром 0.1f
, и результат сохраняется в переменной invokeRes
. Объект Result
содержит возвращаемое значение функции и
информацию об успешности выполнения.
Создание экземпляров классов¶
Функциональность создания экземпляров классов скриптов из C++ кода находится в разработке и будет доступна в будущих версиях Nau Engine. Следите за обновлениями!
Использование Typescript в Nau Engine¶
В текущей бета-версии Nau Engine для поддержки скриптов разработан модуль LuaScripts. Lua — это компактный, стабильный и широко распространенный язык, подходящий для встраивания в игровые движки. Он работает на различных платформах и имеет JIT-реализации для повышения производительности. Однако, как динамический язык без строгой типизации, Lua имеет некоторые недостатки, особенно при разработке крупных проектов, например в этом языке «из коробки» нет стандартной поддержки модульности, а отсутствие системы типов влечёт за собой:
сложность разработки больших проектов;
сложность поддержки на уровне IDE: организации даже простейшего intellisense подразумевает нетривиальный анализ всего проекта;
невозможность декларации внешних типов, т.е. биндинги привносят runtime объекты, но нет возможности (в рамках языка) ввести декларацию типов этих объектов.
Поэтому использование Lua позиционируется только в качестве «Backend» - целевой системы исполнения. Тем временем в качестве «Frontend» рекомендуется использовать Typescript , который должен быть использован в качестве основного языка и впоследствии трансформирован в **Lua** через инструмент TypescriptToLua.
Настройка проекта Typescript¶
Для работы с Typescript в Nau Engine необходимо следующее:
Установленный Node.js: Typescript и TypescripToLua основаны на Node.js.
Проект оформляется как node package: следуйте инструкциям по настройке проекта в документации TypescriptToLua Getting started
Файлы
package.json
иtsconfig.json
: эти файлы содержат настройки проекта и компилятора Typescript.
package.json:
{
"name": "nau_scripts_sample",
"version": "1.0.0",
"scripts": {
"build": "tstl",
"dev": "tstl --watch"
},
"devDependencies": {
"Typescript**": "^5.6.2",
"Typescript-to-Lua": "^1.27.1"
}
}
tsconfig.json:
{
"$schema": "https://raw.githubusercontent.com/TypescriptToLua/TypescriptToLua/master/tsconfig-schema.json",
"compilerOptions": {
"target": "ESNext",
"lib": ["ESNext"],
"moduleResolution": "Node",
"types": [],
"strict": true,
"outDir": "out.**Lua**",
"experimentalDecorators": true
},
"tstl": {
"LuaTarget": "5.4",
"noImplicitSelf": true
}
}
В этой статье мы рассмотрели основные аспекты работы со ScriptManager в Nau Engine, включая настройку путей поиска скриптов, выполнение скриптов из памяти и из файлов, а также использование Typescript для разработки скриптов. Понимание этих принципов позволит вам эффективно использовать скрипты для реализации игровой логики и создания интерактивных приложений. Следите за обновлениями документации, чтобы быть в курсе последних изменений и новых возможностей.