Докуметация Cтарт Статьи Форум Лента Вход
Не официальное русскоязычное сообщество
Главная
    Документация jMonkeyEngine
        jMonkeyEngine Уроки и Документация
            jMonkeyEngine3: Привет мир, Обучающая Серия
                jMonkeyEngine 3 урок (7) — Hello Animation

jMonkeyEngine 3 урок (7) — Hello Animation

Опубликованно: 04.04.2017, 21:48
Последняя редакция, Andry: 08.03.2018 19:18

Предыдущий: Hello Material, Следующий: Hello Picking

В этом уроке показано, как добавить контроллер анимации и каналы, а также, как реализовать реакцию на действия(ввод) пользователя, в виде вызова анимации у загруженной модели.

beginner-animation

Для того, чтобы использовать примеры игровых ресурсов в вашем новом проекте в jMonkeyEngine SDK, щелкните [ПК мыши] ваш проект, выберите Свойства, перейдите в раздел Библиотеки, нажмите кнопку [Добавить библиотеку] и добавьте библиотеку jme3-test-data.

Пример кода

package jme3test.helloworld;
 
import com.jme3.animation.AnimChannel;
import com.jme3.animation.AnimControl;
import com.jme3.animation.AnimEventListener;
import com.jme3.animation.LoopMode;
import com.jme3.app.SimpleApplication;
import com.jme3.input.KeyInput;
import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.KeyTrigger;
import com.jme3.light.DirectionalLight;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.jme3.scene.Node;
 
/** Образец 7 - как загрузить модель OgreXML и воспроизвести анимацию,
  * с помощью каналов, контроллера, а также AnimEventListener. */
public class HelloAnimation extends SimpleApplication
  implements AnimEventListener {
  private AnimChannel channel;
  private AnimControl control;
  Node player;
  public static void main(String[] args) {
    HelloAnimation app = new HelloAnimation();
    app.start();
  }
 
  @Override
  public void simpleInitApp() {
    viewPort.setBackgroundColor(ColorRGBA.LightGray);
    initKeys();
    DirectionalLight dl = new DirectionalLight();
    dl.setDirection(new Vector3f(-0.1f, -1f, -1).normalizeLocal());
    rootNode.addLight(dl);
    player = (Node) assetManager.loadModel("Models/Oto/Oto.mesh.xml");
    player.setLocalScale(0.5f);
    rootNode.attachChild(player);
    control = player.getControl(AnimControl.class);
    control.addListener(this);
    channel = control.createChannel();
    channel.setAnim("stand");
  }
 
  public void onAnimCycleDone(AnimControl control, AnimChannel channel, String animName) {
    if (animName.equals("Walk")) {
      channel.setAnim("stand", 0.50f);
      channel.setLoopMode(LoopMode.DontLoop);
      channel.setSpeed(1f);
    }
  }
 
  public void onAnimChange(AnimControl control, AnimChannel channel, String animName) {
    // не использовано
  }
 
  /** Пользовательские назначения клавиш: сопоставления названий действий с клавишами. */
  private void initKeys() {
    inputManager.addMapping("Walk", new KeyTrigger(KeyInput.KEY_SPACE));
    inputManager.addListener(actionListener, "Walk");
  }
  private ActionListener actionListener = new ActionListener() {
    public void onAction(String name, boolean keyPressed, float tpf) {
      if (name.equals("Walk") && !keyPressed) {
        if (!channel.getAnimationName().equals("Walk")) {
          channel.setAnim("Walk", 0.50f);
          channel.setLoopMode(LoopMode.Loop);
        }
      }
    }
  };
}


Создание и загрузка анимированных моделей

Вы можете создавать анимированные модели с помощью такого инструмента, как Blender. Потратьте некоторое время что бы научится создавать свои собственные модели в этих Уроках по Анимации в Blender. А сейчас, в качестве примера будут использоваться бесплатные модели из jme3-test-data скачивать которые для этого примера не нужно, но если вы захотите, то вы можете скачать их из (Oto Голем, и Ninja).

Загрузка анимированной модели осуществляется довольно просто, как вы могли убедится в предыдущих главах. Анимированные Ogre модели представляют из себя набора файлов: Модель в Oto.mesh.xml, а детали анимации в Oto.skeleton.xml, плюс обычные файлы вроде материалов и текстур. Убедитесь, что все файлы модели находятся вместе в одной и той же подпапке папки Model.

 public void simpleInitApp() {
    /* Для отображение модели требует источник света */
    DirectionalLight dl = new DirectionalLight();
    dl.setDirection(new Vector3f(-0.1f, -1f, -1).normalizeLocal());
    rootNode.addLight(dl);
    /* загрузите и прикрепите модель, как обычно, */
    player = assetManager.loadModel("Models/Oto/Oto.mesh.xml");
    player.setLocalScale(0.5f); // зададим размер
    rootNode.attachChild(player);
    ...
    }

Не забудьте добавить источник света, чтобы сделать материал видимым.


Контроллер анимации и канал

