Докуметация Cтарт Статьи Форум Лента Вход
Не официальное русскоязычное сообщество
Главная
    Создание плагина библиотеки расширений
        Создание плагина библиотеки расширений

Andry

Опубликованно: AndryAndry17.10.2017, 7:51
Последняя редакция, Andry: 17.10.2017 7:51

На этой странице описывается, как вы можете обернуть любую библиотеку jar в плагин, который пользователь jMonkeyEngine SDK может загрузить, установить, а затем использовать содержащуюся библиотеку в своих собственных игровых проектах.

Убедитесь, что ваш SDK настроен для разработки плагинов, как описано здесь.

Создание проекта плагина (в jMonkeyEngine SDK):

  • Create a new Module Suite (or use an existing one)
  • Open the suite, right-click the “Modules folder and select “Add new..
  • For “Project Name enter an all-lowercase name without spaces like my-library
  • Make sure the “Project Location is inside the module suite folder and press “Next
  • Enter the base java package for your plugin in “Code Name Base like com.mycompany.plugins.mylibrary
  • Enter a “Module Display Name for your plugin like “My Library
  • Press Finish

Добавление библиотеки:

  • Right click the Module Project and select “New→Other
  • Under “Module Development select the “Java SE Library Descriptor template and press “Next
  • If you dont have the external library registered in the jMonkeyEngine SDK yet, click “Manage Libraries and do the following:
    • Click “New Library, enter a name for the library and press OK
    • In the “Classpath tab, press “Add JAR/Folder and select the jar file(s) needed for the library
    • In the “JavaDoc tab, press “Add ZIP/Folder and add the javadoc for the library (zipped or folder)
    • In the “Sources tab you can add a folder or jar file containing the source files of the library if available
    • Press OK
  • Select the external library from the list and press “Next
  • Enter a name for the Library (used as filename for the description file)
  • Enter a display name for the Library (This is the name the user later sees in his library list)
  • Press OK

Вы увидите новый файл «MyLibrary.xml» создается в базовом пакете плагинов и связан с файлом layer.xml. Кроме того, файл jar и sources / javadoc копируются в папку выпуска в корне проекта. Это в основном это, вы можете настроить номер версии, файл лицензии (должен быть помещен в корневую папку модуля) и многое другое через Свойства модуля.

Обратите внимание, что файлы в папке выпуска не обновляются автоматически при изменении библиотеки, вам необходимо вручную упаковать и заменить файлы jar и zip. См. Расширение скрипта сборки в приведенной ниже ссылке о том, как вы можете сделать скрипт сборки модуля автоматически.

После того, как вы закончите, вы можете внести плагин в центр обновления вклада jMonkeyEngine SDK.


Переведено для jmonkeyengine.ru, оригинал
Автор перевода: Andry

SDK сильно использует системы, обеспечиваемые базовой платформой для обработки активов и проектов, и расширяет систему с помощью специальных функций jME3.

ProjectAssetManager

Все объекты AssetDataObjects и SceneExplorerNodes позволяют получить доступ к ProjectAssetManager проекта, из которого они были загружены.

ProjectAssetManager pm = node.getLookup().lookup(ProjectAssetManager.class)

ProjectAssetManager в основном является обычным DesktopAssetManager для каждого проекта с добавленной функциональностью:

  • Доступ к файлу FileObject в папке с ресурсами проекта для загрузки и сохранения данных
  • Преобразование абсолютных путей файлов в пути относительных активов и наоборот
  • Получите списки всех текстур, материалов и т. Д. В проекте
  • более удобный материал .. :)

AssetDataObject

Большинство «файлов, с которыми вы сталкиваетесь в SDK, поступают в виде объектов AssetDataObjects. Все узлы, с которыми вы сталкиваетесь, содержат объект AssetDataObject, из которого они были загружены. Он обеспечивает не только доступ к FileObject конкретного файла, но и объект AssetData, который позволяет получить доступ к конкретным свойствам и данным jME. Объект AssetData также позволяет загружать объект через jME3 assetManager. Он доступен через поиск узла или объекта AssetDataObject:

assetDataObject.getLookup().lookup(AssetData.class)

Новые типы файлов Asset

Когда вы добавляете новый тип файла для формата модели или другого файла активов, который может быть загружен в jME3, вы можете начать с использования нового шаблона типа файла (Новый файл → Разработка модуля → Тип файла). Измените объект DataObject, чтобы расширить AssetDataObject (общий), SpatialAssetDataObject (некоторый тип модели) или BinaryModelDataObject (в основном файл j3o savable). И, возможно, переопределите методы loadAsset и saveAsset, которые используются объектом AssetData, чтобы вернуть правильный тип AssetKey (необходимый для работы импорта).

public class BlenderDataObject extends SpatialAssetDataObject {
    public BlenderDataObject(FileObject pf, MultiFileLoader loader) throws DataObjectExistsException, IOException {
        super(pf, loader);
    }
}

Класс AssetManagerConfigurator может быть создан, чтобы настроить assetManager проектов и импортера модели для использования нового типа актива:

@org.openide.util.lookup.ServiceProvider(service = AssetManagerConfigurator.class)
public class BlenderAssetManagerConfigurator implements AssetManagerConfigurator {
    public void prepareManager(AssetManager manager) {
        manager.registerLoader(com.jme3.scene.plugins.blender.BlenderModelLoader.class, "blend");
    }
}

Переведено для jmonkeyengine.ru, оригинал
Автор перевода: Andry

Добавление типов узлов в SceneExplorer

Если ваш плагин имеет свои собственные объекты SceneGraph, вы все равно можете работать как любой другой элемент SceneExplorer, включая его специальные свойства.

Если вы хотите поддерживать специальные свойства ваших объектов, которые не открываются SDK автоматически, вам придется создать свой собственный класс, который расширяет org.openide.nodes.Node и реализует интерфейс com.jme3.gde.core.sceneexplorer. nodes.AbstractSceneExplorerNode. Затем вы регистрируете этот класс, добавляя

@org.openide.util.lookup.ServiceProvider(service=SceneExplorerNode.class)

над телом вашего класса. То есть, ваш Spatial-тип будет автоматически использоваться и отображаться в SceneExplorer. Убедитесь, что вы зарегистрировали jar с используемыми классами в настройках плагина под «обернутыми библиотеками», иначе среда IDE не сможет получить доступ к этим классам.

