First of all, to understand the result of what I'm about to show, check out my video of my various models. I show some big cats, but especially show a python snake that is fully articulated. I even have an elephant that has a trunk that moves, ears that flap, and that rears up when attacked. Anyway, check it out here: Jabelar's Wild Animal Entity Animations
The python is what I show you how to make in this tutorial below.
This is something I've just gone through learning, and I am proud to say that I've got a fully animated slithering snake, and an elephant with flapping ears and articulated trunk. Here are a few tips that might help others.
Techne Versus Modeling Directly in Java
First of all I found that using the Java exported directly from Techne is not a good idea. Techne is useful though; I use Techne to visualize the model and animation, and especially use it for figuring out texture map, but ultimately I ended up coding the Java myself. And the Java is pretty simple because it is simply a bunch of boxes (we're talking Minecraft(tm) after all). Actually the biggest benefit of coding it manually is that you get a good understanding of how the rotation points and offsets really work.
Note there is also advanced modeling supported in Forge using .obj models. Personally though the Minecraft "feel" to me is about blocky models, and Java is pretty easy to use for blocky models.
General Modeling Guidelines
Here are some ideas to think about:
- Your whole model will only be manageable if you orient it the right way -- I once spent a lot of time on one model which had head pointed 90 degrees to what Minecraft considers the front and while it could be fixed with some overall rotation it is much better to simply orient it correctly in the first place. You can check the ModelCow in Techne to ensure you have the right axis orientation -- I believe it should be that negative Z direction is the direction the entity should face.
- Get your rotation point in proper place first, then figure out your offset. You can create two models that look the same but operate very differently/wrongly if you don't get the rotation points right. The rotation point should be the joint for something like an arm, and should be the center for something like a body. In particular, make sure each joint is working properly before adding the next part. I have found that implementing some simple debug functions for spinning a part are immensely useful to help visualize that you have the rotation point and offsets correct.
- Use a hierarchical model by associating blocks with the addChild() method. For examples, the ears and nose should be children of the head. Then when the head rotates they stay in proper place, and then the animations of the ears and nose can be programmed relatively (much easier to think about than using spatial transformation).
- The fancy rendering stuff like animation goes into the render() method of the model class, not into your renderer class! The good thing about the render() method is that it gets the Entity passed to it, so you can (after casting to your custom entity) then test the fields and state of the entity to control your animations and other aspects of the rendering.
- It is extremely useful to use the entity's tickExisted property to help control the cycles through an animation loop. I used the modulo (also called remainder function) to detect "every X ticks". For example, parEntity.ticksExisted%60==0 will be true for one tick every 3 seconds (there are 20 ticks per second). Even better, something like parEntity.ticksExisted%6 will work as an index through a six-step animation sequence. Note that ticksExisted is reset when a saved game is loaded which will cause all your entities to synchronize -- so you may want to add some random offset (I'll explain that later).
- Don't be afraid to "hard code" an animation loop. Just like a cartoon artist, you only need a few set positions to give the illusion of motion. For example, for my snake I spent days trying to figure out a mathematical equation to control the slithering and then realized that with a very simple matrix of preset rotations I could achieve the same effect.
- You may need to add public variables or access methods to your entities to control animations, in which case you need to ensure there are packets sent to client side (where rendering takes place) to control the animation.
- A really important thing is that the default 0, 0, 0 position of an added box is on one corner, not in the center of the box. This means you will almost always want to offset by half the dimension of the sides for two (if you're rotating from an end) or three (if you're rotating around the middle) of the sides.
- Don't worry about the texture until you get the model correct. You can work with no texture at all (in which case there is a pink-and-black checkered default texture), but I suggest working with a texture map that is filled in with a solid color -- this will let you test that you've got the texture asset in right location. Changing your texture is a pain, so you want to get your model fully finished before you invest much time in texture creation.
- For entity models, while testing your mod by playing it, use the F3+B shortcut to show the bounding boxes of your entity. It is really important to check that the actual bounding box is positioned correctly within the model.
Example: Entity Serpent
The Model Class
Okay, here is my example ModelSerpent class for the EntitySerpent:
The first part that I want to bring attention to is the animation cycle I hard-coded:
Basically, each row is a step in the animation and each column is one of the snake's body parts. I came up with this table by simply drawing a snake (in each of its positions of slithering) on a piece of paper and figuring out the relative angles between parts (they are relative because I use child parts, as explained below).
Using Part Hierarchy (Child Parts) To Make The Model Easy To Manage
Note that each body part in the snake is child of the previous, so that all the parts remain connected. You need to create one part that you consider the main part of the model, for most entities I would use the body (or body1 in the case of my snake with multiple parts to its body).
Then for each body part, I use the following code structure to create a hierarchy of parts using the addChild() method:
Special Tip For Converting Techne Models Into Hierarchical Models
If you have created a complex model in Techne, you may find that it can be a lot of work to convert it into a hierarchical model. This is because you have to take all the rotation points and make them relative, meaning subtracting out the parent's rotation point. If you have a lot of parts, this is time consuming and error prone. Instead you can use a simple helper function method which I call convertToChild() to do this for you: Jabelar's convertToChild() Tutorial.