最全面最细致我的世界Fabric模组开发02 - 方块和物品

我的世界1.21.5 Fabric模组开发02 - 方块和物品

前言

  • 在我的世界中,世界主要由方块、物品、环境、实体,这四种要素组成,它们互相影响,相互组合,构成五彩纷纷的世界。所以,本节课详细讲述如何创建并注册方块和物品,还要了解如何运用数据生成,以及什么是CRD模式等
  • 如果你是经验比较丰富程序员,可以直接跳转到运用数据生成器即可

流程图

  • 箭头表示编写步骤
  • 不使用数据生成器情况下
    在这里插入图片描述
  • 常用流程(使用数据生成器)
    在这里插入图片描述

文件结构

在创建方块物品之前,有必要搞懂文件结构,每个文件夹含义,知道这个文件应该放在哪里。

  • java包下文件结构
    java包下文件结构

  • resources包下文件结构
    资源文件夹

    • fabric.mod.json: 这个文件告诉这个项目/游戏,通过配置文件寻找模组主入口(实现ModInitializer接口的class类),来初始化创建新的方块和物品
    • tutorial-mod.mixins.json: 这个文件用来配置Mixin类,用于原版代码注入操作
  • assets包下文件结构在这里插入图片描述

  • data包下文件结构(以后再说)

CRD模式

了解文件结构(项目结构)后,在了解CRG模式

  • 什么是CRD模式
    • CRD模式是Create Register Datagen,意思是创建、注册、数据生成
  • 无论是类是方块还是物品,或者其他类,大多数都满足这三步,并且还有先后顺序
    • 第一步:创建(方块、物品、药水、地物等)
    • 第二步:注册(方块、物品等)
    • 第三步:数据生成(方块模型、物品模型、物品模型映射等)
  • 如果是简单方块类,或者物品类时,无需创建类(class 文件),只需调用原版对应类即可
  • 什么是简单类
    • 这个类继承原版的类(例如Block类和Item类)且只有构造方法存在,没有添加状态方法,实体方法,使用类等操作时,不用创建新的类,直接注册即可,防止类爆炸问题**

创建并注册方块

创建方块

main/java/com/crystal/tutorial/block包下新建CruciateStoneBlock类,继承extends)方块类(Block),而且每个方块必须要有含一个形式参数Settings)的构造方法(构造函数)

public class CruciateStoneBlock {
	public CruciateStoneBlock(Settings settings) {
		super(settings);
	}
}
  • 类的命名必须使用驼峰命名规则,且通常情况下是以Block单词结尾,例如:ExampleBlock、StoneBlock、SandBlock等,这样做目的是加以区分那个是方块?那个是物品?这样每个类有明确的含义。

注册方块

main/java/com/crystal/tutorial包下的TutorialMod类,在onInitialize()方法完成方块注册。
在注册方块之前,建议写of (String)方法,如下

public static Identifier of(String path) {
	return Identifier.of("modid", path);
}

这样方便后续注册操作,避免模组modid使用过于频繁,只需填入一个字符串即可。

public void onInitialize() {
	/* Block Register */
	RegistryKey<Block> key = RegistryKey.of(RegistryKeys.BLOCK, TutorialMod.of("cruciate_stone"));
	Function<Settings, Block> factory = new Function<Settings, Block>() {
		@Override
		public Block apply(Settings settings) {
			return new CruciateStoneBlock(settings);
		}
	};
	Settings settings = Settings.copy(Blocks.STONE);
	Block block = Blocks.register(key, factory, settings);
	/* Block Item Register */
	Items.register(block);
}
  • RegistryKey(注册关键): 注册、标记类的类型,类型为方块(RegistryKeys.BLOCK),并记录模组id和方块名称,然后生成默认名称为block.tutorial.cruciate_stone,可以通过lang包使默认名称覆盖新的(方块)名字。
  • Function<Settings, Block>(方块函数): 在1.21.2之后,方块注册改为函数注册,将方块对象放在方块函数之后输出结果
  • Settings(设置): 用来设置方块基本属性,例如:方块声音、方块硬度、方块材质等。
  • Items.register(block) 方块物品注册: 将方块添加register(Block)中,即可完成方块物品(BlockItem)注册

方块外观

方块状态
  • src/main/resources/assets/tutorial/blockstates/包下编写cruciate_stone.json文件如下
{
  "variants": {
    "": {
      "model": "tutorial:block/cruciate_stone"
    }
  }
}
  • variants(变种): 通常情况下,简单方块没有指定任何方块属性,则方块模型只有一种。不像:红石灯、熔炉、覆雪草方块等,有多种不同情况下的模型
  • model(模型): 简单方块六个面都对应六个模型,如果""空字符串,则六个面均应用一个模型,并指向models/block/包下的模型Json文件
