tutorial:entity
Differences
This shows you the differences between two versions of the page.
| Previous revision | |||
| — | tutorial:entity [2025/03/31 13:02] (current) – new Identifier -> Identifier.of slainlight | ||
|---|---|---|---|
| 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 PathAwareEntity, | ||
| + | * | ||
| + | * LivingEntity has health and can deal damage. | ||
| + | * MobEntity has movement controls and AI capabilities. | ||
| + | * PathAwareEntity has pathfinding favor and slightly tweaked leash behavior. | ||
| + | */ | ||
| + | public class CubeEntity extends PathAwareEntity { | ||
| + | |||
| + | 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 SpawnGroup# | ||
| + | * It has a hitbox size of .75x.75, or 12 " | ||
| + | */ | ||
| + | public static final EntityType< | ||
| + | Registries.ENTITY_TYPE, | ||
| + | Identifier.of(" | ||
| + | EntityType.Builder.create(CubeEntity:: | ||
| + | ); | ||
| + | |||
| + | @Override | ||
| + | public void onInitialize() { | ||
| + | | ||
| + | } | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | Entities need // | ||
| + | |||
| + | ===== Registering Entity Attributes ===== | ||
| + | |||
| + | **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. ZombieEntity# | ||
| + | */ | ||
| + | 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 MobEntityRenderer< | ||
| + | |||
| + | public CubeEntityRenderer(EntityRendererFactory.Context context) { | ||
| + | super(context, | ||
| + | } | ||
| + | |||
| + | @Override | ||
| + | public Identifier getTexture(CubeEntity entity) { | ||
| + | return Identifier.of(" | ||
| + | } | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | To register this renderer, use '' | ||
| + | <code java [enable_line_numbers=" | ||
| + | @Environment(EnvType.CLIENT) | ||
| + | public class EntityTestingClient implements ClientModInitializer { | ||
| + | public static final EntityModelLayer MODEL_CUBE_LAYER = new EntityModelLayer(Identifier.of(" | ||
| + | @Override | ||
| + | public void onInitializeClient() { | ||
| + | /* | ||
| + | * Registers our Cube Entity' | ||
| + | * | ||
| + | * Entity Renderers can also manipulate the model before it renders based on entity context (EndermanEntityRenderer# | ||
| + | */ | ||
| + | EntityRendererRegistry.INSTANCE.register(EntityTesting.CUBE, | ||
| + | return new CubeEntityRenderer(context); | ||
| + | }); | ||
| + | // In 1.17, use EntityRendererRegistry.register (seen below) instead of EntityRendererRegistry.INSTANCE.register (seen above) | ||
| + | EntityRendererRegistry.register(EntityTesting.CUBE, | ||
| + | return new CubeEntityRenderer(context); | ||
| + | }); | ||
| + | | ||
| + | EntityModelLayerRegistry.registerModelLayer(MODEL_CUBE_LAYER, | ||
| + | } | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | ===== 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(EntityModelPartNames.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 TexturedModelData getTexturedModelData() { | ||
| + | ModelData modelData = new ModelData(); | ||
| + | ModelPartData modelPartData = modelData.getRoot(); | ||
| + | modelPartData.addChild(EntityModelPartNames.CUBE, | ||
| + | return TexturedModelData.of(modelData, | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | Our entity model now has a single cube that is 12x12x12 wide (75% of a block) centered around 0, 0, 0. | ||
| + | '' | ||
| + | '' | ||
| + | than the entity hitbox, so we translate the model down to account for this. | ||
| + | |||
| + | <code java [enable_line_numbers=" | ||
| + | public class CubeEntityModel extends EntityModel< | ||
| + | | ||
| + | private final ModelPart base; | ||
| + | | ||
| + | public CubeEntityModel() [...] | ||
| + | | ||
| + | public static TexturedModelData getTexturedModelData() [...] | ||
| + | |||
| + | @Override | ||
| + | public void setAngles(CubeEntity entity, float limbAngle, float limbDistance, | ||
| + | } | ||
| + | |||
| + | @Override | ||
| + | public void render(MatrixStack matrices, VertexConsumer vertices, int light, int overlay, float red, float green, float blue, float alpha) { | ||
| + | ImmutableList.of(this.base).forEach((modelRenderer) -> { | ||
| + | modelRenderer.render(matrices, | ||
| + | }); | ||
| + | } | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | To complete our model, we need to add a texture file. The default texture size is 64 wide and 32 tall; | ||
| + | you can change this by adding a return of your texturedModelData | ||
| + | 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 TexturedModelData getTexturedModelData() { | ||
| + | [...] | ||
| + | return TexturedModelData.of(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: | ||