Animation blending issue

Hi,

I am trying to blend between multiple animations on key presses. I want to move from the regular walking animation to different animations on different keys.

This is my script so far - I have added a new function at the bottom but I’m a little stuck - could anyone tell me where I’m going wrong? Currently I can only blend to the bottom animation “dancing” and not “stretch”…

var AnimationBlending = pc.createScript('animationBlending');

AnimationBlending.states = {
    idle: {
        animation: 'catwalk_walking_inPlace (1).json'
    },
    stretch: {
        animation: 'arm_stretching.json'
    },
    dancing: {
        animation: 'jazz_dancing_inPlace.json'
    }
};

// initialize code called once per entity
AnimationBlending.prototype.initialize = function() {
    this.blendTime = 1;

    this.setState('idle');

    this.app.keyboard.on(pc.EVENT_KEYDOWN, this.keyDown, this);
    this.app.keyboard.on(pc.EVENT_KEYUP, this.keyUp, this);
};

AnimationBlending.prototype.setState = function (state) {
    var states = AnimationBlending.states;

    this.state = state;
    // Set the current animation, taking 0.2 seconds to blend from
    // the current animation state to the start of the target animation.
    this.entity.animation.play(states[state].animation, this.blendTime);
};

AnimationBlending.prototype.keyDown = function (e) {
    if ((e.key === pc.KEY_P) && (this.state !== 'stretch')) {
        this.setState('stretch');
    }
};

AnimationBlending.prototype.keyUp = function (e) {
    if ((e.key === pc.KEY_P) && (this.state === 'strech')) {
        this.setState('idle');
    }
};


AnimationBlending.prototype.keyDown = function (e) {
    if ((e.key === pc.KEY_O) && (this.state !== 'dancing')) {
        this.setState('dancing');
    }
};

AnimationBlending.prototype.keyUp = function (e) {
    if ((e.key === pc.KEY_O) && (this.state === 'dancing')) {
        this.setState('idle');
    }
};

I think it is because the bottom keyDown and keyUp override the previous one.

You can try to merge them:

AnimationBlending.prototype.keyDown = function (e) {
    if ((e.key === pc.KEY_P) && (this.state !== 'stretch')) {
        this.setState('stretch');
    }
    if ((e.key === pc.KEY_O) && (this.state !== 'dancing')) {
        this.setState('dancing');
    }
};

AnimationBlending.prototype.keyUp = function (e) {
    if ((e.key === pc.KEY_P) && (this.state === 'strech')) {
        this.setState('idle');
    }

    if ((e.key === pc.KEY_O) && (this.state === 'dancing')) {
        this.setState('idle');
    }
};

Worked perfectly thank you!

Hi,

The above solution fixed that initial problem, but I have one other. I am also swapping out my model (but retaining the same animation) with the below code. I have two issues:

  • When I swap to object ‘c’ - pressing the ‘Q’ key, the model swaps fine but the animation stops - but works when I go to object ‘b’.

  • Ideally, rather than start the animation again I want to carry it on so that it doesn’t restart, is there a good to way to achieve this?

Apologies for all the questions, am new to this but keen to learn and I am really enjoying the experience so far.

Thanks!

// Model swapper

var UpdateAsset = pc.createScript('updateAsset');

UpdateAsset.attributes.add('a', {
    type: 'asset',
    assetType: 'model'
});

UpdateAsset.attributes.add('b', {
    type: 'asset',
    assetType: 'model'
});

UpdateAsset.attributes.add('c', {
    type: 'asset',
    assetType: 'model'
});


UpdateAsset.prototype.initialize = function() {
    this.app.keyboard.preventDefault = true;
};


// update code called every frame
UpdateAsset.prototype.update = function(dt) {
    var app = this.app;
    
    if (app.keyboard.isPressed(pc.KEY_Q)) {
        if (this.entity.model.model !== this.b.resource) {
            // update the model component to the new model
            this.entity.model.model = this.b.resource;
        }
    } else {
        if (this.entity.model.model !== this.a.resource) {
            // restore original model
            this.entity.model.model = this.a.resource;    
        }

        if (app.keyboard.isPressed(pc.KEY_W)) {
           if (this.entity.model.model !== this.c.resource) {
            // update the model component to the new model
            this.entity.model.model = this.c.resource;
        }
    } else {
        if (this.entity.model.model !== this.a.resource) {
            // restore original model
            this.entity.model.model = this.a.resource;    
        }
    }

    } 

    // clear

    if (app.keyboard.isPressed(pc.KEY_L)) {
        app.assets.load(this.c);
    }
};

You can play the same animation on the other model and then set the currentTime property on the animation component to move it where you want. So first store the currentTime before changing models and then set it again after playing the animation.

That makes sense, thanks a lot.

Would I add that into my above code? Sorry as I say, new to this so unsure how to approach…

var AnimationBlending = pc.createScript(‘animationBlending’);

AnimationBlending.states = {
idle: {
animation: ‘Rifle Run.json’
},
punch: {
animation: ‘Great_Sword_Slash.json’
}
};

// initialize code called once per entity
AnimationBlending.prototype.initialize = function() {
this.blendTime = 0.2;

this.setState('Rifle Run.json');

this.app.keyboard.on(pc.EVENT_KEYDOWN, this.keyDown, this);
this.app.keyboard.on(pc.EVENT_KEYUP, this.keyUp, this);

};

AnimationBlending.prototype.setState = function (state) {
var states = AnimationBlending.states;

this.state = state;
// Set the current animation, taking 0.2 seconds to blend from
// the current animation state to the start of the target animation.
this.entity.animation.play(states[state].animation, this.blendTime);

};

AnimationBlending.prototype.keyDown = function (e) {
if ((e.key === pc.KEY_P) && (this.state !== ‘Great_Sword_Slash.json’)) {
this.setState(‘Great_Sword_Slash.json’);
}
};

same basic idea here, something about set State or passed to or set function