方块物品模型映射
  • src/main/resources/assets/tutorial/items/包下编写cruciate_stone.json文件
{
  "model": {
    "type": "minecraft:model",
    "model": "tutorial:block/cruciate_stone"
  }
}
  • model(模型): 在1.21.4之后,可以为物品创建对应的物品模型映射,让物品直接使用方块的模型,并指向models/block/包下的模型Json文件
方块模型
  • src/main/resources/assets/tutorial/models/block/包下编写cruciate_stone.json文件
{
  "parent": "block/cube_all",
  "textures": {
    "all": "tutorial:block/cruciate_stone"
  }
}
  • minecraft:block/cube_all(标准模型所有面): 在我的世界里大部分方块的基本结构。这部分方块使用同一个基本模型,以此模型使用它们的纹理,如果是原版模板文件,这个字符串minecraft:可以省略不写
  • 除了原版外,我们可以自定义自己的模板文件,例如:连接纹理、双层纹理等(先挖个坑)
  • textures(材质/纹理): 注意:textures单词是复数形式,不是texture单数形式
  • 这个textures会指向src/main/resources/assets/tutorial/textures/block/包下,包括block本身以及block的子包,其他文件夹都无效果,且控制台不会报任何错误,游泳却出现紫黑方块,即使文件路径写对情况也是如此。
方块材质
  • src/main/resources/assets/tutorial/textures/block/包下放置16*16方块像素图
  • 通常情况下,大部分都是16*16像素画,而且是 2 n ( n ∈ N ∗ ) 2^n (n \in N^*) 2n(nN)的倍数关系,如果不是会出现材质错位现象(材质包除外)。

创建并注册物品

开端

  • 自从1.21.2以后,物品注册方式改变,需要在Items.register(RegistryKey<Item>, Function<Settings, Item>, Settings)方法注册物品,才能使物品模型存储到物品组件上,否则出现空指针异常

java.lang.NullPointerException: Item id not set

创建物品

main/java/com/crystal/tutorial/item包下新建DiamondAppleItem类,继承extends)方块类(Item),而且每个方块必须要有含一个形式参数Settings)的构造方法(构造函数)

public class DiamondApple extends Item {
    public DiamondApple(Settings settings) {
        super(settings);
    }
}
  • 与方块同理,如果是简单物品,不要新建物品类,直接注册物品即可

注册物品

  • main/java/com/crystal/tutorial包下的TutorialMod类,在onInitialize()方法完成物品注册
public void onInitialize() {
	RegistryKey<Item> key1 = RegistryKey.of(RegistryKeys.ITEM, TutorialMod.of("diamond_apple"));
	Function<Item.Settings, Item> factory1 = new Function<Item.Settings, Item>() {
		@Override
		public Item apply(Item.Settings settings) {
				return new DiamondAppleItem(settings);
				}
	};
	Item.Settings item = new Item.Settings();
	Items.register(key1, factory1, item);
}
    • RegistryKey(注册关键): 与方块类似,这个类型是物品(RegistryKeys.ITEM),生成默认名称为item.tutorial.diamond_apple,可以通过lang包使默认名称覆盖新的(物品)名字。

物品外观

物品材质
  • src/main/resources/assets/tutorial/models/item/包下编写diamond_apple.json文件
{
  "parent": "item/generated",
  "textures": {
    "layer0": "tutorial:item/diamond_apple"
  }
}
物品模型映射
  • src/main/resources/assets/tutorial/items包下编写diamond_apple.json文件
{
  "model": {
    "type": "model",
    "model": "tutorial:item/diamond_apple"
  }
}

