User Tools

Site Tools


tutorial:entity

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
Next revisionBoth sides next revision
tutorial:entity [2020/06/11 20:18] – created draylartutorial:entity [2022/01/04 13:12] banana
Line 1: Line 1:
 ===== Creating an Entity ===== ===== Creating an Entity =====
 +
 +//The source code for this project can be found [[https://github.com/Draylar/entity-testing/tree/entity|here]].//
  
 Entities are a movable object in a world with logic attached to them. A few examples include: Entities are a movable object in a world with logic attached to them. A few examples include:
Line 8: Line 10:
 Living Entities are Entities that have health and can deal damage.  Living Entities are Entities that have health and can deal damage. 
 There are various classes that branch off `LivingEntity` for different purposes, including: There are various classes that branch off `LivingEntity` for different purposes, including:
-  * ''HostileEntity'' for Zombies, Creepersand Skeletons +  * ''HostileEntity'' for Zombies, Creepers and Skeletons 
-  * ''AnimalEntity'' for Sheep, Cowsand Pigs+  * ''AnimalEntity'' for Sheep, Cows and Pigs
   * ''WaterCreatureEntity'' for things that swim   * ''WaterCreatureEntity'' for things that swim
   * ''FishEntity'' for fishies   * ''FishEntity'' for fishies
    
-What you extend depends on your needs and goals are. +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. 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 ''LivingEntity'' are: The two generic entity classes that come after ''LivingEntity'' are:
   * ''MobEntity''   * ''MobEntity''
-  * ''MobEntityWithAi''+  * ''PathAwareEntity''
    
-''MobEntity'' has AI logic and movement controls. ''MobEntityWithAi'' provides extra capabilities+''MobEntity'' has AI logic and movement controls. ''PathAwareEntity'' provides extra capabilities
 for pathfinding favor, and various AI tasks require this to operate. for pathfinding favor, and various AI tasks require this to operate.
  
-In this tutorial, we will look at creating a cube entity that extends ''MobEntityWithAi''.+In this tutorial, we will look at creating a cube entity that extends ''PathAwareEntity''.
 This entity will have a model & texture. Movement and mechanics will be covered in a future tutorial. This entity will have a model & texture. Movement and mechanics will be covered in a future tutorial.
  
 ===== Creating & Registering an Entity ===== ===== Creating & Registering an Entity =====
  
-Create a class that extends ''MobEntityWithAi''. This class serves as the brains and main hub for our custom entity.+Create a class that extends ''PathAwareEntity''. This class serves as the brains and main hub for our custom entity.
  
 <code java [enable_line_numbers="true"]> <code java [enable_line_numbers="true"]>
 /* /*
- * Our Cube Entity extends MobEntityWithAi, which extends MobEntity, which extends LivingEntity.+ * Our Cube Entity extends PathAwareEntity, which extends MobEntity, which extends LivingEntity.
  *  *
  * LivingEntity has health and can deal damage.  * LivingEntity has health and can deal damage.
  * MobEntity has movement controls and AI capabilities.  * MobEntity has movement controls and AI capabilities.
- MobEntityWithAi has pathfinding favor and slightly tweaked leash behavior.+ PathAwareEntity has pathfinding favor and slightly tweaked leash behavior.
  */  */
