1500字范文,内容丰富有趣,写作好帮手!
1500字范文 > Minecraft 1.16.5模组开发(四十七) 动画生物实体

Minecraft 1.16.5模组开发(四十七) 动画生物实体

时间:2023-08-16 08:35:51

相关推荐

Minecraft 1.16.5模组开发(四十七) 动画生物实体

1.18.2动画生物实体教程

今天我们尝试在1.16.5中添加一个能够做各种动作的生物实体,由于使用的是geckolib进行开发,所以代码方面和1.18.2没有太大差别。

1.首先,为了实现这些效果,我们需要首先使用到一个模组:geckolib(下载地址)

找到项目的build.gradle文件,在repositoriesdependencies中添加依赖。

repositories {//添加这个maven {url 'https://dl.cloudsmith.io/public/geckolib3/geckolib/maven/'} }dependencies {minecraft 'net.minecraftforge:forge:1.16.5-36.2.34'//添加这个implementation fg.deobf('software.bernie.geckolib:geckolib-forge-1.16.5:3.0.56')}

之后我们重新构建gradle项目

构建好了项目后在项目的Main类中添加一句geckolib的初始化语句:

Main.java

public Main() {IEventBus bus = FMLJavaModLoadingContext.get().getModEventBus();ItemInit.ITEMS.register(bus);//添加GeckoLib初始化函数GeckoLib.initialize();MinecraftForge.EVENT_BUS.register(this);}

2.之后,与之前的教程一样,我们需要在blockbench中制作一个模组中的生物实体:

进入软件后我们要找到一个插件按钮,然后再搜索栏中输入GeckoLib Animation Utils,并下载这个插件

将我们制作好的生物实体进行模型转换工作,找到Convert Project,之后选择Geckolib Animated Model

在这之后,你会发现你的生物实体栏多了一个Animate栏,点击进去:

具体动作制作的视频:Blockbench动画制作

在制作好所有的动画后我们导出模型和动画json文件。

3.模型制作完成,接下来需要制作生物实体类,我们的生物的动画事件类似于状态机,所以要对生物实体的状态进行枚举。

EntityAda.java

package com.mon.entity;import com.mon.init.ModEffects;import com.mon.init.SoundInit;import net.minecraft.entity.Entity;import net.minecraft.entity.EntityType;import net.minecraft.entity.LivingEntity;import net.minecraft.entity.MobEntity;import net.minecraft.entity.ai.attributes.AttributeModifierMap;import net.minecraft.entity.ai.attributes.Attributes;import net.minecraft.entity.ai.goal.Goal;import net.minecraft.entity.ai.goal.HurtByTargetGoal;import net.minecraft.entity.ai.goal.NearestAttackableTargetGoal;import net.minecraft.entity.ai.goal.WaterAvoidingRandomWalkingGoal;import net.minecraft.entity.boss.WitherEntity;import net.minecraft.entity.merchant.villager.AbstractVillagerEntity;import net.minecraft.entity.monster.RavagerEntity;import net.minecraft.entity.monster.ZombifiedPiglinEntity;import net.minecraft.entity.passive.IronGolemEntity;import net.minecraft.entity.player.PlayerEntity;import work.datasync.DataParameter;import work.datasync.DataSerializers;import work.datasync.EntityDataManager;import net.minecraft.potion.EffectInstance;import net.minecraft.potion.Effects;import net.minecraft.util.DamageSource;import net.minecraft.util.SoundEvent;import net.minecraft.util.SoundEvents;import net.minecraft.util.math.MathHelper;import net.minecraft.util.math.vector.Vector3d;import net.minecraft.world.World;import software.bernie.geckolib3.core.IAnimatable;import software.bernie.geckolib3.core.PlayState;import software.bernie.geckolib3.core.builder.AnimationBuilder;import software.bernie.geckolib3.core.controller.AnimationController;import software.bernie.geckolib3.core.event.predicate.AnimationEvent;import software.bernie.geckolib3.core.manager.AnimationData;import software.bernie.geckolib3.core.manager.AnimationFactory;import java.util.Random;public class EntityAda extends RavagerEntity implements IAnimatable {private AnimationFactory factory = new AnimationFactory(this);private static final DataParameter<Integer> STATE = EntityDataManager.defineId(EntityAda.class, DataSerializers.INT);public EntityAda(EntityType<? extends RavagerEntity> type, World worldIn) {super(type, worldIn);this.xpReward = 105;}public static AttributeModifierMap.MutableAttribute setAttributes() {return MobEntity.createMobAttributes().add(Attributes.MAX_HEALTH, 35.0D).add(Attributes.MOVEMENT_SPEED, 0.3D).add(Attributes.FOLLOW_RANGE, 18.0D).add(Attributes.ARMOR, 4D).add(Attributes.ARMOR_TOUGHNESS, 6.0D).add(Attributes.ATTACK_DAMAGE, 6.0D);}protected void registerGoals() {this.goalSelector.addGoal(1, new EntityAda.AttackGoal(this));this.goalSelector.addGoal(7, new WaterAvoidingRandomWalkingGoal(this, 1.0D));this.targetSelector.addGoal(1, (new HurtByTargetGoal(this)).setAlertOthers(ZombifiedPiglinEntity.class));this.targetSelector.addGoal(2, new NearestAttackableTargetGoal<>(this, PlayerEntity.class, true));this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, AbstractVillagerEntity.class, false));this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, IronGolemEntity.class, true));this.targetSelector.addGoal(4, new NearestAttackableTargetGoal<>(this, EntityEthan.class, true));this.targetSelector.addGoal(4, new NearestAttackableTargetGoal<>(this, EntityChris.class, true));this.targetSelector.addGoal(4, new NearestAttackableTargetGoal<>(this, EntityHeisen.class, true));this.targetSelector.addGoal(4, new NearestAttackableTargetGoal<>(this, EntityMiranda1.class, true));this.targetSelector.addGoal(4, new NearestAttackableTargetGoal<>(this, EntityMiranda2.class, true));this.targetSelector.addGoal(4, new NearestAttackableTargetGoal<>(this, EntityMiranda4.class, true));}public boolean doHurtTarget(Entity p_70652_1_) {if(!super.doHurtTarget(p_70652_1_)){return false;}else{if(p_70652_1_ instanceof LivingEntity){float f = this.level.getCurrentDifficultyAt(this.blockPosition()).getEffectiveDifficulty();if(((LivingEntity) p_70652_1_).getHealth()>15.0f)((LivingEntity)p_70652_1_).addEffect(new EffectInstance(Effects.HARM, 20 * (int)f));else((LivingEntity)p_70652_1_).addEffect(new EffectInstance(Effects.MOVEMENT_SLOWDOWN, 40 * (int)f));if(p_70652_1_ instanceof EntityMiranda1 || p_70652_1_ instanceof EntityMiranda2|| p_70652_1_ instanceof EntityMiranda3 || p_70652_1_ instanceof EntityMiranda4|| p_70652_1_ instanceof EntityRe8Dimi || p_70652_1_ instanceof EntityMuHeisen) {this.addEffect(new EffectInstance(Effects.REGENERATION, 20*3,1,false,true));}}return true;}}@Overridepublic void customServerAiStep(){if(this.getHealth() >= 10.0F && this.getHealth()<=20.0F){this.addEffect(new EffectInstance(Effects.REGENERATION, 20,1,false,true));}else if(this.getHealth()<8.0F){this.addEffect(new EffectInstance(Effects.MOVEMENT_SPEED, 20,1,false,true));this.addEffect(new EffectInstance(Effects.INVISIBILITY, 20,0,false,false));}super.customServerAiStep();}@Overrideprotected SoundEvent getAmbientSound() {Random ran = new Random();int co = ran.nextInt(3);if(co==0){return SoundInit.ENTITY_ADA_AMBIENT1.get();}else if(co==1){return SoundInit.ENTITY_ADA_AMBIENT2.get();}return SoundInit.ENTITY_ADA_AMBIENT3.get();}@Overrideprotected SoundEvent getHurtSound(DamageSource source) {return SoundEvents.SLIME_BLOCK_HIT;}@Overrideprotected SoundEvent getDeathSound() {Random ran = new Random();int co = ran.nextInt(2);if(co==1){return SoundInit.ENTITY_ADA_DEATH.get();}return SoundInit.ENTITY_BELA_DEATH.get();}public int getAttckingState() {return this.entityData.get(STATE);}public void setAttackingState(int time) {this.entityData.set(STATE, time);}//初始化我们生物的攻击状态参数@Overrideprotected void defineSynchedData() {super.defineSynchedData();this.entityData.define(STATE, 0);}//写一个生物攻击目标的ai,并在上方registerGoals()中注册static class AttackGoal extends Goal {private final EntityAda parentEntity;protected int attackTimer = 0;public AttackGoal(EntityAda mob) {this.parentEntity = mob;}public boolean canUse() {return this.parentEntity.getTarget() != null;}public void start() {super.start();this.parentEntity.setAggressive(true);}@Overridepublic void stop() {super.stop();this.parentEntity.setAggressive(false);this.parentEntity.setAttackingState(0);this.attackTimer = -1;}public void tick() {LivingEntity livingentity = this.parentEntity.getTarget();if (this.parentEntity.canSee(livingentity)) {World world = this.parentEntity.level;++this.attackTimer;Random rand = new Random();Vector3d vector3d = this.parentEntity.getViewVector(1.0F);double d0 = Math.min(livingentity.getY(), livingentity.getY());double d1 = Math.max(livingentity.getY(), livingentity.getY()) + 1.0D;double d2 = livingentity.getX() - (this.parentEntity.getX() + vector3d.x * 2.0D);double d3 = livingentity.getY(0.5D) - (0.5D + this.parentEntity.getY(0.5D));double d4 = livingentity.getZ() - (this.parentEntity.getZ() + vector3d.z * 2.0D);float f = (float) MathHelper.atan2(livingentity.getZ() - parentEntity.getZ(),livingentity.getX() - parentEntity.getX());this.parentEntity.getNavigation().moveTo(livingentity, 1.5D);System.out.println(this.attackTimer);//当攻击刻达到5时,我们判断一下生物的血量,然后赋予其不同的攻击状态if (this.attackTimer == 5) {if((this.parentEntity.getHealth()<30F && this.parentEntity.getHealth()>22F) ||(this.parentEntity.getHealth()<16F && this.parentEntity.getHealth()>8F))this.parentEntity.setAttackingState(2);else{this.parentEntity.setAttackingState(1);}}if (this.attackTimer == 30) {this.parentEntity.setAttackingState(0);this.attackTimer = -5;}}else if (this.attackTimer > 0) {--this.attackTimer;}this.parentEntity.lookAt(livingentity, 30.0F, 30.0F);}}private <E extends IAnimatable> PlayState predicate(AnimationEvent<E> event) {//生物在走路就播放走路动画if (event.isMoving()) {event.getController().setAnimation(new AnimationBuilder().addAnimation("animation.ada.walk", true));return PlayState.CONTINUE;}//不走路就不放闲置动画event.getController().setAnimation(new AnimationBuilder().addAnimation("animation.ada.idle", true));return PlayState.CONTINUE;}private <E extends IAnimatable> PlayState predicate1(AnimationEvent<E> event) {//生物攻击状态为1就播放攻击1动画if (this.entityData.get(STATE) == 1 && !(this.dead || this.getHealth() < 0.01 || this.isDeadOrDying())) {event.getController().setAnimation(new AnimationBuilder().addAnimation("animation.ada.attack", true));//System.out.println("打!");return PlayState.CONTINUE;}//生物攻击状态为1就播放攻击2动画if (this.entityData.get(STATE) == 2 && !(this.dead || this.getHealth() < 0.01 || this.isDeadOrDying())) {event.getController().setAnimation(new AnimationBuilder().addAnimation("animation.ada.attack2", true));return PlayState.CONTINUE;}return PlayState.STOP;}//将上面两个动画事件注册@Overridepublic void registerControllers(AnimationData data) {data.addAnimationController(new AnimationController(this, "controller",0, this::predicate));data.addAnimationController(new AnimationController(this, "controller1",0, this::predicate1));}@Overridepublic AnimationFactory getFactory() {return this.factory;}}

