当前位置: 首页 > news >正文

Minecraft 1.19.2 Fabric模组开发 04.动画效果方块

我们本次尝试在1.19 Fabric中制作一个具有动画效果的方块

fabric 00_00_01-00_00_04 00_00_00-00_00_30.gif
效果演示 效果演示 效果演示

首先,请确保你的开发包中引入了geckolib依赖,相关教程请参考:Minecraft 1.19.2 Fabric模组开发 03.动画生物实体

1.首先我们要使用geckolib制作一个物品和对应的动画:

在blockbench中新建一个Geckolib动画模型

cr0.jpg

制作相关的模型和动画:

mdr.jpg

之后导出方块模型文件,动画文件,展示文件:

cr2.jpg

之后我们找到Geckolib Model Settings并点击将模型转换为Block/Item格式:

cr1.jpg

导出物品模型文件:

cri.jpg

将这些文件分别放入到resources包中的如下位置:

39383_0cf2862181-crp.jpg

2.在block包中新建一个我们的方块类BlockGooseBody:

BlockGooseBody.java

package net.joy187.joyggd.block;

import net.joy187.joyggd.init.BlockEntityInit;
import net.minecraft.block.*;
import net.minecraft.block.entity.BlockEntity;
import net.minecraft.block.entity.BlockEntityTicker;
import net.minecraft.block.entity.BlockEntityType;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemPlacementContext;
import net.minecraft.screen.NamedScreenHandlerFactory;
import net.minecraft.state.StateManager;
import net.minecraft.state.property.DirectionProperty;
import net.minecraft.state.property.Properties;
import net.minecraft.util.*;
import net.minecraft.util.function.BooleanBiFunction;
import net.minecraft.util.hit.BlockHitResult;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.shape.VoxelShape;
import net.minecraft.util.shape.VoxelShapes;
import net.minecraft.world.BlockView;
import net.minecraft.world.World;
import org.jetbrains.annotations.Nullable;

import java.util.stream.Stream;

public class BlockGooseBody extends BlockWithEntity implements BlockEntityProvider {
	//定义方块的朝向
    public static final DirectionProperty FACING = Properties.HORIZONTAL_FACING;

    public BlockGooseBody(Settings settings) {
        super(settings);
    }
    
    //定义方块的碰撞体积
    private static final VoxelShape SHAPE = Stream.of(
            Block.createCuboidShape(3.0D, 0.0D, 3.0D, 13.0D, 13.0D, 13.0D)
    ).reduce((v1, v2) -> VoxelShapes.combineAndSimplify(v1, v2, BooleanBiFunction.OR)).get();

    //确定与之绑定的方块实体
    @Nullable
    @Override
    public BlockEntity createBlockEntity(BlockPos pos, BlockState state) {
        return new BlockEntityGooseBody(pos, state);
    }
    
    @Override
    public VoxelShape getOutlineShape(BlockState state, BlockView world, BlockPos pos, ShapeContext context) {

        return SHAPE;
    }

    @Nullable
    @Override
    public BlockState getPlacementState(ItemPlacementContext ctx) {
        return this.getDefaultState().with(FACING, ctx.getPlayerFacing().getOpposite());
    }

    @Override
    public BlockState rotate(BlockState state, BlockRotation rotation) {
        return state.with(FACING, rotation.rotate(state.get(FACING)));
    }

    @Override
    public BlockState mirror(BlockState state, BlockMirror mirror) {
        return state.rotate(mirror.getRotation(state.get(FACING)));
    }

    @Override
    protected void appendProperties(StateManager.Builder<Block, BlockState> builder) {
        builder.add(FACING);
    }

    @Override
    public BlockRenderType getRenderType(BlockState state) {
        return BlockRenderType.ENTITYBLOCK_ANIMATED;
    }
    
}

在BlockInit类中将我们的物品进行注册:

BlockInit.java

package net.joy187.joyggd.init;

import net.minecraft.block.Block;