AbstractSceneExplorerNode предлагает некоторые другие полезные функции, которые вы можете включить, например, автоматическое создание корректно заданных свойств и т. Д. JmeSpatial, например, основывается на нем. Простой пример SceneExplorerNode для объекта, расширяющего пространственный диапазон, будет JmeGeometry (см. Ниже). Редакторы для специальных типов переменных могут быть добавлены с помощью интерфейса SceneExplorerPropertyEditor, который также может быть зарегистрирован как ServiceProvider.

SceneExplorerNode может использоваться для объектов типа Spatial и Control.

  • Добавьте в свой проект API-интерфейсы Nodes API и API Lookup, если вы хотите использовать этот

Пример Spatial

@org.openide.util.lookup.ServiceProvider(service=SceneExplorerNode.class)
public class JmeGeometry extends JmeSpatial {

    private static Image smallImage =
            ImageUtilities.loadImage("com/jme3/gde/core/sceneexplorer/nodes/icons/geometry.gif");
    private Geometry geom;

    public JmeGeometry() {
    }

    public JmeGeometry(Geometry spatial, SceneExplorerChildren children) {
        super(spatial, children);
        getLookupContents().add(spatial);
        this.geom = spatial;
        setName(spatial.getName());
    }

    @Override
    public Image getIcon(int type) {
        return smallImage;
    }

    @Override
    public Image getOpenedIcon(int type) {
        return smallImage;
    }

    @Override
    protected Sheet createSheet() {
        Sheet sheet = super.createSheet();
        Sheet.Set set = Sheet.createPropertiesSet();
        set.setDisplayName("Geometry");
        set.setName(Geometry.class.getName());
        Geometry obj = geom;//getLookup().lookup(Geometry.class);
        if (obj == null) {
            return sheet;
        }

        set.put(makeProperty(obj, int.class, "getLodLevel", "setLodLevel", "Lod Level"));
        set.put(makeProperty(obj, Material.class, "getMaterial", "setMaterial", "Material"));
        set.put(makeProperty(obj, Mesh.class, "getMesh", "Mesh"));

        sheet.put(set);
        return sheet;

    }

    public Class getExplorerObjectClass() {
        return Geometry.class;
    }

    public Class getExplorerNodeClass() {
        return JmeGeometry.class;
    }

    public org.openide.nodes.Node[] createNodes(Object key, Object key2, boolean readOnly) {
        SceneExplorerChildren children=new SceneExplorerChildren((com.jme3.scene.Spatial)key);
        children.setReadOnly(readOnly);
        return new org.openide.nodes.Node[]{new JmeGeometry((Geometry) key, children).setReadOnly(readOnly)};
    }
}

Пример Control

@org.openide.util.lookup.ServiceProvider(service=SceneExplorerNode.class)
public class JmeGhostControl extends AbstractSceneExplorerNode {

    private static Image smallImage =
            ImageUtilities.loadImage("com/jme3/gde/core/sceneexplorer/nodes/icons/ghostcontrol.gif");
    private GhostControl control;

    public JmeGhostControl() {
    }

    public JmeGhostControl(GhostControl control, DataObject dataObject) {
        super(dataObject);
        getLookupContents().add(this);
        getLookupContents().add(control);
        this.control = control;
        setName("GhostControl");
    }

    @Override
    public Image getIcon(int type) {
        return smallImage;
    }

    @Override
    public Image getOpenedIcon(int type) {
        return smallImage;
    }

    protected SystemAction[] createActions() {
        return new SystemAction[]{
                    //                    SystemAction.get(CopyAction.class),
                    //                    SystemAction.get(CutAction.class),
                    //                    SystemAction.get(PasteAction.class),
                    SystemAction.get(DeleteAction.class)
                };
    }

    @Override
    public boolean canDestroy() {
        return !readOnly;
    }

    @Override
    public void destroy() throws IOException {
        super.destroy();
        final Spatial spat=getParentNode().getLookup().lookup(Spatial.class);
        try {
            SceneApplication.getApplication().enqueue(new Callable<Void>() {

                public Void call() throws Exception {
                    spat.removeControl(control);
                    return null;
                }
            }).get();
            ((AbstractSceneExplorerNode)getParentNode()).refresh(true);
        } catch (InterruptedException ex) {
            Exceptions.printStackTrace(ex);
        } catch (ExecutionException ex) {
            Exceptions.printStackTrace(ex);
        }
    }

    @Override
    protected Sheet createSheet() {
        Sheet sheet = super.createSheet();
        Sheet.Set set = Sheet.createPropertiesSet();
        set.setDisplayName("GhostControl");
        set.setName(GhostControl.class.getName());
        GhostControl obj = control;//getLookup().lookup(Spatial.class);
        if (obj == null) {
            return sheet;
        }

        set.put(makeProperty(obj, Vector3f.class, "getPhysicsLocation", "setPhysicsLocation", "Physics Location"));
        set.put(makeProperty(obj, Quaternion.class, "getPhysicsRotation", "setPhysicsRotation", "Physics Rotation"));

        set.put(makeProperty(obj, CollisionShape.class, "getCollisionShape", "setCollisionShape", "Collision Shape"));
        set.put(makeProperty(obj, int.class, "getCollisionGroup", "setCollisionGroup", "Collision Group"));
        set.put(makeProperty(obj, int.class, "getCollideWithGroups", "setCollideWithGroups", "Collide With Groups"));

        sheet.put(set);
        return sheet;

    }

    public Class getExplorerObjectClass() {
        return GhostControl.class;
    }

    public Class getExplorerNodeClass() {
        return JmeGhostControl.class;
    }

    public org.openide.nodes.Node[] createNodes(Object key, DataObject key2, boolean cookie) {
        return new org.openide.nodes.Node[]{new JmeGhostControl((GhostControl) key, key2).setReadOnly(cookie)};
    }
}

Добавление элементов в меню добавления и инструментов

Чтобы добавить Spatials, Contols и для общих инструментов, вы можете создавать абстрактные классы, которые вы можете использовать для расширения опций. Отменить / Повторить обрабатывается абстрактным классом. AbstractNewSpatial * Wizard * Action позволяет показать мастер AWT перед созданием пространственного. Вы также можете просто реализовать базовый класс ServiceProvider и вернуть любые действия (например, мастер), в этом случае вам придется обрабатывать потоки самостоятельно!

