Всем доброго времени суток!
Возникла потребность встроить рекламу в свою игру на Love2D. Решил показывать баннер после выигрыша игрока и тут появились сложности: банер вызывается Java кодом приложения, а выигрыш определяется в Lua коде. Связывает их код на Си, туториалов, как добавлять свои методы в движок не было, и пришлось копаться в коде самостоятельно. Репозиторий Love2D для Android лежит вот тут.
С чего начать?
Начать я решил с изучения метода love.system.vibrate()
– метод, который появляется при использовании Love2D на андроид, а значит его где-то добавляют также, как я хочу добавить рекламу.
Если открыть класс GameActivity, то там можно найти метод vibrate, который мы ищем, и вот тут стоит объяснить, как происходит вызов Java кода из Lua.
Когда приложение только запускается, для каждого модуля Love2D создается экземпляр класса модуля и экземляр класса связки (объект, который привязывает Сишный объект к переменной Lua). У объекта связки для каждого метода, который нужно интегрировать в Lua есть свой маленький метод и список, в котором указано какой метод в Lua сопостовляется сишной связке. Выглядит это так:
// Список связок
static const luaL_Reg functions[] =
{
{ "getOS", w_getOS },
{ "getProcessorCount", w_getProcessorCount },
{ "setClipboardText", w_setClipboardText },
{ "getClipboardText", w_getClipboardText },
{ "getPowerInfo", w_getPowerInfo },
{ "openURL", w_openURL },
{ "vibrate", w_vibrate },
{ 0, 0 }
};
extern "C" int luaopen_love_system(lua_State *L)
{
// Эземпляр модуля
System *instance = instance();
if (instance == nullptr)
{
instance = new love::system::sdl::System();
}
else
instance->retain();
// Итоговая связка
WrappedModule w;
w.module = instance;
w.name = "system";
w.type = MODULE_ID;
w.functions = functions;
w.types = nullptr;
return luax_register_module(L, w);
}
Так же замечу, что дополнительные методы, которые добавлены для андроида, хранятся в отдельном классе, который лежит в папке ./jni/love/src/common/
и называется android
.
Добавляем свой метод
Сначала создадим статичный метод в классе GameActivity:
private static GameActivity instance;
@Override
protected void onCreate(Bundle savedInstanceState) {
instance = this;
// ...
}
// ...
// Важно, чтобы метод был статичным, потому что доступ к
// экземпляру класса получить будет сложнее
public static void showAd() {
Toast.makeText(instance, "Ad example", Toast.LENGTH_LONG).show();
}
Теперь создадим метод в модуле love.system
. Я выбрал этот модуль, потому что внедряю рекламу, но использовать именно system не обязательно. Можно даже создать свой модуль, в зависимости от того, что вам нужно.
Сначала нужно написать главную часть метода в классе android
. Объявляем:
// ./jni/love/src/common/android.h
bool openURL(const std::string &url);
void showAd();
void vibrate(double seconds);
И создаем:
// ./jni/love/src/common/android.cpp
void showAd()
{
// Получаем среду исполнения Java
JNIEnv *env = (JNIEnv*) SDL_AndroidGetJNIEnv();
// И класс, в котором мы создали статичный метод
jclass activity = env->FindClass("org/love2d/android/GameActivity");
// Теперь сам метод
jmethodID show_ad_method = env->GetStaticMethodID(activity, "showAd", "()V");
// И вызываем его
env->CallStaticVoidMethod(activity, show_ad_method);
env->DeleteLocalRef(activity);
}
При получении идентификатора метода третим параметром мы указываем, что возвращает метод и какие параметры принимаем. Если ваш метод будет принимать аргументы, то в скобках их нужно перечислить. Если ваш метод возвращает значение, то также нужно будет изменить V
на соответствующую букву. Так, чтобы описать вот такой метод:
bool isGreater(double a, double b) { return a > b; }
Будет использоваться следующая строка: (DD)Z
. Подробнее можно прочитать вот тут.
Добавляем метод showAd
в сам модуль:
// ./jni/love/src/modules/system/System.h
/**
* Shows ad
*/
virtual void showAd() const;
Ну и сам код:
// ./jni/love/src/modules/system/System.cpp
void System::showAd() const {
#ifdef LOVE_ANDROID
love::android::showAd();
#endif
}
Немного клея
Теперь осталось все это соединить с помощью связки. Добавляем соответсвующий метод в класс связки:
int w_showAd(lua_State *L)
{
instance()->showAd();
return 0;
}
// Ну и список связок конечно же
static const luaL_Reg functions[] =
{
{ "getOS", w_getOS },
{ "getProcessorCount", w_getProcessorCount },
{ "setClipboardText", w_setClipboardText },
{ "getClipboardText", w_getClipboardText },
{ "getPowerInfo", w_getPowerInfo },
{ "openURL", w_openURL },
{ "vibrate", w_vibrate },
{ "showAd", w_showAd },
{ 0, 0 }
};
Собираем все это по туториалу с самого начала.
Добавляем код в луа (love.system.showAd()
) и проверяем:
Вуаля.
Заключение
С помощью подобных манипуляций можно встраивать рекламу, управлять светодиодом, камерой и вообще делать много полезных вещей с помощью игры, что местами бывает очень полезно для интересных игровых задумок.
Спасибо за прочтение (: