In this series I try to tackle topics about modeling in Minecraft, each article will build up on the previous ones - so if this is the first time you visit, you may want to read the previous posts as well.
This time I’m going to talk about the setRoationAngles-method and its parameters.
I already gave a peak in last week’s post but only superficially (and partially wrong :/ )
I’ll repost the code to refresh your memory:
public void render(Entity entity, float
public void setRotationAngles(float var1, float
Think of the walk animation as a function, a cosine function to be exact.
Where y(x) is the rotation in radians at t(x).
I’ll use ModelChicken as an example - it’s decompiled with ff and mcp:
leg0.rotationX = MathHelper.cos(var1 * 0.6662F) * 1.4F * var2;
leg1.rotationX = MathHelper.cos(var1 * 0.6662F + 3.1415927F) * 1.4F * var2;
1st and 2nd argument
This means that var1 is used for time and var2 modifies the amplitude. And this makes sense, the faster a mob walks, the more/higher their legs move. So I think it’s safe to call var1 “time” and var2 “walkSpeed”.
Let’s look at the next graph.
Now guess how this would look if it was applied to rotationX of a leg ( y(time) = cos(time) * walkspeed )
This could describe a mod that stands still, begins to walk, reaches a max speed (of 1) and gradually slows down again.
How are the values calculated?
The magic happens in RenderLiving.render(Entity entity, double var2, double var4, double var6, float var8, float var9):
float time = mob.field_703_S - mob.field_704_R * (1 - var6);
float walkSpeed = mob.field_705_Q + (mob.field_704_R - mob.field_705_Q) * var6;
I’m not really sure how to name var3, it’s being used for three different purposes and the calculation of it is up to the renderer-file.
- Wolf: angle for its tail
- Squid: angle for the tentacles
- Chicken: angle for the wings
So, it’s basically up to you what this is, all you need to do is override handleRotationFloat in the renderfile.
And it’s pretty much up to you how you do that as well, the Wolf just gets the tail angle, while squid and chicken calculate it.
protected float handleRotationFloat(EntitySquid entitysquid, float f)
//f == Timer.renderPartialTicks and represents the passed ticks since the last rendercall (0.0 - 1.0), it gets passed down from runGameLoop() in Minecraft.java.
return entitysquid.lastTentacleAngle + (entitysquid.tentacleAngle - entitysquid.lastTentacleAngle) * f;
Since lastTentacleAngle and tentacleAngle get set in onLivingUpdate which is only called 20 times per second, we need to tween between angles to make sure we get a fluid animation and this is done here.
4th and 5th argument
They are rotationYaw and rotationPitch respectively, tweened like in handleRotationFloat. In RenderLiving:
float rotationYaw = entityliving.prevRotationYaw + (entityliving.rotationYaw - entityliving.prevRotationYaw) * f1;
float rotationPitch = entityliving.prevRotationPitch + (entityliving.rotationPitch - entityliving.prevRotationPitch) * f1;
You use them to determine where your model should look, think of it as headRotationX and headRotationY and this is how it’s being used as well. In your model-class:
head.rotateAngleY = f3 / 57.29578F;
head.rotateAngleX = f4 / 57.29578F;
You might wonder why you divide by 57.29578, answer is simple, rotationYaw/rotationPitch are in degrees and must be converted to radians before assigning it to rotateAngleX/Y :)
This amounts to scale, but you normally don’t have to mess with it, you just pass it to the render-method of you ModelRender.
It’s set to
float scale = 1 / 16.0f;
in code, remember 1 block is 16x16 pixels in texturesize.
To sum up, arguments passed to .setRotationAngeles are
- time for the walk animation
- speed for the walk animation
- unsure how to name it, use is pretty much up to you
I hope this helps you understand how animations are done :)
This post focuses on the setRotationAngles-method on purpose, we need that knowledge for later posts - if you have questions about something that goes deeper than what I wrote leave a comment and I might just write another article answering it :)
Next up: EnderDragon explained