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

Некоторые предлагаемые решения

Опубликованно: 27.04.2017, 19:37
Последняя редакция, AdiDOS: 28.04.2017 7:25

Это предложенная пользователем группа решений для некоторых или всех упражнений, представленных во всех уроков в учебнике для начинающих (jME3 уроки для начинающих). Есть несколько способов выполнять упражнения, поэтому не считайте то, что вы видите здесь, единственно правильны, и лучше попытайтесь сделать это сами, вместо того, чтобы прыгать к решению, потому что это лучший способ учиться!

Hello Update Loop

Упражнение 1

Он будет вращаться в другую сторону.

Упражнение 2

Во-первых, нужно объявить другую геометрию, например красный куб:

protected Geometry redCube;

public void simpleInitApp() {
    ...

    // Создает новый куб
    Box b2 = new Box(Vector3f.ZERO, 1, 1, 1);
    redCube = new Geometry("red cube", b2);

    // Сделает новый куб красным
    Material mat2 = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
    mat2.setColor("Color", ColorRGBA.Red);
    redCube.setMaterial(mat2);

    // Расположить красный куб рядом с другим кубом
    redCube.move(2, 0, 0);

    // Поместит красный куб на экран
    rootNode.attachChild(redCube);
}

Чтобы красный куб вращаться вдвое быстрее, чем другой куб, просто вращайте его на той же оси, но с удвоенным значением:

public void simpleUpdate(float tpf) {
    // Заставить player вращаться
    player.rotate(0, 2*tpf, 0);

    // Сделайте красный куб вращаться в два раза быстрее player
    redCube.rotate(0, 4*tpf, 0);
}

Упражнение 3

Одним из возможных решений является увеличение или уменьшение в зависимости от текущего размера. Куб может начинать либо увеличиваться, либо уменьшаться. Если куб увеличивался, то он начнет уменьшаться, только тогда когда он достигнет достаточно большого размера. Если куб уменьшается, то он начнет увеличиваться снова, только когда размер будет достаточно мал. Короче говоря, куб должен переключаться между ростом и уменьшением, когда он достигает заданного максимального и минимального размеров. Следующий код является примером этого решения:

private boolean grow = true;
...
public void simpleUpdate(float tpf) {
        if (grow) {
                player.scale(1 + (3f * tpf));
        } else {
                player.scale(1 - (3f * tpf));
        }

        Vector3f s = player.getLocalScale();
        if (s.getX() > 1.2f) {
                grow = false;
        } else if (s.getX() < 0.8f) {
                grow = true;
        }
}

Куб сначала начинает расти, и когда он достигает размера более 120% от его первоначального размера, он начинает уменьшаться. Куб будет продолжать уменьшаться, пока он не достигнет размера меньше 80% от его первоначального размера, что заставит его начать расти снова и так далее.

Другой подход состоит в том, чтобы переключаться между уменьшением и ростом в каждую выбранную единицу времени. В переменной tpf хранится время на кадр, поэтому если вы суммируете каждый tpf в методе simpleUpdate, вы получите время, прошедшее с начала игры. Используя время, подобное секундомеру, можно наращивать куб в течение некоторого времени, а затем сокращать куб на такое же количество времени и начинать заново. Следующий пример кода показывает пример этого решения:

// Время прошло
private float timeVar = 0;
...
public void simpleUpdate(float tpf) {
    timeVar += tpf;
    if (timeVar < 2) {
        player.scale(1 + tpf * 0.4f);
    } else if (timeVar < 4) {
        player.scale(1 - tpf * 0.4f);
    } else {
        timeVar = 0;
    }
}

Куб растет в течение двух двух секунд, затем сжимается еще 2 секунды и это повторяется неопределенно долго.

Другой подход — установить масштаб куба в зависимости от синусоидальной волны. Это приводит к плавной повторяющейся осциллирующей шкале. Обратите внимание, однако, что этот подход является дорогостоящим для вычислений из-за использования синусной функции. Можно создать синусоидальную волну, вычисляя синус как функцию времени. Таким образом, для каждой итерации метода simpleUpdate масштаб устанавливается как результат синуса как функции времени плюс оригинальная кубическая шкала. Следующий пример кода показывает пример такого подхода:

public void simpleUpdate(float tpf) {
    float timeInSec = timer.getTimeInSeconds();
    float initScale = 1;
    float amplitude = 0.5f;
    float angularFrequency = 1;
    float scale = initScale + amplitude * FastMath.sin(timeInSec * angularFrequency);
    player.setLocalScale(scale);
}

Куб должен многократно и плавно расти и сжиматься и иметь максимальный и минимальный масштаб 0,5 и 1,5 его первоначального размера. Следующие переменные могут изменить поведение шкалы:

  • initScale — Устанавливает начальную шкалу куба
  • amplitude — Увеличивает минимальную и максимальную шкалу
  • angularFrequency — Увеличивает скорость