Обратите внимание, что создаваемые вами классы — это синглтоны, которые используются на нескольких узлах, и вы не должны хранить данные в локальных переменных!

Чтобы добавить новый инструмент, создайте новый AbstractToolAction:

@org.openide.util.lookup.ServiceProvider(service = ToolAction.class)
public class GenerateTangentsTool extends AbstractToolAction {

    public GenerateTangentsTool() {
        name = "Generate Tangents";
    }

    @Override
    protected Object doApplyTool(AbstractSceneExplorerNode rootNode) {
        Geometry geom = rootNode.getLookup().lookup(Geometry.class);
        Mesh mesh = geom.getMesh();
        if (mesh != null) {
            TangentBinormalGenerator.generate(mesh);
        }
        return geom;
    }

    @Override
    protected void doUndoTool(AbstractSceneExplorerNode rootNode, Object undoObject) {
        Geometry geom = rootNode.getLookup().lookup(Geometry.class);
        Mesh mesh = geom.getMesh();
        if (mesh != null) {
            mesh.clearBuffer(Type.Tangent);
        }
    }

    public Class<?> getNodeClass() {
        return JmeGeometry.class;
    }

}

Для нового Spatial или Control используйте AbstractNewSpatialAction

@org.openide.util.lookup.ServiceProvider(service = NewSpatialAction.class)
public class NewSpecialSpatialAction extends AbstractNewSpatialAction {

    public NewSpecialSpatialAction() {
        name = "Spatial";
    }

    @Override
    protected Spatial doCreateSpatial(Node parent) {
        Spatial spatial=new Node();
        return spatial;
    }
}

или AbstractNewControlAction:

@org.openide.util.lookup.ServiceProvider(service = NewControlAction.class)
public class NewRigidBodyAction extends AbstractNewControlAction {

    public NewRigidBodyAction() {
        name = "Static RigidBody";
    }

    @Override
    protected Control doCreateControl(Spatial spatial) {
        RigidBodyControl control = spatial.getControl(RigidBodyControl.class);
        if (control != null) {
            spatial.removeControl(control);
        }
        Node parent = spatial.getParent();
        spatial.removeFromParent();
        control = new RigidBodyControl(0);
        if (parent != null) {
            parent.attachChild(spatial);
        }
        return control;
    }
}

Добавление с помощью мастера

Вы можете создать новый мастер с помощью шаблона мастера в SDK (New File → Module Development → Wizard). Действие, созданное шаблоном, может быть легко изменено на одно для добавления Control или Spatial или для применения инструмента. Обратите внимание, что мы расширяем действие AbstractNewSpatial * Wizard *.

Хорошим примером является «Добавить SkyBox Wizard:

@org.openide.util.lookup.ServiceProvider(service = NewSpatialAction.class)
public class AddSkyboxAction extends AbstractNewSpatialWizardAction {

    private WizardDescriptor.Panel[] panels;

    public AddSkyboxAction() {
        name = "Skybox..";
    }

    @Override
    protected Object showWizard(org.openide.nodes.Node node) {
        WizardDescriptor wizardDescriptor = new WizardDescriptor(getPanels());
        wizardDescriptor.setTitleFormat(new MessageFormat("{0}"));
        wizardDescriptor.setTitle("Skybox Wizard");
        Dialog dialog = DialogDisplayer.getDefault().createDialog(wizardDescriptor);
        dialog.setVisible(true);
        dialog.toFront();
        boolean cancelled = wizardDescriptor.getValue() != WizardDescriptor.FINISH_OPTION;
        if (!cancelled) {
            return wizardDescriptor;
        }
        return null;
    }

    @Override
    protected Spatial doCreateSpatial(Node parent, Object properties) {
        if (properties != null) {
            return generateSkybox((WizardDescriptor) properties);
        }
        return null;
    }

    private Spatial generateSkybox(WizardDescriptor wiz) {
        if ((Boolean) wiz.getProperty("multipleTextures")) {
            Texture south = (Texture) wiz.getProperty("textureSouth");
            Texture north = (Texture) wiz.getProperty("textureNorth");
            Texture east = (Texture) wiz.getProperty("textureEast");
            Texture west = (Texture) wiz.getProperty("textureWest");
            Texture top = (Texture) wiz.getProperty("textureTop");
            Texture bottom = (Texture) wiz.getProperty("textureBottom");
            Vector3f normalScale = (Vector3f) wiz.getProperty("normalScale");
            return SkyFactory.createSky(pm, west, east, north, south, top, bottom, normalScale);
        } else {
            Texture textureSingle = (Texture) wiz.getProperty("textureSingle");
            Vector3f normalScale = (Vector3f) wiz.getProperty("normalScale");
            boolean useSpheremap = (Boolean) wiz.getProperty("useSpheremap");
            return SkyFactory.createSky(pm, textureSingle, normalScale, useSpheremap);
        }
    }

    /**
     * Initialize panels representing individual wizard's steps and sets
     * various properties for them influencing wizard appearance.
     */
    private WizardDescriptor.Panel[] getPanels() {
        if (panels == null) {
            panels = new WizardDescriptor.Panel[]{
                        new SkyboxWizardPanel1(),
                        new SkyboxWizardPanel2()
                    };
            String[] steps = new String[panels.length];
            for (int i = 0; i < panels.length; i++) {
                Component c = panels[i].getComponent();
                // Default step name to component name of panel. Mainly useful
                // for getting the name of the target chooser to appear in the
                // list of steps.
                steps[i] = c.getName();
                if (c instanceof JComponent) { // assume Swing components
                    JComponent jc = (JComponent) c;
                    // Sets step number of a component
                    // TODO if using org.openide.dialogs >= 7.8, can use WizardDescriptor.PROP_*:
                    jc.putClientProperty("WizardPanel_contentSelectedIndex", new Integer(i));
                    // Sets steps names for a panel
                    jc.putClientProperty("WizardPanel_contentData", steps);
                    // Turn on subtitle creation on each step
                    jc.putClientProperty("WizardPanel_autoWizardStyle", Boolean.TRUE);
                    // Show steps on the left side with the image on the background
                    jc.putClientProperty("WizardPanel_contentDisplayed", Boolean.TRUE);
                    // Turn on numbering of all steps
                    jc.putClientProperty("WizardPanel_contentNumbered", Boolean.TRUE);
                }
            }
        }
        return panels;
    }
}
Абстрактные пространственные и управляющие действия реализуют отмену / повтор автоматически, для инструментальных средств, которые вы должны реализовать самостоятельно.

