How to stop an animation to start other

I have a character developed with Blender and it has several actions loaded. Each action is loaded in a different channel.

In my Java code, I have diverse conditions that could be triggered. When a condition is triggered, it is expected for an action to get fired. This kind of works. The problem is that the new fired action has to wait for the current action to finish and then it is played.

Is there any way to stop the current action to give place to the new action to be played?

I tried using the “channel.reset(true)” but it did not work.

Your code looks fine from here. I can’t see the problem.

1 Like

I found no info on this myself when learning this but what I did was to set the AnimChannel to max time.

The way AnimationControl works in my example is it uses an AnimEventListener where all it does is check UserData for a int position type (see EnumPosType) every time an animation ends and sets a new animation based off that type.

So I set the positionType() before calling stop because the AnimationControl will check position type immediately upon animation end.

Edit: Forgot to mention, Im not a pro at this so others may have a better answer. What Paul is saying is he cant read your code/mind if you don’t show any.

Did you read this? https://jmonkeyengine.github.io/wiki/jme3/beginner/hello_animation.html#toolbar

Yes.

•Optionally, use channel.setTime() to Fast-forward or rewind to a certain moment in time of this animation.

This is an accurate description of what setTime() does but its not really descriptive of what it should be used for.

Note: my read of OP’s post is that he does’t want to wait until one animation finishes until the next one plays. He wants it to switch right away and it isn’t.

But my experience is that the animation will already switch right away… which is why I thought seeing his code might be useful.

Hi all, thanks for your promptly responses.

I tried your suggestions, using the setTime to maxTime but it does not work :frowning:

Here is my code, I hope it is clear enough. Hope to hear from you soon :slight_smile:

I have a class called Viewer.java… inside this class, I have this line of code:

   actionController.animate(actionToPlay, 0.75f, 1f, 1, AudioMessage.getAudioLength());

As you may infer, there is another class called ActionController that has a method called animate(…)

Here is the code of the class. I am reusing this class from Tommi S.E. Laukkanen. I am adjusting it as I need.

package Companion;

import BehaviorEngine.BehaviorEngine;
import com.jme3.animation.*;
import com.jme3.scene.Geometry;
import com.jme3.scene.Node;
import com.jme3.scene.SceneGraphVisitorAdapter;
import com.jme3.scene.Spatial;
import java.util.*;

/**
 * Animates multi mesh models with multiple AnimControllers.
 * @author Tommi S.E. Laukkanen
 */
public class ActionController {
    /**
     * Character animation controllers.
     */
    final Map<String, AnimControl> animControls = new HashMap<>();
    /**
     * Character animation channels.
     */
    final Map<String, AnimChannel> animChannels = new HashMap<>();
    /**
     * The character animator listener.
     */
    private ActionListener animationListener;
    /**
     * Name of the last animation played.
     */
    private String animationName = null;
    private String lastAnimationName = null;
    private AnimChannel lastChannel = null;
    private AnimControl lastControl = null;
    /**
     * The animation speed multiplier.
     */
    private float speedMultiplier = 0f;
    /**
     * The loop count.
     */
    private int loopCount = 0;
    /**
     * The animation max time.
     */
    private float animationMaxTime = 0f;
    /**
     * The animation time.
     */
    private float animationTime = 0f;

    /**
     * Constructor which gets animation controls from character spatial recursively
     * and create animation channels.
     * @param character the character spatial
     */
    public ActionController(final Spatial character) {
        SceneGraphVisitorAdapter visitor = new SceneGraphVisitorAdapter() {
            @Override
            public void visit(final Geometry geometry) {
                super.visit(geometry);
                checkForAnimControl(geometry);
            }

            @Override
            public void visit(final Node node) {
                super.visit(node);
                checkForAnimControl(node);
            }

            /**
             * Checks whether spatial has animation control and constructs animation channel
             * of it has.
             * @param spatial the spatial
             */
            private void checkForAnimControl(final Spatial spatial) {
                AnimControl animControl = spatial.getControl(AnimControl.class);
                if (animControl == null) {
                    return;
                }
                final AnimChannel animChannel = animControl.createChannel();
                animControls.put(spatial.getName(), animControl);
                animChannels.put(spatial.getName(), animChannel);
            }
        };
        character.depthFirstTraversal(visitor);
    }

    /**
     * Plays animation.
     *
     * @param animationName the animation
     * @param speedMultiplier the speed multiplier (1 = animation native speed, 2 = double speed...)
     * @param blendTime the blend time in seconds
     * @param loopCount the loop count or 0 for infinite looping
     * @param audioLength the time that last the audio, if any, related to the action
     */
    public void animate(final String animationName, final float speedMultiplier, final float blendTime,
                        final int loopCount, long audioLength) {
        
        //This is to stop the current animation
        System.out.println("Animation being played: " + this.lastAnimationName);
        System.out.println("Animation to be played: " + animationName);
        stopCurrentAnim();

        this.loopCount = loopCount - 1;
        this.animationName = animationName;
        this.speedMultiplier = speedMultiplier;
        this.animationTime = 0;
        this.animationMaxTime = 0;
        
        for (final String spatialName : animChannels.keySet()) {
            final AnimControl animControl = animControls.get(spatialName);
            final Animation animation = animControl.getAnim(animationName);
            if (animation != null) {
                final AnimChannel animChannel = animChannels.get(spatialName);
                
                this.lastChannel = animChannel;
                this.lastAnimationName = animationName;

                if (blendTime != 0) {
                    animChannel.setAnim(animationName, blendTime);
                } else {
                    animChannel.setAnim(animationName);
                }
                
                //If LoopMode is Loop - the animation on this channel will repeat from the beginning when it ends.
                //If LoopMode is DontLoop - the animation on this channel will play once, and the freeze at the last keyframe.
                animChannel.setLoopMode(LoopMode.Loop);
                //animChannel.setLoopMode(LoopMode.DontLoop);
                animChannel.setSpeed(speedMultiplier);
                this.animationMaxTime = animChannel.getAnimMaxTime();
            }
        }
    }
    
    public void onAnimChange(AnimControl control, AnimChannel channel, String animName) {
     // no used
    }
    
    private void stopCurrentAnim (){
      if (this.lastChannel != null){
        System.out.println("Current channel is != null");
        System.out.println("Stopping animation: " + this.lastAnimationName);
        this.lastChannel.setTime(this.lastChannel.getAnimMaxTime());
      }  
    }
    /**
     * Gets list of spatial names with animations.
     * @return list of spatial names
     */
    public Collection<String> getSpatialNamesWithAnimations() {
        return animControls.keySet();
    }

    /**
     * Gets animation control with spatial name.
     * @param spatialName the spatial name
     * @return the animation control or null
     */
    public AnimControl getAnimControl(final String spatialName) {
        return animControls.get(spatialName);
    }

    /**
     * Gets last animation played.
     * @return the last animation name or null
     */
    public String getAnimationName() {
        return animationName;
    }

  public float getAnimationMaxTime() { 
    return animationMaxTime;
  }

  public float getAnimationTime() {
    return animationTime;
  }

  public void setAnimationTime(float animationTime) {
    this.animationTime = animationTime;
  }

    
    
    
    /**
     * Updates animation manually.
     * @param tpf time per frame
     */
    public void update(final float tpf) {
        if (animationTime > 0f && animationTime > animationMaxTime) {
            if (loopCount == 0) {
                speedMultiplier = 0f;
                animationListener.onAnimCycleDone(animationName);
            } else {
                loopCount--;
            }
            animationTime = 0f;
        }

        animationTime = animationTime + speedMultiplier * tpf;

        for (final AnimChannel channel : animChannels.values()) {
            channel.setSpeed(0f);
            channel.setTime(animationTime);
        }
    }

    /**
     * Sets character animator listener.
     * @param animationListener the character animator listener
     */
    public void setAnimationListener(final ActionListener animationListener) {
        this.animationListener = animationListener;
    }

}```

Sorry about the lack of format in my previous post… as you requested/suggested, I formatted it.