[SOLVED] When AnimComposer reaches the end of an Action

In JME 3.2, each AnimChannel has a LoopMode that controls what it does when it reaches the end of an Animation. Furthermore, there’s an AnimEventListener interface that makes it simple to detect when an AnimChannel reaches the end of an Animation.

I’m currently reworking TestBoneRagdoll to use the new animation system. I’ve figured out how to play an action using AnimComposer.setCurrentAction() but not how to prevent the action from looping or detect when it is about to loop.

Has anyone figured out how do these things in JME 3.3?

3 Likes

@sgold thanks for asking this :slightly_smiling_face:

There are couple of ways to do this.

As you know I made a PR to add support for looping in AnimComposer. It is not merged yet.

https://github.com/jMonkeyEngine/jmonkeyengine/pull/1038

workaround is to create your own Action by extending BaseAction.

for example :

public class CharacterAction extends BaseAction {
        
        AnimComposer ac;
        String layer;
        boolean loop;
        
        public CharacterAction(Tween delegate, AnimComposer ac, String layer, boolean loop) {
            super(delegate);
            this.ac = ac;
            this.layer = layer;
            this.loop = loop;
        }

        public boolean isLooping() {
            return loop;
        }
        
        public void setLooping(boolean loop){
            this.loop = loop;
        }
        
        @Override
        public boolean interpolate(double t) {
            boolean running = super.interpolate(t);
            if (!loop && !running) {
               // animation done running, now we can :
               // set speed on this action to 0 to stop
               this.setSpeed(0);
               
               // or we can remove this action from the layer it is attached to 
               ac.removeCurrentAction(layer); 
               //or this if we are using DEFAULT_LAYER 
               ac.removeCurrentAction(AnimComposer.DEFAULT_LAYER);
               
            }
            return running;
        }
        
    }

You can use this method to add your own action :

Another way is to add a CallMethod tween at the end of sequence then this CallMethod tween will get run at the end of animation.

For example you can call “removeCurrentAction” method on AnimComposer :

BaseAction myAction = new BaseAction(Tweens.sequence(delegate, Tweens.callMethod(ac, "removeCurrentAction", layer)));

3 Likes

Thank you!

I used the CallMethod technique in both TestBoneRagdoll and TestRagdollCharacter.

For me, the key insight was that Action implements Tween. Once I realized that, things went fairly smoothly.

5 Likes

Reactive an old chain. I was putting my first animation into the game, and I used the CallMethod to figure out when the animation is done.

My question is when you define a BlendAnimation. How do you know the animation is completed. Since it doesn’t take Tweens. You define it with string name of actions. Those actions have a Tween callmethod. but the callMethod doesn’t get called when doing a BlendAnimation.

            Tween doneTween = Tweens.callMethod(this, "onSnakeDoneWalking");
            composer.actionSequence("walk",
                    composer.makeAction("walk"), doneTween).setSpeed(1);

            composer.actionSequence("attack",
                    composer.makeAction("attack"), doneTween).setSpeed(1);

            action = composer.actionBlended("attackBlend", new LinearBlendSpace(0.1f, 0.5f),
            		"attack", "walk");

Thanks for your help.

You can do something like:


attackBlend = composer.actionBlended("attackBlend", new LinearBlendSpace(0.1f, 0.5f),
            		"attack", "walk");

composer.actionSequence("attackBlend", attackBlend, doneTween);

By the way, why do you need to blend “walk” animation with “attack”?

1 Like

It was just testing. Never did animation before other than through sprite sheets for quads.

The wiki pages are old and don’t work for the new animation system.