[SOLVED] How to run multiple animations in parallel?

I made some animations in Blender for my model. I imported each animation as a separate FBX file. I need to run several animations in parallel, but I can’t do it. Only the last attached animation is always played. How can I run multiple animations at once?

On separate entities or the same entity but as blended animations?

On separate child objects.

I try to get the child nodes and apply animation only to them.

I’m trying to do something like this:

var AnimationComponent = pc.createScript('animationComponent');

// Добавление атрибутов
AnimationComponent.attributes.add('enteringEvent', { type: 'string', default: 'event', title: 'Entering Event' });
AnimationComponent.attributes.add('nodeName1', { type: 'string', default: 'name', title: 'Node Name'});
AnimationComponent.attributes.add('nodeName2', { type: 'string', default: 'name', title: 'Node Name'});
AnimationComponent.attributes.add('nodeName3', { type: 'string', default: 'name', title: 'Node Name'});
AnimationComponent.attributes.add('nameAnimation1', { type: 'string', default: 'animation', title: 'Animation Name' });
AnimationComponent.attributes.add('nameAnimation2', { type: 'string', default: 'animation', title: 'Animation Name' });
AnimationComponent.attributes.add('nameAnimation3', { type: 'string', default: 'animation', title: 'Animation Name' });
// AnimationComponent.attributes.add('nameAnimation4', { type: 'string', default: 'animation', title: 'Animation Name' });
// AnimationComponent.attributes.add('nameAnimation5', { type: 'string', default: 'animation', title: 'Animation Name' });
// AnimationComponent.attributes.add('nameAnimation6', { type: 'string', default: 'animation', title: 'Animation Name' });

// Разовая инициализация кода
AnimationComponent.prototype.initialize = function() {
    
    // Если устройство не является смартфоном или планшетом
    if (!pc.platform.mobile) {
        
        var self = this;

        // Инициализация объекта, который хранит все меши сущности
        this.searchesMeshes = {};
        
        // Добавление в объект мешей по их имени
        this.searchMesh(this.nodeName1);
        this.searchMesh(this.nodeName2);
        this.searchMesh(this.nodeName3);
        
        // console.log(this.searchesMeshes[this.nodeName1].getLocalRotation());
        console.log(this.searchesMeshes[this.nodeName1]);
        // console.log(this.searchesMeshes[this.nodeName2]);
        // console.log(this.searchesMeshes[this.nodeName3]);

        // Состояние анимации группы 1
        this.stateAnimationGroup1 = true;
        
        // Сохранение анимаций в переменные
        this.animation1 = this.entity.animation.getAnimation(this.nameAnimation1);
        this.animation2 = this.entity.animation.getAnimation(this.nameAnimation2);
        this.animation3 = this.entity.animation.getAnimation(this.nameAnimation3);
        
        // console.log(this.animation1.nodes[0]._keys);
        console.log(this.animation1);
        // console.log(this.animation2);
        // console.log(this.animation2);

//         for (var index = 0; index < this.animation1.nodes[0]._keys.length; index++) {
            
//             console.log(this.animation1.nodes[0]._keys[index].rotation);
            
//         }
        
        // Инициализация переменной, которая хранит значение времени продолжительности анимации
        this.durationAnimation = 0;

        // Инициализация переменной, которая хранит состояние анимации
        // this.stateAllAnimation = true;
        
//         // Состояние анимации группы 2
//         this.stateAnimationGroup2 = false;
        
//         // Сохранение анимаций в переменные
//         this.animation4 = this.entity.animation.getAnimation(this.nameAnimation4);
//         this.animation5 = this.entity.animation.getAnimation(this.nameAnimation5);
//         this.animation6 = this.entity.animation.getAnimation(this.nameAnimation6);

        // Переменная, которая определяет текущее состояние анимации
        this.state = false;

        // Прослушивать событие, которое запускает сущность ограничивающей области
        this.app.on(this.enteringEvent , function(interactionEntity) {    

            // Если сущность из события равна текущей сущности
            if (interactionEntity === self.entity) {

                // Подписаться на событие нажатия клавиш
                self.app.keyboard.on(pc.EVENT_KEYDOWN, self.keyDown, self); 

            }

            // Обновить значение состояния анимации
            self.state = true;

        });
        
    }
    
};

// Вызов функции каждый кадр
AnimationComponent.prototype.update = function(dt) {
    
    // console.log(this.searchesMeshes[this.nodeName1].getLocalRotation());
    
    // Если устройство не является смартфоном или планшетом
    if (!pc.platform.mobile) {
    
        // Если нет взаимодействия с анимацией
        if (this.state === false) {

            // Отписаться от события нажатия клавиш
            this.app.keyboard.off(pc.EVENT_KEYDOWN, this.keyDown, this);

        }

        // Обновлять значение переменной каждый кадр (для того, чтобы отключить взаимодействие с анимацией, когда сущность пользователя находится за пределами ограничивающей области)
        this.state = false;

        // Если продолжительность анимации больше 0, то есть сейчас проигрывается анимация
        if (this.durationAnimation >= 0) {

            // Обновлять значение переменной, путем нахождения оставшегося времени проигрывания анимации
            this.durationAnimation -= dt;

        }
        
    }
    
};

// Функция, которая отвечает за обработку нажатия клавищ
AnimationComponent.prototype.keyDown = function(event) {
    
    // Если устройство не является смартфоном или планшетом
    if (!pc.platform.mobile) {
    
        // Если нажата кнопка и время проигрывания анимации меньше или равно нулю и 
        if ((event.key === pc.KEY_1 || event.key === pc.KEY_NUMPAD_1) && this.durationAnimation <= 0 && this.stateAnimationGroup1 === true) {

            console.log(true);
            
            // Запустить анимации
            this.entity.animation.play(this.nameAnimation1);
            this.entity.animation.play(this.nameAnimation2);
            // this.entity.animation.play(this.nameAnimation3);

            // Обновить значение переменной, значением продолжительности анимации
            this.durationAnimation = this.animation1.duration;
            
            // Изменить состояния групп анимаций
            // this.stateAnimationGroup1 = false;
            // this.stateAnimationGroup2 = true;

        }

//         // Если нажата кнопка и время проигрывания анимации меньше или равно нулю и 
//         if ((event.key === pc.KEY_1 || event.key === pc.KEY_NUMPAD_1) && this.durationAnimation <= 0 && this.stateAnimationGroup2 === true) {

//             // Запустить анимации
//             this.entity.animation.play(this.nameAnimation4);
//             this.entity.animation.play(this.nameAnimation5);
//             this.entity.animation.play(this.nameAnimation6);

//             // Обновить значение переменной, значением продолжительности анимации
//             this.durationAnimation = this.animation4.duration;
            
//             // Изменить состояния групп анимаций
//             this.stateAnimationGroup1 = true;
//             this.stateAnimationGroup2 = false;

//         }
        
    }
    
};

// Функция, которая сохраняет меши сущности, как независимые элементы объекта
AnimationComponent.prototype.searchMesh = function(nodeName) {
       
    // Инициализация переменной, которая хранит все дочерние инстансы (меши) текущей модели
    var meshs = this.entity.model.model.meshInstances;

    // Проход в цикле по всем дочерним мешам
    for (var meshItem = 0; meshItem < meshs.length; meshItem++) {

        // Если название текущего меша равно названию искомого мешу
        if (meshs[meshItem].node.name === nodeName) {
            
            // Сохранить имя в новую переменную для упрощенного взаимодействия
            var name = nodeName;

            // Сохранить текущий меш в глобальный объект
            this.searchesMeshes[name] = meshs[meshItem].node;

        }

    }
    
};

I don’t think you can play different animations on the same mesh if that’s what you are trying to do.

Not out of the box though. You are effectively wanting to blend animations on the same entity.

I can display the node I need and its animation in the console, but I do not know how to apply this animation on this node. The animation contains rotation angles and I think that I can apply these angles to the node. Is not it so?
1

I solved the problem using Skeleton.

1 Like