注:1.16.5的实体教程和本文基本类似,只是一些类中的函数名称有所不同。
我们今天在1.18.1的模组中添加一个生物实体
1.新建entity文件夹 -> 文件夹中新建一个model文件夹,一个render文件夹,一个我们的生物类(以EntityRe8Dimi.java为例)
我们本次要制作一个boss类怪物,类似于凋零,具有boss血条
EntityRe8Dimi.java
package com.joy187.re8joymod.entity;
import java.util.Random;
import java.util.function.Predicate;
import javax.annotation.Nullable;
import com.joy187.re8joymod.init.EntityInit;
import com.mojang.blaze3d.vertex.PoseStack.Pose;
import net.minecraft.client.renderer.EffectInstance;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.chat.Component;
import net.minecraft.network.syncher.EntityDataAccessor;
import net.minecraft.network.syncher.EntityDataSerializers;
import net.minecraft.network.syncher.SynchedEntityData;
import net.minecraft.server.level.ServerBossEvent;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.sounds.SoundEvent;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.world.BossEvent;
import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.world.effect.MobEffectInstance;
import net.minecraft.world.effect.MobEffects;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityDimensions;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.MobType;
import net.minecraft.world.entity.ai.attributes.AttributeSupplier;
import net.minecraft.world.entity.ai.attributes.Attributes;
import net.minecraft.world.entity.ai.goal.LookAtPlayerGoal;
import net.minecraft.world.entity.ai.goal.RandomLookAroundGoal;
import net.minecraft.world.entity.ai.goal.WaterAvoidingRandomStrollGoal;
import net.minecraft.world.entity.ai.goal.target.HurtByTargetGoal;
import net.minecraft.world.entity.ai.goal.target.NearestAttackableTargetGoal;
import net.minecraft.world.entity.animal.IronGolem;
import net.minecraft.world.entity.boss.wither.WitherBoss;
import net.minecraft.world.entity.monster.Monster;
import net.minecraft.world.entity.monster.Ravager;
import net.minecraft.world.entity.monster.ZombifiedPiglin;
import net.minecraft.world.entity.npc.AbstractVillager;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.pathfinder.BlockPathTypes;
import net.minecraftforge.client.event.RenderGameOverlayEvent.BossInfo;
//我们的boss继承自劫掠兽
public class EntityRe8Dimi extends Ravager {
//boss血条信息
private final ServerBossEvent bossInfo = (ServerBossEvent)(new ServerBossEvent(this.getDisplayName(), BossEvent.BossBarColor.PURPLE, BossEvent.BossBarOverlay.PROGRESS)).setDarkenScreen(true);
private static final EntityDataAccessor<Integer> DATA_ID_INV = SynchedEntityData.defineId(EntityRe8Dimi.class, EntityDataSerializers.INT);
//我们的boss不攻击类型为不死亡灵类的生物(凋零骷髅一类)
private static final Predicate<LivingEntity> LIVING_ENTITY_SELECTOR = (p_31504_) -> {
return p_31504_.getMobType() != MobType.UNDEAD && p_31504_.attackable();
};
public EntityRe8Dimi(EntityType<? extends Ravager> type, Level worldIn) {
super(type, worldIn);
this.xpReward = 150;
this.isNonBoss();
this.isSunSensitive();
this.setPathfindingMalus(BlockPathTypes.LAVA, 8.0F);
}
//是否怕阳光
protected boolean isSunSensitive() {
return true;
}
public void aiStep() {
super.aiStep();
}
//设置生物属性(最大血量、移动速度、攻击力、护甲值等)
public static AttributeSupplier.Builder prepareAttributes() {
return Monster.createMonsterAttributes().add(Attributes.MAX_HEALTH, 120.0D).
add(Attributes.MOVEMENT_SPEED, 0.28D).
add(Attributes.FOLLOW_RANGE, 48.0D).
add(Attributes.ARMOR, 8.0D).
add(Attributes.ARMOR_TOUGHNESS, 10.0D).
add(Attributes.KNOCKBACK_RESISTANCE, 0.85D).
add(Attributes.ATTACK_DAMAGE, 9.0D);
}
//给生物设置攻击行为
@Override
protected void registerGoals() {
super.registerGoals();
this.goalSelector.addGoal(1, new RandomLookAroundGoal(this));
this.goalSelector.addGoal(2, new LookAtPlayerGoal(this, Player.class, 8.0F));
this.targetSelector.addGoal(1, new NearestAttackableTargetGoal<>(this, LivingEntity.class, 0, false, false, LIVING_ENTITY_SELECTOR));
this.addBehaviourGoals();
}
//给生物添加其行为
protected void addBehaviourGoals() {
this.goalSelector.addGoal(7, new WaterAvoidingRandomStrollGoal(this, 1.0D));
this.targetSelector.addGoal(1, (new HurtByTargetGoal(this)).setAlertOthers(ZombifiedPiglin.class));
this.targetSelector.addGoal(2, new NearestAttackableTargetGoal<>(this, Player.class, true));
this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, AbstractVillager.class, false));
this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, IronGolem.class, true));
// this.targetSelector.addGoal(4, new NearestAttackableTargetGoal<>(this, EntityEthan.class, true));
}
//生物攻击其他生物
public boolean doHurtTarget(Entity entityIn) {
if(!super.doHurtTarget(entityIn))
{
return false;
}
else{
//如果攻击的对象是生物,就给这个对象一个凋零效果,持续1s(20ticks=1s)
if(entityIn instanceof LivingEntity)
{
((LivingEntity)entityIn).addEffect(new MobEffectInstance(MobEffects.WITHER, 20,0,true,true));
}
return true;
}
}
//生物死亡音效
@Override
protected SoundEvent getDeathSound() {
// Random ran = new Random();
// int co = ran.nextInt(3);
// if(co==0)
// {
// return SoundInit.ENTITY_DIMI_DEATH1.get();
// }
// else if(co==1) return SoundInit.ENTITY_DIMI_DEATH2.get();
return SoundEvents.BEE_DEATH;
}
// 生物在玩家身边的音效
protected SoundEvent getAmbientSound() {
// Random ran = new Random();
// int co = ran.nextInt(2);
// if(co==0)
// {
// return SoundInit.ENTITY_DIMI_AMBIENT1.get();
// }
// return SoundInit.ENTITY_DIMI_AMBIENT2.get();
return SoundEvents.ZOMBIE_AMBIENT;
}
// 生物受伤音效
// @Override
// protected SoundEvent getHurtSound(DamageSource source) {
// Random ran = new Random();
// int co = ran.nextInt(2);
// if(co==0)
// {
// return SoundInit.ENTITY_DIMI_HURT1.get();
// }
// return SoundInit.ENTITY_DIMI_HURT2.get();
// }
protected float getStandingEyeHeight(Pose p_213348_1_, EntityDimensions p_213348_2_) {
return 3F;
}
public void setInvulnerableTicks(int p_82215_1_) {
this.entityData.set(DATA_ID_INV, p_82215_1_);
}
public void readAdditionalSaveData(CompoundTag p_70037_1_) {
super.readAdditionalSaveData(p_70037_1_);
this.setInvulnerableTicks(p_70037_1_.getInt("Invul"));
if (this.hasCustomName()) {
this.bossInfo.setName(this.getDisplayName());
}
}
public void setCustomName(@Nullable Component p_200203_1_) {
super.setCustomName(p_200203_1_);
this.bossInfo.setName(this.getDisplayName());
}
protected void customServerAiStep() {
super.customServerAiStep();
if(this.isSunSensitive()){
this.addEffect(new MobEffectInstance(MobEffects.FIRE_RESISTANCE, 20*10,1,true,true));
}
Random ran = new Random();
if(this.getHealth() >= 20.0F && this.getHealth()<=30.0F)
{
for(int i=0;i<5;i++)
this.heal(1.0F*ran.nextFloat());
}
if(this.getHealth() >= 60.0F && this.getHealth()<=65.0F)
{
for(int i=0;i<4;i++)
this.heal(1.5F*ran.nextFloat());
}
// if(this.getHealth() >= 0.1F && this.getHealth()<=10.0F)
// {
// this.convertTo(EntityDimi2,true);
// EntityDimi2 e = new EntityDimi2(EntityInit.DIMI2.get(),this.level);
// e.copyPosition(this);
// this.level.addFreshEntity(e);
// this.remove();
//
// }
this.bossInfo.setProgress(this.getHealth() / this.getMaxHealth());
}
public boolean isNonBoss()
{
return false;
}
//什么时候能看见boss血条
public void startSeenByPlayer(ServerPlayer p_184178_1_) {
super.startSeenByPlayer(p_184178_1_);
this.bossInfo.addPlayer(p_184178_1_);
}
//什么时候看不见boss血条
public void stopSeenByPlayer(ServerPlayer p_184203_1_) {
super.stopSeenByPlayer(p_184203_1_);
this.bossInfo.removePlayer(p_184203_1_);
}
}
打开我们的blockbench -> 制作boss的3D模型 -> 导出制作好的模型
把我们的模型文件放入上面新建的model文件夹中
ModelRe8Dimi.java
package com.joy187.re8joymod.entity.model;
import com.joy187.re8joymod.Main;
import com.joy187.re8joymod.entity.EntityRe8Dimi;
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.CubeDeformation;
import net.minecraft.client.model.geom.builders.CubeListBuilder;
import net.minecraft.client.model.geom.builders.LayerDefinition;
import net.minecraft.client.model.geom.builders.MeshDefinition;
import net.minecraft.client.model.geom.builders.PartDefinition;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.util.Mth;
// Made with Blockbench 4.1.3
// Exported for Minecraft version 1.17 with Mojang mappings
// Paste this class into your mod and generate all required imports
public class ModelRe8Dimi<T extends EntityRe8Dimi> extends EntityModel<T> {
// This layer location should be baked with EntityRendererProvider.Context in the entity renderer and passed into this model's constructor
//注意这个皮肤路径
public static final ModelLayerLocation LAYER_LOCATION = new ModelLayerLocation(new ResourceLocation(Main.MOD_ID, "re8dimi"), "main");
private final ModelPart Head;
private final ModelPart Body;
private final ModelPart RightArm;
private final ModelPart LeftArm;
private final ModelPart RightLeg;
private final ModelPart LeftLeg;
public ModelRe8Dimi(ModelPart root) {
this.Head = root.getChild("Head");
this.Body = root.getChild("Body");
this.RightArm = root.getChild("RightArm");
this.LeftArm = root.getChild("LeftArm");
this.RightLeg = root.getChild("RightLeg");
this.LeftLeg = root.getChild("LeftLeg");
}
public static LayerDefinition createBodyLayer() {
MeshDefinition meshdefinition = new MeshDefinition();
PartDefinition partdefinition = meshdefinition.getRoot();
PartDefinition Head = partdefinition.addOrReplaceChild("Head", CubeListBuilder.create(), PartPose.offsetAndRotation(-0.4444F, -23.0556F, -3.3889F, -0.1047F, 0.0F, 0.0F));
PartDefinition Head_r1 = Head.addOrReplaceChild("Head_r1", CubeListBuilder.create().texOffs(62, 33).addBox(-4.0F, -9.9993F, -6.9476F, 8.0F, 2.0F, 8.0F, new CubeDeformation(0.0F))
.texOffs(51, 0).addBox(-7.0F, -7.9993F, -6.9476F, 14.0F, 2.0F, 8.0F, new CubeDeformation(0.0F))
.texOffs(75, 43).addBox(-3.0F, -4.9993F, -10.9476F, 13.0F, 1.0F, 2.0F, new CubeDeformation(0.0F))
.texOffs(87, 0).addBox(-12.0F, -4.9993F, -10.9476F, 9.0F, 2.0F, 2.0F, new CubeDeformation(0.0F))
.texOffs(0, 77).addBox(-13.0F, -4.9993F, -10.9476F, 1.0F, 2.0F, 15.0F, new CubeDeformation(0.0F))
.texOffs(68, 66).addBox(9.0F, -5.9993F, -9.9476F, 3.0F, 1.0F, 14.0F, new CubeDeformation(0.0F))
.texOffs(0, 23).addBox(-12.0F, -5.9993F, -9.9476F, 21.0F, 2.0F, 14.0F, new CubeDeformation(0.0F))
.texOffs(32, 80).addBox(-4.0F, -5.9993F, -6.9476F, 8.0F, 8.0F, 8.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(0.4444F, 3.0556F, 5.3889F, 0.1309F, 0.0F, 0.0F));
PartDefinition Body = partdefinition.addOrReplaceChild("Body", CubeListBuilder.create().texOffs(56, 12).addBox(-6.0F, -16.0F, -6.0F, 12.0F, 10.0F, 11.0F, new CubeDeformation(0.0F))
.texOffs(46, 65).addBox(-5.0F, -8.0F, -5.0F, 10.0F, 7.0F, 8.0F, new CubeDeformation(0.0F))
.texOffs(0, 60).addBox(-6.0F, -3.0F, -7.0F, 12.0F, 6.0F, 11.0F, new CubeDeformation(0.0F))
.texOffs(86, 33).addBox(-6.0F, -1.0F, 4.0F, 12.0F, 4.0F, 2.0F, new CubeDeformation(0.0F))
.texOffs(44, 46).addBox(-8.0F, 2.0F, -7.0F, 16.0F, 5.0F, 14.0F, new CubeDeformation(0.0F)), PartPose.offset(0.0F, 0.0F, 0.0F));
PartDefinition Body_r1 = Body.addOrReplaceChild("Body_r1", CubeListBuilder.create().texOffs(0, 39).addBox(-8.0F, -9.0F, -8.0F, 16.0F, 11.0F, 13.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(0.0F, 22.0F, 0.0F, 0.0F, 0.0436F, 0.0F));
PartDefinition Body_r2 = Body.addOrReplaceChild("Body_r2", CubeListBuilder.create().texOffs(0, 0).addBox(-9.0F, -4.0F, -9.0F, 18.0F, 8.0F, 15.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(0.0F, 9.0F, 0.0F, 0.0F, -0.0436F, 0.0F));
PartDefinition Body_r3 = Body.addOrReplaceChild("Body_r3", CubeListBuilder.create().texOffs(88, 65).addBox(-3.0F, -3.0F, -3.5F, 6.0F, 6.0F, 6.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(0.0F, -16.0F, -0.5F, 0.0F, 0.0436F, 0.0F));
PartDefinition Body_r4 = Body.addOrReplaceChild("Body_r4", CubeListBuilder.create().texOffs(64, 81).addBox(-5.0F, -0.5F, -4.0F, 10.0F, 5.0F, 5.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(0.0F, -13.5654F, -6.5679F, 1.0036F, 0.0F, 0.0F));
PartDefinition RightArm = partdefinition.addOrReplaceChild("RightArm", CubeListBuilder.create(), PartPose.offsetAndRotation(-9.0F, -10.0F, -1.0F, -0.2182F, 0.0F, 0.0F));
PartDefinition RightArm_r1 = RightArm.addOrReplaceChild("RightArm_r1", CubeListBuilder.create().texOffs(90, 46).addBox(-3.9816F, -2.2586F, -3.0789F, 4.0F, 6.0F, 6.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(2.0F, -1.759F, -0.7541F, 0.0436F, -0.1745F, 1.4399F));
PartDefinition Rightbacktlib = RightArm.addOrReplaceChild("Rightbacktlib", CubeListBuilder.create(), PartPose.offset(0.0F, 2.0F, 0.0F));
PartDefinition RightArm_r2 = Rightbacktlib.addOrReplaceChild("RightArm_r2", CubeListBuilder.create().texOffs(0, 94).addBox(-5.0F, -6.9981F, -5.0872F, 4.0F, 7.0F, 4.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(3.0F, 0.644F, 3.0686F, 0.1745F, 0.0F, 0.0F));
PartDefinition Rightfrontlib = Rightbacktlib.addOrReplaceChild("Rightfrontlib", CubeListBuilder.create(), PartPose.offset(0.0F, 0.0F, 0.0F));
PartDefinition RightArm_r3 = Rightfrontlib.addOrReplaceChild("RightArm_r3", CubeListBuilder.create().texOffs(0, 38).addBox(-0.1511F, -7.7229F, -1.5045F, 0.0F, 12.0F, 1.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(-3.0422F, 18.6266F, -6.0745F, -0.3054F, 0.0436F, 0.0873F));
PartDefinition RightArm_r4 = Rightfrontlib.addOrReplaceChild("RightArm_r4", CubeListBuilder.create().texOffs(6, 38).addBox(-1.1702F, 4.3202F, -1.0721F, 0.0F, 11.0F, 1.0F, new CubeDeformation(0.0F))
.texOffs(10, 0).addBox(-2.1702F, 3.3202F, -1.0721F, 1.0F, 2.0F, 1.0F, new CubeDeformation(0.0F))
.texOffs(51, 3).addBox(-2.1702F, 3.3202F, -2.0721F, 1.0F, 2.0F, 1.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(0.0F, 6.8017F, -1.1584F, -0.3491F, 0.0F, 0.0873F));
PartDefinition RightArm_r5 = Rightfrontlib.addOrReplaceChild("RightArm_r5", CubeListBuilder.create().texOffs(4, 39).addBox(0.8391F, -3.262F, -0.014F, 1.0F, 12.0F, 0.0F, new CubeDeformation(0.0F))
.texOffs(9, 49).addBox(0.8391F, -3.262F, -0.014F, 1.0F, 2.0F, 1.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(-1.0774F, 11.6115F, -4.6201F, -0.6545F, 0.0F, -0.1745F));
PartDefinition RightArm_r6 = Rightfrontlib.addOrReplaceChild("RightArm_r6", CubeListBuilder.create().texOffs(2, 39).addBox(-0.1609F, -0.9749F, 0.5562F, 1.0F, 12.0F, 0.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(-1.0774F, 11.6115F, -2.6201F, -0.3491F, 0.0F, -0.1745F));
PartDefinition RightArm_r7 = Rightfrontlib.addOrReplaceChild("RightArm_r7", CubeListBuilder.create().texOffs(51, 0).addBox(-0.1609F, -2.6589F, 1.4355F, 1.0F, 2.0F, 1.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(-1.0774F, 11.6115F, -4.6201F, -0.3491F, 0.0F, -0.1745F));
PartDefinition RightArm_r8 = Rightfrontlib.addOrReplaceChild("RightArm_r8", CubeListBuilder.create().texOffs(0, 77).addBox(-2.0F, -6.6868F, -3.0746F, 3.0F, 10.0F, 4.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(0.0F, 6.8017F, -1.1584F, -0.3491F, 0.0F, 0.0F));
PartDefinition nail = Rightfrontlib.addOrReplaceChild("nail", CubeListBuilder.create(), PartPose.offsetAndRotation(-1.3274F, 14.8615F, -4.6201F, -0.0436F, 0.0F, 0.0F));
PartDefinition Rightnail_r1 = nail.addOrReplaceChild("Rightnail_r1", CubeListBuilder.create().texOffs(8, 38).addBox(-0.1281F, -0.5693F, -1.6828F, 0.0F, 11.0F, 1.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(0.25F, -3.25F, 0.0F, -0.1745F, -0.6109F, -0.4363F));
PartDefinition RightArm_r9 = nail.addOrReplaceChild("RightArm_r9", CubeListBuilder.create().texOffs(51, 10).addBox(0.3164F, -2.4682F, -1.5852F, 1.0F, 2.0F, 1.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(0.25F, -3.25F, 0.0F, -0.3491F, 0.0F, -0.4363F));
PartDefinition LeftArm = partdefinition.addOrReplaceChild("LeftArm", CubeListBuilder.create(), PartPose.offsetAndRotation(8.4442F, -8.8343F, -0.4302F, 0.2094F, 0.0F, 0.0F));
PartDefinition LeftArm_r1 = LeftArm.addOrReplaceChild("LeftArm_r1", CubeListBuilder.create().texOffs(88, 85).addBox(-0.0164F, -3.2557F, -2.0027F, 4.0F, 6.0F, 6.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(-0.5558F, -3.3343F, -0.4302F, 0.0436F, -0.2182F, -1.4399F));
PartDefinition Leftlib = LeftArm.addOrReplaceChild("Leftlib", CubeListBuilder.create(), PartPose.offset(0.5558F, 2.5308F, -0.3245F));
PartDefinition LeftArm_r2 = Leftlib.addOrReplaceChild("LeftArm_r2", CubeListBuilder.create().texOffs(17, 77).addBox(-2.0F, -5.4988F, -1.9302F, 4.0F, 7.0F, 4.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(0.0F, -3.0F, 0.0F, -0.1745F, 0.0F, 0.0F));
PartDefinition LeftArm_r3 = Leftlib.addOrReplaceChild("LeftArm_r3", CubeListBuilder.create().texOffs(16, 94).addBox(-1.0F, -9.076F, -3.2313F, 3.0F, 7.0F, 4.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(0.0F, 4.0829F, -5.6691F, -0.8727F, 0.0F, 0.0F));
PartDefinition Leftfrontlib = Leftlib.addOrReplaceChild("Leftfrontlib", CubeListBuilder.create(), PartPose.offset(0.0F, 1.0F, -2.0F));
PartDefinition LeftArm_r4 = Leftfrontlib.addOrReplaceChild("LeftArm_r4", CubeListBuilder.create().texOffs(0, 23).addBox(-2.0F, -9.076F, -3.2313F, 4.0F, 11.0F, 3.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(0.0F, 3.0829F, -3.6691F, -0.8727F, 0.0F, 0.0F));
PartDefinition LeftArm_r5 = Leftfrontlib.addOrReplaceChild("LeftArm_r5", CubeListBuilder.create().texOffs(45, 46).addBox(0.4117F, 1.9822F, -3.162F, 1.0F, 3.0F, 2.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(0.3084F, 2.5147F, -3.6691F, -0.8727F, 0.0F, 0.3054F));
PartDefinition LeftArm_r6 = Leftfrontlib.addOrReplaceChild("LeftArm_r6", CubeListBuilder.create().texOffs(45, 39).addBox(-1.0F, 2.0373F, -1.364F, 2.0F, 3.0F, 1.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(0.0F, 3.0829F, -3.6691F, -0.9599F, 0.0F, 0.0F));
PartDefinition LeftArm_r7 = Leftfrontlib.addOrReplaceChild("LeftArm_r7", CubeListBuilder.create().texOffs(0, 0).addBox(-1.0F, -0.6472F, -6.2955F, 1.0F, 3.0F, 1.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(0.0F, 7.0829F, -3.6691F, -0.8727F, 0.0F, 0.0F));
PartDefinition RightLeg = partdefinition.addOrReplaceChild("RightLeg", CubeListBuilder.create(), PartPose.offsetAndRotation(-1.9F, 12.0F, 0.0F, 0.192F, 0.0F, 0.0349F));
PartDefinition RightLeg_r1 = RightLeg.addOrReplaceChild("RightLeg_r1", CubeListBuilder.create().texOffs(64, 91).addBox(-3.9698F, -6.9878F, -1.7911F, 4.0F, 12.0F, 4.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(1.9F, 5.0F, 0.0F, -0.0873F, 0.0F, 0.0F));
PartDefinition LeftLeg = partdefinition.addOrReplaceChild("LeftLeg", CubeListBuilder.create(), PartPose.offsetAndRotation(1.9F, 12.0F, 0.0F, -0.1745F, 0.0F, -0.0349F));
PartDefinition LeftLeg_r1 = LeftLeg.addOrReplaceChild("LeftLeg_r1", CubeListBuilder.create().texOffs(91, 6).addBox(-0.0302F, -8.9988F, -2.0F, 4.0F, 12.0F, 4.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(-1.9F, 7.0F, 0.0F, 0.1745F, 0.0F, 0.0F));
return LayerDefinition.create(meshdefinition, 128, 128);
}
@Override
public void setupAnim(T entity, float limbSwing, float limbSwingAmount, float ageInTicks, float netHeadYaw, float headPitch) {
this.Head.yRot = netHeadYaw * 0.007453292F;
this.Head.xRot = headPitch * 0.007453292F;
// this.beak.xRot = this.head.xRot;
// this.beak.yRot = this.head.yRot;
// this.redThing.xRot = this.head.xRot;
// this.redThing.yRot = this.head.yRot;
// this.body.xRot = ((float)Math.PI / 2F);
this.LeftArm.xRot = Mth.cos(limbSwing * 0.7662F) * 1.3F * limbSwingAmount;
this.RightArm.xRot = Mth.cos(limbSwing * 0.7662F + (float)Math.PI) * 1.3F * limbSwingAmount;
this.LeftLeg.xRot = Mth.cos(limbSwing * 0.5662F) * 1.4F * limbSwingAmount;
this.RightLeg.xRot = Mth.cos(limbSwing * 0.5662F + (float)Math.PI) * 1.4F * limbSwingAmount;
}
public void setRotationAngle(ModelPart ModelPart, float x, float y, float z) {
ModelPart.xRot = x;
ModelPart.yRot= y;
ModelPart.zRot = z;
}
@Override
public void renderToBuffer(PoseStack poseStack, VertexConsumer buffer, int packedLight, int packedOverlay, float red, float green, float blue, float alpha) {
Head.render(poseStack, buffer, packedLight, packedOverlay);
Body.render(poseStack, buffer, packedLight, packedOverlay);
RightArm.render(poseStack, buffer, packedLight, packedOverlay);
LeftArm.render(poseStack, buffer, packedLight, packedOverlay);
RightLeg.render(poseStack, buffer, packedLight, packedOverlay);
LeftLeg.render(poseStack, buffer, packedLight, packedOverlay);
}
}
为了让我们的生物在游戏中可以显示出来,我们需要编写生物的渲染文件
在render文件夹中新建渲染类(以RenderRe8Dimi.java为例)
RenderRe8Dimi.java
package com.joy187.re8joymod.entity.render;
import com.joy187.re8joymod.Main;
import com.joy187.re8joymod.entity.EntityRe8Dimi;
import com.joy187.re8joymod.entity.model.ModelRe8Dimi;
import net.minecraft.client.renderer.entity.EntityRendererProvider;
import net.minecraft.client.renderer.entity.MobRenderer;
import net.minecraft.resources.ResourceLocation;
public class RenderRe8Dimi extends MobRenderer<EntityRe8Dimi, ModelRe8Dimi<EntityRe8Dimi>> {
//注意这个路径,要和上面model文件中的路径保持一致
public static final ResourceLocation TEXTURE = new ResourceLocation(Main.MOD_ID, "textures/entity/re8dimi.png");
public RenderRe8Dimi(EntityRendererProvider.Context manager) {
super(manager, new ModelRe8Dimi<>(manager.bakeLayer(ModelRe8Dimi.LAYER_LOCATION)), 0.7F);
}
@Override
public ResourceLocation getTextureLocation(EntityRe8Dimi p_110775_1_) {
return TEXTURE;
}
}
2.在init包中新建一个EntityInit类用于初始化我们所有的生物
EntityInit.java
package com.joy187.re8joymod.init;
import com.joy187.re8joymod.Main;
import com.joy187.re8joymod.entity.EntityRe8Dimi;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.MobCategory;
import net.minecraftforge.registries.DeferredRegister;
import net.minecraftforge.registries.ForgeRegistries;
import net.minecraftforge.registries.RegistryObject;
public class EntityInit {
public static final DeferredRegister<EntityType<?>> ENTITY_TYPES = DeferredRegister.create(ForgeRegistries.ENTITIES,
Main.MOD_ID);
//我们的生物类型为MONSTER(怪物),你可以定义其他类型MOB等,两个字符串要一样比如"re8dimi"
public static final RegistryObject<EntityType<EntityRe8Dimi>> RE8DIMI = ENTITY_TYPES.register("re8dimi",
() -> EntityType.Builder.of(EntityRe8Dimi::new, MobCategory.MONSTER).sized(0.8f,3.0f).setTrackingRange(30)
.build(new ResourceLocation(Main.MOD_ID, "re8dimi").toString()));
//你可以往下续写
}
3.新建一个ClientModEventSubscriber类用于提交我们的渲染信息
ClientModEventSubscriber.java
package com.joy187.re8joymod;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.Mod.EventBusSubscriber;
import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent;
import com.joy187.re8joymod.entity.EntityRe8Dimi;
import com.joy187.re8joymod.entity.model.ModelRe8Dimi;
import com.joy187.re8joymod.entity.render.RenderRe8Dimi;
import com.joy187.re8joymod.init.EntityInit;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.client.event.EntityRenderersEvent;
import net.minecraftforge.event.entity.EntityAttributeCreationEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
@Mod.EventBusSubscriber(modid = Main.MOD_ID, value = Dist.CLIENT, bus = Mod.EventBusSubscriber.Bus.MOD)
public class ClientModEventSubscriber
{
//将所有的生物的皮肤贴图信息写在这个函数里,有几个写几个
@SubscribeEvent
public static void onRegisterLayers(EntityRenderersEvent.RegisterLayerDefinitions event) {
event.registerLayerDefinition(ModelRe8Dimi.LAYER_LOCATION, ModelRe8Dimi::createBodyLayer);
}
//将所有的生物的渲染信息写在这个函数里,有几个写几个
@SubscribeEvent
public static void onRegisterRenderer(EntityRenderersEvent.RegisterRenderers event) {
event.registerEntityRenderer(EntityInit.RE8DIMI.get(), RenderRe8Dimi::new);
}
//将所有的生物的属性信息写在这个函数里,有几个写几个
@SubscribeEvent
public static void onAttributeCreate(EntityAttributeCreationEvent event) {
event.put(EntityInit.RE8DIMI.get(), EntityRe8Dimi.prepareAttributes().build());
}
}
4.在Main.java中添加:
public Main() {
IEventBus bus = FMLJavaModLoadingContext.get().getModEventBus();
ItemInit.ITEMS.register(bus);
BlockInit.BLOCKS.register(bus);
//把生物初始化语句加入
EntityInit.ENTITY_TYPES.register(bus);
MinecraftForge.EVENT_BUS.register(this);
}
5.在textures包下新建一个entity文件夹存放我们的生物皮肤贴图,将.png贴图放入其中:
在en_us.lang文件中添加游戏中的生物名称
"entity.re8joymod.re8dimi": "Alcina Dimitrescu",
怪物掉落物:
在resources\data\re8joymod\loot_tables下新建一个entities文件夹 -> 在文件夹中新建我们的生物掉落物.json文件(文件名称与EntityInit.java中保持一致)
{
"type": "minecraft:entity",
"pools": [
{
"rolls": 1.0,
"bonus_rolls": 0.0,
"entries": [
{
"type": "item",
"name": "re8joymod:blackfeather", //掉落物格式: 模组名称:物品名称
"weight": 6,
"functions": [
{
"function": "set_count", //掉落个数
"count": {
"min": 0, //最少掉几个
"max": 2 //最多掉几个
}
},
{
"function": "looting_enchant",
"count": {
"min": 0,
"max": 1
}
}
]
},
{
"type": "item",
"weight": 5,
"name": "minecraft:totem_of_undying", //原版掉落物格式: minecraft:物品名称
"functions": [
{
"function": "set_count",
"count": {
"min": 2,
"max": 3
}
}
]
},
{
"type": "item",
"weight": 5,
"name": "minecraft:nether_star",
"functions": [
{
"function": "set_count",
"count": {
"min": 3,
"max": 5
}
}
]
}
]
},
{
"name": "pool1",
"rolls": 1,
"entries": [
{
"type": "item",
"name": "minecraft:bone",
"weight": 10
},
{
"type": "item",
"name": "minecraft:ghast_tear",
"weight": 4
},
{
"type": "item",
"weight": 5,
"name": "minecraft:nether_star",
"functions": [
{
"function": "set_count",
"count": {
"min": 3,
"max": 5
}
}
]
}
]
}
]
}
6.生物蛋制作
在ItemInit中添加:
//刷怪蛋格式:ForgeSpawnEggItem(生物类,颜色1,颜色2,放在哪个物品栏)
public static final RegistryObject<Item> THIEF_EGG = ITEMS.register("re8dimi_spawn_egg",
() -> new ForgeSpawnEggItem(EntityInit.RE8DIMI, 9577503, 13423070, new Item.Properties().tab(Main.TUTORIAL_TAB)));
在resources\assets\re8joymod\models\item中新建一个刷怪蛋.json文件(名称与ItemInit中的名称保持一致)
re8dimi_spawn_egg.json
{
"parent": "item/template_spawn_egg"
}
在en_us.lang中添加语言信息:
"item.re8joymod.re8dimi_spawn_egg": "Alcina Dimitrescu Spawn Egg",
7.保存所有文件,刷新项目 -> 启动游戏