-
Notifications
You must be signed in to change notification settings - Fork 2
Making an animated mob
Before reading further make sure you have created the model and the animations already. If you haven't done that you can read how to do that just Creating a model
On this page I'll showcase how to integrate this mod into your project. First up we will create a simple custom mob, let's extend EntityCreature for this, but you can extend any class you like.
package net.testmod;
import net.minecraft.entity.EntityCreature;
import net.minecraft.world.World;
import net.minecraft.util.ResourceLocation;
import com.github.worldsender.mcanm.client.model.mcanmmodel.animation.IAnimation;
import com.github.worldsender.mcanm.client.model.mcanmmodel.animation.stored.AnimationRegistry;
import com.github.worldsender.mcanm.client.model.mcanmmodel.data.RenderPassInformation;
import com.github.worldsender.mcanm.client.renderer.IAnimatedObject;
import com.github.worldsender.mcanm.common.CommonLoader;
public class TestEntity extends EntityCreature implements IAnimatedObject {
private static final IAnimation testAnimation = CommonLoader
.loadAnimation(new ResourceLocation("testmod:mobs/test/animation.mcanm"));
private int frame = 0;
public TestEntity(World world) {
super(world);
this.setSize(1.0F, 1.8F);
}
public void onUpdate() {
if (this.worldObj.isRemote)
frame++;
}
public RenderPassInformation preRenderCallback(float subFrame,
RenderPassInformation callback) {
return callback.setFrame(frame + subFrame).setAnimation(testAnimation);
}
}
I'll try to explain every line of code contributing to the animation:
private static final IAnimation testAnimation = CommonLoader.loadAnimation("testmod:mobs/test/animation.mcanm");
This line loads an animation from the asset-file "assets/testmod/mobs/test/animation.mcanm" make sure you type that path correctly. On the client, this file will be loaded from the active resource packs, on the server this will load the file from the jar of your mod.
private int frame = 0;
This initializes a frame counter to zero (we only need it on CLIENT side but for simplicity we out it into the entity).
public void onUpdate() {...}
By overriding this method we increase the frame counter on Client-worlds each tick. We also reset the frame when it hits 100 with frame %= 100
.
public RenderPassInformation preRenderCallback(float subFrame, RenderPassInformation callback)
This is a core method you really need to understand. It is called on the Client only and returns information about the state of the object. It should manipulate and return the callback
given as argument. There are two things we do.
We first set the frame of callback
to frame + subFrame
to tell it at what point in the animation we are. To be able to make smooth transitions between keyframes subFrame
is given as an argument. You can set this value to ANY value you like, allowing advanced users to do some cool stuff for sure.
We then set the animation to the one we previously loaded but feel free to load multiple animations and switch them whenever you like to - maybe resetting the frame
counter at this point, there are no limits.
We then simply return the callback we just built (to the render-manager).
Advanced users can also use the preRenderCallback to apply simple transformations or scalings with raw OpenGL commands because preRenderCallback is pretty much called immediatly before the object is actually rendered.
Again, first the full code:
package net.testmod;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.fml.client.registry.RenderingRegistry;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.event.FMLInitializationEvent;
import net.minecraftforge.fml.common.registry.EntityRegistry;
import com.github.worldsender.mcanm.client.mcanmmodel.IModel;
import com.github.worldsender.mcanm.client.renderer.entity.RenderAnimatedModel;
import com.github.worldsender.mcanm.client.ClientLoader;
import com.github.worldsender.mcanm.common.CommonLoader;
import com.github.worldsender.mcanm.common.skeleton.ISkeleton;
@Mod(modid = "testmod")
public class Core {
@Mod.EventHandler
void init(FMLInitializationEvent init) {
EntityRegistry.registerGlobalEntityID(TestEntity.class, "testmob", 200,
0x12548d, 0xDEAD11);
ISkeleton testMobSkeleton = CommonLoader.loadSkeleton(
new ResourceLocation("testmod:mob/test/model.mcskl"));
IModel testMobModel = ClientLoader.loadModel(
new ResourceLocation("testmod:mob/test/model.mcmd"),
testMobSkeleton);
RenderingRegistry.registerEntityRenderingHandler(
TestEntity.class, // Our entity class
RenderAnimatedModel.fromModel(testMobModel, 2.0F));
}
}
First, we use CommonLoader.loadSkeleton(...)
to load the skeleton of the model from the from Blender exported .skl file. We then load the exported .mcmd model file with ClientLoader.loadModel(...)
, handing it the skeleton we just loaded. Finally, the model is used to call RenderAnimatedModel.fromModel(...)
, also providing the shadow size, that should roughly correspond to the actual size of your mob, as an argument. We get back and IRenderFactory<T>
which we then use to register with forge by calling RenderingRegistry.registerEntityRenderingHandler(...)
for our entity class.
That's it. In my opinion it's really easy to use the mod, so feel free to comment and remind me of mistakes and bugs if you notice any or don't understand this tutorial. I'll be pleased to answer eloquent questions.