运用数据生成器

  • 或许你发现,完成物品和方块流程,需要手动编写7次Json文件,当中只要一个单词错误,整个方块物品材质都失效,太麻烦勒,有没有更轻松方式帮助我们编写材质?有我们可以使用数据生成器,来自动生成对应Json文件。
  • 注意: 如果在resources包下存在上述Json文件,请必须删除,否则测试游戏崩溃,出现文件重复问题,确保文件是唯一的,独一无二(指的是文件内容,不是文件名
  • 在使用数据生成器之前,需要对我们项目做些改进
    1. 改进TutorialMod类,分担注册方块和物品责任,缩小体积。分成物品注册类和方块注册类,让TutorialMod类主入口只需绑定(引用)其他子注册类就行,这样才能降低耦合度
    2. 将方法block和item的局部变量,改为成员常量,这样做的因为能够使用数据生成器上调用它们的class对象,扩大作用范围。
    3. 在物品注册类和方块注册类类提供通用方法,将多余重复单词合并(封装)成一个方法,只需输入对应材料(类名和字符串)即可。

方块注册类

在java中的../block/包下新建ModBlocks方法,提供两个方法,一个用来注册方块,一个用来被TutorialMod类调用并注册

public class ModBlocks {
    
    /**
    * 如果是简单方块,不用新建方块类,直接采用Block方块注册即可
    */
    public static Block register(String name, Settings settings) {
        return register(name, Block::new, settings);
    }

    public static Block register(String name, Function<Settings, Block> factory, Settings settings) {
        RegistryKey<Block> key = RegistryKey.of(RegistryKeys.BLOCK, TutorialMod.of(name));
        Block block = Blocks.register(key, factory, settings);
        Items.register(block);
        return block;
    }
    
    public static void init() {
        
    }
}
  • 然后编写成员常量,变量字母需要大写,每个单词用**_**分割
public static final Block CRUCIATE_STONE_BLOCK = register("cruciate_stone", Block::new, Settings.copy(Blocks.STONE)); 

物品注册类

在java中的../item/包下新建ModItems方法,提供两个方法,一个用来注册方块,一个用来被TutorialMod类调用并注册

public class ModItems {

    public static final Item DIAMOND_APPLE = register("diamond_apple", new Settings());

	/**
    * 如果是简单物品,不用新建物品类,直接采用Item物品注册即可
    */
    public static Item register(String name, Settings settings) {
        return register(name, Item::new, settings);
    }

    public static Item register(String name, Function<Settings, Item> factory, Settings settings) {
        RegistryKey<Item> key = RegistryKey.of(RegistryKeys.ITEM, TutorialMod.of(name));
        return Items.register(key, factory, settings);
    }
}
  • 和方块成员常量同理,只是new Item.Settings(),需要new出对应Setting内部class对象
public static final Item DIAMOND_APPLE = register("diamond_apple", new Settings());

数据模型

client/java/com/crystal/tutorial/datagen/包下新建一个TutorialModelGenerator(模型构造器/模型生成器),继承Fabric加载器准备好的数据生成器:FabricModelProvider,并且必须实现一个构成方法,两个无返回值的方法

  • 优点:效率快,操作简单,一键生成文件,无需手动添加(Json)文件
  • 缺点:灵活性较差,新模型需要手动构建对应的模型,且需要游戏进行前,还需要生成一次
public class TutorialModelGenerator extends FabricModelProvider {

    public TutorialModelGenerator(FabricDataOutput output) {
        super(output);
    }

    @Override
    public void generateBlockStateModels(BlockStateModelGenerator create) {
    	// code...
    }

    @Override
    public void generateItemModels(ItemModelGenerator create) {
    	// code...
    }
}
  • FabricDataOutput(Fabric 数据输出): 这个类主要目的是将TutorialModelGenerator类打包(封装),发送并分析里面内容,来打印输出对应Json文件
  • BlockStateModelGenerator(方块状态模型生成器): 这个类提供大量构造模型方法,其中最简单模型为标准模型(Cube);通过调用ModBlocks类中的成员常量即可创建对应模型,并且包括自动生成对应的方块状态、方块模型、方块物品模型映射、自动连接材质等功能
  • ItemModelGenerator(物品模型生成器):方块状态模型生成器一样作用,自动生成对应的物品模型,物品模型映射。
  • 在使用TutorialModelGenerator之前,首先在TutorialModDataGenerator(模组数据构造器/模组数据生成器),调用(连接)模型构造器,这样这个类才能找到这个类来生成对应文件
  • 注意:在这个方法完成绑定
public void onInitializeDataGenerator(FabricDataGenerator generator) {
	// 获取数据构造器的打包器,进行类名封装处理
	FabricDataGenerator.Pack pack = generator.createPack();
	// 添加名单
	pack.addProvider(TutorialModelGenerator::new);
}
  • 然后才能在这里继续编写代码
@Override
public void generateBlockStateModels(BlockStateModelGenerator create) {
    create.registerSimpleCubeAll(ModBlocks.CRUCIATE_STONE);
}
@Override
public void generateItemModels(ItemModelGenerator create) {
    create.register(ModItems.DIAMOND_APPLE, Models.GENERATED);
}
  • registerSimpleCubeAll(Block)(注册简单标准模型所有面):这个方法用来创建,最简单方块(标准模型),所有面都用一个材质,一个模型
  • register(Item, Model):用这个方法注册物品,生成item/generated模型;除了这个模型以外,还可以这样:create.register(ModItems.DIAMOND_APPLE, Models.HANDHELD);(像手里拿把武器一样)
  • 最后,先点击Data Generation,生成完成之后,在点击Minecraft Client 即可

总结

  • 在实际开发当中,通常情况下,都遵循6步:创建(方块或物品)、注册(方块或物品)、(初始化)、数据生成、加入物品组、配置语言
  • 开始创建第一方块和物品时,只需要初始化init()一次,然后第二次不用初始化,注册之后,可直接进入下一步“数据生成”
  • 第一步:在blockitem)包下创建新的方块类(物品类),如果是简单类,不需要创建,直接注册即可。
  • 第二步:在ModBlockModItem)类下,注册方块类(物品类)
  • 第三步:在TutorialModelGenerator类,完成方块模型(物品模型)数据生成。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值