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

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

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

Предыдущий: 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. А сейчас, скачайте и используйте бесплатно модели которые используются здесь в качестве примера (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 написал:

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

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

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

control = player.getControl(AnimControl.class);

Эта строка кода вернет NULL, если AnimeControl не находится в главном узле вашей модели. Чтобы проверить это, в SDK щелкните [ПК мыши] модель и выберите пункт Edit in SceneComposer, затем вы можете увидеть дерево для модели. После этого вы можете переместить все на главный узел. Вы также можете получить доступ к подузлу с помощью следующего кода:

player.getChild("Subnode").getControl(AnimControl.class);

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

Добавите 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. Добавление сопоставления клавиш с именем действия, которое вы хотите вызвать.
    • Вот, например, хождение по карте с помощью клавиши Пробел.
  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

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

Содержание

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