tutorial:entity
Differences
This shows you the differences between two versions of the page.
| Previous revision | |||
| — | tutorial:entity [2026/03/02 22:49] (current) – Mojmap and 1.21.11 cassiancc | ||
|---|---|---|---|
| Line 1: | Line 1: | ||
| + | ===== Creating an Entity ===== | ||
| + | |||
| + | //The source code for this project can be found [[https:// | ||
| + | |||
| + | Entities are a movable object in a world with logic attached to them. A few examples include: | ||
| + | * Minecarts | ||
| + | * Arrows | ||
| + | * Boats | ||
| + | |||
| + | Living Entities are Entities that have health and can deal damage. | ||
| + | There are various classes that branch off `LivingEntity` for different purposes, including: | ||
| + | * '' | ||
| + | * '' | ||
| + | * '' | ||
| + | * '' | ||
| + | |||
| + | What you extend depends on what your needs and goals are. | ||
| + | As you get further down the chain, the entity logic becomes more specific and curated to certain tasks. | ||
| + | The two generic entity classes that come after '' | ||
| + | * '' | ||
| + | * '' | ||
| + | |||
| + | '' | ||
| + | for pathfinding favor, and various AI tasks require this to operate. | ||
| + | |||
| + | In this tutorial, we will look at creating a cube entity that extends '' | ||
| + | This entity will have a model & texture. Movement and mechanics will be covered in a future tutorial. | ||
| + | |||
| + | ===== Creating & Registering an Entity ===== | ||
| + | |||
| + | Create a class that extends '' | ||
| + | |||
| + | <code java [enable_line_numbers=" | ||
| + | /* | ||
| + | * Our Cube Entity extends '' | ||
| + | * | ||
| + | * '' | ||
| + | * '' | ||
| + | * '' | ||
| + | */ | ||
| + | public class CubeEntity extends PathfinderMob { | ||
| + | |||
| + | public CubeEntity(EntityType<? | ||
| + | super(entityType, | ||
| + | } | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | You can register this entity under the '' | ||
| + | Fabric provides a '' | ||
| + | The Fabric builder class provides extra methods for configuring your entities' | ||
| + | |||
| + | <code java [enable_line_numbers=" | ||
| + | public class EntityTesting implements ModInitializer { | ||
| + | |||
| + | /* | ||
| + | * Registers our Cube Entity under the ID " | ||
| + | * | ||
| + | * The entity is registered under the MobCategory# | ||
| + | * It has a hitbox size of .75x.75, or 12 " | ||
| + | */ | ||
| + | public static final EntityType< | ||
| + | BuiltInRegistries.ENTITY_TYPE, | ||
| + | Identifier.fromNamespaceAndPath(" | ||
| + | EntityType.Builder.create(CubeEntity:: | ||
| + | ); | ||
| + | |||
| + | @Override | ||
| + | public void onInitialize() { | ||
| + | | ||
| + | } | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | Entities need // | ||
| + | |||
| + | ===== Registering Entity Attributes ===== | ||
| + | |||
| + | ~~REDIRECT> | ||
| + | |||
| + | **Attributes** define the properties of the mob: how much health does it have? How much damage does it do? Does it have any default armor points? | ||
| + | |||
| + | Most vanilla entities have a static method that returns their attributes (such as '' | ||
| + | Our custom entity doesn' | ||
| + | |||
| + | Vanilla has a '' | ||
| + | It isn't publicly exposed or easily available, so Fabric provides a '' | ||
| + | The registration of default attributes should occur somewhere in your mod's initialization phase: | ||
| + | |||
| + | <code java [enable_line_numbers=" | ||
| + | public class EntityTesting implements ModInitializer { | ||
| + | | ||
| + | public static final EntityType< | ||
| + | |||
| + | @Override | ||
| + | public void onInitialize() { | ||
| + | /* | ||
| + | * Register our Cube Entity' | ||
| + | * Attributes are properties or stats of the mobs, including things like attack damage and health. | ||
| + | * The game will crash if the entity doesn' | ||
| + | * | ||
| + | * In 1.15, this was done by a method override inside the entity class. | ||
| + | * Most vanilla entities have a static method (eg. Zombie# | ||
| + | */ | ||
| + | FabricDefaultAttributeRegistry.register(CUBE, | ||
| + | } | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | ===== Registering Entity Renderer ===== | ||
| + | |||
| + | The last requirement of an entity is a **Renderer**. Renderers define *what* the entity looks like, generally by providing a model. | ||
| + | '' | ||
| + | and wants 3 parameters for the super constructor: | ||
| + | * '' | ||
| + | * '' | ||
| + | * shadow size of our entity as a '' | ||
| + | |||
| + | The following code showcases a simple entity renderer with a shadow size of 0.5f | ||
| + | and texture at '' | ||
| + | Note that the texture and model class will be created in the next step. | ||
| + | |||
| + | <code java [enable_line_numbers=" | ||
| + | /* | ||
| + | * A renderer is used to provide an entity model, shadow size, and texture. | ||
| + | */ | ||
| + | public class CubeEntityRenderer extends MobRenderer< | ||
| + | |||
| + | public CubeEntityRenderer(EntityRendererProvider.Context context) { | ||
| + | super(context, | ||
| + | } | ||
| + | |||
| + | @Override | ||
| + | public CubeEntityRenderState createRenderState() { | ||
| + | return new CubeEntityRenderState(); | ||
| + | } | ||
| + | |||
| + | @Override | ||
| + | public Identifier getTextureLocation(CubeEntityRenderState livingEntityRenderState) { | ||
| + | return Identifier.fromNamespaceAndPath(" | ||
| + | } | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | To register this renderer, use '' | ||
| + | <code java [enable_line_numbers=" | ||
| + | public class EntityTestingClient implements ClientModInitializer { | ||
| + | public static final ModelLayerLocation MODEL_CUBE_LAYER = new ModelLayerLocation(Identifier.fromNamespaceAndPath(" | ||
| + | @Override | ||
| + | public void onInitializeClient() { | ||
| + | /* | ||
| + | * Registers our Cube Entity' | ||
| + | * | ||
| + | * Entity Renderers can also manipulate the model before it renders based on entity context (EndermanEntityRenderer# | ||
| + | */ | ||
| + | EntityRenderers.register(EntityTesting.CUBE, | ||
| + | return new CubeEntityRenderer(context); | ||
| + | }); | ||
| + | | ||
| + | EntityModelLayerRegistry.registerModelLayer(MODEL_CUBE_LAYER, | ||
| + | } | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | ===== Creating a Render State ===== | ||
| + | |||
| + | The render state is a class that can be used to store data for the renderer. It is passed into the renderer and model, and can be used to store data about the entity, like the entity' | ||
| + | <code java [enable_line_numbers=" | ||
| + | |||
| + | public class CubeEntityRenderState extends EntityRenderState { | ||
| + | // You can add fields here to store data for the renderer and model. | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | ===== Creating a Model and Texture ===== | ||
| + | |||
| + | The final step to finishing our entity is creating a model and texture. | ||
| + | Models define the // | ||
| + | |||
| + | Standard models define " | ||
| + | initialize them in the constructor, | ||
| + | Note that '' | ||
| + | |||
| + | <code java [enable_line_numbers=" | ||
| + | public class CubeEntityModel extends EntityModel< | ||
| + | |||
| + | private final ModelPart base; | ||
| + | |||
| + | public CubeEntityModel(ModelPart modelPart) { | ||
| + | this.base = modelPart.getChild(PartNames.CUBE); | ||
| + | } | ||
| + | | ||
| + | [...] | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | After creating a part, we need to add a shape to it. | ||
| + | To do so, we must add a child to the root. The texture location for the new part is located in '' | ||
| + | the offset for it is located in the first 3 numbers of '' | ||
| + | Note that the origin of a model starts at the corner, so you will need to offset the part to center it: | ||
| + | |||
| + | <code java [enable_line_numbers=" | ||
| + | public class CubeEntityModel extends EntityModel< | ||
| + | |||
| + | private final ModelPart base; | ||
| + | |||
| + | public CubeEntityModel() { | ||
| + | [...] | ||
| + | } | ||
| + | | ||
| + | // You can use BlockBench, make your model and export it to get this method for your entity model. | ||
| + | public static LayerDefinition getTexturedModelData() { | ||
| + | MeshDefinition modelData = new MeshDefinition(); | ||
| + | PartDefinition modelPartData = modelData.getRoot(); | ||
| + | modelPartData.addOrReplaceChild(PartNames.CUBE, | ||
| + | return LayerDefinition.create(modelData, | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | Our entity model now has a single cube that is 12x12x12 wide (75% of a block) centered around 0, 0, 0. | ||
| + | '' | ||
| + | |||
| + | <code java [enable_line_numbers=" | ||
| + | public class CubeEntityModel extends EntityModel< | ||
| + | | ||
| + | private final ModelPart base; | ||
| + | | ||
| + | public CubeEntityModel() [...] | ||
| + | | ||
| + | public static LayerDefinition getTexturedModelData() [...] | ||
| + | |||
| + | @Override | ||
| + | public void setupAnim(CubeEntityRenderState entity) { | ||
| + | } | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | To complete our model, we need to add a texture file. The default texture size is 64 pixels wide and 32 pixels tall; | ||
| + | you can change this by adding a return of your LayerDefinition with a custom width and height. | ||
| + | We will set it to 64x64 for our texture: | ||
| + | |||
| + | {{https:// | ||
| + | |||
| + | <code java [enable_line_numbers=" | ||
| + | public class CubeEntityModel extends EntityModel< | ||
| + | |||
| + | private final ModelPart base; | ||
| + | |||
| + | [...] | ||
| + | | ||
| + | public static LayerDefinition getTexturedModelData() { | ||
| + | [...] | ||
| + | return LayerDefinition.create(modelData, | ||
| + | } | ||
| + | |||
| + | [...] | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | ===== Spawning your Entity ===== | ||
| + | |||
| + | Be sure to add your client entrypoint to fabric.mod.json. | ||
| + | You can do this like so: | ||
| + | <code json> | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ], | ||
| + | " | ||
| + | " | ||
| + | ] | ||
| + | }, | ||
| + | </ | ||
| + | You can spawn your entity by typing ''/ | ||
| + | {{https:// | ||
| + | |||
| + | **NOTE:** If your entity does not extend '' | ||
| + | ===== Adding tasks & activities ===== | ||
| + | |||
| + | To add activities see [[tutorial: | ||