Minecraft 1.19.2 Forge模组开发 03.动画生物实体

1.12.2动画生物实体教程

1.16.5动画生物实体教程

1.18.2动画生物实体教程

在这里插入图片描述

效 果 展 示 效果展示

我们本次尝试在1.19.2中添加一个能够具有各种动画效果动作的生物实体。

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

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

repositories {

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

}

cr1.jpg

之后点击Load Gradle按钮重新构建项目

CR.jpg

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

Main.java

    public Main()
    {
        IEventBus bus = FMLJavaModLoadingContext.get().getModEventBus();
        // Register the commonSetup method for modloading
        bus.addListener(this::commonSetup);
        bus.addListener(this::setup);
        ItemInit.ITEMS.register(bus);
        BlockInit.BLOCKS.register(bus);
        EntityInit.ENTITY_TYPES.register(bus);

        
        //添加这个
        GeckoLib.initialize();

        MinecraftForge.EVENT_BUS.register(this);
    }

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

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

cr6.png

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

cr7.png

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

sam.jpg

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

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

cc.png

3.模型制作完成,接下来需要制作生物实体类,因为我们的生物的动作有很多,所以要在生物的不同状态时做出对应的动作。

EntitySamca.java

package com.joy187.re8joymod.entity;

import java.util.EnumSet;

import net.minecraft.sounds.SoundEvents;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.Mob;
import net.minecraft.world.entity.ai.attributes.AttributeSupplier;
import net.minecraft.world.entity.ai.attributes.Attributes;
import net.minecraft.world.entity.ai.goal.FloatGoal;
import net.minecraft.world.entity.ai.goal.Goal;
import net.minecraft.world.entity.ai.goal.LookAtPlayerGoal;
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.monster.Monster;
import net.minecraft.world.entity.monster.Vex;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.entity.raid.Raider;
import net.minecraft.world.level.Level;
import net.minecraft.world.phys.Vec3;
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;

public class EntitySamca extends Vex implements IAnimatable{

	private AnimationFactory factory = new AnimationFactory(this);

	public EntitySamca(EntityType<? extends Vex> type, Level worldIn) {
        super(type, worldIn);
        this.xpReward = 20;
    }

	public static AttributeSupplier.Builder prepareAttributes() {
		return Monster.createMonsterAttributes().add(Attributes.MAX_HEALTH, 35.0D).
				add(Attributes.ATTACK_DAMAGE, 8.5D).
		    	add(Attributes.MOVEMENT_SPEED, 0.28D).
		        add(Attributes.KNOCKBACK_RESISTANCE, 0.15D);
	}