Переведено для jmonkeyengine.ru, оригинал
Автор перевода: Andry

Чтобы уменьшить системные издержки, jMonkeyEngine SDK Core поставляет одно приложение scene / jme3, которое используется совместно с плагинами. Кроме того, есть «SceneExplorer», который показывает визуальное представление сценграфа и его свойств объектов в плагинах.

Как получить доступ к Сцене

Существует несколько способов взаимодействия вашего плагина со сценой:

  • Он прослушивает выбранные объекты / объекты и предлагает варианты для этих
  • Он запрашивает всю сцену для себя и загружает / упорядочивает содержимое в ней (например, редактор ландшафта или плагин анимации модели).

Прослушивание выбора узла

В SDK jMonkeyEngine все объекты завернуты в узлы NetBeans «Nodes» (иначе, чем jme Nodes!). Такие узлы могут иметь свойства и значки и могут отображаться и выбираться в пользовательском интерфейсе jMonkeyEngine SDK. SceneExplorer показывает дерево узлов, которые обертывают Пространства текущей сцены и позволяют управлять их свойствами при выборе. Например, «JME» Spatial обернут узлом JmeSpatial. Одним из преимуществ этих узлов является то, что можно манипулировать свойствами Spatials непосредственно из потока AWT.

Чтобы прослушать текущий выбор, выполните org.openide.util.LookupListener и зарегистрируйтесь следующим образом:

private final Result<JmeSpatial> result;

//method to register the listener;
private void registerListener(){
    result = Utilities.actionsGlobalContext().lookupResult(JmeSpatial.class);
    result.addLookupListener(this);
}

//implements org.openide.util.LookupListener (called from AWT thread)
public void resultChanged(LookupEvent ev) {
    Collection<JmeSpatial> items = (Collection<JmeSpatial>) result.allInstances();
    for (JmeSpatial jmeSpatial : items) {
        //Using the JmeSpatials properties you can modify the spatial directly from the AWT thread:
        jmeSpatial.getPropertySets()[0].setValue("Local Translation", Vector3f.ZERO);
        return;
    }
}

Вы также можете получить доступ к «реальному пространству», но со своей части сценграфа вам придется изменить его в этом потоке:

//retrieve the "real" spatial class from the JmeNode
for (JmeSpatial jmeSpatial : items) {
    //the spatial is stored inside the JmeSpatials "Lookup", a general container for Objects
    final Spatial realSpatial = jmeSpatial.getLookup().lookup(Spatial.class);
    //use a Callable to execute on the render thread:
    SceneApplication.getApplication().enqueue(new Callable() {
        public Object call() throws Exception {
            realSpatial.setLocalTranslation(Vector3f.ZERO);
            return null;
        }
    });
    return;
}

Запрос сцены

Если ваш плагин хочет использовать сцену сам по себе, сначала нужно реализовать SceneListener и зарегистрироваться на сцене, а затем отправить SceneRequest в SceneApplication. Когда SceneRequest одобрен и текущая сцена закрыта, SceneListener (ваш класс) вызывается со своим собственным SceneRequest в качестве параметра. Когда другой плагин отправляет SceneRequest, вам также сообщается, и ваш намек на то, что ваш RootNode был удален из сцены, и вы больше не контролируете его. Вы также можете подключиться к SceneRequests других плагинов, чтобы узнать, активированы ли они / когда они активированы для отображения дополнительных плагинов для этого плагина.

Объект SceneRequest должен содержать несколько вещей. То, что вы должны поставить, — это jme «Node, завернутый в« объект JmeNode ». Это ваш rootNode, который вы используете для отображения и создания вашей сцены. Как только вы контролируете сцену, вам придется самостоятельно управлять камерой и т. Д.

com.jme3.scene.Node rootNode = new com.jme3.scene.Node("MyRootNode");

private void registerSceneListener(){
    SceneApplication.getApplication().addSceneListener(this);
}

private void requestScene(){
    //create a jmeNode from the rootNode using the NodeUtility
    JmeNode jmeNode = NodeUtility.createNode(rootNode);
    //create the scene request
    SceneRequest request=new SceneRequest(this, jmeNode, assetManager);
    //request the scene
    SceneApplication.getApplication().openScene(request);
}

//implements SceneListener (called from AWT thread)
public void sceneOpened(SceneRequest request){
    //check if its our request
    if (request.getRequester() == this) {
        //we now own the scene, any operations on the scene have to be done via Callables
    }
}

public void sceneClosed(SceneRequest request) {
    if (request.getRequester() == this) {
        //we have to close the scene,  any operations on the scene have to be done via Callables
    }
}

Поддержка Undo/Redo

jMonkeyEngine SDK имеет глобальную очередь отмены / повтора, которая активирует кнопки отмены / повтора. Чтобы использовать его в своем TopComponent, добавьте следующий метод:

@Override
public UndoRedo getUndoRedo() {
return Lookup.getDefault().lookup(SceneUndoRedoManager.class);
}

Чтобы добавить событие отмены / повтора, которое изменяет объекты в Scenegraph, существует специальная версия AbstractUndoableEdit, которая выполняет вызовы отмены / повтора в потоке сцены. Просто реализуйте этот класс и добавьте его в очередь следующим образом:

Lookup.getDefault().lookup(SceneUndoRedoManager.class).addEdit(this, new AbstractUndoableSceneEdit() {

@Override
public void sceneUndo() {
    //undo stuff in scene here
}

@Override
public void sceneRedo() {
    //redo stuff in scene here
}

@Override
public void awtUndo() {
    //undo stuff on awt thread here (updating of visual nodes etc, called post scene edit)
}

@Override
public void awtRedo() {
    //redo stuff on awt thread here
}
});
Важно, чтобы вы использовали метод addEdit (Object source, UndoableEdit edit);

Переведено для jmonkeyengine.ru, оригинал
Автор перевода: Andry

Физика Bullet не лишена проблем. К сожалению, многие из них находятся вне контроля основной команды jMonkeyEngine и поэтому не могут быть исправлены.

