Разработка под Android с использованием Linderdaum Engine

    Привет хабрасообщество!

    Тема написания приложений под андроид на С++ незаслуженно забыта. Сегодня мы узнаем как писать многоплатформенные приложения под Android используя Linderdaum Engine.


    Пост обновлён, чтобы поддержать совместимость с Linderdaum SDK 0.6.08

    1. Настройка билдпроцесса

    Чтобы работать с Linderdaum Engine сначала придётся установить:

    Кроме того, для сборки непосредственно под Android дополнительно понадобятся установленные:

    Устанавливаем всё вышеперечисленное. Linderdaum SDK устанавливаем в папку, в имени которой нет пробелов (иначе будут проблемы с Android NDK). В Linderdaum SDK есть все нужные для сборки библиотеки в скомпилированном виде (лежат в Libs.Win32/Libs.Win64 и BuildAndroid/jni/armeabi-v7a), поэтому достаточно только обновить метаинформацию и билдфайлы. Запускаем из каталока с SDK сначала rebuildLSD.py, а затем makeconfig.py. Всё — теперь можно начинать писать наше первое многоплатформенное приложение.

    2. Наше HelloAndroid приложение

    Чтобы не загружаться деталями движка, а более подробно остановиться на многоплатформенности, рассмотрим вот такое минималистическое 3D приложение, которое мы положим в файл Apps/Test_Android/Src/Test_Android.cpp:

    #include "Linderdaum.h"
    
    sEnvironment* Env = NULL;
    
    LMatrix4              Projection;
    clVirtualTrackball    Trackball;
    clGameCamera*         Camera = NULL;
    clScene*              Scene  = NULL;
    
    void DrawOverlay(LEvent Event, const LEventArgs& Args)
    {
    	// обновим камеру
    	LMatrix4 Trans( Trackball.GetRotationMatrix() * Camera->GetCamera().GetModelViewMatrix() );
    	Scene->SetCameraTransform( Trans );
    	Scene->SetCameraProjection( Projection );
    
    	// отрисуем сцену
    	Scene->SetUseOffscreenBuffer( false, false );
    	Scene->RenderForward();
    
    	// обновим виртуальный трэкбол
    	bool MousePressedL = Env->Console->IsKeyPressed( LK_LBUTTON );
    
    	Env->Viewport->UpdateTrackball( &Trackball, 10.0f, MousePressedL );
    }
    
    void Update( LEvent Event, const LEventArgs& Args )
    {
    	// в Args.FFloatArg хранится DeltaTime в миллисекундах
    }
    
    APPLICATION_ENTRY_POINT
    {
    	LString CommandLine;
    
    	EXTRACT_COMMAND_LINE(CommandLine);
    
    	Env = new sEnvironment();
    
    	// CommonMedia используется только на PC, на Андроиде она будет хитро упакована в ресурсы
    	Env->DeployDefaultEnvironment( CommandLine, "..\\..\\CommonMedia" );
    	Env->FileSystem->Mount("GameData");
    
    	Projection = Math::Perspective( 45.0f, Env->Viewport->GetAspectRatio(), 0.4f, 2000.0f );
    
    	// создадим камеру и подпишем её на события
    	Camera = Env->Linker->Instantiate( "clGameCamera" );
    	Camera->GetCamera().SetPosition( LVector3(0,-10,10) );
    	CONNECTOBJ( L_EVENT_TIMER, &clGameCamera::Event_TIMER, Camera );
    
    	Env->Connect( L_EVENT_DRAWOVERLAY, Utils::Bind( &DrawOverlay ) );
    	Env->Connect( L_EVENT_TIMER,       Utils::Bind( &Update      ) );
    
    	// создадим сцену
    	Scene = Env->Linker->Instantiate("clScene");
    
    	// и добавим в неё меш
    	int ID = Scene->AddGeom( Env->Resources->CreateIcosahedron( 3.0f, LVector3(0) ) );
    
    	// установим ему материал
    	clMaterial* Mtl = Env->Resources->CreateMaterial();
    	Mtl->SetPropertyValue( "DiffuseColor", "1.0 0.0 0.0 0" );
    	Mtl->SetPropertyValue( "CastShadow",   "false" );
    	Scene->SetMtl( ID, Mtl );
    
    	// установим положение
    	Scene->SetLocalTransform( ID, LMatrix4::GetTranslateMatrix( LVector3(  0.0f, 0.0f, 0.0f ) ) );
    
    	Env->RunApplication( DEFAULT_CONSOLE_AUTOEXEC );
    
    	APPLICATION_EXIT_POINT( Env );
    }
    
    APPLICATION_SHUTDOWN
    {
    }
    


    Как не трудно понять, этот код должен вывести красный икосаэдр в центре экрана с возможность вращать его мышью. И, как мы хотим, должен это делать без изменений на андроидном девайсе и на PC под Windows. Сказано — сделано.

    3. Сборка под Windows

    Воспользуемся билдсистемой Linderdaum'а и автосгенерим все билд файлы. Создаём пустые файлы Apps/Test_Android/makeconfig.py и Apps/Test_Android/jni/Android.mk — они будут автосгенерены (второй нам потребуется чуть позже, поэтому заодно создадим и его). Переходим в корень движка и оттуда запускаем Solution/regenerateconfigs.py. Потом запускаем makeconfig.py. Вуаля — файлы .vcproj/.vcxproj для студии и мэйкфайл для gcc готовы.

    Загружаем LinderdaumSDK_VS2008.sln (либо LinderdaumSDK_VS2010.sln) и добавляем к солюшено проект Apps/Test_Android, не забыв выставить ему Dependency на Linderdaum Engine.

    Нажимаем F5 — появляется окно с красным икосаэдром (см. скриншот внизу страницы).

    P.S. Тем кто хочет использовать gcc под Windows достаточно после генерации мейкфайлов запустить build.py и немного подождать.

    4. Сборка движка под Android

    Теперь, когда путь Windows освоен, мы готовы приступить к сборке приложения под Андроид. Это очень легко, но потребует настройки наших тулзов:

    • переменная окружения JAVA_HOME должна ссылаться на папку с JDK (на Ubuntu с OpenJDK это обычно /usr/lib/kvm/default-java);
    • переменная окружения NDK_ROOT должна ссылаться на папку с Android NDK;
    • в файле Apps/Test_Android/local.properties нужно указать, чтобы параметр 'sdk.dir=' указывал на папку с Android SDK.


    Нужно собрать движок под андроид (в комплекте с SDK уже идёт libLinderdaumEngineCore.a, поэтому ручная пересборка нужна только если вы хотите самостоятельно поковыряться в движке). Запускаем Cygwin Bash Shell, переходим в папку BuildAndroid и говорим ndk-build -j4. Немного ждём… В результате должен появиться libLinderdaumEngineCore.a размером чуть больше 100 Мб.

    5. Сборка проекта под Android

    Для сборки нашего минипроекта под Android подребуется ещё несколько файлов в Apps/Test_Android. Вот что в них нужно написать:

    ant.properties
    android.library.reference.1=..\\\\..\\\\BuildAndroid


    project.properties
    target=android-13


    local.properties
    sdk.dir=<здесь путь к вашему Android SDK, например D:\\android-sdk-windows>


    res\values\strings.xml
    <?xml version="1.0" encoding="utf-8"?>
      <resources>
          <string name="app_name">Test_Android</string>
      </resources>
    


    jni\Application.mk
    APP_OPTIM := release
    APP_PLATFORM := android-7
    APP_STL := gnustl_static
    APP_CPPFLAGS += -frtti
    APP_CPPFLAGS += -fexceptions
    APP_CPPFLAGS += -DANDROID
    APP_ABI := armeabi-v7a


    Для использования тулзов из Android SDK нам потребуется манифест AndroidManifest.xml. Например, вот такой:

    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
          package="com.linderdaum.engine.myfirstandroidapp"
          android:versionCode="1"
          android:versionName="0.6.00"
          android:installLocation="auto">
        <!--require Android 2.1 and higher-->
        <uses-sdk android:minSdkVersion="7" />
        <uses-sdk android:targetSdkVersion="9" />
    	<supports-screens
            android:smallScreens="true"
            android:normalScreens="true"
            android:largeScreens="true"
            android:anyDensity="true" />
        <uses-feature android:glEsVersion="0x00020000"/>
        <uses-feature android:name="android.hardware.telephony" android:required="false" />
        <uses-permission android:name="android.permission.INTERNET"/>
        <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
        <application android:label="@string/app_name"
                     android:installLocation="preferExternal"
                     android:debuggable="false">
            <activity android:name="com.linderdaum.engine.LinderdaumEngineActivity"
                      android:launchMode="singleTask"
                      android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
                      android:screenOrientation="landscape"
                      android:configChanges="orientation|keyboardHidden"
                      android:label="@string/app_name">
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />
                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
            </activity>
        </application>
    </manifest>
    


    В будущем не забываем менять строку package=«com.linderdaum.engine.myfirstandroidapp» в разных приложениях.

    После того, как мы перейдём в Apps\Test_Android и запустим ndk-build из Сygwin'a, должно появиться следующее:

    $ ndk-build
    Compile++ thumb  : LinderdaumEngine <= LAndroid.cpp
    Compile thumb  : LinderdaumEngine <= LJNI.c
    Compile++ thumb  : LinderdaumEngine <= Test_Android.cpp
    Prebuilt       : libLinderdaumEngineCore.a <= jni/../../../BuildAndroid/obj/local/armeabi-v7a/
    Prebuilt       : libFreeImage.a <= jni/../../../BuildAndroid/jni/armeabi-v7a/
    Prebuilt       : libFreeType.a <= jni/../../../BuildAndroid/jni/armeabi-v7a/
    Prebuilt       : libVorbis.a <= jni/../../../BuildAndroid/jni/armeabi-v7a/
    Prebuilt       : libOGG.a <= jni/../../../BuildAndroid/jni/armeabi-v7a/
    Prebuilt       : libOpenAL.a <= jni/../../../BuildAndroid/jni/armeabi-v7a/
    Prebuilt       : libModPlug.a <= jni/../../../BuildAndroid/jni/armeabi-v7a/
    Prebuilt       : libstdc++.a <= <NDK>/sources/cxx-stl/gnu-libstdc++/libs/armeabi-v7a/
    SharedLibrary  : libLinderdaumEngine.so
    Install        : libLinderdaumEngine.so => libs/armeabi-v7a/libLinderdaumEngine.so
    


    Мы закончали с C++ частью нашего проекта. Осталось добить Java и собрать дистрибутив в .apk. Для этого нам потребуется вот такой build.xml:

    <?xml version="1.0" encoding="UTF-8"?>
    <project name="Asteroids" default="help">
    
        <import file="../../BuildAndroid/CommonMedia.xml"/>
    
        <property file="local.properties" />
    
        <property file="ant.properties" />
    
        <loadproperties srcFile="project.properties" />
    
        <fail
                message="sdk.dir is missing. Make sure to generate local.properties using 'android update project' or to inject it through an env var"
                unless="sdk.dir"
        />
    
        <target name="copy-game-data">
    	<!-- Game data -->
            <delete dir="assets"/>
            <copy todir="assets/Data">
                <fileset dir="GameData">
                </fileset>
            </copy>
            <copy todir="assets/Data">
                <fileset dir="Data">
                </fileset>
            </copy>
        </target>
    
        <import file="${sdk.dir}/tools/ant/build.xml" />
    </project>
    


    Запускаем ant copy-common-media debug и получаем готовый дистрибутив в Apps\Test_Android\bin\Test_Android-debug.apk. Его можно установить на девайс командой:

    adb install Test_Android-debug.apk

    и запустить приложение. Должно появиться вот такое:

    image

    Сразу отвечаю на некоторые предполагаемые вопросы:

    1. Есть ли возможность создавать приложения под Windows, именно под настольную версию? MacOS?
    Можно создавать приложения под Windows XP/Vista/7, как под 32-х так и под 64-битные версии. Причём приложение не потребует никаких изменений игрового кода при сборке под Android, всё будет работать — и графика, и звук, и всё остальное. Версии движка под MacOS пока нет.
    2. Есть/будет/когда поддержка WP7?
    На данный момент нет. О поддержке WP7 можно будет говорить после релиза C++ API для данный платформы от Microsoft'a.
    3. Какая ситуация с Android 2.1/2.2/2.3/3.0 со стороны движка? Различия?
    С++ и Java части движка поддерживают Андроиды начиная от 2.1 и старше. Различия могут быть, если вы захотите писать Java код для игры, который не будет работать с 2.1/2.2.
    4. Для реализации движка на Android используется NDK или код движка написан на Java?
    Движок написан на С++ c обёрткой на Java и использует Android NDK для сборки. С++ код работает под все поддерживаемые платформы.
    5. Насколько хороши «обёртки» над устройствами ввода, мультитач, мгновенный/буферизированный ввод?
    Поддерживается мультитач. Буферизацию и распознавание жестов придётся делать самому.
    6. Для 2D/3D используется только fixed-function или есть возможность использовать шейдеры?
    Движок основан на OpenGL 3 / OpenGL ES 2 и использует только шейдеры. Fixed-function использовать невозможно.
    7. Какие приложения уже написаны на движке?
    market.android.com/details?id=com.linderdaum.engine.puzzL
    market.android.com/details?id=com.linderdaum.engine.multibricks_free
    8. Почему так много букв, чтобы создать приложение?
    В академических целях. Всё вышеперечисленное можно сделать в 5 кликов используя ProjectWizard из Linderdaum SDK.

    Дополнение

    Чтобы быстро сделать Android-приложение ещё быстрее, запускаем Project Wizard, там выбираем:
    • C++ empty project;
    • Project Folder ставим в подкаталог установленного движка (иначе не будет работать Android NDK);
    • нажимаем Next...;
    • отмечаем «Generate Android SDK and NDK configs» и «Add events processing code: Events + Scene»;
    • ставим Resolution: 800x480 (это нужно для PC, на девайсе будет использоваться полное разрешение экрана).

    Другие опции оставляем по-умолчанию и жмём Generate Project. Всё! Не забываем в local.properties прописать путь к своему Android SDK.
    Поделиться публикацией

    Похожие публикации

    Комментарии 18
      +1
      Linderdaum SDK устанавливаем в папку, в имени которой нет пробелов.
      Тоже самое я бы сказал и про Android SDK. Иначе возникают проблемы с запуском эмулятора (хотя раньше все нормально было).
        +1
        и только с латинскими символами
        +1
        Выглядит заманчиво. Вот только интересно почему примеры игр исключительно 2d? проблемы с производительностью в 3d?
          +1
          Вышеуказанный пример рисует вполне трехмерный икосаэдр.
            0
            Это я вижу, такую сцену можно с приличной скоростью и на чистой яве нарисовать. На сате для ПК есть довольно много серьезных 3d примеров, для андроида как обстоят дела с производительностью в 3d? Или хотя бы сравнение в производительности с чистой явой можно где нибудь посмотреть? Хоть что нибудь что бы оправдало использование этого движка помимо его существования?
              0
              Можно писать один и тот же код и под PC, и под Android и он будет работать. Соответственно разрабатывать на PC можно без эмулятора и очень быстро. Это особенно актуально, когда нужно настраивать игровую логику и арт — это заметно упрощает отладку. Разве хотя бы этой причины не достаточно?
                +1
                LibGDX может тоже самое, да и к тому же с меньшим количеством телодвижений и под MacOS и под Linux, если при использовании этого движка нет выйгрыш в скорости то какой тогда смысл?
                  0
                  Всегда думал, что выйгрыш в скорости это только одна из фишек любого движка. Не менее ценна инфраструктура и «количество телодвижений», которыми можно писать проект и пичкать его контентом. Выбор языка тоже играет роль — у кого-то люди на С++ пишут, у кого-то на Java.
            0
            С производительностью проблем нет — скриншот выше с Samsung Galaxy S и сцена выдаёт 58-60 FPS. Над 3D игрой работаем :)
            +1
            Как обстоят дела с поддержкой шрифтов? Русский язык?
              0
              Поддерживается кодировка UTF-8. FreeType 2 под интегрирован и под Андроид, и под винду. Соответственно можно использовать любые TrueType/OpenType шрифты. Ещё есть поддержка растровых шрифтов из текстуры с 256 (16х16) знакоместами.
              –2
              Спасибо)
                +2
                А в чем преимущество перед cocos-2dx? Те и под айфон и под вин и под андроид позволяют писать. Тоже на плюсах.
                За прекрасное пошаговое руководство спасибо!
                  0
                  С cocos-2dx, да и вообще c библиотеками под маки, сравнивать, к сожалению, не приходилось. Поэтому объективно прокомментировать не могу — думаю чем-то лучше, чем-то хуже, как и в любом другом выборе.

                  >За прекрасное пошаговое руководство спасибо!
                  Пожалуйста! Будем рады вопросам по разработке на нашем форуме или на хабре. Жалобы, багрепорты и пожелания тоже велкам!
                    0
                    Cocos2d-x не под маки. Можно из под винды писать
                      0
                      Он же только 2д!
                        +1
                        Это да. Но я не знаю кто из инди разработчиков будет делать 3Д игры. Все-таки объем работ значительно больше, особенно в плане контента, уже надо бы привлекать моделлеров/аниматоров.
                          0
                          Точно подмечено. Но мы работаем над 3Д игрой и выложим её на маркет.

                Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                Самое читаемое