Gltf Animation paused at last frame

I have a hero, he has attack and death actions, I want to stay in the last frame after the execution of the death action, which is the way he fell to the ground, instead of continuing to attack,I try the following code, not the result I want。It seems that the start method has no parameters to allow the animation to stay at the last frame after execution

 const action = scene.getAnimationGroupByName('11254_die')
            action.start(false, 1.0, action.from, action.to, true)
            action.onAnimationEndObservable.add(()=>{
              action.pause()
            })

action.start(false, 1.0, action.from, action.to, true)

this mean
Let’s say your Aaniamtion has frame 0 to 100

and If around frame 80 he decides to take a nap, the you try to this

action.start(false, 1.0, 0, 80, true)

check this PG
https://playground.babylonjs.com/#Z6SWJU#750
and check if other animations are working

const sambaAnim = scene.getAnimationGroupByName("Samba"); const idleAnim = scene.getAnimationGroupByName("Idle"); idleAnim.stop(); //Play the Samba animation sambaAnim.start(false, 1.0, 0, 80, true);
I found this, the next action starts playing, and it stops at a certain frame. The first step is to stop the current action. Is this a trick to use? I commented out the stop of the previous action and found that the effect is that the latter action is only executed once

I just encountered a bug related to stop. One of my heroes has some idle, attack, and die actions. I use const action=scene.getAnimationGroupByName(‘11254_idle’) to get him, action.start(false, 1.0, action.from, action.to, true) and play it. The default is the idle action. The die action can be called directly to take effect, but if the attack action wants to take effect, the idle action must be stopped first. Calling attack.start() alone is Not valid. I don’t know what is the reason for this. There is no problem playing these actions in the sandbox

It’s a little disorienting So to make it easier to understand, let’s break it down

  1. your Character hav animationGroup(“idle”), animationGroup(“attack”) and animationGroup(“die”)
  2. It’s frames 0 to 100 from each other (ex)
  3. When your Character are “die” in your logic
  4. You want to stop this state, right?

If the last frame of “die” is lying down, the frame can be up to the end of the to frame.

let Idle = getAnimationGroupByName(“idle”);
let attack = getAnimationGroupByName(“attack”);
let die = getAnimationGroupByName("die ");
Idle.start(true, 1.0) //this loop


//when you want stop this state
Idle.stop()
die.start(false,1.0); //just frame 0 to 100(ex: your animation Max frame is 100) and this pause();

animaitonguorp[0] can be executed automatic also, if you’ve set up looping behavior, this is the
will work with other animations and when the other junior animation finishes, the animation left in the previous loop will work.

The goToFrame function doesn’t seem to work. I want to use the following code to achieve my idea above, when the character’s death action is executed, the character goes to the last frame of the death action

const action = scene.getAnimationGroupByName('11254_die')
action.start(false, 1.0, action.from, action.to, true)
action.onAnimationEndObservable.add(() => {
     action.goToFrame(action.to)
})

If I understand you correctly, the change this

const action = scene.getAnimationGroupByName(‘11254_die’)
action.start(false, 1.0, action.to, action.to, true);

”die“ This action does not take effect, and the default action will be played. Drag the model to the action played by default in the sandbox

Does that mean “idle” will run again? :smiling_face_with_tear:
If you set up an idle loop
do

Idle.stop()
const action = scene.getAnimationGroupByName(‘11254_die’)
action.start(false, 1.0, action.to, action.to, true);

If this is not the case, then there must be some other rule or logic involved. Can we share the model?

If that’s not possible, can we get as close as possible with this PG

yes,If I use idle.stop() before executing the die, after the execution of the die, it will automatically execute the next action, such as attack. Every time the character falls to the ground and dies, it will immediately rise up and attack. In this case, I choose without idle.stop()

Are you also running “attack” in a loop?
Or did you do

(“die”).onAnimationEndObservable.add(() => {
(“attack”).start();
})

?

const B = sceneAssetsManager.addMeshTask('A', '', 'https://xxxx', '11256.glb')
      B.onSuccess = (task) => {
        task.loadedMeshes[0].position = new Vector3(0, 0, -groundSize / 2 + 4)
        task.loadedMeshes[0].scaling = new Vector3(heroScale, heroScale, heroScale)
        BIdle = scene.getAnimationGroupByName('11256_idle')
        BAttack = scene.getAnimationGroupByName('11256_attack')
        BDie = scene.getAnimationGroupByName('11256_die')
        BEnter = scene.getAnimationGroupByName('11256_enter')
        BIdle.start(true, 1.0, BIdle.from, BIdle.to, false)
      }

This is my code. I will get the animation data after the model is successfully pulled, and then execute the default model of idle. If I don’t execute idle, it will automatically execute attack

In the next case, I will choose to play the action data obtained above according to the state in the render function

createScene().then((scene) => {
      engine.runRenderLoop(function () {
     if (_vue.state == 17) {
            console.log('B die')
            BDie.start(false, 1.0, BDie.form, BDie.to, true)
          } else if (_vue.state == 18) {
            console.log('B attack')
            BIdle.stop()
            BAttack.start(false, 1.0, BAttack.form, BAttack.to, true)
          }
          else if (_vue.state == 19) {
            console.log('B idle')
            BIdle.start(true, 1.0, BIdle.form, BIdle.to, true)
          } else if (_vue.state == 20) {
            console.log('B enter')
            BEnter.start(false, 1.0, BEnter.form, BEnter.to, true)
            BEnter.onAnimationEndObservable.add(()=>{
              BIdle.start(true, 1.0, BIdle.form, BIdle.to, true)
            })
          }

})

For the attack action, I have to use idle first, and the rest of the actions can be called directly, because the attack action is the default action?

Now I have a trickier problem. I imported a model with three actions: idle, attack, and die. I used createInstance to create 100 clones. How to manage the actions of these clones separately. For example, some will execute die, some will execute attack, and some will execute idle actions.

Okay, that’s clearer.

  1. BIdle.start(true, 1.0, BIdle.from, BIdle.to, false) iis looping, so it must be stopped before any other animation can run.

so

createScene().then((scene) => {
engine.runRenderLoop(function () {
if (_vue.state == 17) {
console.log(‘B die’)
if(BIdle.isPlaying) BIdle.stop();
if(BAttack.isPlaying) BAttack.stop();
BDie.start(false, 1.0, BDie.form, BDie.to, true)
_vue.state = 0;
} else if (_vue.state == 18) {
console.log(‘B attack’)
if(BIdle.isPlaying) BIdle.stop();
if(BDie.isPlaying) BDie.stop(); /If you want a dead character to get up and attack. If not, remove this line
BAttack.start(false, 1.0, BAttack.form, BAttack.to, true)
_vue.state = 0;
}
else if (_vue.state == 19) {
console.log(‘B idle’)
if(BIdle.isPlaying) BIdle.stop();
if(BAttack.isPlaying) BAttack.stop();
BIdle.start(true, 1.0, BIdle.form, BIdle.to, true)
_vue.state = 0;
} else if (_vue.state == 20) {
console.log(‘B enter’)
if(BIdle.isPlaying) BIdle.stop();
if(BAttack.isPlaying) BAttack.stop();
if(BDie.isPlaying) BDie.stop();
> BEnter.start(false, 1.0, BEnter.form, BEnter.to, true)
> // BEnter.onAnimationEndObservable.add(()=>{
> // BIdle.start(true, 1.0, BIdle.form, BIdle.to, true)
> //})
_vue.state = 0;
}
})

runRenderLoop iterates over the frame par second and returns the
so you need to block the value of_vue.state at the end of it
(ex: _vue.state = 0)

1 Like

This means that

  1. the role of the object to fill its surroundings
  2. have constant interaction, such as NPCs or AIs
    Which of these are you closer to?

I use it like this. In conjunction with havok, I use cubes to replace soldiers. There are hundreds of them. When they collide, soldiers will be injured. If their HP is deducted, soldiers will die. Now I have implemented this logic with cubes. I need to introduce a gltf model, and then play the actions they carry at the corresponding time. For example, when going out, soldiers will play the run action, when they collide, they will play the attack action, and when their hp is exhausted, they will play the death action.

 const Bsoldier = sceneAssetsManager.addMeshTask('A', '', 'https:/xxx', '3001.glb')
      Bsoldier.onSuccess = (task) => {
        task.loadedMeshes[0].scaling = new Vector3(heroScale, heroScale, heroScale)
         BsoldierAttack = scene.getAnimationGroupByName('3001_attack')
        BsoldierRun = scene.getAnimationGroupByName('3001_run')
        BsoldierDie = scene.getAnimationGroupByName('3001_die')
        BsoldierDie.start(false, 1.0, BsoldierDie.from, BsoldierDie.to, true)

        for (let i = 0; i < 1000; i++) {
          const instance1 = task.loadedMeshes[1].createInstance(i)
          instance1.position.x = Math.random()*100
          instance1.position.z = Math.random()*100
          instance1.scaling = new Vector3(heroScale, heroScale, heroScale)
        }
      }

The existing examples seem to be for a single object, how to animate the instantiated object?

It’s a tricky thesis
First of all, there are two limitations to keep in mind

  1. your AnimationGroup needs skeletons
    Of course, it’s possible to do without skeletons
    https://playground.babylonjs.com/#ZZVZUN#1
    but This is probably keyframes

  2. Instances share the material, skeleton, etc. of the parent mesh, which means that when you animate the parent mesh, the instances will also run.


If I were working in your situation, I would consider two things

  1. Clone to AssetContainer.instantiateModelsToScene();with a minimum value in the model, and then use the Fill in only what you need
    However, this is great for small numbers but can be very expensive in your case.
  2. “idle”,“run”,“attack” recreate a new instance every time without using the original

Of course, there are more efficient ways to do this if you look for them.

Thanks for your advice. I will try it. At present, I have created 1000 clones using thin instances and the fps has dropped to 60. For this project, what is needed is the number, and action switching has now given way to this requirement. If I use clones to implement each model, it can Manage your own animations yourself, but you can only create 100 or even less, which is not what we want

1 Like

It’s very cheap to create objects with four thin instances Good luck :+1: