[SOLVED] JME 3.1 Animation LoopMode.DontLoop does not work

I have class:
public class EnemyControl extends AbstractControl implements AnimEventListener {

there, in the controlUpdate method, I start animation like this:

if (spatialControl.getNumChannels()>0) {
// ...some code ... 
} else {
        spatialControl.addListener(this);
        AnimChannel enemyAnimChannel = spatialControl.createChannel();
        enemyAnimChannel.setLoopMode(LoopMode.DontLoop);
        enemyAnimChannel.setAnim("Two steps");
}

But when animation stops, it starts again in endless loop.
The only way to kill it is here:

@Override
public void onAnimCycleDone(AnimControl control, AnimChannel channel, String animName) {
    // That is the only way to stop animation currently
    control.setEnabled(false);
}

Is it a known issue?

1 Like

DontLoop works for me.
You’d have to provide a little more info for us to be able to help.
Maybe you could post your whole class?

Hi Robbi,

here it is (sorry for bad code, I am still beginner with JME):

package mygame;
    import com.jme3.animation.AnimChannel;
    import com.jme3.animation.AnimControl;
    import com.jme3.animation.AnimEventListener;
    import com.jme3.animation.LoopMode;
    import com.jme3.math.FastMath;
    import com.jme3.math.Vector3f;
    import com.jme3.renderer.RenderManager;
    import com.jme3.renderer.ViewPort;
    import com.jme3.scene.Spatial;
    import com.jme3.scene.control.AbstractControl;

    /**
     *
     * @author guest
     */
    public class EnemyControl extends AbstractControl implements AnimEventListener {

        private GamePlayAppState gamePlayState;
        private Vector3f currentTranslation;
        private Vector3f newTranslation;

        public EnemyControl(GamePlayAppState state) {
            this.gamePlayState = state;
        }

        @Override
        protected void controlUpdate(float tpf) {
            if (spatial.getUserData("health") != null) {
                if ((int) spatial.getUserData("health") <= 0) {
                    spatial.removeFromParent();
                } else {
                    moveToBase(spatial, tpf);
                }
            }
        }

        @Override
        protected void controlRender(RenderManager rm, ViewPort vp) {
    //        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
        }

        private void moveToBase(Spatial spatial, float tpf) {
    // Check animation frame and stop movement
    AnimControl spatialControl = spatial.getControl(AnimControl.class);
    if (spatialControl.getNumChannels()>0) {
        AnimChannel spatialChannel = spatialControl.getChannel(0);
        float animTime = spatialChannel.getTime();
        if ( (animTime > 1.6f) && (animTime < 1.8f)) {
            return;
        }
        if (animTime > 3.2f) {
            return;
        }
    } else {
    // Start movement randomly for each Enemy Unit    
    //Should be done by Userget value, to control it better later
        if (FastMath.nextRandomInt(0, 200)==1) {
            spatialControl.addListener(this);
            AnimChannel enemyAnimChannel = spatialControl.createChannel();
            enemyAnimChannel.setLoopMode(LoopMode.DontLoop);
            enemyAnimChannel.setAnim("Two steps");
        }
        return; // (Stop movement
    }

    //Base starts at X = -3.5 and has size of 0.5 (probably from -3.5 to -3)
    // Base starts at Y = -0.5 and has size of 1
            currentTranslation = spatial.getLocalTranslation();
            float distance = tpf/2;
            if (currentTranslation.x < -6f ) {
                gamePlayState.playerData.setHealth(gamePlayState.playerData.getHealth() - 1);
                spatial.removeFromParent();
    //Destroy control and make minus 1 life            
            } else {
                newTranslation = new Vector3f(-distance, 0, 0f);
    //            if (currentTranslation.y < -0.4 ) {
    //                newTranslation.y = distance*0.7f;
    //            }
    //            if (currentTranslation.y > 0.4) {
    //                newTranslation.y = -distance*0.7f;
    //            }
                if (newTranslation.y != 0) {
                    newTranslation.x = -distance*0.7f;
                }
                spatial.setLocalTranslation(currentTranslation.add(newTranslation));
            }
        }

        @Override
        public void onAnimCycleDone(AnimControl control, AnimChannel channel, String animName) {
            // That is the only way to stop animation currently
            control.setEnabled(false);
        }

        @Override
        public void onAnimChange(AnimControl control, AnimChannel channel, String animName) {
        }
    }

Hello @Denis_Tislenko

Yes, it is!

When you have a look at the source code of AnimChannel you can see that when you call

enemyAnimChannel.setAnim("Two steps");

That will set the LoopMode to Loop again.

You can solve this issue by just setting the LoopMode after you called .setAnim();

if (spatialControl.getNumChannels()>0) {
// ...some code ... 
} else {
        spatialControl.addListener(this);
        AnimChannel enemyAnimChannel = spatialControl.createChannel();
        enemyAnimChannel.setAnim("Two steps");
        enemyAnimChannel.setLoopMode(LoopMode.DontLoop);   
}
3 Likes

Wow, perfect Domenic, nice solution!

:grinning::chimpanzee_cool: