How to find when an entity animation ends?


#1

Hello, first post. :slight_smile: I wonder if there is a preferred practice for finding when an entity animation hits a particular frame. I am mostly interested in finding when an entity animation ends.

Suppose we have a 30-frame, no-loop animation running at 15 FPS. The following appears to work:

//The animation starts playing.

Script.setTimeout(function() {
  print("The animation just stopped.");
}, 2000); 

However, is time the best way to go about this? Is there some way to know when the last frame has been reached?

I know there’s currentFrame. So something like the following appears to work too:

//The animation starts playing.

var timer = Script.setInterval(function() {
  if (Entities.getEntityProperties(entityID).animation.currentFrame == 30) {
    print("The animation just stopped.");
    Script.clearInterval(timer);
  }
}, 20);

But, again, is this the best way to go about this?

I have seen in some of the scripts around here that Script.update.connect(callbackFunction) is being used to keep track of “frames”? I don’t understand what this method does. What frames does it keep track of? Can I use this to keep track of entity animation frames?


#2

Greetings,

Entity animations are defined by the state of an entity. This state may not always be perfectly synced between clients, but the Domain always updates the entity it self to a specific frame.

You could check if the entity animation has stopped running by checking the running flag of the animation Object provided in the entity properties.


For example This following entity script starts an connects its callback to the update thread, start an animation, then waits until the animation is done: after which it prints to logs and disconnects it self.:

(function(){
   AnimationEntity = function(){return;}
   AnimationEntity.prototype = {
      entityID: null,
      preload: function(entityID){ 
            // Called when loaded as a specific instance of an entity's script.
            this.entityID = entityID;
            // Connect this object instance's callback "updateThread" to the frame update thread of the client
            Script.update.connect(this.updateThread);
           // Edit the entity to start the animation
            Entities.editEntity(this.entityID, {
                animation:{
                    fps: 15,
                    running: true,
                    url: "<insertURLAnimationHere>",
                    startFrame: 0, 
                    endFrame: 120,
                    hold: true,
                    loop: false
                }
            } );
      },
      updateThread: function(dt){
         entity = Entities.getEntityProperties(this.entityID);
         if(entity.animation.running && entity.animation.currentFrame < entity.animation.lastFrame){
            // running
         }else{
            // animation no longer running Disconnect the callback from thread.
            Script.update.disconnect(this.updateThread);
         }
      }
   }
// Gives the entity its prototypial objects, so that preload can be called.
   return new AnimationEntity();    
})


Scripts them selves are client side, so if you have script running on the entity.

Basically this:

Script.update.connect

Connects a callback from the script to the frame update thread of the client.

This means the update is called every frame the client runs on: if you are running at 60 fps, then 60 times per second, if 30 fps, then 30 fps a second. the parameter in the callback, basically is the number of seconds when the last frame was called.

A thing of note however is to avoid doing edits on the entity level at this rate. If doing so, make sure you have a throttle and a way to compensate for the time between updates.

Hopefully that helps :slight_smile:


#3

Thanks @Menithal, it sure helps.

So, as I understand it (since I’m kinda new to most of this), entity animations run client-side. Different clients may run the same animation slightly out of sync. Script.update.connect(callback) runs the callback function once every client frame. And it’s the preferred way of working with entity animations since, in this way, everything is kept client-side.

Ok. I still have a small issue though (although I might have messed it up). running does not turn false once the animation has stopped. It stays true, as it was initially set up. It’s possible that I messed up the code though. I had to rewrite the code you provided because I don’t quite understand JavaScript prototypes. I need to read up on them (again) :confused:

(function() {
    var thisEntityID;
    this.preload = function(entityID) {
        thisEntityID = entityID;
        Script.update.connect(updateThread);
        Entities.editEntity(thisEntityID, {
            animation: {
                url: "some_anim.fbx",
                fps: 15,
                currentFrame: 0,
                running: true,
                loop: false,
                firstFrame: 0,
                lastFrame: 30,
                hold: true
            }
        });
    }
    function updateThread(deltaTime) {
        if (Entities.getEntityProperties(thisEntityID).animation.running) {
            print("The animation is currently running.");
        } else {
            print("The animation just stopped running."); // This is never printed.
            Script.update.disconnect(updateThread);
        }
    }
})

#4

Maybe you could try the current frame.
If it’s 30 the animation must have ended.


#5

Oh yes. Forgot about that one. Thanks.


#6

Yeah, as @Ron.Khondji pointed out, you can switch the running check in the if a check on the currentFrame vs the lastFrame of the property.