Проблемы с Sweep Test

  1. При использовании ссылки: PhysicsSpace.sweepTest(), убедитесь, что расстояние между преобразованиями не менее 0,4 Вт или больше.
  2. Обратите внимание, что sweep не будет обнаруживать столкновения, если он сделана внутри фигуры столкновения. Он должен находиться на краю фигуры столкновения для обнаружения любых столкновений.

Ghost Control только AABB Столкновения

Как говорит javadoc для PhysicsObjectControl, обнаружение столкновения ghost объектов использует только столкновение AABB (с выравниванием по оси ограничивающего куба), независимо от того, какая фигура столкновения ему назначена.

Обход проблемы: Вместо этого используйте PhysicsSpace.sweepTest() или объекты кинематической физики с помощью слушателя столкновений.

Твёрдые тела проваливаются под землю

Обычно это происходит, если объект наземной физики имеет большие треугольники или состоит из большого BoxCollisionShape.

Обход проблемы:

  • Для сеток с большими треугольниками — Разделите сетку в редакторе модели, например Blender.
  • Для больших кубов — Разделите на меньшие кубы или используйте MeshCollisionShape для местности вместо BoxCollisionShape.

Переведено для jmonkeyengine.ru, оригинал
Автор перевода: Andry

Записываем в процессе, выходите на форум за дополнительной информацией Bullet SoftBody в JME3.1

Что такое мягкое тело?

Как моделируется мягкое тело? (узел, змеевик, грань, пружина и демпфер)

Википедия: Динамика мягкого тела(en)

Начнем

Динамические библиотеки динамиков softbody (.so, .dll …) еще не перекомпилированы для вашей платформы, поэтому вам нужно проверить весь проект из GitHub, а затем собрать проект.

Как :

  1. Проверить проект с GitHub.
  2. Войдите в файл gradle.propeties и задайте строку: buildNativeProjecte = true.
  3. Выполните команду: ./gradlew build
  4. Затем соберите sdk: ant -f ./sdk/ build-zip (или соберите установщик sdk)
  5. Создайте новый проект и убедитесь, что вы используете следующие библиотеки: jme3-bullet-native и jme3-bullet (вместо jme3-jBullet)

Простой пример

public void simpleInitApp() {
    softBodyAppState = new BulletSoftBodyAppState();
    getStateManager().attach(softBodyAppState);

    SoftBodyWorldInfo sbwi = softBodyAppState.getPhysicsSoftSpace().getWorldInfo();
    sbwi.setGravity(Vector3f.UNIT_Y.mult(-0.981f));

    Geometry bunny = new Geometry("b", StandfordBunny.getMesh().deepClone());
    Material matN = new Material(assetManager, "Common/MatDefs/Misc/ShowNormals.j3md");
    bunny.setMaterial(matN);
    rootNode.attachChild(bunny);
    bunny.addControl(new SoftBodyControl(false));

    PhysicsSoftBody soft = bunny.getControl(SoftBodyControl.class);
    soft.generateClusters(8);
    soft.config().setDynamicFrictionCoef(0.8f);
    soft.config().setPoseMatchingCoef(0.2f);

    soft.config().setCollisionsFlags(PhysicsSoftBody.Config.CL_SS + PhysicsSoftBody.Config.CL_RS);

    soft.setPose(false, true);
    soft.setTotalMass(100, true);
    soft.randomizeConstraints();
    softBodyAppState.getPhysicsSoftSpace().add(soft);

    Box floorMesh = new Box(100f, 0.5f, 100f);
    Geometry floor = new Geometry("floor", floorMesh);
    floor.move(0, -5f, 0);
    floor.addControl(new RigidBodyControl(0));
    softBodyAppState.getPhysicsSpace().add(floor);
}

Документация

Мягкая сетка / поверхность(soft mesh / surface)

Кластер?

(генерировать) ограничение на изгиб?

Конфигурация столкновения флаг(config collision flag)?

Канаты(Ropes)

Канат можно создать, создав новый SoftBody на сетке с помощью Mesh.Mode.Lines. Дополнительная информация о создании пользовательских сеток.

Пример

Mesh ropeMesh = new Mesh();
Vector3f[] vertices = {
   new Vector3f(0.00f, 0, 0),
   new Vector3f(0.50f, 0, 0),
   new Vector3f(1.00f, 0, 0),
   new Vector3f(1.50f, 0, 0),
   new Vector3f(2.00f, 0, 0),
   new Vector3f(2.50f, 0, 0),
   new Vector3f(3.00f, 0, 0),
   new Vector3f(3.50f, 0, 0),
   new Vector3f(4.00f, 0, 0)};
int[] indices = {
   0, 1,
   1, 2,
   2, 3,
   3, 4,
   4, 5,
   5, 6,
   6, 7,
   7, 8};
ropeMesh.setBuffer(VertexBuffer.Type.Position, 3, BufferUtils.createFloatBuffer(vertices));
ropeMesh.setBuffer(VertexBuffer.Type.Index, 2, BufferUtils.createIntBuffer(indices));
ropeMesh.setMode(Mesh.Mode.Lines);
ropeMesh.updateBound();

После того, как у вас есть Line Mesh, вы можете сделать следующее:

Geometry t = new Geometry("softRope", ropeMesh);
t.move(0, 5, 0);
t.addControl(new SoftBodyControl(false));

Якоря(Anchors)

Якоря(Anchors) действуют как сварка между SoftBody и RigidBody. Добавление якорей к мягкому телу требует указать узел SoftBody и RigidBody для сварки.

soft.appendAnchor(nodeId, rigid);
Якорь(Anchor) привязывает узел SoftBody (или Vertex(Вершину)) к RigidBody, узел будет прикреплен к RigidBody, даже если между ними есть пространство.
Якоря еще не сериализованы

Пример

Geometry t = new Geometry("softRope", ropeMesh);
Box box = new Box(1f, 1f, 1f);
Geometry b = new Geometry("rigidBox", box);
t.move(0, 5, 0);
b.move(3f, 5, 0);

t.addControl(new SoftBodyControl(false));
soft = t.getControl(SoftBodyControl.class);
soft.setMass(0, 0); // сделать первый узел статичным

b.addControl(new RigidBodyControl(1));
rigid = b.getControl(RigidBodyControl.class);

softBodyAppState.getPhysicsSpace().add(rigid);
softBodyAppState.getPhysicsSoftSpace().add(soft);

soft.appendAnchor(8, rigid); //где 8 последний узлов канаты