-public class CubeEntity extends MobEntityWithAi {+public class CubeEntity extends PathAwareEntity {
  
-    public CubeEntity(EntityType<? extends MobEntityWithAi> entityType, World world) {+    public CubeEntity(EntityType<? extends PathAwareEntity> entityType, World world) {
         super(entityType, world);         super(entityType, world);
     }     }
Line 123: Line 125:
 public class CubeEntityRenderer extends MobEntityRenderer<CubeEntity, CubeEntityModel> { public class CubeEntityRenderer extends MobEntityRenderer<CubeEntity, CubeEntityModel> {
  
-    public CubeEntityRenderer(EntityRenderDispatcher entityRenderDispatcher) { +    public CubeEntityRenderer(EntityRendererFactory.Context context) { 
-        super(entityRenderDispatcher, new CubeEntityModel(), 0.5f);+        super(context, new CubeEntityModel(context.getPart(EntityTestingClient.MODEL_CUBE_LAYER)), 0.5f);
     }     }
  
Line 138: Line 140:
 @Environment(EnvType.CLIENT) @Environment(EnvType.CLIENT)
 public class EntityTestingClient implements ClientModInitializer { public class EntityTestingClient implements ClientModInitializer {
 +    public static final EntityModelLayer MODEL_CUBE_LAYER = new EntityModelLayer(new Identifier("entitytesting", "cube"), "main");
     @Override     @Override
     public void onInitializeClient() {     public void onInitializeClient() {
Line 146: Line 148:
          * Entity Renderers can also manipulate the model before it renders based on entity context (EndermanEntityRenderer#render).          * Entity Renderers can also manipulate the model before it renders based on entity context (EndermanEntityRenderer#render).
          */          */
-        EntityRendererRegistry.INSTANCE.register(EntityTesting.CUBE, (dispatcher, context) -> { +        EntityRendererRegistry.INSTANCE.register(EntityTesting.CUBE, (context) -> { 
-            return new CubeEntityRenderer(dispatcher);+            return new CubeEntityRenderer(context);
         });         });
 +        // In 1.17, use EntityRendererRegistry.register (seen below) instead of EntityRendererRegistry.INSTANCE.register (seen above)
 +        EntityRendererRegistry.register(EntityTesting.CUBE, (context) -> {
 +            return new CubeEntityRenderer(context);
 +        });
 +        
 +        EntityModelLayerRegistry.registerModelLayer(MODEL_CUBE_LAYER, CubeEntityModel::getTexturedModelData);
     }     }
 } }
Line 159: Line 167:
  
 Standard models define "parts", or ''ModelPart'' instances at the top of the class,  Standard models define "parts", or ''ModelPart'' instances at the top of the class, 
-initialize them in the constructor, and render them in the ''render'' method. +initialize them in the constructor, obtain data in the ''getTexturedModelData'' method, and render them in the ''render'' method. 
 Note that ''setAngles'' and ''render'' are both required overrides of the ''EntityModel'' class. Note that ''setAngles'' and ''render'' are both required overrides of the ''EntityModel'' class.
- 
-''ModelPart'' has several constructors, with the most simple one taking in: 
-  * the current model instance 
-  * textureOffsetU as an ''int'' 
-  * textureOffsetV as an ''int'' 
-  
-Texture offsets provide the location of the model's texture within your texture file.  
-Our entity is a single cube, so the base ''ModelPart'' texture starts at 0, 0. 
  
 <code java [enable_line_numbers="true"]> <code java [enable_line_numbers="true"]>
Line 175: Line 175:
     private final ModelPart base;     private final ModelPart base;
  
-    public CubeEntityModel() { +    public CubeEntityModel(ModelPart modelPart) { 
-        base = new ModelPart(this, 0, 0);+        this.base = modelPart.getChild(EntityModelPartNames.CUBE);
     }     }
          
Line 183: Line 183:
 </code> </code>
  
-After creating a part, we need to add a shape to it. +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 ''.uv'', 
 +the offset for it is located in the first 3 numbers of ''.cuboid'', and the size is the last 3 numbers in ''.cuboid''
 Note that the origin of a model starts at the corner, so you will need to offset the part to center it: Note that the origin of a model starts at the corner, so you will need to offset the part to center it:
  
Line 192: Line 194:
  
     public CubeEntityModel() {     public CubeEntityModel() {
-        base = new ModelPart(this, 0, 0); +        [...]
-        base.addCuboid(-6, -6, -6, 12, 12, 12);+
     }     }
          
-    [...] +    public static TexturedModelData getTexturedModelData() { 
-}+        ModelData modelData = new ModelData(); 
 +    ModelPartData modelPartData = modelData.getRoot(); 
 +        modelPartData.addChild(EntityModelPartNames.CUBE, ModelPartBuilder.create().uv(0, 0).cuboid(-6F, 12F, -6F, 12F, 12F, 12F), ModelTransform.pivot(0F, 0F, 0F)); 
 +    }
 </code> </code>
  
Line 211: Line 215:
          
     public CubeEntityModel() [...]     public CubeEntityModel() [...]
 +    
 +    public static TexturedModelData getTexturedModelData() [...]
  
     @Override     @Override
     public void setAngles(CubeEntity entity, float limbAngle, float limbDistance, float animationProgress, float headYaw, float headPitch) {     public void setAngles(CubeEntity entity, float limbAngle, float limbDistance, float animationProgress, float headYaw, float headPitch) {
- 
     }     }
  
     @Override     @Override
     public void render(MatrixStack matrices, VertexConsumer vertices, int light, int overlay, float red, float green, float blue, float alpha) {     public void render(MatrixStack matrices, VertexConsumer vertices, int light, int overlay, float red, float green, float blue, float alpha) {
-        // translate model down +        ImmutableList.of(this.base).forEach((modelRenderer) -> { 
-        matrices.translate(0, 1.125, 0); +            modelRenderer.render(matrices, vertices, light, overlay, red, green, blue, alpha); 
- +        });
-        // render cube +
-        base.render(matrices, vertices, light, overlay);+
     }     }
 } }
Line 229: Line 232:
  
 To complete our model, we need to add a texture file. The default texture size is 64 wide and 32 tall; 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 changing ''textureWidth'' and ''textureHeight'' in your model constructor.+you can change this by adding a return of your texturedModelData
 We will set it to 64x64 for our texture: We will set it to 64x64 for our texture:
  
Line 239: Line 242:
     private final ModelPart base;     private final ModelPart base;
  
-    public CubeEntityModel() { +    [...] 
-        this.textureHeight = 64; +     
-        this.textureWidth = 64; +    public static TexturedModelData getTexturedModelData() {
-   +
         [...]         [...]
 +        return TexturedModelData.of(modelData, 64, 64);
     }     }
  
Line 252: Line 255:
 ===== Spawning your Entity ===== ===== Spawning your Entity =====
  
 +Be sure to add your client entrypoint to fabric.mod.json.
 +You can do this like so:
 +<code json>
 +
 +  "entrypoints": {
 +    "main": [
 +      "mod.fabricmc.entitytesting.EntityTesting"
 +    ],
 +    "client": [
 +      "mod.fabricmc.entitytesting.EntityTestingClient"
 +    ]
 +  },
 +</code>
 You can spawn your entity by typing ''/summon entitytesting:cube'' in-game. Press f3+b to view hitboxes: You can spawn your entity by typing ''/summon entitytesting:cube'' in-game. Press f3+b to view hitboxes:
 {{https://i.imgur.com/MmQvluB.png}} {{https://i.imgur.com/MmQvluB.png}}
 +
 +**NOTE:** If your entity does not extend ''LivingEntity'' you have to create your own spawn packet handler. Either do this through the networking API, or mixin to ''ClientPlayNetworkHandler#onEntitySpawn''
 +===== Adding tasks & activities =====
 +
 +To add activities see [[:villager_activities|here]].
  
tutorial/entity.txt · Last modified: 2023/09/13 20:30 by nebelnidas