- PVSM.RU - https://www.pvsm.ru -

Кроссплатформенное приложение в Android Studio на jMonkeyEngine 3

Кроссплатформенное приложение в Android Studio на jMonkeyEngine 3 - 1 jMonkeyEngine (jME) [1] — трёхмерный игровой движок с открытым исходным кодом [2]. Написан на Java и использует по умолчанию LWJGL для рендеринга. Полностью поддерживаются версии OpenGL со второй по четвёртую.
Как-то раз упоминался [3] на Хабре в далёком 2010-м году.

Помимо характеристик [4] примечателен джавой и не очень примечателен средой разработки NetBeans, которая идёт в комплекте с SDK.

В данной статье хочу рассказать о том, как прикрутить обезьянку к привычной Android Studio.

Базовый проект

Создаём новый проект для API не ниже 8 с Blank Activity и в корневой директории проекта создаём папки core и desktop. На языке скриншотов это выглядит как:

Кроссплатформенное приложение в Android Studio на jMonkeyEngine 3 - 2

Подразумеваем, что 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 должны появится указанные библиотеки со своими соратниками:

Кроссплатформенное приложение в Android Studio на jMonkeyEngine 3 - 3

В директориях 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 ...:

Кроссплатформенное приложение в Android Studio на jMonkeyEngine 3 - 4

В 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

Для запуска на 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»):

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="org.lunapark.dev.jme3example">

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme">
        <activity
            android:name=".MainActivity"
            android:launchMode="singleTask"
            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>

    <supports-screens
        android:anyDensity="true"
        android:largeScreens="true"
        android:normalScreens="true"
        android:smallScreens="true" />

</manifest>

Можно запустить 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 какую-нибудь небольшую текстуру:

Кроссплатформенное приложение в Android Studio на jMonkeyEngine 3 - 5

Заменим код в 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")
}

По обычаю, синхронизируем и, с высокой долей вероятности, наблюдаем положительный результат.

Кроссплатформенное приложение в Android Studio на jMonkeyEngine 3 - 6

Что дальше?

Если вы не очень хорошо знакомы с jME, то неплохо будет отправиться в раздел Tutorials for Beginners [5] на официальном сайте и пройтись по основам. Или даже скачать [6] сам движок в комплекте с 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). Полный список модулей на официальном сайте [7].

При разработке под мобильные платформы есть определённые сложности (применение шейдеров, обработка жестов, ...), но что-нибудь вполне играбельное можно смастерить если следовать известному крылатому выражению [8] 1899 года. Хотя, наверное, это относится не только к jMonkeyEngine.

Надеюсь, всё это кому-нибудь поможет и никому не навредит.

Автор: 3h4k

Источник [9]


Сайт-источник PVSM.RU: https://www.pvsm.ru

Путь до страницы источника: https://www.pvsm.ru/java/81130

Ссылки в тексте:

[1] jMonkeyEngine (jME): http://jmonkeyengine.org/

[2] открытым исходным кодом: http://jmonkeyengine.googlecode.com/svn/trunk/engine/

[3] упоминался: http://habrahabr.ru/post/88254/

[4] характеристик: http://wiki.jmonkeyengine.org/doku.php?id=jme3:features

[5] Tutorials for Beginners: http://wiki.jmonkeyengine.org/doku.php/jme3#tutorials_for_beginners

[6] скачать: http://jmonkeyengine.org/?page_id=301327

[7] Полный список модулей на официальном сайте: http://wiki.jmonkeyengine.org/doku.php/jme3:maven

[8] крылатому выражению: https://ru.wikipedia.org/wiki/%D0%9B%D0%B5%D0%BD%D0%B8%D0%BD%D1%81%D0%BA%D0%B8%D0%B5_%D1%84%D1%80%D0%B0%D0%B7%D1%8B#.C2.AB.D0.A3.D1.87.D0.B8.D1.82.D1.8C.D1.81.D1.8F.2C_.D1.83.D1.87.D0.B8.D1.82.D1.8C.D1.81.D1.8F_.D0.B8_.D1.83.D1.87.D0.B8.D1.82.D1.8C.D1.81.D1.8F.C2.BB

[9] Источник: http://habrahabr.ru/post/249305/