Якоря(Anchors) можно удалить, как показано ниже. Обратите внимание, что вы должны поддерживать привязку узла и RigidBody.

soft.removeAnchor(8,rigid);

Суставы(Joints)

Суставы требуют SoftBodies с Кластерами(Clusters) (см. generateClusters(int k)).

Суставы не используют значения pivotA & pivotB (пока)

LinearJoint

public SoftLinearJoint(Vector3f position, PhysicsSoftBody nodeA, PhysicsRigidBody nodeB, Vector3f pivotA, Vector3f pivotB);
public SoftLinearJoint(Vector3f position, PhysicsSoftBody nodeA, PhysicsSoftBody nodeB, Vector3f pivotA, Vector3f pivotB);

AngularJoint

public SoftAngularJoint(Vector3f axis, PhysicsSoftBody nodeA, PhysicsRigidBody nodeB, Vector3f pivotA, Vector3f pivotB);
public SoftAngularJoint(Vector3f axis, PhysicsSoftBody nodeA, PhysicsSoftBody nodeB, Vector3f pivotA, Vector3f pivotB);

Примеры

LinearJoint

Box box = new Box(3f, 1f, 3f);
Geometry b = new Geometry("rigidBox", box);
b.move(0, 5f, 0);
b.addControl(new RigidBodyControl(1));
rigid = b.getControl(RigidBodyControl.class);

Torus torus = new Torus(20, 10, 1f, 1.5f);
Geometry t = new Geometry("softTorus", torus);
t.addControl(new SoftBodyControl(true, false));
soft = t.getControl(SoftBodyControl.class);
soft.generateBendingConstraints(4, soft.material());
soft.generateClusters(4);

softBodyAppState.getPhysicsSpace().add(rigid);
softBodyAppState.getPhysicsSoftSpace().add(soft);

joint = new SoftLinearJoint(Vector3f.UNIT_X, soft, rigid, new Vector3f(0f,2,0f), new Vector3f(0f,-2,0f));
softBodyAppState.getPhysicsSoftSpace().add(joint);

AngularJoint

Box box = new Box(1f, 1f, 1f);
Geometry b = new Geometry("rigidBox", box);
b.move(0, 5f, 0);
b.addControl(new RigidBodyControl(1));
rigid = b.getControl(RigidBodyControl.class);

 Torus torus = new Torus(20, 10, 1f, 1.5f);
Geometry t = new Geometry("softTorus", torus);
t.addControl(new SoftBodyControl(true, false));
soft = t.getControl(SoftBodyControl.class);
soft.generateBendingConstraints(4, soft.material());
soft.generateClusters(4);

softBodyAppState.getPhysicsSpace().add(rigid);
softBodyAppState.getPhysicsSoftSpace().add(soft);

joint = new SoftAngularJoint(Vector3f.UNIT_X, soft, rigid, new Vector3f(0,0,2), new Vector3f(0, 0, 2));
softBodyAppState.getPhysicsSoftSpace().add(joint);

Переведено для jmonkeyengine.ru, оригинал
Автор перевода: Andry

В jMonkeyEngine SDK или NetBeans

Плагины

Убедитесь, что все необходимые плагины установлены и активны:

  • В строке меню выберите Сервис ▸ Подключаемые модули, чтобы открыть диалоговое окно Подключаемые модули.
  • Перейдите на вкладку Доступные подключаемые модули.
  • Отсортируйте список плагинов по категориям.
  • Установите галочку для установки, всем плагинам в категории Developing NetBeans.
  • Нажмите кнопку [Установить] и установите их с помощью мастера.
  • Выберите вкладку Установлены.
  • Активируйте любые неактивные плагины в категории Developing NetBeans.
  • Закройте диалоговое окно Подключаемые модули.

Проверка

  • В строке меню выберите Группа ▸ Git ▸ Клонировать, чтобы открыть диалоговое окно Clone Repository.
  • В URL-адрес репозитория: текстовое поле введите https://github.com/jMonkeyEngine/jmonkeyengine.
  • Очистите текстовые поля Пользователь: и Пароль:.
  • Нажмите кнопку [Далее].
  • Выберите удаленную ветвь, как правило, master и нажмите кнопку [Далее].
  • Нажмите кнопку [Обзор] справа от текстовое поля относящегося к Родительский каталог:, чтобы открыть диалоговое окно Выбор родительского каталога.
  • Выберите пустой или несуществующий каталог (папку), где вы хотите сохранить исходники jMonkeyEngine на своем жестком диске.
  • Нажмите кнопку [Готово].

Проверка проекта может занять некоторое время. Не выполняйте никакие действия до завершения задачи.

Сборка

В командной строке:

  1. cd jmonkeyengine
  2. ./gradlew build

Из SDK:

  • В строке меню выберите Файл ▸ Открыть проект…, чтобы открыть диалоговое окно Открытие проекта.
    • Выделите папку проекта в свободной форме, которую вы использовали для проверки, и нажмите кнопку [Открыть проект].
  • Новый проект в свободной форме с именем jME3-SDK должен появиться в окне Проекты в SDK.
  • Создайте проект свободной формы, щелкнув его [ПК мыши] и выбрав Собрать проект.
  • Подождите, пока задача jME3-SDK (build) не будет завершена. В какой-то момент можно открыть окно веб-браузера.
  • В строке меню выберите Файл ▸ Открыть проект…, чтобы открыть диалоговое окно Открытие проекта.
  • Перейдите в папку проекта в свободной форме, выделите узел sdk и нажмите кнопку [Открытие проекта].
    • В окне Проекты в SDK появится ряд новых проектов.

Сборка основного проекта в свободной форме копируют библиотеки jME3 в sdk, поэтому вы должны запускать скрипт сборки каждый раз, когда изменяется jME3.

Запуск

  • В окне Проекты в SDK щелкните [ПК мыши] проект jMonkeyEngine SDK и выберите Выполнение.
      SDK, который вы только что создали, начнет работать в новом окне.

Переведено для jmonkeyengine.ru, оригинал
Автор перевода: Andry

Для наиболее распространенных расширений, таких как Windows, типы файлов, библиотеки и т. Д. Существуют шаблоны, которые вы можете добавить в свой плагин.

  1. Щелкните правой кнопкой мыши проект модуля и выберите «Создать» → «Другое».
  2. Выберите «Модуль разработки слева»