После того как вы загрузите анимированную модель, вы регистрируете ее в Animation Controller.

  • Объект контроллер дает вам доступ к имеющимся анимационным последовательностям.
  • Контроллер может иметь несколько каналов, каждый канал может запускать одновременно одну анимационную последовательность.
  • Чтобы запустить несколько последовательностей, необходимо создать несколько каналов, и затем задать каждому его анимацию.
  private AnimChannel channel;
  private AnimControl control;
 
  public void simpleInitApp() {
    ...
    /* Загрузим control анимации, слушатель событий анимации,
     * создадим канал анимации, и приведём модель в положение по умолчанию. */
    control = player.getControl(AnimControl.class); 
    control.addListener(this);
    channel = control.createChannel();
    channel.setAnim("stand");
    ...

Эта строка кода вернет NULL, если AnimControl не находится в главном узле вашей модели.

control = player.getControl(AnimControl.class);

Чтобы проверить это, [ПК Мыши] выберите вашу модель и нажмите Edit in SceneComposer, в том случае если расширение файла модели .j3o или View Model, если нет. После этого вы сможете увидеть дерево узлов модели, и найти узел, в котором находится control. Вы можете получить доступ к подузлам используя следующий код.

player.getChild("Subnode").getControl(AnimControl.class);
В ответ на вопрос об анимациях на разных каналах мешающих друг другу, Nehon на форуме jME написал:

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

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

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


Реакция на события анимации

Добавите imlements AnimEventListener в объявлениe класса. Этот интерфейс предоставляет доступ к событиям, которые уведомляют вас, когда последовательность будет выполнена, или при переходе от одной последовательности к другой, для того что бы вы могли реализовать реакцию на это если вам это нужно. В этом примере вы возвращаете персонажа в положение стоя после завершения цикла Walk.

public class HelloAnimation extends SimpleApplication
                         implements AnimEventListener {
  ...
 
  public void onAnimCycleDone(AnimControl control, 
                              AnimChannel channel, String animName) {
    if (animName.equals("Walk")) {
      channel.setAnim("stand", 0.50f);
      channel.setLoopMode(LoopMode.DontLoop);
      channel.setSpeed(1f);
    }
  }
  public void onAnimChange(AnimControl control, AnimChannel channel, String animName) {
    // не использовано
  }

Триггер Анимации после пользовательского ввода

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

  1. Инициализируйте новый контроллер ввода (в simpleInitApp()).
    • Для удобства напишите метод initKey() и сделайте его вызов в simpleInitApp().
  2. Добавьте сопоставления клавиш с названиями действий, которые вы хотите вызывать.
    • К примеру, Walk ходьба по игровому уровню с помощью клавиши Пробел.
  3. Добавьте слушатель ввода для действия Walk.
 private void initKeys() {
    inputManager.addMapping("Walk", new KeyTrigger(KeyInput.KEY_SPACE));
    inputManager.addListener(actionListener, "Walk");
  }

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

  • Второй параметр setAnim() это blendTime (как долго текущая анимация должна совпадать с последней).
  • LoopMode может быть Loop(повтор), Cycle(вперед затем назад), и DontLoop(только один раз).
  • При необходимости используйте channel.setSpeed​​(), чтобы задать скорость этой анимации.
  • При желании, можете использовать channel.setTime() для быстрой перемотки вперед или назад, к определенному моменту времени этой анимации.
  private ActionListener actionListener = new ActionListener() {
    public void onAction(String name, boolean keyPressed, float tpf) {
        if (name.equals("Walk") && !keyPressed) {
            if (!channel.getAnimationName().equals("Walk")){
                channel.setAnim("Walk", 0.50f);
                channel.setLoopMode(LoopMode.Cycle);
            }
        }
    }
  };

Упражнения

Упражнение 1: Две Анимации

Сделайте щелчок мыши, для вызвать другой последовательность анимации!

  1. Создайте второй канал в контроллере
  2. Создайте новую клавишу, т.е. сопоставление триггера действию (см Hello Input)
Вы хотите узнать, какие анимационные последовательности доступны в модели? Используйте:

for (String anim : control.getAnimationNames()) { 
    System.out.println(anim); 
}

Упражнение 2: Раскроем Skeleton(1)

Откройте файл skeleton.xml в текстовом редакторе на ваш выбор. Ва не нужно читать или писать эти XML-файлы (Blender сделает это за вас) — но это хорошо, знать, как работают скелеты. Там нет никакой магии!

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

Упражнение 3: Раскроем Skeleton(2)

Добавьте следующие операторы импорта, классов SkeletonDebugger и Material:

     import com.jme3.scene.debug.SkeletonDebugger;
     import com.jme3.material.Material;

Добавьте следующий фрагмент кода в simpleInitApp(), чтобы сделать кости (о которых вы только что прочитали) видимыми!

     SkeletonDebugger skeletonDebug = 
         new SkeletonDebugger("skeleton", control.getSkeleton());
     Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
     mat.setColor("Color", ColorRGBA.Green);
     mat.getAdditionalRenderState().setDepthTest(false);
     skeletonDebug.setMaterial(mat);
     player.attachChild(skeletonDebug);

Можете ли вы идентифицировать отдельные кости в скелете?


Вывод

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

Теперь, когда ваш персонаж может ходить, было бы круто, если бы он мог также подбирать вещи, или стрелять из оружие по объектам, или открывать двери? Пришло время, раскрыть секреты собирания или выбор мышью!


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


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

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

Содержание

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