Упражнение 4

Та же логика! Используйте timeVar, и сделайте в объявлении Material + инициализационную строку @ simpleInitApp() только инициализацию, с Material mat; Как глобальной переменной, тогда мы можем получить к ней доступ через simpleUpdate()! Вот так:

protected Material mat;

У глобальной переменной, инициализация отсекает биты Material:

mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");

И затем simpleUpdate()

public void simpleUpdate(float tpf) {
    timeVar += tpf;
    if (timeVar > 1) {
        mat.setColor("Color", ColorRGBA.randomColor());
        timeVar= 0;
    }
}

Упражнение 5

Возможное решение — изменить ось вращения player от y до x и заставить его двигаться вдоль оси z:

public void simpleUpdate(float tpf) {
    // make the player rotate
    player.rotate(2*tpf, 0, 0);
    player.move(0, 0, 2*tpf);
}

Вышеприведённый код должен заставить player накреняться к камере.


Hello Input

Упражнение 1

Сначала добавьте сопоставления для действий Up и Down в методе initKeys():

private void initKeys() {
    ...
    inputManager.addMapping("Up", new KeyTrigger(KeyInput.KEY_H));
    inputManager.addMapping("Down", new KeyTrigger(KeyInput.KEY_L));
    ...
    inputManager.addListener(combinedListener, new String[]{"Left", "Right", "Up", "Down", "Rotate"});
}

Затем реализуйте действия в методе onAnalog():

public void onAnalog(String name, float value, float tpf) {
    if (isRunning) {
        ...
        if (name.equals("Up")) {
            Vector3f v = player.getLocalTranslation();
            player.setLocalTranslation(v.x, v.y + value * speed, v.z);
        }
        if (name.equals("Down")) {
            Vector3f v = player.getLocalTranslation();
            player.setLocalTranslation(v.x, v.y - value * speed, v.z);
        }
    } else {
        ...
    }
}

Это должно позволить кубу двигаться вверх, если нажата клавиша H, и вниз, если нажата клавиша L.

Упражнение 2

Следуя предложенному решению 1, добавьте новые сопоставления для колеса мыши в методе initKeys():

private void initKeys() {
    ...
    inputManager.addMapping("Up", new KeyTrigger(KeyInput.KEY_H),
                                  new MouseAxisTrigger(MouseInput.AXIS_WHEEL, true));
    inputManager.addMapping("Down", new KeyTrigger(KeyInput.KEY_L),
                                    new MouseAxisTrigger(MouseInput.AXIS_WHEEL, false));
    ...
}

Теперь вы можете прокручивать куб вверх или вниз с помощью колеса мыши.

Упражнение 3

Когда элементы управления выбраны пользователем.


Hello Picking

Упражнение 1

Вы можете сразу же перейти к получению материала объекта атаки, обратившись к «ближайшему объекту, так же как ранее мы получали его геометрию через .getGeometry(), а затем получить материал Геометрии через .getMaterial(), вот так:

Material g = closest.getGeometry().getMaterial();

Это то же самое, что и пройти два шага, указанных в подсказках: Geometry g = closest.getGeometry(); Material = g.getMaterial(); Наконец, вам нужно только добавить эту строку: material.setColor(«Color, ColorRGBA.randomColor()), которая изменит материал у объекта попадания на случайный цвет!

Строки могут быть добавлены в любом месте блока if (results.size()> 0) после объявления самого близкого объекта. Конечный результат выглядит следующим образом:

Material material = closest.getGeometry().getMaterial();
material.setColor("Color", ColorRGBA.randomColor());

Упражнение 2

Прежде всего, нам нужен источник света, чтобы сделать модель видимой! Добавьте простой DirectionalLight, как было показано ранее. Затем объявите Spatial переменную голема вне методов. Затем инициализируйте голема, чтобы загрузить его модель:

golem = assetManager.loadModel("Models/Oto/Oto.mesh.xml");

Теперь нам нужно, чтобы он появился! Поэтому мы должны его прикрепить: но rootNode не будет делать этого, потому что мы проверяем столкновение с его дочерним узлом — shootables! Поэтому мы присоединяем его к shootables!

shootables.attachChild(golem);

Упражнение 3

Вот мой код, он работает, и он хорошо прокомментирован.

package jme3test.helloworld;

import com.jme3.app.SimpleApplication;
import com.jme3.collision.CollisionResult;
import com.jme3.collision.CollisionResults;
import com.jme3.font.BitmapText;
import com.jme3.input.KeyInput;
import com.jme3.input.MouseInput;
import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.KeyTrigger;
import com.jme3.input.controls.MouseButtonTrigger;
import com.jme3.light.DirectionalLight;
import com.jme3.material.MatParam;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Ray;
import com.jme3.math.Vector3f;
import com.jme3.scene.Geometry;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
import com.jme3.scene.shape.Box;
import com.jme3.scene.shape.Sphere;
import com.jme3.system.SystemListener;

