Вторник, 12.12.2017, 09:21
Поиск
Никнэйм
Сертификат на никнейм Olelucoye, зарегистрирован на Тимофеев Константин Михайлович
Зарегистрируй свой никнейм
Обратная связь
olelucoye.tk@yandex.ru
Реклама AdSense
Реклама
Друзья сайта
  • Лига медицинского права
  • Гостиница "Зай"
  • FAQ по системе
  • Инструкции для uCoz
  • Главная » Статьи » libGDX

    libGDX. Анимация персонажа.

    libGDX. Анимация персонажа.

    Продолжим работать с кодом созданным в предыдущей статье, в которой мы сделали управление для персонажа. Но робот при движении не шевелит конечностями - чтобы он стал больше похож на реального, нужно его анимировать. Анимация должна быть создана для модели на этапе создания в 3D-редакторе. В используемой нами модели уже есть несколько анимаций, нужно только задействовать необходимую в нужный момент. (Модель из предыдущей статьи была немного доработана, новый вариант можно взять здесь)

    Чтобы это сделать, объявим контроллер анимации. При создании экземпляра модели инициализируем его, передав в качестве параметра сам экземпляр. И сразу же установим для робота анимацию "Stay" - чтобы он не стоял как истукан, а изучал окружение. В первом параметре метода setAnimation передаем имя анимации, во втором количество повторений - если передать, например, 4, анимация повторится четыре раза , затем остановится. -1 означает, что анимация будет повторяться бесконечно, пока мы её не остановим или не установим другую анимацию. Чтобы анимация начала работать, в render() установим обновление состояние контролера анимации.

    AnimationController animController;
           
        public void doneLoading(){
            .....
            man = assets.get("data/robot3.g3db", Model.class);
            .....
            animController = new AnimationController(manInst);
            animController.setAnimation("robot_rig|Stay", -1);
            .....
        }
        
        @Override
        public void render () {
                .....
                animController.update(Gdx.graphics.getDeltaTime());
                .....
        }

    Если запустить код на исполнение, персонаж будет шевелиться. Но при нажатии кнопок анимация не меняется. Исправим это, устанавливая при нажатии клавиш соответствующие анимации. При отпускании возвращаем анимацию стоящего робота.

        
       
    @Override
        public boolean keyDown(int keycode) {
            switch(keycode){
            case Keys.UP:
                animController.setAnimation("robot_rig|Walk", -1);
                forward = true;
                break;
            case Keys.DOWN:
                animController.setAnimation("robot_rig|Back", -1);
                back = true;
                break;
            case Keys.RIGHT:
                animController.setAnimation("robot_rig|Right", -1);
                right = true;
                break;
            case Keys.LEFT:
                animController.setAnimation("robot_rig|Left", -1);
                left = true;
                break;
            case Keys.SPACE:
                animController.setAnimation("robot_rig|Jump", 1);
                jump = 0;
                break;
            }
            return true;
        }
        @Override
        public boolean keyUp(int keycode) {
            switch(keycode){
            case Keys.UP:
                animController.setAnimation("robot_rig|Stay", -1);
                forward = false;
                break;
            case Keys.DOWN:
                animController.setAnimation("robot_rig|Stay", -1);
                back = false;
                break;
            case Keys.RIGHT:
                animController.setAnimation("robot_rig|Stay", -1);
                right = false;
                break;
            case Keys.LEFT:
                animController.setAnimation("robot_rig|             left = false;
                break;
            }
            return true;
        }
        

    Запускаем.

    Персонаж реагирует на нажатия кнопок, но если нажать две кнопки, например вперед и вправо, установится анимация последней нажатой кнопки. Затем, если одну из кнопок отпустить, установится анимация стойки, хотя движение продолжается. Такая реакция на нажатия нас не устраивает. Чтобы исправить это, сделаем проверку нажатых кнопок и будем устанавливать ту анимацию, которая соответствует комбинации нажатых кнопок.

       private String CheckAnimation(){
            String anim = "Stay";
            if(Gdx.input.isKeyPressed(Keys.DOWN))anim = "robot_rig|Back";
            if(Gdx.input.isKeyPressed(Keys.UP))anim = "robot_rig|Walk";
            if(Gdx.input.isKeyPressed(Keys.RIGHT))anim = "robot_rig|Right";
            if(Gdx.input.isKeyPressed(Keys.LEFT))anim = "robot_rig|Left";
            return anim;
        }
        @Override
        public boolean keyDown(int keycode) {
            switch(keycode){
            case Keys.UP:
                animController.setAnimation(CheckAnimation(), -1);
                forward = true;
                break;
            case Keys.DOWN:
                animController.setAnimation(CheckAnimation(), -1);
                back = true;
                break;
            case Keys.RIGHT:
                animController.setAnimation(CheckAnimation(), -1);
                right = true;
                break;
            case Keys.LEFT:
                animController.setAnimation(CheckAnimation(), -1);
                left = true;
                break;
            case Keys.SPACE:
                animController.setAnimation("robot_rig|Jump", 1);
                jump = 0;
                break;
            }
            return true;
        }
        @Override
        public boolean keyUp(int keycode) {
            switch(keycode){
            case Keys.UP:
                animController.setAnimation(CheckAnimation(), -1);
                forward = false;
                break;
            case Keys.DOWN:
                animController.setAnimation(CheckAnimation(), -1);
                back = false;
                break;
            case Keys.RIGHT:
                animController.setAnimation(CheckAnimation(), -1);
                right = false;
                break;
            case Keys.LEFT:
                animController.setAnimation(CheckAnimation(), -1);
                left = false;
                break;
           }
            return true;
        }

    В методе CheckAnimation проверяем нажатые кнопки, определяем анимацию, которая будет воспроизводиться и возвращаем её. В setAnimation устанавливаем полученную анимацию.

    Осталось разобраться с прыжком. Анимация прыжка воспроизводится один раз и должна быть проиграна до конца, затем нужно установить новую анимацию. Предыдущий способ в этом случае нам не подойдет. Здесь нам на помощь придет AnimationListener.

        AnimationListener jumpListener;
        .....
        @Override
        public void create () {
            .....
            jumpListener = new AnimationListener(){
                @Override
                public void onEnd(AnimationDesc animation) {
                    animController.queue(CheckAnimation(), -1, 1, null, 1);
               }
                @Override
                public void onLoop(AnimationDesc animation) {
                    
                }
           };
        }
        
        @Override
        public boolean keyDown(int keycode) {
            switch(keycode){
            ....
            case Keys.SPACE:
                animController.setAnimation("robot_rig|Jump", 1, jumpListener);
                jump = 0;
                break;
            }
            return true;
        }

    Объявим слушатель и инициализируем его в create. AnimationListener имеет два метода: onEnd - срабатывает по окончании анимации, onLoop - срабатывает, когда начинается следующая петля анимации (в случае если анимация зациклена). Нам нужен onEnd. Эти методы срабатывают, когда в render обновляется контролер анимации animController.update(Gdx.graphics.getDeltaTime()). Поэтому, если установить анимацию в onEnd методом setAnimation, при исполнении кода вылезет ошибка вроде - "невозможно установить анимацию во время обновления". Чтобы этого избежать этого, поместим анимацию в очередь методом queue. Это значит, что анимация будет воспроизведена, когда будет закончена предыдущая анимация. В нашем случае в очереди будет только одна анимация и она будет применена при следующем обновлении.

    В обработчике нажатия кнопки прыжка добавим в метод set Animation третий параметр - слушатель.

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

    Исправить это не сложно - нужно вместо setAnimation использовать метод animate.

        @Override
        public boolean keyDown(int keycode) {
            switch(keycode){
            case Keys.UP:
                animController.animate(CheckAnimation(), -1, null, 1);
                forward = true;
                break;
            case Keys.DOWN:
                animController.animate(CheckAnimation(), -1, null, 1);
                back = true;
                break;
            case Keys.RIGHT:
                animController.animate(CheckAnimation(), -1, null, 1);
                right = true;
                break;
            case Keys.LEFT:
                animController.animate(CheckAnimation(), -1, null, 1);
                left = true;
                break;
            case Keys.SPACE:
                animController.animate("robot_rig|Jump", 1, jumpListener, 1);
                jump = 0;
                break;
            }
            return true;
        }
        @Override
        public boolean keyUp(int keycode) {
            switch(keycode){
            case Keys.UP:
                animController.animate(CheckAnimation(), -1, null, 1);
                forward = false;
                break;
            case Keys.DOWN:
                animController.animate(CheckAnimation(), -1, null, 1);
                back = false;
                break;
            case Keys.RIGHT:
                animController.animate(CheckAnimation(), -1, null, 1);
                right = false;
                break;
            case Keys.LEFT:
                animController.animate(CheckAnimation(), -1, null, 1);
                left = false;
                break;
            }
            return true;
        }

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

    Теперь нужно реализовать обработку нажатий на сенсорные кнопки. Осуществляется это аналогично.

    public class TheStage extends Stage{
           public boolean touchDown(int screenX, int screenY, int pointer, int button) {
                screenY = scrY - screenY;
                Actor actor = hit(screenX, screenY, true);
                if(actor == null){
                    aName = "null";
                    return false;
                }else{
                    aName = actor.getName();
                    if(aName.equals("forward")){
                        forward = true;
                        animController.animate(CheckAnimationSens(), -1, null, 1);
                    }
                    if(aName.equals("back")){
                        back = true;
                        animController.animate(CheckAnimationSens(), -1, null, 1);
                        
                    }
                    if(aName.equals("right")){
                        right = true;
                        animController.animate(CheckAnimationSens(), -1, null, 1);
                   }
                    if(aName.equals("left")){
                        left = true;
                        animController.animate(CheckAnimationSens(), -1, null, 1);
                   }
                    if(aName.equals("rotate_left")){
                        rotateAngle = -1;                    
                    }
                    if(aName.equals("rotate_right")){
                        rotateAngle = 1;                    
                    }
                    if(aName.equals("jump")){
                        animController.animate("robot_rig|Jump", 1, jumpListener, 1);
                        if(jump >= 1)jump = 0;
                    }
                    return true;
                }
            }
            @Override
            public boolean touchUp(int screenX, int screenY, int pointer, int button) {
                screenY = scrY - screenY;
                Actor actor = hit(screenX, screenY, true);
                if(actor == null){
                    aName = "null";
                    return false;
                }else{
                    aName = actor.getName();
                    if(aName.equals(null)){
                        return false;
                    }else if(aName.equals("rotate_right")||aName.equals("rotate_left")){
                        rotateAngle = 0;
                        return true;
                    }else if(aName.equals("forward")){
                        forward = false;
                        animController.animate(CheckAnimationSens(), -1, null, 1);
                        return true;
                    }else if(aName.equals("back")){
                        back = false;
                        animController.animate(CheckAnimationSens(), -1, null, 1);
                        return true;
                    }else if(aName.equals("right")){
                        right = false;
                        animController.animate(CheckAnimationSens(), -1, null, 1);
                        return true;
                    }else if(aName.equals("left")){
                        left = false;
                        animController.animate(CheckAnimationSens(), -1, null, 1);
                        return true;
                    }else{
                        return false;
                    }
                }
            @Override
            public boolean touchDragged(int screenX, int screenY, int pointer) {
                return false;
            }
            @Override
            public Actor hit(float x, float y, boolean touchable) {
                Actor  actor  = super.hit(x,y,touchable);
                return actor;
            }
        }
       public String CheckAnimationSens(){
            String anim = "robot_rig|Stay";
            if(back)anim = "robot_rig|Back";
            if(forward)anim = "robot_rig|Walk";
            if(right)anim = "robot_rig|Right";
            if(left)anim = "robot_rig|Left";
            return anim;
        }

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

                @Override
                public void onEnd(AnimationDesc animation) {
                    switch(Gdx.app.getType()) {
                       case Android:
                           animController.queue(CheckAnimationSens(), -1, 1, null, 1);
                           break;
                       case Desktop:
                           animController.queue(CheckAnimation(), -1, 1, null, 1);
                           break;
                    default:
                        break;
                    }
                }

    В слушателе анимации нам нужно определить каким методом нам получить нужную анимацию. Для этого мы определяем платформу методом Gdx.app.getType() и в зависимости от результата используем тот или иной метод.

    Теперь можем запустить код и на десктопе и на Андроид-устройстве и посмотреть результаты.

    Полный код главного класса можно посмотреть здесь.

    libGDX. Scene2D. Сенсорное управление персонажем.
    libGDX. Scene2D.
    libGDX. Формы столкновений.
    libGDX. Bullet. Динамика твердого тела. Часть 2.
    libGDX. Bullet. Динамика твердого тела.
    libGDX. Обработка столкновений. Библиотека Bullet. Часть 3.
    libGDX. Обработка столкновений. Библиотека Bullet. Часть 2.
    libGDX. Обработка столкновений. Библиотека Bullet.
    libGDX. Интерактивное взаимодействие с 3D объектами.
    libGDX. Отбраковка объектов не попадающих в обзор камеры.
    3D модель  для libGDX. Пишем код.
    3D модель для движка libGDX
    Строим модель с помощью ModelBuilder
    libGDX. Основы 3D программирования.
    Игра Flower. Ловим капли.
    TexturePacker.Создаем атлас текстур.
    Создаем проект на движке libGDX

     

    Категория: libGDX | Добавил: Olelucoye (11.06.2015)
    Просмотров: 2416 | Комментарии: 1
    | Теги: анимация персонажа, AnimationListener, AnimationController, слушатель анимации, определение платформы, 3D, libGDX | Рейтинг: 0.0/0
    Всего комментариев: 1
    1 dmnew   (25.01.2016 19:47)
    Большое спасибо за подробное описание! Но что то не могу разобраться - персонаж не управляется. Использую полный код главного класса.

    Добавлять комментарии могут только зарегистрированные пользователи.
    [ Регистрация | Вход ]
    Меню сайта
    Категории раздела
    Андроид разработка [23]
    libGDX [24]
    Мои андроид проекты [6]
    Excel [7]
    Железяки [5]
    Скрипты в блокноте [4]
    Разное [1]
    Форма входа
    Статистика

    Онлайн всего: 1
    Гостей: 1
    Пользователей: 0
    Яндекс Метрика
    Яндекс.Метрика