	protected void registerGoals() {
		      super.registerGoals();
		      this.goalSelector.addGoal(0, new FloatGoal(this));
		      this.goalSelector.addGoal(4, new ChargeAttackGoal());
		      this.goalSelector.addGoal(9, new LookAtPlayerGoal(this, Player.class, 3.0F, 1.0F));
		      this.goalSelector.addGoal(10, new LookAtPlayerGoal(this, Mob.class, 8.0F));
		      this.targetSelector.addGoal(1, (new HurtByTargetGoal(this, Raider.class)).setAlertOthers());
		      this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, Player.class, true));
		      //this.targetSelector.addGoal(2, new NearestAttackableTargetGoal<>(this, EntityEthan.class, true));
		      this.targetSelector.addGoal(2, new NearestAttackableTargetGoal<>(this, IronGolem.class, true));

	}
	
    //我们生物的AI,决定使用哪种攻击方式
    class ChargeAttackGoal extends Goal {
        public ChargeAttackGoal() {
            this.setFlags(EnumSet.of(Flag.MOVE));
        }

        public boolean canUse() {
            if (EntitySamca.this.getTarget() != null && !EntitySamca.this.getMoveControl().hasWanted() && EntitySamca.this.random.nextInt(7) == 0) {
                return EntitySamca.this.distanceToSqr(EntitySamca.this.getTarget()) > 4.0D;
            } else {
                return false;
            }
        }

        public boolean canContinueToUse() {
            return EntitySamca.this.getMoveControl().hasWanted() && EntitySamca.this.isCharging() && EntitySamca.this.getTarget() != null && EntitySamca.this.getTarget().isAlive();
        }

        public void start() {
            LivingEntity livingentity = EntitySamca.this.getTarget();
            Vec3 vector3d = livingentity.getEyePosition(1.0F);
            EntitySamca.this.moveControl.setWantedPosition(vector3d.x, vector3d.y, vector3d.z, 1.0D);
            EntitySamca.this.setIsCharging(true);
            EntitySamca.this.playSound(SoundEvents.VEX_CHARGE, 1.0F, 1.0F);
        }

        public void stop() {
            EntitySamca.this.setIsCharging(false);
        }

        public void tick() {
            LivingEntity livingentity = EntitySamca.this.getTarget();
            if (EntitySamca.this.getBoundingBox().intersects(livingentity.getBoundingBox())) {
                EntitySamca.this.doHurtTarget(livingentity);
                EntitySamca.this.setIsCharging(false);
            } else {
                double d0 = EntitySamca.this.distanceToSqr(livingentity);
                if (d0 < 9.0D) {
                    Vec3 vector3d = livingentity.getEyePosition(1.0F);
                    EntitySamca.this.moveControl.setWantedPosition(vector3d.x, vector3d.y, vector3d.z, 1.0D);
                }
            }

        }
    }
    
    //该状态播放器控制生物的各种动作
    private <E extends IAnimatable> PlayState predicate(AnimationEvent<E> event) {

        //找到了敌人,就播放攻击动画
    	if (this.isCharging()) {
            event.getController().setAnimation(new AnimationBuilder().playOnce("animation.samca.attack"));
            this.attackAnim=1;
            return PlayState.CONTINUE;
        }
        
        //平时就是飞行动画
        event.getController().setAnimation(new AnimationBuilder().addAnimation("animation.samca.fly", true));
        return PlayState.CONTINUE;
    }
    
    //将我们之前的所有动画控制器进行注册
	@Override
	public void registerControllers(AnimationData data) {
        data.addAnimationController(new AnimationController(this, "controller",
                0, this::predicate));
	}

	@Override
	public AnimationFactory getFactory() {
		return this.factory;
	}

}

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

ModelSamca.java

package com.joy187.re8joymod.entity.model;

import com.joy187.re8joymod.Main;
import com.joy187.re8joymod.entity.EntitySamca;

import net.minecraft.client.model.geom.ModelLayerLocation;
import net.minecraft.resources.ResourceLocation;
import software.bernie.geckolib3.model.AnimatedGeoModel;


public class ModelSamca extends AnimatedGeoModel<EntitySamca>{
	public static final ModelLayerLocation LAYER_LOCATION = new ModelLayerLocation(new ResourceLocation(Main.MOD_ID, "samca"), "main");

    @Override
    public ResourceLocation getModelResource(EntitySamca object) {
        return new ResourceLocation(Main.MOD_ID, "geo/samca.geo.json");
    }

    @Override
    public ResourceLocation getTextureResource(EntitySamca object) {
        return new ResourceLocation(Main.MOD_ID, "textures/entity/dund2.png");
    }

    @Override
    public ResourceLocation getAnimationResource(EntitySamca animatable) {
        return new ResourceLocation(Main.MOD_ID, "animations/samca.animation.json");
    }
}

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

RenderDund.java

package com.joy187.re8joymod.entity.render;

import com.joy187.re8joymod.Main;
import com.joy187.re8joymod.entity.EntitySamca;
import com.joy187.re8joymod.entity.model.ModelSamca;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.VertexConsumer;

import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.entity.EntityRendererProvider;
import net.minecraft.resources.ResourceLocation;
import software.bernie.geckolib3.renderers.geo.GeoEntityRenderer;


public class RenderSamca extends GeoEntityRenderer<EntitySamca>{

    public RenderSamca(EntityRendererProvider.Context renderManager) {
        super(renderManager, new ModelSamca());
        this.shadowRadius = 0.5f;
    }

    @Override
    public ResourceLocation getTextureLocation(EntitySamca instance) {
        //return LOCATION_BY_VARIANT.get(instance.getVariant());
    	return new ResourceLocation(Main.MOD_ID, "textures/entity/dund2.png");
    }

    @Override
    public RenderType getRenderType(EntitySamca animatable, float partialTicks, PoseStack stack,
                                    MultiBufferSource renderTypeBuffer, VertexConsumer vertexBuilder, int packedLightIn,
                                    ResourceLocation textureLocation) {
//        if(animatable.isBaby()) {
//            stack.scale(0.4F, 0.4F, 0.4F);
//        } else {
//            stack.scale(0.8F, 0.8F, 0.8F);
//        }
    	stack.scale(1F, 1F, 1F);

        return super.getRenderType(animatable, partialTicks, stack, renderTypeBuffer, vertexBuilder, packedLightIn, textureLocation);
    }
}

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