import net.fabricmc.fabric.api.item.v1.FabricItemSettings;
import net.fabricmc.fabric.api.object.builder.v1.block.FabricBlockSettings;
import net.joy187.joyggd.ModMain;
import net.joy187.joyggd.block.BlockGooseBody;
import net.minecraft.block.*;
import net.minecraft.entity.effect.StatusEffects;
import net.minecraft.item.BlockItem;
import net.minecraft.item.Item;
import net.minecraft.item.ItemGroup;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.intprovider.UniformIntProvider;
import net.minecraft.util.registry.Registry;

public class BlockInit {
	//注册该方块
    public static final Block GOOSEBODY = registerBlockWithoutBlockItem("goosebody" ,
    		new BlockGooseBody(FabricBlockSettings.copy(Blocks.BONE_BLOCK).nonOpaque()));
    
    private static Block registerBlockWithoutBlockItem(String name, Block block) {
        return Registry.register(Registry.BLOCK, new Identifier(ModMain.MOD_ID, name), block);
    }
    
    private static Block registerBlock(String name, Block block, ItemGroup group) {
        registerBlockItem(name, block, group);
        return Registry.register(Registry.BLOCK, new Identifier(ModMain.MOD_ID, name), block);
    }

    private static Item registerBlockItem(String name, Block block, ItemGroup group) {
        return Registry.register(Registry.ITEM, new Identifier(ModMain.MOD_ID, name),
                new BlockItem(block, new FabricItemSettings().group(group)));
    }

    public static void registerModBlocks() {
        System.out.println("Registering Mod Blocks for " + ModMain.MOD_ID);
    }
    
}

3.在block包新建一个方块实体类BlockEntityGooseBody:

BlockEntityGooseBody.java

package net.joy187.joyggd.block;

import net.joy187.joyggd.entity.EntityGoose;
import net.joy187.joyggd.init.BlockEntityInit;
import net.minecraft.block.BlockState;
import net.minecraft.block.entity.BlockEntity;
import net.minecraft.block.entity.BlockEntityType;
import net.minecraft.util.math.BlockPos;
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 BlockEntityGooseBody extends BlockEntity implements IAnimatable {
	private AnimationFactory manager = new AnimationFactory(this);
	
	public BlockEntityGooseBody(BlockPos pos, BlockState state) {
		super(BlockEntityInit.BLOCKGOOSEBODY , pos, state);
		// TODO Auto-generated constructor stub
	}
    
    //指定该状态机播放什么动画
    private <E extends IAnimatable> PlayState predicate(AnimationEvent<E> event) {
        event.getController().setAnimation(new AnimationBuilder().addAnimation("animation.goosebody.rotate", true));

        return PlayState.CONTINUE;
    }

	//将状态机进行注册
	@Override
	public void registerControllers(AnimationData data) {
		data.addAnimationController(new AnimationController<BlockEntityGooseBody>(this, "controller",
                0, this::predicate));
	}

	@Override
	public AnimationFactory getFactory() {
		// TODO Auto-generated method stub
		return this.manager;
	}

}

新建一个BlockEntityInit类将该方块实体进行注册:

BlockEntityInit.java

package net.joy187.joyggd.init;

import net.fabricmc.fabric.api.object.builder.v1.block.entity.FabricBlockEntityTypeBuilder;
import net.joy187.joyggd.ModMain;
import net.joy187.joyggd.block.BlockEntityGooseBody;
import net.minecraft.block.entity.BlockEntityType;
import net.minecraft.util.Identifier;
import net.minecraft.util.registry.Registry;

public class BlockEntityInit {

	public static BlockEntityType<BlockEntityGooseBody> BLOCKGOOSEBODY;
    
	public static void registerAllBlockEntities() {
	    //将该方块实体进行注册
		BLOCKGOOSEBODY = Registry.register(Registry.BLOCK_ENTITY_TYPE,
			new Identifier(ModMain.MOD_ID, "goosebody"),FabricBlockEntityTypeBuilder.create(BlockEntityGooseBody::new
					,BlockInit.GOOSEBODY).build(null));
	}
	
}

