Pull to refresh

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

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

Тема написания приложений под андроид на С++ незаслуженно забыта. Сегодня мы узнаем как писать многоплатформенные приложения под 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.
Tags:androidndkc plus pluslinderdaum
Hubs: Game development
Total votes 28: ↑26 and ↓2 +24
Views9.3K

Popular right now

Android developer
from 130,000 ₽СберЛогистикаRemote job
Android разработчик
from 200,000 ₽KinddaМоскваRemote job
Разработчик Android / С++ (релокация на Кипр)
from 4,000 €MetaQuotes Software Corp.Лимассол
Senior Android developer
to 250,000 ₽Zenia-AIRemote job
Android разработчик (Middle/Senior)
from 140,000 to 230,000 ₽Coding TeamRemote job