package com.joy187.re8joymod.init;

import com.joy187.re8joymod.Main;
import com.joy187.re8joymod.entity.EntitySamca;
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.ENTITY_TYPES,
            Main.MOD_ID);

    public static final RegistryObject<EntityType<EntitySamca>> SAMCA = ENTITY_TYPES.register("samca",
            () -> EntityType.Builder.of(EntitySamca::new, MobCategory.MONSTER).sized(1f,1.8f).setTrackingRange(20)
                    .build(new ResourceLocation(Main.MOD_ID, "samca").toString()));


}
ClientModEventSubscriber.java中添加我们的模型渲染、属性注册语句:
@Mod.EventBusSubscriber(modid = Main.MOD_ID, value = Dist.CLIENT, bus = Mod.EventBusSubscriber.Bus.MOD)
public class ClientModEventSubscriber
{


    @SubscribeEvent
    public static void onRegisterRenderer(EntityRenderersEvent.RegisterRenderers event) {
		//添加渲染注册语句
        event.registerEntityRenderer(EntityInit.SAMCA.get(), RenderSamca::new);
        //event.registerEntityRenderer(EntityInit.DETONATOR_ENTITY.get(), RenderDetonatorEntity::new);

    }
    
    @SubscribeEvent
    public static void onAttributeCreate(EntityAttributeCreationEvent event) {
		//添加属性注册语句
        event.put(EntityInit.SAMCA.get(), EntitySamca.prepareAttributes().build());

    }
}

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

在ItemInit类中添加我们的刷怪蛋物品:
    public static final RegistryObject<Item> SAMCA_SPAWN_EGG = ITEMS.register("samca_spawn_egg",
            () -> new ForgeSpawnEggItem(EntityInit.SAMCA, 3093009, 4390912, new Item.Properties().tab(Main.TUTORIAL_TAB)));

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

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

	"item.re8joymod.samca_spawn_egg": "Mob Spawn Egg",
	"entity.re8joymod.samca": "Mob",
models\item包中添加刷怪蛋模型文件:

samca_spawn_egg.json

{
	"parent": "item/template_spawn_egg"
}
textures\entity中添加生物实体的皮肤贴图
新建一个geo包和animation包,把第二步中的模型和动画文件分别放进去

cr10.png

9.最后我们还要给这个生物设定其掉落物

resources\data\你的modid中新建loot_tables包-> loot_tables包中新建entities包 -> entities包中新建我们的战利品文件samaca.json

crk.jpg
战利品文件中参数含义
name为物品名称,weight为掉落权重,越大掉这个物品的概率越高,count为掉落个数,min为最小掉几个,max为最大掉几个。

samaca.json

{
    "pools": [
        {
            "rolls": 1.0,
            "bonus_rolls": 0.0,
            "entries": [
                {
                    "type": "item",
                    "name": "re8joymod:lei",
                    "weight": 5,
                    "functions": [
                        {
                            "function": "set_count",
                            "count": {
                                "min": 1,
                                "max": 3
                            }
                        },
                        {
                            "function": "looting_enchant",
                            "count": {
                                "min": 0,
                                "max": 1
                            }
                        }
                    ]
                },
                {
                    "type": "item",
                    "weight": 10,
                    "name": "minecraft:iron_nugget",
					"functions": [
                       {
                            "function": "set_count",
                            "count": {
                                "min": 2,
                                "max": 3
                            }
                       }
                   ]
                },
                {
                    "type": "item",
                    "weight": 10,
                    "name": "minecraft:rotten_flesh",
					"functions": [
                       {
                            "function": "set_count",
                            "count": {
                                "min": 0,
                                "max": 2
                            }
                       }
                   ]
                },
                {
                    "type": "item",
                    "weight": 5,
                    "name": "re8joymod:blacksheephead",
					"functions": [
                       {
                            "function": "set_count",
                            "count": {
                                "min": 0,
                                "max": 2
                            }
                       }
                   ]
                }
             ]
        }
    ]
}

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

fly.png

起飞!

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 21
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 21
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Jay_fearless

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值