There are two parts to creating Animation for our characters and other objects, within jMonkeyEngine. The first part involves design using Blender or similar software. This might take some time. However, the end result is a few text files and images. We will cover the second part, importing the design files into jMonkeyEngine.

The design files for a few models and animations are included in jMonkeyEngine, inside a compressed jar file. We just have to add the jar file containing the models to the project Library. This is done by right-clicking on the Project, select Properties, and then Libraries. After clicking on Add Library, we find jme3-test-data.

Now, if we expand Libraries in our project, we can find the relevant Model.

We have to have animation object variables.

// *** 1. Start (Animation variables)
private AnimChannel channel;
private AnimControl control;
// *** 1. End
We also have a ArrayList of strings to hold the list of animations. We will create a Node for the model. There will be variables for current animation, as well as text that will be outputted.

// *** 2. Start (variables)
ArrayList<String> animNames; // list of animations
Node sinbad; // Model
private boolean finished = true; // Current Animation Finished
private int animNum; // Points to random animation
private float playTime; // Current Animation Duration
private String stringOut; // Text that will written
BitmapText outText; // Bitmap Text for guiNode
// *** 2. End
Some of the initialization code will be used to create Bitmap Text object so it can be used later to print status text. The Node is loaded with the model. Now the Animation Control can be set and we can find the list of Animations, using methods on control.

// *** 3. Start (Initialization)
guiFont = assetManager.loadFont(
"Interface/Fonts/Default.fnt"); // font
outText = new BitmapText(guiFont, false); // test Bitmap
outText.setSize(guiFont.getCharSet().getRenderedSize());
sinbad = (Node)assetManager.loadModel(
"Models/Sinbad/Sinbad.mesh.xml"); // model
sinbad.setLocalScale(0.5f); // scale
rootNode.attachChild(sinbad); // visual
control = sinbad.getControl(AnimControl.class); // anim control
animNames = new ArrayList<String>(control.getAnimationNames());
// animNames is ArrayList String array holding all Animations.
// *** 3. End
New animation is started, inside the simpleUpdate(), provided the last animation has finished.

// *** 4. Start (New Animation, Write Text)
if (finished) {
animNum = FastMath.nextRandomInt(0, animNames.size()-1);
channel.setAnim(animNames.get(animNum));
playTime = channel.getAnimMaxTime();
channel.setLoopMode(LoopMode.DontLoop);
stringOut = "Starting (" +
animNum + ")\t" + animNames.get(animNum) +
"\tplay time = " + playTime;
System.out.println(stringOut);
if (playTime>tpf) finished = false;
guiNode.detachAllChildren();
outText.setText(stringOut);
outText.setLocalTranslation(50, 50, 0);
guiNode.attachChild(outText);
}
// *** 4. End
Once any animation is finished it will call this method, since the animation listener was set, and our class implements the animation listener. This will set our finished boolean to true, so in the next simpleUpdate(), a new animation may be started.

// *** 5. Start (Called when current Animation finishes)
finished = true;
// *** 5. End
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.font.BitmapText;
import com.jme3.light.DirectionalLight;
import com.jme3.math.ColorRGBA;
import com.jme3.math.FastMath;
import com.jme3.math.Vector3f;
import com.jme3.renderer.RenderManager;
import com.jme3.scene.Node;
import com.jme3.system.AppSettings;
import java.util.ArrayList;
public class JMonkey33 extends SimpleApplication
implements AnimEventListener {
public static void main(String[] args) {
AppSettings cfg = new AppSettings(true);
cfg.setFrameRate(60);
JMonkey33 app = new JMonkey33();
app.setSettings(cfg);
app.setDisplayFps(false);
app.setDisplayStatView(false);
app.start();
}
// *** 1. Start (Animation variables)
private AnimChannel channel;
private AnimControl control;
// *** 1. End
// *** 2. Start (variables)
ArrayList<String> animNames; // list of animations
Node sinbad; // Model
private boolean finished = true; // Current Animation Finished
private int animNum; // Points to random animation
private float playTime; // Current Animation Duration
private String stringOut; // Text that will written
BitmapText outText; // Bitmap Text for guiNode
// *** 2. End
@Override
public void simpleInitApp() {
viewPort.setBackgroundColor(ColorRGBA.DarkGray);
flyCam.setEnabled(false);
// *** 3. Start (Initialization)
guiFont = assetManager.loadFont(
"Interface/Fonts/Default.fnt"); // font
outText = new BitmapText(guiFont, false); // test Bitmap
outText.setSize(guiFont.getCharSet().getRenderedSize());
sinbad = (Node)assetManager.loadModel(
"Models/Sinbad/Sinbad.mesh.xml"); // model
sinbad.setLocalScale(0.5f); // scale
rootNode.attachChild(sinbad); // visual
control = sinbad.getControl(AnimControl.class); // anim control
animNames = new ArrayList<String>(control.getAnimationNames());
// animNames is ArrayList String array holding all Animations.
// *** 3. End
System.out.println("There are " + animNames.size()
+ " animations!");
for (String anim : animNames) {
System.out.printf("%20s\n",anim);
}
// ***
/** A white, directional light source */
DirectionalLight sun = new DirectionalLight();
sun.setDirection((new Vector3f(-0.5f, -0.5f, -0.5f)).normalizeLocal());
sun.setColor(ColorRGBA.White);
rootNode.addLight(sun);
control.addListener(this); // Listen
channel = control.createChannel(); // Animation control
}
@Override
public void simpleUpdate(float tpf) {
// *** 4. Start (New Animation, Write Text)
if (finished) {
animNum = FastMath.nextRandomInt(0, animNames.size()-1);
channel.setAnim(animNames.get(animNum));
playTime = channel.getAnimMaxTime();
channel.setLoopMode(LoopMode.DontLoop);
stringOut = "Starting (" +
animNum + ")\t" + animNames.get(animNum) +
"\tplay time = " + playTime;
System.out.println(stringOut);
if (playTime>tpf) finished = false;
guiNode.detachAllChildren();
outText.setText(stringOut);
outText.setLocalTranslation(50, 50, 0);
guiNode.attachChild(outText);
}
// *** 4. End
}
@Override
public void simpleRender(RenderManager rm) {
}
public void onAnimCycleDone(AnimControl control, AnimChannel channel, String animName) {
// *** 5. Start (Called when current Animation finishes)
finished = true;
// *** 5. End
}
public void onAnimChange(AnimControl control, AnimChannel channel, String animName) {
}
}
Output:
No comments:
Post a Comment