public class HelloPicking extends SimpleApplication
{

    public static void main(String[] args)
    {
        HelloPicking app = new HelloPicking();
        app.start();
    }
    private Node shootables;
    private Node inventory;
    private Vector3f oldPosition;

    @Override
    public void simpleInitApp()
    {
        initCrossHairs();
        initKeys();
        shootables = new Node("Shootables");
        inventory = new Node("Inventory");
        guiNode.attachChild(inventory);
        // Добавьте свет в HUD, чтобы мы могли видеть робота
        DirectionalLight sun = new DirectionalLight();
        sun.setDirection(new Vector3f(0, 0, -1.0f));
        guiNode.addLight(sun);
        rootNode.attachChild(shootables);
        shootables.attachChild(makeCube("a Dragon", -2f, 0f, 1f));
        shootables.attachChild(makeCube("a tin can", 1f, -2f, 0f));
        shootables.attachChild(makeCube("the Sheriff", 0f, 1f, -2f));
        shootables.attachChild(makeCube("the Deputy", 1f, 0f, -4f));
        shootables.attachChild(makeFloor());
        shootables.attachChild(makeCharacter());
    }
    private ActionListener actionListener = new ActionListener()
    {
        public void onAction(String name, boolean keyPressed, float tpf)
        {
            if (name.equals("Shoot") && !keyPressed)
            {
                if (!inventory.getChildren().isEmpty())
                {
                    Spatial s1 = inventory.getChild(0);
                    // уменьшим
                    s1.scale(.02f);
                    s1.setLocalTranslation(oldPosition);
                    inventory.detachAllChildren();
                    shootables.attachChild(s1);
                }
                else
                {
                    CollisionResults results = new CollisionResults();
                    Ray ray = new Ray(cam.getLocation(), cam.getDirection());
                    shootables.collideWith(ray, results);

                    if (results.size() > 0)
                    {
                        CollisionResult closest = results.getClosestCollision();
                        Spatial s = closest.getGeometry();
                        // Мы изменяем Модель по-другому с простой Геометрией
                        // s.parent - Oto-ogremesh когда s - Oto_geom-1 и это то, что нам нужно
                        if (s.getName().equals("Oto-geom-1"))
                        {
                            s = s.getParent();
                        }
                        // Важно получить клон или иначе он будет вести себя странно
                        oldPosition = s.getLocalTranslation().clone();
                        shootables.detachChild(s);
                        inventory.attachChild(s);
                        // сделаем его больше, чтобы увидеть на HUD
                        s.scale(50f);
                        // Сделаем это в центре HUD
                        s.setLocalTranslation(settings.getWidth() / 2, settings.getHeight() / 2, 0);
                    }
                }
            }
        }
    };

    private void initKeys()
    {
        inputManager.addMapping("Shoot",
                                new KeyTrigger(KeyInput.KEY_SPACE),
                                new MouseButtonTrigger(MouseInput.BUTTON_LEFT));
        inputManager.addListener(actionListener, "Shoot");
    }
    protected Geometry makeCube(String name, float x, float y, float z)
    {
        Box box = new Box(1, 1, 1);
        Geometry cube = new Geometry(name, box);
        cube.setLocalTranslation(x, y, z);
        Material mat1 = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
        mat1.setColor("Color", ColorRGBA.randomColor());
        cube.setMaterial(mat1);
        return cube;
    }
    protected Geometry makeFloor()
    {
        Box box = new Box(15, .2f, 15);
        Geometry floor = new Geometry("the Floor", box);
        floor.setLocalTranslation(0, -4, -5);
        Material mat1 = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
        mat1.setColor("Color", ColorRGBA.Gray);
        floor.setMaterial(mat1);
        return floor;
    }
    protected void initCrossHairs()
    {
        setDisplayStatView(false);
        guiFont = assetManager.loadFont("Interface/Fonts/Default.fnt");
        BitmapText ch = new BitmapText(guiFont, false);
        ch.setSize(guiFont.getCharSet().getRenderedSize() * 2);
        ch.setText("+");
        ch.setLocalTranslation(
                settings.getWidth() / 2 - ch.getLineWidth() / 2, settings.getHeight() / 2 + ch.getLineHeight() / 2, 0);
        guiNode.attachChild(ch);
    }
    protected Spatial makeCharacter()
    {
        Spatial golem = assetManager.loadModel("Models/Oto/Oto.mesh.xml");
        golem.scale(0.5f);
        golem.setLocalTranslation(-1.0f, -1.5f, -0.6f);
        System.out.println("golem.locaoTranslation:" + golem.getLocalTranslation());
        DirectionalLight sun = new DirectionalLight();
        sun.setDirection(new Vector3f(0, 0, -1.0f));
        golem.addLight(sun);
        return golem;
    }
}

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

Добавить комментарий

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