一.创建三个类分别继承 Entity , EntityRenderer , EntityModel<>
public class FlyingSwordEntity extends Entity {
public FlyingSwordEntity(EntityType<?> entityType, Level level){
super(entityType, level);
}
}
public class FlyingSwordEntityRenderer extends EntityRenderer {
public FlyingSwordEntityRenderer(EntityRendererProvider.Context context) {
super(context);
flyingSwordModel = new FlyingSwordModel(context.bakeLayer(FlyingSwordModel.LAYER_LOCATION));
}
}
public class FlyingSwordModel extends EntityModel<FlyingSwordEntity> {
private final ModelPart body;
public static final ModelLayerLocation LAYER_LOCATION =
new ModelLayerLocation(new ResourceLocation(TestMod.MODID, "flying_sword_entity"), "main");
public FlyingSwordModel(ModelPart modelPart) {
this.body = modelPart.getChild("body");
}
}
二.完善FlyingSwordEntity
private static final EntityDataAccessor<Integer> COUNTER =
SynchedEntityData.defineId(FlyingSwordEntity.class, EntityDataSerializers.INT);
@Override
public void tick() {
Integer i=this.entityData.get(COUNTER); //获取实体数据
if(!this.level().isClientSide()){ //服务端执行逻辑
this.entityData.set(COUNTER,i+1); //设置实体数据
}
super.tick();
}
@Override
protected void defineSynchedData() {
this.entityData.define(COUNTER,0);
}
@Override
protected void readAdditionalSaveData(CompoundTag compoundTag) {
this.entityData.set(COUNTER,compoundTag.getInt("counter"));
}
@Override
protected void addAdditionalSaveData(CompoundTag compoundTag) {
compoundTag.putInt("counter",this.entityData.get(COUNTER));
}
- COUNTER : 实体数据同步器(INT类型)
- tick : 状态更新
- defineSynchedData : 初始化
- readAdditionalSaveData/addAdditionalSaveData : 数据更新和储存
三. 完善FlyingSwordEntityRenderer
private EntityModel<FlyingSwordEntity> flyingSwordModel;
@Override
public ResourceLocation getTextureLocation(Entity entity) {
return new ResourceLocation(TestMod.MODID, "textures/entity/flying_sword_entity.png");
}
@Override
public void render(Entity entity, float entityYaw, float partialTick, PoseStack poseStack, MultiBufferSource buffer, int packedLight) {
super.render(entity, entityYaw, partialTick, poseStack, buffer, packedLight);
poseStack.pushPose();
poseStack.mulPose(Axis.YN.rotationDegrees(45));
poseStack.translate(0, -1, 0);
VertexConsumer vertexConsumer =
buffer.getBuffer(flyingSwordModel.renderType(getTextureLocation(entity)));
this.flyingSwordModel.renderToBuffer(
poseStack,vertexConsumer,packedLight,
OverlayTexture.NO_OVERLAY,1f,1f,1f,1f
);
poseStack.popPose();
}
- flyingSwordModel : 实体模型存储
- getTextureLocation : 获取实体模型文件
- render : 渲染
四.把这三个东西注册到游戏中
先注册Entity,另外两个有点特殊
public static final DeferredRegister<EntityType<?>> ENTITY_TYPES =
DeferredRegister.create(Registries.ENTITY_TYPE, TestMod.MODID);
public static final Supplier<EntityType<FlyingSwordEntity>> FLYING_SWORD_ENTITY =
ENTITY_TYPES.register("flying_sword_entity",
() -> EntityType.Builder.of(FlyingSwordEntity::new, MobCategory.MISC).sized(2, 0.5F).build("flying_sword_entity"));
记得放进线程
ENTITY_TYPES.register(bus);
然后再注册另外两个
@SubscribeEvent
public static void registerEntityLayers(EntityRenderersEvent.RegisterLayerDefinitions evt) {
evt.registerLayerDefinition(FlyingSwordModel.LAYER_LOCATION, FlyingSwordModel::createBodyLayer);
}
@SubscribeEvent
public static void onClientEvent(FMLClientSetupEvent event){
event.enqueueWork(()->{
EntityRenderers.register(Registry.FLYING_SWORD_ENTITY.get(), FlyingSwordEntityRenderer::new);
});
}
最后导入材质,进入游戏就可以用summon指令生成我们的实体啦
附完整代码
FlyingSwordEntity
import com.mojang.logging.LogUtils;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.syncher.EntityDataAccessor;
import net.minecraft.network.syncher.EntityDataSerializers;
import net.minecraft.network.syncher.SynchedEntityData;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityType;
import org.slf4j.Logger;
import net. minecraft. world. level. Level;
public class FlyingSwordEntity extends Entity {
private static final Logger LOGGER = LogUtils.getLogger(); //创建日志
//实体数据同步器(INT类型)
private static final EntityDataAccessor<Integer> COUNTER =
SynchedEntityData.defineId(FlyingSwordEntity.class, EntityDataSerializers.INT);
@Override
public void tick() {
Integer i=this.entityData.get(COUNTER); //获取实体数据
LOGGER.info(i.toString()); //打印日志
if(!this.level().isClientSide()){ //服务端执行逻辑
this.entityData.set(COUNTER,i+1); //设置实体数据
}
super.tick();
}
//构造方法
public FlyingSwordEntity(EntityType<?> entityType, Level level){
super(entityType, level);
}
//实体数据同步器初始化
@Override
protected void defineSynchedData() {
this.entityData.define(COUNTER,0);
}
@Override
protected void readAdditionalSaveData(CompoundTag compoundTag) {
this.entityData.set(COUNTER,compoundTag.getInt("counter"));
}
@Override
protected void addAdditionalSaveData(CompoundTag compoundTag) {
compoundTag.putInt("counter",this.entityData.get(COUNTER));
}
}
FlyingSwordEntityRenderer
import com.XXXYJade17.TestMod.TestMod;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.VertexConsumer;
import com.mojang.math.Axis;
import net.minecraft.client.model.EntityModel;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.entity.EntityRenderer;
import net.minecraft.client.renderer.entity.EntityRendererProvider;
import net.minecraft.client.renderer.texture.OverlayTexture;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.entity.Entity;
public class FlyingSwordEntityRenderer extends EntityRenderer {
private EntityModel<FlyingSwordEntity> flyingSwordModel;
public FlyingSwordEntityRenderer(EntityRendererProvider.Context context) {
super(context);
flyingSwordModel = new FlyingSwordModel(context.bakeLayer(FlyingSwordModel.LAYER_LOCATION));
}
@Override
public ResourceLocation getTextureLocation(Entity entity) {
return new ResourceLocation(TestMod.MODID, "textures/entity/flying_sword_entity.png");
}
@Override
public void render(Entity entity, float entityYaw, float partialTick, PoseStack poseStack, MultiBufferSource buffer, int packedLight) {
super.render(entity, entityYaw, partialTick, poseStack, buffer, packedLight);
poseStack.pushPose();
poseStack.mulPose(Axis.YN.rotationDegrees(45));
poseStack.translate(0, -1, 0);
VertexConsumer vertexConsumer = buffer.getBuffer(flyingSwordModel.renderType(getTextureLocation(entity)));
this.flyingSwordModel.renderToBuffer(poseStack,vertexConsumer,packedLight, OverlayTexture.NO_OVERLAY,1f,1f,1f,1f);
poseStack.popPose();
}
}
FlyingSwordModel
import com.XXXYJade17.TestMod.TestMod;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.VertexConsumer;
import net.minecraft.client.model.EntityModel;
import net.minecraft.client.model.geom.ModelLayerLocation;
import net.minecraft.client.model.geom.ModelPart;
import net.minecraft.client.model.geom.PartPose;
import net.minecraft.client.model.geom.builders.*;
import net.minecraft.resources.ResourceLocation;
public class FlyingSwordModel extends EntityModel<FlyingSwordEntity> {
public static final ModelLayerLocation LAYER_LOCATION = new ModelLayerLocation(new ResourceLocation(TestMod.MODID, "flying_sword_entity"), "main");
private final ModelPart body;
public FlyingSwordModel(ModelPart modelPart) {
this.body = modelPart.getChild("body");
}
public static LayerDefinition createBodyLayer() {
MeshDefinition meshDefinition = new MeshDefinition(); // 创建网格定义
PartDefinition partDefinition = meshDefinition.getRoot();
PartDefinition body= partDefinition.addOrReplaceChild("body",
CubeListBuilder.create().texOffs(0, 0).addBox(-1.0F, -1.0F, -18.0F, 3.0F, 1.0F, 19.0F, new CubeDeformation(0.0F))
.texOffs(0, 20).addBox(-3.0F, -2.0F, -1.0F, 7.0F, 3.0F, 3.0F, new CubeDeformation(0.0F))
.texOffs(0, 0).addBox(-1.0F, -1.0F, 1.0F, 3.0F, 1.0F, 5.0F, new CubeDeformation(0.0F)), PartPose.offset(0.0F, 23.0F, 0.0F));
return LayerDefinition.create(meshDefinition, 64, 64);
}
@Override
public void setupAnim(FlyingSwordEntity entity, float limbSwing, float limbSwingAmount, float ageInTicks, float netHeadYaw, float headPitch) {
//置剑身体body的三维旋转角度,分别对应于X轴(pLimbSwing)、Y轴(pNetHeadYaw)和Z轴(pHeadPitch)的旋转。
body.xRot = limbSwing;
body.yRot = netHeadYaw;
body.zRot = headPitch;
}
@Override
public void renderToBuffer(PoseStack poseStack, VertexConsumer buffer, int packedLight, int packedOverlay, float red, float green, float blue, float alpha) {
body.render(poseStack, buffer, packedLight, packedOverlay, red, green, blue, alpha);
}
}
ClientEventHandler
import com.XXXYJade17.TestMod.Registry;
import net.minecraft.client.renderer.entity.EntityRenderers;
import net.neoforged.api.distmarker.Dist;
import net.neoforged.bus.api.SubscribeEvent;
import net.neoforged.fml.common.Mod;
import net.neoforged.fml.event.lifecycle.FMLClientSetupEvent;
import net.neoforged.neoforge.client.event.EntityRenderersEvent;
@Mod.EventBusSubscriber(bus = Mod.EventBusSubscriber.Bus.MOD,value = Dist.CLIENT)
public class ClientEventHandler {
@SubscribeEvent
public static void registerEntityLayers(EntityRenderersEvent.RegisterLayerDefinitions evt) {
evt.registerLayerDefinition(FlyingSwordModel.LAYER_LOCATION, FlyingSwordModel::createBodyLayer);
}
@SubscribeEvent
public static void onClientEvent(FMLClientSetupEvent event){
event.enqueueWork(()->{
EntityRenderers.register(Registry.FLYING_SWORD_ENTITY.get(), FlyingSwordEntityRenderer::new);
});
}
}