Вы увидите список компонентов, которые вы можете добавить в свой проект. Мастер поможет вам в создании компонента.


Переведено для jmonkeyengine.ru, оригинал
Автор перевода: Andry

Обратите внимание, что создание Модульного Пакета необходимо только в том случае, если вы хотите загрузить плагин в центр обновления вкладов.

Использование jMonkeyEngine SDK для разработки

  1. Установите Разработки подключаемых модулей NetBeans и NetBeans API Documentation с помощью Сервис ▸ Подключаемые модули
  2. Создадим новый проект Модуль (можете любое название, это будет ваша локальная коллекция создаваемых вами плагинов)
  3. Если ни одна платформа не указана, добавьте ее, выбрав папку приложения SDK
    • Пользователям Mac необходимо щелкнуть [ПК мыши] jmonkeyplatform application и выбрать «show contents», а затем выбрать папку jmonkeyplatform в разделе Contents/Resources/
  4. Откройте пакет, щелкните [ПК мыши] папку «Modules» и выберите «Добавить новое».
  5. Для «Название проекта» введите все строчные имена без пробелов, таких как моя библиотека
  6. Убедитесь, что «Местоположение проекта находится внутри папки пакета модулей и нажмите« Далее ».
  7. Введите базовый пакет java для вашего плагина в «Base Code Base», например com.mycompany.plugins.mylibrary
  8. Введите «Дисплейное имя модуля» для вашего плагина, например «Моя библиотека»
  9. Нажмите Готово
  10. Чтобы использовать основные функции SDK или jME3, добавьте «SDK Core и» SDK Engine через «Свойства модуля → Библиотека → Добавить зависимость

jMonkeyEngine SDK Contributions Update Center

Если вы хотите, чтобы ваш плагин появлялся в «Центре обновления вкладок jMonkeyEngine SDK», чтобы пользователи могли легко загружать, устанавливать и обновлять его через диспетчер плагинов, вы можете разместить свой плагин в хранилище svn-хранилища обновлений. Центр обновлений вкладов основан на проекте googlecode для предоставленных плагинов, который будет автоматически скомпилирован, помечен в соответствии с версией и добавлен в центр обновлений вкладов, такой как базовые модули jMonkeyEngine SDK.

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

Добавление вашего плагина в репозиторий

Чтобы добавить плагин в репозиторий, выполните следующие действия:

  • Убедитесь, что плагин является частью «Модульного пакета» и его расположено в папке пакета (это избавляет вас от проблем с svn и локальной версией, которые не настроены одинаково)
  • В «Свойства модуля → Источники
    • Установите «Source Level» равным 1.5, если это возможно (jMonkeyEngine SDK совместим с Java 1.5)
  • В «Свойства модуля» → «Версии API»
    • Установите версию спецификации для вашего плагина (например, 0.8.1)
    • Установите «версия реализации» на «0» и выберите «автоматически добавить версии реализации
  • В «Свойства модуля → Дисплей
    • Введите целевое описание вашего плагина и одну из следующих категорий:
      • Для библиотечного плагина: «jME3 — Библиотека
      • Для плагина SDK: «jME3 — плагин SDK
      • Для плагина модельного загрузчика: «jME3 — загрузчик
  • В «Свойства модуля → Сборка → Упаковка»
    • Добавьте свое имя
    • Добавить ссылку на ваш форум / домашнюю страницу, связанную с плагином
    • Добавьте лицензию, вы можете использовать ../license-jme.txt, чтобы вставить стандартную лицензию jME BSD или использовать текстовый файл, который вы храните в папке проекта
  • Попросите менеджеров или разработчиков получить доступ к проекту gc
  • Перенесите только проект модуля в магистраль:
    • Щелкните правой кнопкой мыши Project Module и выберите «Versioning → Import in Subversion Repository
    • Введите https://jmonkeyplatform-contributions.googlecode.com/svn/trunk в поле URL
    • Введите имя пользователя и пароль фиксации googlecode (иначе, чем пароль для входа, вы можете найти здесь свой пароль!) И нажмите «Далее».
    • Убедитесь, что папка «Репозиторий» — это соединительная линия / mypluginfolder и введите сообщение об импорте
    • Нажмите «Готово»

И вот, с этого момента каждый раз, когда вы вносите изменения в свой модуль, он будет автоматически создан и добавлен в центр вкладов, а номер версии будет расширен номером версии svn (например, 0.8.1.1234)

Создание обернутых файлов библиотеки jar на сервере

Вы можете просто локально создать свою библиотеку и обновить и перенести файл jar и javadoc / sources zip в папку release / libs вашего плагина в репозитории Contrib. Плагины пользователей будут автоматически обновляться с новыми файлами jar. Однако вы также можете создать проект библиотеки на сервере.

Как обычно на сервере строится только проект модуля, любые проекты, которые создают фактические файлы jar для плагинов библиотеки («обычные проекты из SDK / NetBeans»), должны быть построены из файла сборки модуля. Для этого просто добавьте следующие файлы муравьев в файл сборки модуля (приспосабливайтесь к файлам проекта и именам папок):

<target name="init" depends="basic-init,files-init,build-init,-javac-init,-build-subproject"/>
<target name="-build-subproject">
    <ant dir="./AI" inheritall="false" inheritrefs="false" target="clean"/>
    <ant dir="./AI" inheritall="false" inheritrefs="false" target="jar"/>
    <ant dir="./AI" inheritall="false" inheritrefs="false" target="javadoc"/>
    <zip basedir="./AI/dist/javadoc" file="release/libs/jME3-ai-javadoc.zip"/>
    <zip basedir="./AI/src" file="release/libs/jME3-ai-sources.zip"/>
    <copy file="./AI/dist/jME3-ai.jar" todir="release/libs"/>
</target>

Обратите внимание, что для того, чтобы номер версии модуля автоматически увеличивался при фиксации проекта библиотеки, проект библиотеки должен быть подпапкой основного проекта модуля.


Переведено для jmonkeyengine.ru, оригинал
Автор перевода: Andry

Независимо от того, работаете ли вы в команде разработчиков или в одиночку: Управление версиями файлов это удобный метод, чтобы поддерживать постоянство кода, сравнивать файлы по очереди и даже откатывать нежелательные изменения. В этой документации показано, как максимально использовать интегрированные в SDK возможности управления версиями для Subversion, Mercurial и Git.