4.之后就是该实体的渲染工作了,新建一个模型类ModelGooseBody和一个渲染类RenderGooseBody

ModelGooseBody.java

package net.joy187.joyggd.block.model;

import net.joy187.joyggd.ModMain;
import net.joy187.joyggd.block.BlockEntityGooseBody;
import net.joy187.joyggd.entity.EntityGoose;
import net.minecraft.util.Identifier;
import software.bernie.geckolib3.model.AnimatedGeoModel;

public class ModelGooseBody extends AnimatedGeoModel<BlockEntityGooseBody> {
    
    //方块模型文件地址
    @Override
    public Identifier getModelResource(BlockEntityGooseBody animatable) {
        return new Identifier(ModMain.MOD_ID, "geo/goosebody.geo.json");
    }
    
    //方块贴图文件地址
    @Override
    public Identifier getTextureResource(BlockEntityGooseBody entity) {

        return new Identifier(ModMain.MOD_ID, "textures/block/body.png");
    }
    //方块动画文件地址
    @Override
    public Identifier getAnimationResource(BlockEntityGooseBody entity) {
        return new Identifier(ModMain.MOD_ID, "animations/goosebody.animation.json");
    }
    
}

这个类用来将我们刚刚的模型进行渲染

RenderGooseBody.java

package net.joy187.joyggd.block.render;


import net.joy187.joyggd.ModMain;
import net.joy187.joyggd.block.BlockEntityGooseBody;
import net.joy187.joyggd.block.model.ModelGooseBody;
import net.minecraft.client.render.RenderLayer;
import net.minecraft.client.render.VertexConsumer;
import net.minecraft.client.render.VertexConsumerProvider;
import net.minecraft.client.render.block.entity.BlockEntityRendererFactory;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.util.Identifier;
import software.bernie.geckolib3.renderers.geo.GeoBlockRenderer;

public class RenderGooseBody extends GeoBlockRenderer<BlockEntityGooseBody> {
	public RenderGooseBody(BlockEntityRendererFactory.Context context) {
	    //将上面的模型传进来
		super(new ModelGooseBody());
	}
    
    @Override
    public RenderLayer getRenderType(BlockEntityGooseBody animatable, float partialTicks, MatrixStack stack,
                                     VertexConsumerProvider renderTypeBuffer, VertexConsumer vertexBuilder,
                                     int packedLightIn, Identifier textureLocation) {

        return RenderLayer.getEntityTranslucent(getTextureResource(animatable));
    }
}

5.方块制作完了,需要有一个物品与之对应,所以在Items包中新建一个物品类ItemGooseBody:

ItemGooseBody.java

package net.joy187.joyggd.items;

import net.minecraft.block.Block;
import net.minecraft.item.BlockItem;
import net.minecraft.item.Item;
import software.bernie.geckolib3.core.IAnimatable;
import software.bernie.geckolib3.core.PlayState;
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 ItemGooseBody extends BlockItem implements IAnimatable{

	public AnimationFactory factory = new AnimationFactory(this);
	
	public ItemGooseBody(Block block,Settings settings){
		super(block,settings);
	}
	
	//指定该状态机播放什么动画
	private <E extends IAnimatable> PlayState predicate(AnimationEvent<E> event){
		//event.getController().setAnimation(new AnimationBuilder().addAnimation("idle" ,stoudloop trwe));
		return PlayState.CONTINUE;
	}
	
	//注册所有状态机
	@Override
	public void registerControllers(AnimationData animationData){
		animationData.addAnimationController(new AnimationController(this,"controller",
		0, this::predicate));
	}
		
	@Override
	public AnimationFactory getFactory() 
	{
		return this.factory; 
	}
}

之后我们要对该方块进行建模和渲染,分别新建一个模型类ModelItemGooseBody和渲染类RenderItemGooseBody:

ModelItemGooseBody.java

package net.joy187.joyggd.items.model;

import net.joy187.joyggd.ModMain;
import net.joy187.joyggd.items.ItemGooseBody;
import net.minecraft.util.Identifier;
import software.bernie.geckolib3.model.AnimatedGeoModel;

                                                        //将上面的物品类填入<>中