4.新建生物实体模型文件ModelAdawang类

ModelAdawang.java

import com.joy187.re8joymod.Utils;import net.minecraft.util.ResourceLocation;import software.bernie.geckolib3.model.AnimatedGeoModel;public class ModelAdawang extends AnimatedGeoModel {//获取geo模型文件地址@Overridepublic ResourceLocation getModelLocation(Object object) {return new ResourceLocation(Utils.MOD_ID, "geo/ada.geo.json");}//获取贴图文件地址@Overridepublic ResourceLocation getTextureLocation(Object object) {return new ResourceLocation(Utils.MOD_ID, "textures/entity/ada.png");}//获取动画文件地址@Overridepublic ResourceLocation getAnimationFileLocation(Object animatable) {return new ResourceLocation(Utils.MOD_ID, "animations/ada.animation.json");}}

5.模型部分结束,开始着手渲染类的编写。新建RenderAda类。

RenderAda.java

import com.joy187.re8joymod.Utils;import com.mon.entity.EntityAda;import com.mon.entity.model.ModelAdawang;import com.mojang.blaze3d.matrix.MatrixStack;import com.mojang.blaze3d.vertex.IVertexBuilder;import net.minecraft.client.renderer.IRenderTypeBuffer;import net.minecraft.client.renderer.RenderType;import net.minecraft.client.renderer.entity.EntityRendererManager;import net.minecraft.client.renderer.entity.MobRenderer;import net.minecraft.util.ResourceLocation;import software.bernie.example.client.model.entity.BikeModel;import software.bernie.example.entity.BikeEntity;import software.bernie.geckolib3.renderers.geo.GeoEntityRenderer;public class RenderAda extends GeoEntityRenderer<EntityAda> {public RenderAda(EntityRendererManager renderManager) {super(renderManager, new ModelAdawang());this.shadowRadius = 0.7f;}@Overridepublic ResourceLocation getTextureLocation(EntityAda instance) {return new ResourceLocation(Utils.MOD_ID, "textures/entity/ada.png");}@Overridepublic RenderType getRenderType(EntityAda animatable, float partialTicks, MatrixStack stack,IRenderTypeBuffer renderTypeBuffer, IVertexBuilder vertexBuilder, int packedLightIn,ResourceLocation textureLocation) {//生物按多少比例渲染如果是2F,2F,2F就是按照原有模型的2倍大小进行渲染stack.scale(1F, 1F, 1F);return RenderType.entityTranslucent(getTextureLocation(animatable));}}

6.在EntityInit.java中添加我们的生物信息:

public static final RegistryObject<EntityType<EntityAda>> ADA = ENTITY_TYPES.register("ada",() -> EntityType.Builder.of(EntityAda::new, EntityClassification.MONSTER).sized(1.5f,1.8f).setTrackingRange(30).build(new ResourceLocation(Utils.MOD_ID, "ada").toString()));

ClientModEventSubscriber.java中添加我们的模型渲染、属性注册语句:

@Mod.EventBusSubscriber(modid = Main.MOD_ID, value = Dist.CLIENT, bus = Mod.EventBusSubscriber.Bus.MOD)public class ClientModEventSubscriber{@SubscribeEventpublic static void onFMLClientSetupEvent(final FMLClientSetupEvent event) {//添加渲染注册语句RenderingRegistry.registerEntityRenderingHandler(EntityInit.ADA.get(), RenderAda::new);//RenderingRegistry.registerEntityRenderingHandler(EntityInit.MIA.get(), RenderMia::new);}}

在项目主类的setup函数的中添加属性注册:

Main.java

private void setup(final FMLCommonSetupEvent event) {DeferredWorkQueue.runLater(() -> GlobalEntityTypeAttributes.put(EntityInit.ADA.get(), EntityAda.setAttributes().build()));//DeferredWorkQueue.runLater(() -> GlobalEntityTypeAttributes.put(EntityInit.MIA.get(), EntityMia.setAttributes().build()));}

7.生物实体部分结束,接下来我们要给生物制作一个刷怪蛋:

在ItemInit类中添加我们的刷怪蛋物品:

public static final RegistryObject<SpawnEggItem> ADA_SPAWN_EGG = ITEMS.register("ada_spawn_egg",() -> new CustomSpawnEggItem(EntityInit.ADA, 14496298 , 3000,new Item.Properties().tab(RegistryEvents.RE8GROUP)));

7.代码部分结束,来到资源包制作环节

resources\assets\你的modid中的lang包中的en_us.json添加刷怪蛋和生物实体英文名称:

"item.re8joymod.ada_spawn_egg": "Mob Spawn Egg","entity.re8joymod.ada": "Mob",

models\item包中添加刷怪蛋模型文件:

ada_spawn_egg.json

{"parent": "item/template_spawn_egg"}

textures\entity中添加生物实体的皮肤贴图

新建一个geo包和animation包,把第二步中的模型和动画文件分别放进去

8.保存所有文件 -> 进行测试:

翻跟头

OK!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。