A Few Simple Animation Questions

Hey there everyone. I am starting to program my character to use his animations that I just finished making, and I had a few very noobish questions about how to go about coding them.

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.app.SimpleApplication;
import com.jme3.input.KeyInput;
import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.KeyTrigger;
import com.jme3.light.DirectionalLight;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.jme3.scene.Node;
import com.jme3.app.SimpleApplication;
import com.jme3.bullet.BulletAppState;
import com.jme3.bullet.PhysicsSpace;
import com.jme3.bullet.collision.shapes.CapsuleCollisionShape;
import com.jme3.bullet.control.CharacterControl;
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.math.Vector3f;
import com.jme3.renderer.RenderManager;
import com.jme3.scene.CameraNode;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
import com.jme3.scene.control.CameraControl.ControlDirection;

/** Sample 7 - how to load an OgreXML model and play an animation,

  • using channels, a controller, and an AnimEventListener. */
    public class Main extends SimpleApplication
    implements AnimEventListener {
    private AnimChannel channel;
    private AnimControl control;
    Node player;
    public static void main(String[] args) {
    Main app = new Main();
    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/Link/glow_blade.mesh.xml”);
player.setLocalScale(0.5f);
rootNode.attachChild(player);
control = player.getControl(AnimControl.class);
control.addListener(this);
channel = control.createChannel();
channel.setAnim(“Run”);
channel.setAnim(“Attack 1”);
channel.setAnim(“Ocarina Raise”);
channel.setAnim(“Ocarina Play”);
channel.setAnim(“Idle”);
flyCam.setEnabled(true);

}

public void onAnimCycleDone(AnimControl control, AnimChannel channel, String animName) {

if (animName.equals("Run")) {
  channel.setAnim("Idle", 0.50f);
  channel.setLoopMode(LoopMode.Loop);
  channel.setSpeed(1f);
}
else channel.setAnim("Idle");

}

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

/** Custom Keybinding: Map named actions to inputs. */
private void initKeys() {
inputManager.addMapping(“Run”, new KeyTrigger(KeyInput.KEY_W));
inputManager.addListener(actionListener, “Run”);
inputManager.addMapping(“Ocarina Raise”, new KeyTrigger(KeyInput.KEY_O));
inputManager.addListener(actionListener, “Ocarina Raise”);
inputManager.addMapping(“Attack 1”, new MouseButtonTrigger(MouseInput.BUTTON_LEFT));
inputManager.addListener(actionListener, “Attack 1”);
}
private ActionListener actionListener = new ActionListener() {
public void onAction(String name, boolean keyHeld, float tpf) {

  if (name.equals("Run") && !keyHeld) {
    if (!channel.getAnimationName().equals("Run")) {
      channel.setAnim("Run", 0.5f);
      channel.setLoopMode(LoopMode.Loop);
    }
  if (name.equals("Ocarina Raise") && !keyHeld){
      if (!channel.getAnimationName().equals("Ocarina Raise")) {
          channel.setAnim("Ocarina Raise", 0.5f);
          channel.setLoopMode(LoopMode.Loop);
      }
        if (name.equals("Attack 1") && !keyHeld){
      if (!channel.getAnimationName().equals("Attack 1")) {
          channel.setAnim("Attack 1", 0.5f);
          channel.setLoopMode(LoopMode.DontLoop);
      }       
      }
    }     

}

}

};
}

1: For all of the code examples at which I look, the actions are all done upon releasing the key. I want some of my actions (like running) to be if the key is held. That way, you don’t have to keep spamming w to make your character run. I’m sure that there is an easy way to do this, probably something around the lines of ifKeyHeld, but I’d just like to hear it from you all first.

2: As you can see, I added in the Ocarina Raise and Attack 1 animations right into my code, and assigned them to the O key and left mouse button, respectively. I think that the code is right, but it obviously isn’t because when I press O and the left mouse button in my application, nothing happens. Any ideas? I think followed the directions exactly.

Sorry that I’m a noob, this is really my first stab at making a game.

Thanks to such a great community!

-Winner