public class ModelItemGooseBody extends AnimatedGeoModel<ItemGooseBody> {
    
    //模型地址
    @Override
    public Identifier getModelResource(ItemGooseBody animatable) {
        return new Identifier(ModMain.MOD_ID, "geo/goosebody.geo.json");
    }
    
    //贴图地址
    @Override
    public Identifier getTextureResource(ItemGooseBody entity) {

        return new Identifier(ModMain.MOD_ID, "textures/block/body.png");
    }
    
    //动画文件地址
    @Override
    public Identifier getAnimationResource(ItemGooseBody entity) {
        return new Identifier(ModMain.MOD_ID, "animations/goosebody.animation.json");
    }
    
}

之后是渲染文件,用于将上面的物品模型进行渲染:

RenderItemGooseBody.java

package net.joy187.joyggd.items.render;

import net.joy187.joyggd.items.ItemGooseBody;
import net.joy187.joyggd.items.model.ModelItemGooseBody;
import software.bernie.geckolib3.renderers.geo.GeoItemRenderer;
                                                    //将上面的物品类填入<>中
public class RenderItemGooseBody extends GeoItemRenderer<ItemGooseBody> {
	public RenderItemGooseBody() { 
	    //将上面的物品模型文件放入super()中
		super(new ModelItemGooseBody());
	}
}

在ItemInit中注册我们的方块:

ItemInit.java

package net.joy187.joyggd.init;

import net.minecraft.item.Item;
import net.minecraft.item.SpawnEggItem;
import net.fabricmc.fabric.api.item.v1.FabricItemSettings;
import net.joy187.joyggd.ModMain;
import net.joy187.joyggd.items.ItemGooseBody;
import net.joy187.joyggd.items.ItemPele;
import net.joy187.joyggd.items.ItemSheriff;
import net.minecraft.util.Identifier;
import net.minecraft.util.registry.Registry;

public class ItemInit {
    
    //注册该物品
   public static final Item GOOSEBODY =  registerItem("goosebody",
    						 //这个是指定该物品与BlockInit中的一个方块形成对应关系
    		new ItemGooseBody(BlockInit.GOOSEBODY,new FabricItemSettings().group(ModMain.ITEMTAB)));
    
    private static Item registerItem(String name, Item item) {
        return Registry.register(Registry.ITEM, new Identifier(ModMain.MOD_ID, name), item);
    }

    public static void registerModItems() {
    	ModMain.LOGGER.debug("Registering Mod Items for " + ModMain.MOD_ID);
    }
}

6.在项目主类中添加相关类注册事件:

ModMain.java

package net.joy187.joyggd;

import net.fabricmc.api.ModInitializer;
import net.fabricmc.fabric.api.client.itemgroup.FabricItemGroupBuilder;
import net.fabricmc.fabric.api.client.rendering.v1.EntityRendererRegistry;
import net.fabricmc.fabric.api.object.builder.v1.entity.FabricDefaultAttributeRegistry;
import net.joy187.joyggd.entity.EntityGoose;
import net.joy187.joyggd.init.BlockEntityInit;
import net.joy187.joyggd.init.BlockInit;
import net.joy187.joyggd.init.EntityInit;
import net.joy187.joyggd.init.ItemInit;
import net.minecraft.client.render.entity.FlyingItemEntityRenderer;
import net.minecraft.item.ItemGroup;
import net.minecraft.item.ItemStack;
import net.minecraft.util.Identifier;
import software.bernie.geckolib3.GeckoLib;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class ModMain implements ModInitializer {
	
	public static final String MOD_ID = "joyggd";
	public static final Logger LOGGER = LoggerFactory.getLogger(MOD_ID);

    public static final ItemGroup ITEMTAB = FabricItemGroupBuilder.build(
            new Identifier(MOD_ID, "itemtab"), () -> new ItemStack(ItemInit.SHERIFF));
	
	@Override
	public void onInitialize() {
	    //物品总类注册
		ItemInit.registerModItems();
		//方块类BlockInit注册
		BlockInit.registerModBlocks();
		//方块实体类注册
		BlockEntityInit.registerAllBlockEntities();
		
		GeckoLib.initialize();
	}
}

来到客户端类,将一系列方块和实体的渲染进行注册:

ModClient.java

package net.joy187.joyggd;

import net.fabricmc.api.ClientModInitializer;
import net.fabricmc.fabric.api.blockrenderlayer.v1.BlockRenderLayerMap;
import net.fabricmc.fabric.api.client.rendering.v1.BlockEntityRendererRegistry;
import net.fabricmc.fabric.api.client.rendering.v1.EntityRendererRegistry;
import net.joy187.joyggd.block.render.RenderGooseBody;
import net.joy187.joyggd.entity.render.RenderGoose;
import net.joy187.joyggd.init.BlockEntityInit;
import net.joy187.joyggd.init.BlockInit;
import net.joy187.joyggd.init.EntityInit;
import net.joy187.joyggd.init.ItemInit;
import net.joy187.joyggd.items.render.RenderItemGooseBody;
import net.minecraft.client.render.RenderLayer;
import software.bernie.geckolib3.renderers.geo.GeoItemRenderer;

public class ModClient implements ClientModInitializer{

	@Override
	public void onInitializeClient() {
		
		//方块渲染类型注册
		BlockRenderLayerMap.INSTANCE.putBlock(BlockInit.GOOSEBODY, RenderLayer.getCutout());
		
		//方块实体渲染进行注册
		BlockEntityRendererRegistry.register(BlockEntityInit.BLOCKGOOSEBODY, RenderGooseBody::new);	
		
		//物品渲染类型进行注册
		GeoItemRenderer.registerItemRenderer(ItemInit.GOOSEBODY, new RenderItemGooseBody());
	}
	
}

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

在lang语言包的en_us.json中添加方块的名称:

en_us.json

"block.joyggd.goosebody":"Block Name"

在blockstates中添加方块状态文件:

goosebody.json

{
  "variants":{
    "facing=north":{"model":"joyggd:block/goosebody"},
    "facing=east":{"model":"joyggd:block/goosebody","y":90},
    "facing=south":{"model":"joyggd:block/goosebody","y":180},
    "facing=west":{"model":"joyggd:block/goosebody","y":270}
  }
}

来到数据包中,在data\你的modid\loot_tables\blocks中创建一个方块挖掉后的掉落物文件:

goosebody.json

{
  "type": "minecraft:block",
  "pools": [
    {
      "rolls": 1,
      "entries": [
        {
          "type": "minecraft:item",
          "name": "joyggd:goosebody"
        }
      ]
    }
  ]
}

8.进入游戏调试。

第一步中导出的文件源代码:

方块的geo文件(放入geo文件夹):

goosebody.geo.json

{
	"format_version": "1.12.0",
	"minecraft:geometry": [
		{
			"description": {
				"identifier": "geometry.goosebody - Converted",
				"texture_width": 16,
				"texture_height": 16,
				"visible_bounds_width": 2,
				"visible_bounds_height": 2.5,
				"visible_bounds_offset": [0, 0.75, 0]
			},
			"bones": [
				{

						{
							"origin": [-4.33043, 0, -5.47826],
							"size": [0.17391, 0.08696, 3.92609],
							"uv": {
								"north": {"uv": [2.66957, 14.8913], "uv_size": [0.17391, -0.51304]},
								"east": {"uv": [2.86957, 3.65217], "uv_size": [0.08696, 11.82609]},
								"south": {"uv": [3.04348, 3.65217], "uv_size": [-0.17391, 0.08696]},
								"west": {"uv": [2.95652, 3.65217], "uv_size": [0.08696, 11.82609]},
								"up": {"uv": [3.73043, 14.52174], "uv_size": [-0.17391, -0.51304]},
								"down": {"uv": [3.26848, 14.27717], "uv_size": [-0.17391, 0.32609]}
							}
						},
						//略
						{
							"origin": [1.06087, 0, -5.47826],
							"size": [0.34783, 0.08696, 6.88261],
							"uv": {
								"north": {"uv": [8.06087, 14.8913], "uv_size": [0.34783, -0.51304]},
								"east": {"uv": [8.26087, 0.69565], "uv_size": [0.08696, 14.78261]},
								"south": {"uv": [8.6087, 0.69565], "uv_size": [-0.34783, 0.08696]},
								"west": {"uv": [8.52174, 0.69565], "uv_size": [0.08696, 14.78261]},
								"up": {"uv": [9.29565, 14.52174], "uv_size": [-0.34783, -3.46957]},
								"down": {"uv": [8.8337, 11.32065], "uv_size": [-0.34783, 3.28261]}
							}
						}
					]
				}
			]
		}
	]
}

