Hello Animation: Stuck on multiple channels

I’m doing the extra exercises in Tutorial 7: Hello Animation (“Make a mouse click trigger another animation sequence!”). I have the extra channel and input working, but in doing it I’ve created two problems:



  • 1. My golem plays the Dodge animation upon program startup, but moving (or deleting) the setAnim in simpleInitApp() always results in crashes. What have I forgotten?

  • 2. After adding a second channel for the Dodge animation, the Walk animation has slowed down so that only the feet and hands move. It looks like the model is trying to both stand still and walk. How do I avoid this?



[java]
package jme3test.helloworld;

import com.jme3.animation.AnimChannel;
import com.jme3.animation.AnimControl;
import com.jme3.animation.AnimEventListener;
import com.jme3.animation.LoopMode;
import com.jme3.app.SimpleApplication;
import com.jme3.input.KeyInput;
import com.jme3.input.MouseInput;
import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.KeyTrigger;
import com.jme3.input.controls.MouseButtonTrigger;
import com.jme3.light.DirectionalLight;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.jme3.scene.Node;
import com.jme3.scene.debug.SkeletonDebugger;
import com.jme3.material.Material;

/** Sample 7 - how to load an OgreXML model and play an animation,
* using channels, a controller, and an AnimEventListener. */
public class HelloAnimation extends SimpleApplication implements AnimEventListener {

private AnimChannel channel;
private AnimChannel channel2;
private AnimControl control;
Node player;

public static void main(String[] args) {
HelloAnimation app = new HelloAnimation();
app.start();
}

@Override
public void simpleInitApp()
{
viewPort.setBackgroundColor(ColorRGBA.LightGray);
initKeys();
DirectionalLight dl = new DirectionalLight();
dl.setDirection(new Vector3f(-0.1f, -1f, -1).normalizeLocal());
rootNode.addLight(dl);

player = (Node) assetManager.loadModel("Models/Oto/Oto.mesh.xml");
player.setLocalScale(0.5f);
rootNode.attachChild(player);
control = player.getControl(AnimControl.class);
control.addListener(this);

channel = control.createChannel();
channel.setAnim("stand");

channel2 = control.createChannel();
channel2.setAnim("Dodge");

// // Find names of animations in model
// for (String anim : control.getAnimationNames())
// {
// System.out.println(anim);
// }
// // Dodge, Walk, stand, pull, push

// Skeleton debugger
SkeletonDebugger skeletonDebug = new SkeletonDebugger("skeleton", control.getSkeleton());
Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
mat.setColor("Color", ColorRGBA.Green);
mat.getAdditionalRenderState().setDepthTest(false);
skeletonDebug.setMaterial(mat);
player.attachChild(skeletonDebug);
}

public void onAnimCycleDone(AnimControl control, AnimChannel channel, String animName)
{
// CAUTION
// It seems that these two animations are cancelling each other out. When the golem tries to
// walking while also standing still (since he's not dodging), it stifles his walk animation.
if (animName.equals("Walk"))
{
channel.setAnim("stand", 0.50f);
channel.setLoopMode(LoopMode.DontLoop);
channel.setSpeed(1f);
}
if (animName.equals("Dodge"))
{
channel2.setAnim("stand", 0.50f);
channel2.setLoopMode(LoopMode.DontLoop);
channel2.setSpeed(0.5f);
}
}

public void onAnimChange(AnimControl control, AnimChannel channel, String animName)
{
// Unused
}

// Custom keybinds: map named actions to inputs
private void initKeys()
{
inputManager.addMapping("Walk", new KeyTrigger(KeyInput.KEY_SPACE));
inputManager.addMapping("Dodge", new MouseButtonTrigger(MouseInput.BUTTON_LEFT));
inputManager.addListener(actionListener, new String[] {"Walk", "Dodge"});
}

private ActionListener actionListener = new ActionListener()
{
public void onAction(String name, boolean keyPressed, float tpf)
{
if (name.equals("Walk") && !keyPressed)
{
if (!channel.getAnimationName().equals("Walk"))
{
channel.setAnim("Walk", 0.50f);
channel.setLoopMode(LoopMode.Loop);
}
}
if (name.equals("Dodge") && !keyPressed)
{
if (!channel2.getAnimationName().equals("Dodge"))
{
channel2.setAnim("Dodge", 0.05f);
channel2.setLoopMode(LoopMode.DontLoop);
}
}
}
};
}
[/java]

Look at the output console sometimes is useful, channel.getAnimationName() is nil if you don’t set it at start. Try this:



[java]

private ActionListener actionListener = new ActionListener()

{

public void onAction(String name, boolean keyPressed, float tpf)

{

if (name.equals(“Walk”) && !keyPressed)

{

if (!“Walk”.equals(channel.getAnimationName()))

{

channel.setAnim(“Walk”, 0.50f);

channel.setLoopMode(LoopMode.Loop);

}

}

if (name.equals(“Dodge”) && !keyPressed)

{

if (!“Dodge”.equals(channel2.getAnimationName()))

{

channel2.setAnim(“Dodge”, 0.05f);

channel2.setLoopMode(LoopMode.DontLoop);

}

}

}

};[/java]

Sadly, that solution didn’t work (same result: only feet and hands move during walk cycle). I’ll keep going with the tutorials and try again tomorrow.

You don’t have to use another channel, just change the anim on the same channel.



You have to consider channels as part of the skeleton that are animated. the default behavior is to use the whole skeleton for a channel.

In your example the fist channel plays the walk anim, then the second channel plays the dodge animation.

Arms and feet are probably not affected by the doge animation so you can see the walk anim for them but the rest of the body plays the dodge animation.



Usually multiple channels are used to animate different part of the body. For example you create one channel for the lower part of the body and one for the upper part. This allow you to play a walk animation with the lower part and for example a shoot animation with the upper part. this way your character can walk while shooting.



In your case, where you want animations to chain for the whole skeleton, you just have to use one channel.

1 Like

I test the code and solves the first problem:


1. My golem plays the Dodge animation upon program startup, but moving (or deleting) the setAnim in simpleInitApp() always results in crashes. What have I forgotten?


I think he is trying this, dodge while the character is walking, or not?
@nehon said:
You have to consider channels as part of the skeleton that are animated. the default behavior is to use the whole skeleton for a channel.
In your example the fist channel plays the walk anim, then the second channel plays the dodge animation.
Arms and feet are probably not affected by the doge animation so you can see the walk anim for them but the rest of the body plays the dodge animation.

Ah, thank you for the clarification. I made the second channel because the tutorial said, "Create a second channel in the controller" (Exercise 1), so I figured that the tutorial wanted me to implement two separate channels so that partway through the walk animation, he could do the dodge animation and then finish walking.

Thank you both for the answers.

EDIT: I've added Nehon's comments to the Channels section of that tutorial as a supplementary note.
1 Like