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