About AnimComposer use questions

I need the model to be unable to move when I release the attack animation

How do I know if the animation is currently playing or if the animation is finished playing

You can determine which animation is currently paying using this code:


Action currentAction = animComposer.getCurrentAction(); 
 //or
Action currentActionPlayingOnLayer = animComposer.getCurrentAction(layerName); //will give you the current animatino playing on a specific animationMask's layer

You can check the currentAction and use this information to avoid playing other animations or doing other things at the same time.

However you would also need to stop the attack animation when it is done playing once, because the default functionality is to loop every animation.

You can stop an animation when its done playing using Tweens to call a method at the end of an animation. (however i have personally ran into a bug using tweens like this with armatureMasks, so I cannot say if it will work in every case)

public void playAnimationOnLayer(String currentAnimation){
       this.currentAnimation = currentAnimation;
       Action action = animComposer.action(currentAnimation);
       Tween doneTween = Tweens.callMethod(this, "stopCurrentAnim");
       singleAction = animComposer.actionSequence(currentAnimation + "_nonLooping", action , doneTween);                
       animComposer.setCurrentAction(currentAnimation + "_nonLooping", layerName);
}


public void stopCurrentAnim(){        
        if(armatureMask != null){
            animComposer.removeCurrentAction(layerName);
        }
        else{
            animComposer.removeCurrentAction();
        }
        currentAnimation = null;
    }

Or you could also set a timer equal to the duration of your attack animation, and when the timer runs out you can call the method to stop the animation. (this is my preferred way, because I can set a unique timer for each armatureMask / layer so I can block animations from playing over each other per layer)

//update loop from one of my class' that stores a reference to an armatureMask and has extra data and conveneince methods for playing animations on different layers)
public void update(float tpf){        
    if(animTimer > 0 && LoopMode.DontLoop.equals(loopMode)){
        animTimer -= tpf;
        
        if(animTimer <= 0){
            this.stopCurrentAnim();
        }
    }

}

I still use references to the depreacted LoopMode enum in my own code to make things easier. Even though it is not used internally by the AnimComposer, I still use it with my own abstraction layer ( i think that abstraction layer is the correct term, my apologies if not) over top of the AnimComposer and ArmatureMasks to avoid extra boiler plate code every time I want to play an animation or determine which animation is playing in which mode on a specific layer.

1 Like

Oops my mistake, I actually do not think this code will work if you are looking for the String name of the animation that is currently playing… The Action class does not appear to have a getName() method, so there is no way to know if an action is a specific animation…

After looking at my own code, it appears that I actually have to store the name of the current animation in a String variable in my own class that serves as an AbstractionLayer overtop of each ArmatureMask.

1 Like

hello yaRnMcDonuts

As you said

com.jme3.anim.tween.action.BaseAction@4e9ab2e7

currentAction return hash
I searched the forums and couldn’t find a single case
I need to determine if my attack is done
If it is not finished, do not perform other operations
getCurrentAction() It cannot be returned correctly now

Are there any other methods or cases now :thinking: :thinking: :thinking:

 public void onAction(String name, boolean isPressed, float tpf) {
  if (BUTTON_LEFT.equals(name)&& isPressed) {// Press the left mouse button to play the attack animation
                       System.err.println("鼠标左键按下");
                    Action sk1 = control.action("sk1");
                    Tween doneTween = Tweens.callMethod(control, "setCurrentAction", "Stand");
                    Action sk1Once = control.actionSequence("sk1Once", sk1, doneTween);
                    control.setCurrentAction("sk1Once");
                         // control.setCurrentAction("sk1");
                          control.setGlobalSpeed(0.8f);

        }else if (FORWARD.equals(name)) {// Press W to move to play the moving animation
                            if (isPressed) {
                    // 播放“行走”动画
//                    animChannel.setAnim("Walk");
//                    animChannel.setLoopMode(LoopMode.Loop);// 循环播放
                         System.err.println("按下W");
                          
                          control.setCurrentAction("Walk");
                          control.setGlobalSpeed(1f);
                 
                   
                          
                } else {
                    // 播放“闲置”动画
//                    animChannel.setAnim("Idle");
//                    animChannel.setLoopMode(LoopMode.Loop);
                             System.err.println("弹起W");
                            control.setCurrentAction("Stand");
                             control.setGlobalSpeed(1f);
             
                }
            up = isPressed;
        }
}

My idea is to press the key to see if the attack animation is currently playing

If an attack animation is playing then pressing W to move will not work

For this I need to use getCurrentAction();

But getCurrentAction (); Doesn’t seem to be able to judge correctly

So now the question is what should I do

I would suggest writing your own custom class for managing the current animation state, so when you want to run an animation, you would call the playAnimation() method in your custom class. It will also make your code much cleaner, and will create a much stronger foundation for when your project grows and requires more complex animation state management.

something like this:

public class YourCustomAnimationStateManager(){
   private AnimComposer animComposer;
   public String currentAnimation = null;
   public String getCurrentAnimation(){ return currentAnimation; }

   public YourCustomAnimationStateManager(AnimComposer animComposer){
           this.animComposer = animComposer;
   }
   
   public void playAnimation(String animationString, float speed){
          this.currentAnimation = animationString;


         //code to play your animation here: 
          animComposer.setCurrentAction(animationString);
          animComposer.setGlobalSpeed(speed);

     //can add more code here in the future to determine if the animation should play any doneTweens or if it is a looping or non looping animation

   }

}

And then you can change your walk code like this to check if an attack animation is being played, and block movement if it is being played:

public void onAction(String name, boolean isPressed, float tpf) {
      if (BUTTON_LEFT.equals(name)&& isPressed) {// Press the left mouse button to play the attack animation
              System.err.println("鼠标左键按下");

              yourCustomAnimationStateManager.playAnimation("sk1", 0.8f);

        }else if (FORWARD.equals(name) && !yourCustomAnimationStateManager.getCurrentAnimation().equals("sk1")) {// Press W to move to play the moving animation
               if (isPressed) {
                    // 播放“行走”动画
                    yourCustomAnimationStateManager.playAnimation("walk", 1.0f);
                 
                   
                          
                } else {
                    // 播放“闲置”动画
                    yourCustomAnimationStateManager.playAnimation("stand", 1.0f);
             
                }
            up = isPressed;
        }
}
1 Like
    public void playOneAnimation(String animationString, float speed,String animationTransitionString){
          this.currentAnimation = animationString;
         //code to play your animation here: 
           Action action = animComposer.action(animationString);
           Tween doneTween = Tweens.callMethod(animComposer, "setCurrentAction", animationTransitionString);
           Action actionOnce = animComposer.actionSequence(animationString+"Once", action, doneTween);               
          animComposer.setCurrentAction(animationString+"Once");               
          animComposer.setGlobalSpeed(speed);
     //can add more code here in the future to determine if the animation should play any doneTweens or if it is a looping or non looping animation
    }

I tried to use the example you gave to write a way to play some actions only once and make transitions(Like the attack animation)

I found a problem that I couldn’t change “String currentAnimation” when the action finished playing and transitioned to another action.

Now back to our original question, how do I know when the animation is finished
(creating a Manager is a great idea.)
(I’m very sorry to bother you and your reply was very helpful to me. The content on the wiki may be a little out of date and I couldn’t find what I needed)

This code uses the done tween to call the stopCurrentAnim() method when the action is done playing

So when stopCurrentAnimis called, that’s when you know the animation is finished.

Specifically, this line is creating a sequenced action where it first plays the singleAction and then plays the doneTween when the singleAction is finished

singleAction = animComposer.actionSequence(currentAnimation + "_nonLooping", action , doneTween);

1 Like

@icyboxs I suggest taking a look at the Tweens tutorial, it will help you better understand how to use them: Effects and Animation · jMonkeyEngine-Contributions/Lemur Wiki · GitHub

Tweens were first introduced in the Lemur GUI library and then found their way to JME’s new animation system.

1 Like

Thank you for your help and guidance

Thank you for reminding me

I’m using SDK version 3.3.0 and there is no such method called “getCurrentAction” in AnimComposer class.
Am I missing something or doing something wrong ?

I took a look at the branches on github, and it appears that getCurrentAction() is not a method in version 3.3

It looks like the method exists in version 3.4 and all versions since then.

I would recommend upgrading to the newest version which is 3.5.2 stable if you can, it should be fairly easy if you are using the gradle template for your project. And if not, then now could be a good time to switch to gradle so you can use newer engine versions.

1 Like

Thanks,just downloaded jmonkey 3.5.2 and replaced project libraries and now i can use “getCurrentAction()” method.

3 Likes

sweet, and also welcome to the forums!

1 Like