本次方块的动画文件(放入animations文件夹):

goosebody.animations.json

{
	"format_version": "1.8.0",
	"animations": {
		"animation.goosebody.rotate": {
			"loop": true,
			"animation_length": 2,
			"bones": {
				"body": {
					"rotation": {
						"0.0": {
							"vector": [0, 0, 0]
						},
						"0.5": {
							"vector": [0, -90, 0]
						},
						"1.0": {
							"vector": [0, -180, 0]
						},
						"1.5": {
							"vector": [0, -270, 0]
						},
						"2.0": {
							"vector": [0, -360, 0]
						}
					}
				}
			}
		}
	},
	"geckolib_format_version": 2
}

方块展示文件(放入models/block文件夹):

goosebody.json

{
  "credit": "Made with Blockbench",
  "parent": "builtin/entity",
  "display": {
    "thirdperson_righthand": {
      "scale": [
        0.75,
        0.75,
        0.75
      ]
    },
    "thirdperson_lefthand": {
      "scale": [
        0.75,
        0.75,
        0.75
      ]
    },
    "firstperson_righthand": {
      "rotation": [
        -180,
        -3.25,
        -180
      ],
      "translation": [
        0,
        -1.5,
        -3
      ],
      "scale": [
        0.75,
        0.75,
        0.75
      ]
    },
    "firstperson_lefthand": {
      "rotation": [
        -180,
        32,
        180
      ],
      "translation": [
        0.75,
        -1.75,
        -1.75
      ],
      "scale": [
        0.75,
        0.75,
        0.75
      ]
    },
    "ground": {
      "translation": [
        0,
        -3.5,
        0
      ]
    },
    "gui": {
      "translation": [
        0,
        -7.5,
        0
      ]
    },
    "head": {
      "translation": [
        0,
        6.25,
        0
      ]
    },
    "fixed": {
      "translation": [
        -0.75,
        -5.5,
        0
      ]
    }
  }
}

物品模型文件(放入models/item文件夹):

goosebody.json

{}

相关文章:

  • 网站介绍怎么写/百度框架户开户渠道代理
  • 做思路导图的网站manage/岳阳seo公司
  • 做网站开通手机验证功能/网络营销讲师
  • 环保企业网站建设现状/济宁百度推广公司
  • php 操作 wordpress数据库/湖南网站定制
  • 网站优化seo四个建议/企业网站推广效果指标分析
  • C 语言目标文件
  • 第四十六章 使用 ^SystemPerformance 监视性能 - 生成 ^SystemPerformance 性能报告
  • 微信小程序textarea的placeholder的行高怎么修改
  • 修改配置文件的定时任务
  • Python实战项目1——自动获取小说工具
  • javaweb10 JSP语法、JSTL、EL表达式、JSP标签、九大内置对象
  • 音视频技术开发周刊 | 279
  • ❤️自动化-文件路径管理-详细教程附代码⚡
  • R-P-Faster R-CNN day65 读论文:高分辨率遥感影像综合地理空间目标检测框架
  • Android 深入系统完全讲解(19)
  • Docker部署jeecgboot微服务使用记录
  • 实时即未来,大数据项目车联网之车联网之Flink Watermark(水位线)【十四】