Для каждого члена команды процесс управления версиями файлов выглядит следующим образом:

  1. Единожды: Загрузите рабочую копию проекта из репозитория («checkout»).
  2. Регулярно: Добавление собственных изменений в репозиторий («commit»).
  3. Регулярно: Загружать обновления сделанные другими пользователями из репозитория («update»).
Поскольку jMonkeyEngine SDK основан на платформе фреймворка NetBeans, вы можете узнать о некоторых функциях jMonkeyEngine SDK, прочитав соответствующие учебники по NetBeans IDE (в разделе «См. Также ссылку»).

Системы управления версиями

jMonkeyEngine SDK поддерживает различные системы управления версиями, такие как Subversion, Mercurial и Git. Независимо от того, какой из них вы используете, все они имеют общий пользовательский интерфейс.

Вы можете использовать управление версиями файлов самостоятельно или в команде. Преимущества в том, что вы можете отслеживать изменения (кто это сделал, когда и почему), вы можете сравнивать версии по очереди, вы можете отменить изменения в файлах и строках, объединить несколько изменений в одном файле, и вы можете даже восстановить файлы.

Создание репозитория (Загрузка)

Требования:

  • У вас должен быть проект, нужной вам версии.
  • Необходимо установить программное обеспечение контроля версий (Subversion, Mercurial или Git) и инициализировать репозиторий.
    • Например, для Subversion команда инициализации выглядит следующим образом: svnadmin create /home/joe/jMonkeyProjects/MyGame
  • Компьютер, на котором размещается репозиторий, должен быть доступен в сети для вашей команды, иначе вы сможете использовать свой репозиторий только локально.
    • Хосты, такие как SourceForge, GoogleCode, dev.java.net, предлагают бесплатные службы контроля версий для проектов с открытым исходным кодом.

Теперь вы создаете репозиторий для хранения файлов вашего проекта.

  1. В jMonkeyEngine SDK щелкните [ПК мыши] проект в окне Проекты и выберите Управление версиями ▸ Импортировать в репозиторий Subversion(или выполните инициализацию Mercurial Project и.т.д.).
    • Если вы еще не определились, какую систему выбрать, начните с Subversion на данный момент.
  2. Пройдите мастер и заполните поля, чтобы настроить хранилище.

Проверка репозитория (загрузка)

Вы и ваши товарищи по команде проверяете (загружаете) хранилище на свои отдельные рабочие станции.

  1. Перейдите в меню Группа и выберите Subversion ▸ Checkout (или Git или Mercurial соответственно)
  2. Заполните ваши данные репозитория в мастер и нажмите «Готово».
    • Типичный URL-адрес репозитория выглядит следующим образом: http://jmonkeyengine.googlecode.com/svn/trunk/engine
    • Если вы хотите иметь возможность отправлять изменения, вы должны иметь имя пользователя и пароль в этом репозитории. В противном случае эти поля будут пустыми.
  3. Репозиторий загружается и сохраняется в выбранном вами месте.
  4. Используйте меню Файл ▸ Открыть проект, чтобы открыть checkout в качестве проекта и начать работу.
    • Если проверка не распознана, вам нужно выбрать Файл ▸ Создать ▸ Java ▸ Проект Java с существующими исходными файлами

Конечно, вы также можете проверить существующие репозитории и код доступный из других проектов с открытым исходным кодом (например, SourceForge, GoogleCode, dev.java.net).

Обновление и фиксация изменений (отправка и получение)

Получение последних изменений из репозитория команды называется updating. Отправка ваших изменений в репозиторий команды называется commiting.

  1. Перед внесением изменений щелкните [ПК мыши] проект и выберите Subversion ▸ Update, чтобы убедиться, что у вас есть последняя версия.
    • Регулярно обновляйтесь, прежде чем редактировать контрольную версией файлов. Это избавит вас от огорчений.
  2. После внесения изменений в проект убедитесь, что ваше изменение ничего не сломало в проекте.
  3. Обновление, сборка, запуск, тестирование.
  4. Посмотрите красные/зеленые/синие метки в редакторе, чтобы просмотреть, что вы удалили/добавили/изменили. кликните по метки, чтобы просмотреть все отличия файла.
  5. Выберите Subversion ▸ Show Changes, чтобы просмотреть все файлы, которые были недавно изменены — вами и другими членами команды.
  6. Обновите снова, на тот случай если ваши товарищи по команде внесли изменения в то время когда вы просматривали изменения.
  • Если конфликтов нет и вы хотите зафиксировать свои изменения, выберите в меню пункт Subversion ▸ Commit.
  • Напишите сообщение в commit, описывающее, что вы изменили.
    • Помните, вы пишете «сообщение себе на будущее». Никогда не пишите лишние вещи вроде «Я что-то изменил».
  • Сравнение и возврат изменений

    • Если вы и другой член команды отредактировали одну и ту же строку, возникает конфликт, и в jMonkeyEngine SDK появится сообщение об ошибке.
      • Щелкните файл [ПК мыши]. Выберите Subversion ▸ Resolve Conflict
        1. Сравните конфликтующие версии. Нажимайте кнопки, чтобы принимать или отклонять каждое изменение отдельно.
        2. После того, как resolver отобразит зеленый цвет, сохраните разрешино.
        3. Собирайте и тестируйте на разрешение, обновляйте и commit(фиксируйте).
    • Щелкните [ПК мыши] файл и выберите Subversion ▸ History History.
      • Вы можете проверить историю файла и посмотреть, кто что изменил, почему и когда.
      • При необходимости вы можете откатить файл к более старой версии.
    • В общем, вы можете выбрать Subversion ▸ Diff для любого файла, чтобы увидеть две версии файла рядом друг с другом.

    Без контроля версий? История!

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

    • Щелкните файл или каталог [ПК мыши] и выберите История, чтобы отображать или отменять изменения или удалять файлы.
    • Вы также можете выбрать любые два файла в окне Проекты и выбрать Инструменты ▸ Различия для их сравнения.
    • История работает только для файлов, отредактированных в проектах jMonkeyEngine SDK (для других файлов это не работает, например, в окне Избранное).

    Смотрите также:


    Переведено для jmonkeyengine.ru, оригинал
    Автор перевода: Andry

    jMonkeyEngine.ru © 2017. Все права сохранены.