[Из песочницы] Кроссплатформенное приложение в Android Studio на jMonkeyEngine 3
jMonkeyEngine (jME) — трёхмерный игровой движок с открытым исходным кодом. Написан на Java и использует по умолчанию LWJGL для рендеринга. Полностью поддерживаются версии OpenGL со второй по четвёртую.Как-то раз упоминался на Хабре в далёком 2010-м году.Помимо характеристик примечателен джавой и не очень примечателен средой разработки NetBeans, которая идёт в комплекте с SDK.
В данной статье хочу рассказать о том, как прикрутить обезьянку к привычной Android Studio.
Создаём новый проект для API не ниже 8 с Blank Activity и в корневой директории проекта создаём папки core и desktop. На языке скриншотов это выглядит как:
Подразумеваем, что core — основной код приложения, а desktop и app — запускатели для десктопа и Андроида соответственно.
В корневом settings.gradle указываем эти директории:
include ': app', ': core', ': desktop' Жмём Sync Now в правом верхнем углу окна. Это нужно будет делать при любой модификации gradle-файлов.В директориях core и desktop создаём файл build.gradle: apply plugin: «java» sourceSets.main.java.srcDirs = [«src/»] В корневой build.gradle добавляем репозиторий jmonkeyengine и минимальный набор библиотек для наших подпроектов: buildscript { repositories { jcenter () } dependencies { classpath 'com.android.tools.build: gradle:1.0.0' } }
allprojects { repositories { jcenter () maven { url 'http://updates.jmonkeyengine.org/maven' } } }
project (»: core») { apply plugin: «java» dependencies { compile 'com.jme3: jme3-core:3.0.+' } }
project (»: desktop») { apply plugin: «java» dependencies { compile project (»: core») compile 'com.jme3: jme3-desktop:3.0.+' compile 'com.jme3: jme3-lwjgl:3.0.+' } }
project (»: app») { apply plugin: «android» dependencies { compile project (»: core») compile 'com.jme3: jme3-android:3.0.+' } } После синхронизации в External Libraries должны появится указанные библиотеки со своими соратниками:
В директориях core и desktop создаём директории src, добавляем в core/src файл Game.java с содержимым из базового примера:
package org.lunapark.dev.jme3example;
import com.jme3.app.SimpleApplication; import com.jme3.material.Material; import com.jme3.math.ColorRGBA; import com.jme3.scene.Geometry; import com.jme3.scene.shape.Box;
public class Game extends SimpleApplication {
@Override public void simpleInitApp () { Box b = new Box (1, 1, 1); Geometry geom = new Geometry («Box», b);
Material mat = new Material (assetManager, «Common/MatDefs/Misc/Unshaded.j3md»); mat.setColor («Color», ColorRGBA.Blue); geom.setMaterial (mat);
rootNode.attachChild (geom); } } Package укажите тот же, что и при создании проекта и вылечите недуги при помощи Alt + Enter и Move to package …:
В desktop/src создаём файл DesktopLauncher.java:
package org.lunapark.dev.jme3example;
public class DesktopLauncher {
public static void main (String[] args) { Game game = new Game (); game.start (); } } Можно запустить DesktopLauncher.java и полюбоваться фантастической трёхмерной моделькой синего кубика. Для запуска на Android заменим код в MainActivity.java на код из примера (обязательно измените значение переменной appClass): package org.lunapark.dev.jme3example;
import android.content.pm.ActivityInfo;
import com.jme3.app.AndroidHarness; import com.jme3.system.android.AndroidConfigChooser;
import java.util.logging.Level; import java.util.logging.LogManager;
public class MainActivity extends AndroidHarness {
public MainActivity () { // Set the application class to run appClass = «org.lunapark.dev.jme3example.Game»;
// Try ConfigType.FASTEST; or ConfigType.LEGACY if you have problems eglConfigType = AndroidConfigChooser.ConfigType.BEST;
// Exit Dialog title & message exitDialogTitle = «Exit?»; exitDialogMessage = «Are you sure you want to quit?»;
// Choose screen orientation screenOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
// Enable MouseEvents being generated from TouchEvents (default = true) mouseEventsEnabled = true;
// Set the default logging level (default=Level.INFO, Level.ALL=All Debug Info)
LogManager.getLogManager ().getLogger (»).setLevel (Level.INFO);
}
}
Дополним AndroidManifest.xml рекомендуемыми параметрами (android: launchMode=«singleTask» и блок «supports-screens»):
Можно запустить app и созерцать кубик уже на телефоне. Если вместо кубика вы созерцаете ClassNotFound Exception и прочее NPE, скорее всего вы забыли поменять переменную appClass в MainActivity.java. Со мной так было.Можно, конечно, в MainActivity.java заменить переменную appClass на
appClass = Game.class.getCanonicalName (); и избавиться от хардкода в переменных для диалога, но какой вы после этого индус, правда? Для использования ресурсов создадим в app директорию assets. Добавим sourceSets { main { assets.srcDirs = ['src/main/assets', 'assets/'] } } в app/build.gradle: apply plugin: 'com.android.application'
android { compileSdkVersion 21 buildToolsVersion »21.1.2»
defaultConfig { applicationId «org.lunapark.dev.jme3example» minSdkVersion 8 targetSdkVersion 21 versionCode 1 versionName »1.0» } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile ('proguard-android.txt'), 'proguard-rules.pro' } } sourceSets { main { assets.srcDirs = ['src/main/assets', 'assets/'] } } }
dependencies { compile fileTree (dir: 'libs', include: ['*.jar']) compile 'com.android.support: appcompat-v7:21.0.3' } Создатели движка рекомендуют такую структуру каталогов:
jMonkeyProjects/MyGame/assets/Interface/ # .font, .jpg, .png, .xml jMonkeyProjects/MyGame/assets/MatDefs/ # .j3md jMonkeyProjects/MyGame/assets/Materials/ # .j3m jMonkeyProjects/MyGame/assets/Models/ # .j3o jMonkeyProjects/MyGame/assets/Scenes/ # .j3o jMonkeyProjects/MyGame/assets/Shaders/ # .j3f, .vert, .frag jMonkeyProjects/MyGame/assets/Sounds/ # .ogg, .wav jMonkeyProjects/MyGame/assets/Textures/ # .jpg, .png; also .mesh.xml+.material, .mtl+.obj, .blend (!) Поддержим товарищей и запихнём для проверки в assets/Textures какую-нибудь небольшую текстуру:
Заменим код в Game.java:
@Override public void simpleInitApp () { Box b = new Box (1, 1, 1); Geometry geom = new Geometry («Box», b);
Material mat = new Material (assetManager, «Common/MatDefs/Misc/Unshaded.j3md»); TextureKey key = new TextureKey («Textures/poster.jpg»); Texture tex = assetManager.loadTexture (key); mat.setTexture («ColorMap», tex); geom.setMaterial (mat);
rootNode.attachChild (geom); } Запуск приложения на андроид-устройстве должен пройти успешно, в то время как при запуске десктоп-версии ЭВМ выругается злым красным AssetNotFoundException.Отправляемся в desktop/build.gradle и объясняем:
apply plugin: «java»
sourceSets.main.java.srcDirs = [«src/»]
dependencies { compile files (»…/app/assets») } По обычаю, синхронизируем и, с высокой долей вероятности, наблюдаем положительный результат.
Если вы не очень хорошо знакомы с jME, то неплохо будет отправиться в раздел Tutorials for Beginners на официальном сайте и пройтись по основам. Или даже скачать сам движок в комплекте с IDE на базе NetBeans, JDK, Блендером и всякими другими полезными штуками.При изучении примеров в корневой build.gradle рекомендую добавить:
project (»: core») { apply plugin: «java» dependencies { compile 'com.jme3: jme3-core:3.0.+'
compile 'com.jme3: jme3-effects:3.0.+' compile 'com.jme3: jme3-networking:3.0.+' compile 'com.jme3: jme3-plugins:3.0.+' compile 'com.jme3: jme3-jogg:3.0.+' compile 'com.jme3: jme3-terrain:3.0.+' compile 'com.jme3: jme3-blender:3.0.+' compile 'com.jme3: jme3-jbullet:3.0.+' compile 'com.jme3: jme3-niftygui:3.0.+'
compile 'net.sf.sociaal: jME3-testdata:3.0.0.20130526' } } Это почти все модули движка плюс ресурсы для примеров (testdata). Полный список модулей на официальном сайте.При разработке под мобильные платформы есть определённые сложности (применение шейдеров, обработка жестов, …), но что-нибудь вполне играбельное можно смастерить если следовать известному крылатому выражению 1899 года. Хотя, наверное, это относится не только к jMonkeyEngine.
Надеюсь, всё это кому-нибудь поможет и никому не навредит.