concerning the first question ,you can add an analogue listener instead of an actionlistener ,that way you wont have to keep pressing w.Concerning your animations not playing ,you seem to have mapped your keys correctly ,so in my opinion ,either those animations are not there or they are playing too quick for you to notice ,or you play the after you press the run key after which your code resets your anim to stand. I suggest you remove that code in onanimcycledone and see what happens, i had a similar problem where all my animations couldnt play after my run animation was reset to stand .It is a problem im yet to understand still.

oh and something i didnt notice ,remove that ! from keyPressed so that your animation plays whenever it is keypressed is true.

Haven’t tried out the analogue listener yet, but I did remove the onAnimCycleDone code, and basically what happened was that once I pushed w, he never stopped running. I restarted the program, and when I clicked o and the left mouse button, absolutely nothing happened, as usual. I’m having trouble finding out what’s wrong :/. I do not believe that the animations are too fast, in fact, I know that they aren’t, and I am 100% sure that they do in fact exist.

Removing the ! made it so that when the key was pressed it worked. I imported AnalogListener, and then wrote

private Analog analogListener = new AnalogListener() {
public void onAnalog(String name, boolean keyHeld, float tpf) {

and I got an error.

Still need help on both questions.

i dont think you need to check if the key is still held to play those two animations ,the second condition !keyPressed is not necessary ,try removing that ,and you set all your animations after you created your channel and jme will prob try to play them in less than a sec and will look ugly ,i dont see a need to set all your animation before a key is pressed,maybe you can set one of your animations at start,idle

And the reason why he didnt stop running is because you need to set idle once the run animation is done so you need that code back in onanimcycledone .just try removing !keypressed for the animations that are not playing.

I think I’m on to something. When I totally got rid of the if (name.equals(“String”) && keyHeld, it tried to just do all of the animations at once.

Getting warmer. And I got rid of the ! in front of keyHeld. Now it doesn’t do the action on release, but it doesn’t loop it. Ah well, to be honest the animation problem is bigger than that. Once I get that sorted out I can move on to the keyHeld problem.

Here is my code now.

package mygame;

import com.jme3.input.ChaseCamera;
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.controls.ActionListener;
import com.jme3.input.controls.AnalogListener;
import com.jme3.input.controls.KeyTrigger;
import com.jme3.light.DirectionalLight;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.jme3.scene.Node;
import com.jme3.app.SimpleApplication;
import com.jme3.bullet.BulletAppState;
import com.jme3.bullet.PhysicsSpace;
import com.jme3.bullet.collision.shapes.CapsuleCollisionShape;
import com.jme3.bullet.control.CharacterControl;
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.math.Vector3f;
import com.jme3.renderer.RenderManager;
import com.jme3.scene.CameraNode;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
import com.jme3.scene.control.CameraControl.ControlDirection;

/** Sample 7 - how to load an OgreXML model and play an animation,

  • using channels, a controller, and an AnimEventListener. */
    public class Main extends SimpleApplication
    implements AnimEventListener {
    private AnimChannel channel;
    private AnimControl control;
    Node player;
    public static void main(String[] args) {
    Main app = new Main();
    app.start();
    CameraNode camNode;
    }

@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/Link/glow_blade.mesh.xml”);
player.setLocalScale(0.5f);
rootNode.attachChild(player);
control = player.getControl(AnimControl.class);
control.addListener(this);
channel = control.createChannel();

channel.setAnim("Run");
channel.setAnim("Attack 1");
channel.setAnim("Ocarina Raise");
channel.setAnim("Ocarina Play");
channel.setAnim("Idle");
flyCam.setEnabled(false);

}

public void onAnimCycleDone(AnimControl control, AnimChannel channel, String animName) {

if (animName.equals("Run")) {
  channel.setAnim("Idle", 0.50f);
  channel.setLoopMode(LoopMode.Loop);
  channel.setSpeed(1f);
}

}

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

/** Custom Keybinding: Map named actions to inputs. */
private void initKeys() {
inputManager.addMapping(“Run”, new KeyTrigger(KeyInput.KEY_W));
inputManager.addListener(actionListener, “Run”);
inputManager.addMapping(“Ocarina Raise”, new KeyTrigger(KeyInput.KEY_O));
inputManager.addListener(actionListener, “Ocarina Raise”);
inputManager.addMapping(“Attack 1”, new MouseButtonTrigger(MouseInput.BUTTON_LEFT));
inputManager.addListener(actionListener, “Attack 1”);
}
private ActionListener actionListener = new ActionListener() {
public void onAction(String name, boolean keyHeld, float tpf) {

  if (name.equals("Run") && keyHeld) {
    if (!channel.getAnimationName().equals("Run")) {
      channel.setAnim("Run", 0.5f);
      channel.setLoopMode(LoopMode.Loop);
    }
  if (name.equals("Ocarina Raise") && keyHeld){
      if (!channel.getAnimationName().equals("Ocarina Raise")) {
          channel.setAnim("Ocarina Raise", 0.5f);
          channel.setLoopMode(LoopMode.Loop);
      }
        if (name.equals("Attack 1") && keyHeld){
      if (!channel.getAnimationName().equals("Attack 1")) {
          channel.setAnim("Attack 1", 0.5f);
          channel.setLoopMode(LoopMode.DontLoop);
      }       
      }
    }     

}

}

};
}

I figured something else out. It had to do with the fact that the “run” part of the animation code was first. When the ocarina part is first, he plays his ocarina, and when the attack part is first, he attacks. Now how do I fix it?

like i said ,you dont necessarily need to set any animation after you create your channel in the simpleinit so you can remove all the channel.setAnim code in the init. Regarding your animation not looping ,i was saying remove &&keypressed second condition so that your animation plays out whenever the key is pressed and loops if pressed again.

I tried everything you said and none of it helped the matter. You were right, you don’t need to set the animations in the simpleinit, so I got rid of that, and it still worked just the way it was, but nothing changed. As far as your second suggestion, all that happened, as I expected by what what your instructions meant, the animation was played upon both pressing and releasing the key, but nothing looped. I reverted the code back to what it is in the above except for the setAnim code.

P.S. If you meant get rid of the boolean keyHeld entirely, then I wouldn’t be able to use the ActionListener. Maybe I’m just stupid.

Anyone have any other ideas? Again, this is my first stab at this, and I’m rather lost.

Sorry for double post.

Bump

Set the run animation to repeat, start it when they press the key down, stop it when they release the key.

If you want it to look good you are going to need to think about transitioning animations, interacting world movement with animations, etc.

The animation is already on loop, it does start when I press the key, but doesn’t end when I stop holding it. That must be the problem. What do I use to see if the key isn’t being held?

But the really pressing issue is that none of my animations past the first work! I did some System.out.println testing and the others in fact are not working at all.

SOMEONE HELP!

You could try posting your model, see if anyone has time to look at it.

One thought I just had: Open up your imported model in the scene explorer and look inside.

The blender importer creates 2 anim controls for some reason, and only one has all the animations.

Everything works in the scene explorer, and I used ogre.

Dude,sorry for pushing you back and forth over the !keypressed and keypressed effect seems i confuse them at times ,im sure i told you not to test if a key is pressed to play the animations that are not playing ,seems like you need !keypressed to play an instance of the animation and remove the ! to remain with keypressed to play the animation if the key is pressed .When everything looks okay and am not getting the results ,i think outside the box and debug every major line of code until i get results and i usually do,guess i took you down that road then ,and im not a jme guru myself,feel free to question my suggestions.

That last post didn’t make a lot of sense to me.

The problem is this simple.

Why doesn’t any of the code after my first animation work?

It is that simple.

Please help.

i was saying you need to test if the key is not held to play an instance of your animation by adding &&!keyheld

I fixed the problem that none of you seemed to realize that I was having. Now more than one animation actually works. Now as for holding it down. I was trying to make a while loop to make sure that the key was pressed down and to break the cycle if it wasn’t by using the !keyHeld but the game crashed.

Can someone tell me in Java and English what I should do? I’ve tried following all of your suggestions but I’m still lost.