يتيح لك محرك ألعاب Corona إنشاء تطبيقات وألعاب عبر الأنظمة الأساسية. ولكن في بعض الأحيان لا يكفي API الذي يقدمونه. في مثل هذه الحالات ، هناك Corona Native ، والذي يسمح لك بتوسيع الوظائف باستخدام التعليمات البرمجية الأصلية لكل منصة.
ستناقش هذه المقالة استخدام Java في مشاريع Corona لنظام Android
لفهم ما يحدث في المقالة ، تحتاج إلى معرفة أساسية بجافا ولوا ومحرك كورونا
الشروع في العمل
يجب تثبيت Corona و Android Studio على جهاز الكمبيوتر
يحتوي مجلد تثبيت Corona أيضًا على قالب المشروع: Native \ Project Template \ App. انسخ المجلد بالكامل وأعد تسميته إلى اسم مشروعك.
تخصيص القالب
ملاحظة: استخدمت أحدث بناء عام متاح لـ Corona - 2017.3184 . في الإصدارات الجديدة ، قد يتغير القالب ، ولن تكون هناك حاجة لبعض الاستعدادات من هذا الفصل.
بالنسبة إلى Android ، نحتاج إلى مجلدين بالداخل: Corona و android
من مجلد Corona ، احذف Images.xcassets و LaunchScreen.storyboardc - لا نحتاج إلى هذه المجلدات. في ملف main.lua ، نقوم أيضًا بحذف جميع التعليمات البرمجية - سنبدأ في إنشاء المشروع من البداية. إذا كنت ترغب في استخدام مشروع موجود ، فاستبدل جميع الملفات الموجودة في مجلد Corona بملفك الخاص
مجلد android هو مشروع منتهي لـ Android Studio ، نحتاج إلى فتحه. الرسالة الأولى من الاستوديو ستكون "فشل مزامنة Gradle". تحتاج إلى إصلاح build.gradle:

لإصلاح الموقف ، أضف رابطًا إلى المستودعات في buildscript. قمت أيضًا بتغيير الإصدار في classpath 'com.android.tools.build:gradle' إلى إصدار أحدث.
كود Build.gradle// Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { dependencies { classpath 'com.android.tools.build:gradle:3.1.3' } repositories { jcenter() google() } } allprojects { repositories { jcenter() google() } } task clean(type: Delete) { delete rootProject.buildDir }
الخطوة التالية هي تغيير gradle-wrapper.properties . يمكنك تغييره يدويًا عن طريق استبدال إصدار gradle في DistributionUrl. أو دع الاستوديو يفعل كل شيء من أجلك.

بالإضافة إلى ذلك ، تحتاج إلى إصلاح build.gradle لوحدة التطبيق: في cleanAssets تحتاج إلى إضافة سطر الحذف "$ projectDir / build / intermediates / jniLibs" ، والذي بدونه سيكون عليك القيام بمشروع نظيف قبل كل بداية ( مأخوذ من هنا )
الآن المزامنة ناجحة ، لا يوجد سوى عدد قليل من التحذيرات ذات الصلة ببناء buildToolsVersion القديم وبناء الجملة القديم في التكوين. تصحيحها ليس بالأمر الصعب.
الآن في الاستوديو نرى وحدتين: التطبيق والمكون الإضافي. أعد تسمية التطبيق (com.mycompany.app) والمكون الإضافي (plugin.library) قبل المتابعة.
علاوة على ذلك ، سيتم استدعاء البرنامج المساعد في plugin.habrExamplePlugin
يحتوي المكون الإضافي على فئة LuaLoader بشكل افتراضي - سيكون مسؤولاً عن معالجة المكالمات من رمز lua. يوجد بالفعل بعض التعليمات البرمجية ، ولكن دعونا نمسحها.
كود LuaLoader package plugin.habrExamplePlugin; import com.naef.jnlua.JavaFunction; import com.naef.jnlua.LuaState; @SuppressWarnings({"WeakerAccess", "unused"}) public class LuaLoader implements JavaFunction { @Override public int invoke(LuaState luaState) { return 0; } }
استخدام كود البرنامج المساعد من كود لوا
يستخدم Corona Native jnlua للربط بين Java و lua code. تطبق LuaLoader واجهة jnlua.JavaFunction ، لذا فإن طريقة الاستدعاء الخاصة بها متاحة من كود lua. للتأكد من أن كل شيء على ما يرام ، أضف رمز التسجيل إلى LuaLoader.invoke واجعل المكون الإضافي المطلوب في main.lua
@Override public int invoke(LuaState luaState) { Log.d("Corona native", "Lua Loader invoke called"); return 0; }
local habrPlugin = require("plugin.habrExamplePlugin") print("test:", habrPlugin)
بعد إطلاق التطبيق ، من بين السجلات ، سنرى السطرين التاليين:
د / كورونا الأصلي: استدعاء لوا لودر دعا
I / Corona: اختبار حقيقي
لذلك ، قام تطبيقنا بتنزيل المكون الإضافي ، ويتطلب إرجاعًا صحيحًا. الآن دعنا نحاول إرجاع جدول lua بوظائف من كود Java.
لإضافة وظائف إلى الوحدة النمطية ، نستخدم واجهة jnlua.NamedJavaFunction. مثال على دالة بسيطة بدون وسيطات ولا قيمة إرجاع:
class HelloHabrFunction implements NamedJavaFunction { @Override public String getName() { return "helloHabr"; } @Override public int invoke(LuaState L) { Log.d("Corona native", "Hello Habr!"); return 0; } }
لتسجيل وظيفتنا الجديدة في lua ، نستخدم طريقة LuaState.register:
public class LuaLoader implements JavaFunction { @Override public int invoke(LuaState luaState) { Log.d("Corona native", "Lua Loader invoke called"); String libName = luaState.toString(1);
يتطلب هذا الرمز شرحًا إضافيًا:
LuaState ، معلمة طريقة الاستدعاء ، تمثل بشكل أساسي غلافًا على جهاز Lua الظاهري (يرجى تصحيح لي إذا وضعته بشكل خاطئ). بالنسبة لأولئك الذين على دراية باستخدام كود lua من C ، فإن LuaState هو نفس مؤشر lua_State في C.
بالنسبة لأولئك الذين يرغبون في الخوض في غابة العمل مع lua ، أوصي بقراءة الدليل ، بدءًا من واجهة برنامج التطبيق
لذا ، عندما يتم استدعاء الاستدعاء ، نحصل على LuaState. يحتوي على مكدس يحتوي على معلمات تم تمريرها إلى دالتنا من كود lua. في هذه الحالة ، هذا هو اسم الوحدة ، حيث يتم تنفيذ LuaLoader عندما تتطلب المكالمة ("plugin.habrExamplePlugin").
يظهر الرقم الذي تم إرجاعه بواسطة استدعاء عدد المتغيرات من المكدس التي سيتم إرجاعها إلى رمز lua. في حالة الطلب ، لن يكون لهذا الرقم أي تأثير ، ولكننا سنستخدم هذه المعرفة لاحقًا عن طريق إنشاء دالة تُرجع عدة قيم
إضافة حقول إلى الوحدة
بالإضافة إلى الوظائف ، يمكننا أيضًا إضافة حقول إضافية إلى الوحدة ، على سبيل المثال ، الإصدار:
luaState.register(libName, luaFunctions);
في هذه الحالة ، استخدمنا فهرس -2 للإشارة إلى أنه يجب تعيين الحقل للوحدة النمطية الخاصة بنا. يعني المؤشر السالب أن العد يبدأ في نهاية المكدس. سيشير -1 إلى السلسلة "0.1.2" (في lua ، تبدأ الفهارس بواحد).
لكي لا تسد المكدس ، بعد ضبط الحقل ، أوصي باستدعاء luaState.pop (1) - يرمي عنصرًا واحدًا من المكدس.
كود LuaLoader الكامل @SuppressWarnings({"WeakerAccess", "unused"}) public class LuaLoader implements JavaFunction { @Override public int invoke(LuaState luaState) { Log.d("Corona native", "Lua Loader invoke called"); String libName = luaState.toString(1); // ( require) NamedJavaFunction[] luaFunctions = new NamedJavaFunction[]{ new HelloHabrFunction(), // }; luaState.register(libName, luaFunctions); // , luaState.register(libName, luaFunctions); // , luaState.pushString("0.1.2"); // luaState.setField(-2, "version"); // version . // 1 lua . // require , require return 0; } }
أمثلة على الوظائف
مثال على دالة تأخذ سلاسل متعددة وتسلسلها من خلال String builderالتنفيذ:
class StringJoinFunction implements NamedJavaFunction{ @Override public String getName() { return "stringJoin"; } @Override public int invoke(LuaState luaState) { int currentStackIndex = 1; StringBuilder stringBuilder = new StringBuilder(); while (!luaState.isNone(currentStackIndex)){ String str = luaState.toString(currentStackIndex); if (str != null){
الاستخدام في لوا:
local joinedString = habrPlugin.stringJoin("this", " ", "was", " ", "concated", " ", "by", " ", "Java", "!", " ", "some", " ", "number", " : ", 42); print(joinedString)
مثال لإرجاع قيم متعددةتطبق فئة SumFunction NamedJavaFunction {
تجاوز
السلسلة العامة getName () {
إرجاع "المبلغ" ؛
}}
@Override public int invoke(LuaState luaState) { if (!luaState.isNumber(1) || !luaState.isNumber(2)){ luaState.pushNil(); luaState.pushString("Arguments should be numbers!"); return 2; } int firstNumber = luaState.toInteger(1); int secondNumber = luaState.toInteger(1); luaState.pushInteger(firstNumber + secondNumber); return 1; }
}}
انعكاس جافا - باستخدام فئات جافا مباشرة في لوا
تحتوي مكتبة jnlua على فئة JavaReflector خاصة مسؤولة عن إنشاء جدول lua من كائن java. وهكذا ، يمكنك كتابة فئات في جافا وإعطائهم رمز لوا للاستخدام في المستقبل.
للقيام بذلك أمر بسيط للغاية:
مثال على الفصل
@SuppressWarnings({"unused"}) public class Calculator { public int sum(int number1, int number2){ return number1 + number2; } public static int someStaticMethod(){ return 4; } }
إضافة نسخة من هذه الفئة إلى وحدتنا
luaState.pushJavaObject(new Calculator()); luaState.setField(-2, "calc"); luaState.pop(1);
الاستخدام في لوا:
local calc = habrPlugin.calc print("call method of java object", calc:sum(3,4)) print("call static method of java object", calc:getClass():someStaticMethod())
لاحظ النقطتين في استدعاء أسلوب الفئة. بالنسبة للطرق الثابتة ، يجب عليك أيضًا استخدام النقطتين.
ثم لاحظت ميزة مثيرة للاهتمام للعاكس: إذا مررنا فقط مثيل من الفئة إلى lua ، فإن استدعاء أسلوبه الثابت ممكن عبر getClass (). ولكن بعد إجراء مكالمة من خلال getClass () ، سيتم تشغيل المكالمات اللاحقة على الكائن نفسه:
print("call method of java object", calc:sum(3,4))
أيضًا ، باستخدام getClass () ، يمكننا إنشاء كائنات جديدة مباشرةً في lua:
local newInstance = calc:getClass():new()
للأسف ، لم أتمكن من حفظ Calculator.class في حقل الوحدة النمطية بسبب "java.lang.IllegalArgumentException: نوع غير قانوني" داخل setField .
إنشاء واستدعاء وظائف لوا على الطاير
ظهر هذا القسم لأن التاج لا يوفر القدرة على الوصول إلى الوظائف من واجهة برمجة تطبيقاته مباشرة في Java. لكن jnlua.LuaState يسمح لك بتحميل كود Lua التعسفي وتنفيذه:
class CreateDisplayTextFunction implements NamedJavaFunction{
تذكر تسجيل الوظيفة من خلال LuaLoader.invoke ، على غرار الأمثلة السابقة
المكالمة في لوا:
habrPlugin.createText("Hello Habr!")
الخلاصة
وبالتالي ، يمكن لتطبيق Android الخاص بك استخدام جميع القدرات الأصلية للمنصة. العيب الوحيد لهذا الحل هو أنك تفقد القدرة على استخدام Corona Simulator ، مما يبطئ التطور (إعادة تشغيل المحاكي شبه فورية ، على عكس تصحيح الأخطاء في محاكي أو جهاز يتطلب بناء + تثبيت)
روابط مفيدة
الرمز الكامل متاح على جيثب
توثيق كورونا الأصلي
3) أحد مستودعات جنلوا . ساعدني على فهم الغرض من بعض الوظائف.