这期再来讲讲上一期没讲完的东西,怎么新建一个火球,这个火球和原版的火球不一样,他不会破坏方块,被点燃的实体不会停止燃烧,这就需要新建一个火球类继承原版的火球,冷却时间在下方显示,要绘制HUD然后动态显示冷却时间。
一、实体的定义
在我的世界中,实体(entity)是游戏中可以互动的虚拟物体,如生物、怪物、玩家角色等。实体可以移动、进行攻击、被攻击、进行交互等操作。与实体不同,投掷物(projectile)是一种特殊的实体,通常是由玩家或某些生物投掷出去的物体,如箭矢、火球等。
在我的世界中,实体分为多种类型,包括但不限于:
生物类实体:如动物、怪物以及玩家本身都属于生物类实体,它们可以移动、进行攻击等操作。
物品实体:如掉落的物品、放置的物品等,可以被玩家拾取或进行交互。
方块实体:如推动的方块、活塞推出的方块等,也属于实体的一种。
总的来说,在我的世界中,实体是游戏中重要的元素之一,玩家与实体的互动和操作是游戏的核心内容之一。
二、新建实体
在 Minecraft 1.20.1 Forge 模组开发中,创建一个新的实体涉及多个步骤。
首先需要定义一个继承自 `Entity` 类的新实体类。
public class ExampleEntity extends Entity {
private static final EntityDataAccessor<Integer> DATA_EXAMPLE_VALUE = SynchedEntityData.defineId(ExampleEntity.class, EntityDataSerializers.INT);
public ExampleEntity(EntityType<?> type, Level world) {
super(type, world);
}
@Override
protected void defineSynchedData() {
this.entityData.define(DATA_EXAMPLE_VALUE, 0);
}
@Override
protected void readAdditionalSaveData(CompoundTag compoundTag) {
this.entityData.set(DATA_EXAMPLE_VALUE, compoundTag.getInt("ExampleValue"));
}
@Override
protected void addAdditionalSaveData(CompoundTag compoundTag) {
compoundTag.putInt("ExampleValue", this.entityData.get(DATA_EXAMPLE_VALUE));
}
}
代码功能总结:
这段代码定义了一个名为
ExampleEntity
的类,这个类继承自Minecraft中的Entity
类。它主要用于在Minecraft中创建一个自定义实体,并实现了同步数据和保存/加载额外数据的功能。下面是对代码的详细分解:
类定义和继承:
public class ExampleEntity extends Entity {
ExampleEntity
类继承了Entity
类,意味着它是一个实体对象,可以存在于Minecraft的世界中。public
关键字表示这个类可以被其他类访问。定义同步数据:
private static final EntityDataAccessor<Integer> DATA_EXAMPLE_VALUE = SynchedEntityData.defineId(ExampleEntity.class, EntityDataSerializers.INT);
EntityDataAccessor<Integer>
是一个泛型接口,用于访问实体的同步数据。DATA_EXAMPLE_VALUE
是一个静态常量,用于存储这个实体的一个整型同步变量。SynchedEntityData.defineId
方法用于为实体定义一个唯一标识符,这个标识符用于在网络中同步数据。EntityDataSerializers.INT
指定这个同步变量的数据类型为整型。构造方法:
public ExampleEntity(EntityType<?> type, Level world) { super(type, world); }
- 构造方法用于创建
ExampleEntity
对象。EntityType<?> type
表示该实体的类型,Level world
表示该实体所在的Minecraft世界。super(type, world)
调用了父类Entity
的构造方法,初始化了实体的基本属性。定义同步数据值:
@Override protected void defineSynchedData() { this.entityData.define(DATA_EXAMPLE_VALUE, 0); }
- 重写了
defineSynchedData()
方法,用于定义实体的同步数据。this.entityData.define(DATA_EXAMPLE_VALUE, 0)
使用之前定义的DATA_EXAMPLE_VALUE
标识符,将一个初始值为0的整型数据添加到entityData
中。entityData
是一个SynchedEntityData
对象,用于管理实体的同步数据。读取附加保存数据:
@Override protected void readAdditionalSaveData(CompoundTag compoundTag) { this.entityData.set(DATA_EXAMPLE_VALUE, compoundTag.getInt("ExampleValue")); }
- 重写了
readAdditionalSaveData()
方法,用于从CompoundTag
对象中读取实体的额外保存数据。CompoundTag
是一种数据结构,可以存储多种类型的数据,这里用于存储实体的状态信息。compoundTag.getInt("ExampleValue")
从CompoundTag
中读取名为ExampleValue
的整数值,并将其设置到实体的同步数据中。添加附加保存数据:
@Override protected void addAdditionalSaveData(CompoundTag compoundTag) { compoundTag.putInt("ExampleValue", this.entityData.get(DATA_EXAMPLE_VALUE)); }
- 重写了
addAdditionalSaveData()
方法,用于将实体的额外数据保存到CompoundTag
对象中。this.entityData.get(DATA_EXAMPLE_VALUE)
从实体的同步数据中获取DATA_EXAMPLE_VALUE
的值。compoundTag.putInt("ExampleValue", ...)
将获取到的值保存到CompoundTag
对象中,键名为ExampleValue
。总结
这段代码的主要功能是定义一个自定义的Minecraft实体
ExampleEntity
,并实现了一个整型同步变量DATA_EXAMPLE_VALUE
的同步和保存/加载功能。同步功能使得客户端和服务器上的实体数据保持一致,而保存/加载功能允许实体的状态在游戏存档中持久化。
注册实体到事件总线中
private static final DeferredRegister<EntityType<?>> ENTITY_TYPES = DeferredRegister.create(ForgeRegistries.ENTITY_TYPES, "example_mod");
public static final RegistryObject<EntityType<ExampleEntity>> EXAMPLE_ENTITY = ENTITY_TYPES.register("example_entity", () ->
EntityType.Builder.<ExampleEntity>of(ExampleEntity::new, MobCategory.MISC)
.sized(0.6F, 1.8F).clientTrackingRange(8).updateInterval(3).build(new ResourceLocation("example_mod:example_entity").toString()));
public static void init() {
IEventBus modEventBus = FMLJavaModLoadingContext.get().getModEventBus();
ENTITY_TYPES.register(modEventBus);
}
这段代码是Minecraft Forge模组开发中用于注册自定义实体类型的一部分。下面是对这段代码的逐步分解和详细解释:
实体类型注册器的创建:
private static final DeferredRegister<EntityType<?>> ENTITY_TYPES = DeferredRegister.create(ForgeRegistries.ENTITY_TYPES, "example_mod");
这行代码创建了一个
DeferredRegister
对象,专门用于注册实体类型。DeferredRegister
是Forge提供的一个类,允许在游戏生命周期的适当阶段(如数据加载阶段)注册内容,而不是在构造函数中立即注册。ForgeRegistries.ENTITY_TYPES
表示要注册的是实体类型,而"example_mod"
是模组的ID。注册自定义实体类型:
public static final RegistryObject<EntityType<ExampleEntity>> EXAMPLE_ENTITY = ENTITY_TYPES.register("example_entity", () -> EntityType.Builder.<ExampleEntity>of(ExampleEntity::new, MobCategory.MISC) .sized(0.6F, 1.8F).clientTrackingRange(8).updateInterval(3).build(new ResourceLocation("example_mod:example_entity").toString()));
这段代码通过
DeferredRegister
的register
方法注册了一个自定义实体类型ExampleEntity
。RegistryObject<EntityType<ExampleEntity>>
是一个引用对象,它将在实体类型实际注册后引用该实体类型。EntityType.Builder
用于构建实体类型实例,其中ExampleEntity::new
是一个构造函数引用,表示如何实例化实体。MobCategory.MISC
表示该实体的分类,这里使用的是“杂项”分类。sized(0.6F, 1.8F)
设置了实体的大小,宽度为0.6,高度为1.8。clientTrackingRange(8)
定义了客户端跟踪此实体的最大距离为8个方块。updateInterval(3)
定义了客户端和服务器之间同步实体状态的频率,这里每3个游戏刻同步一次。最后,build(new ResourceLocation("example_mod:example_entity").toString())
构建了实体类型,并使用ResourceLocation
来唯一标识该实体类型。初始化实体注册:
public static void init() { IEventBus modEventBus = FMLJavaModLoadingContext.get().getModEventBus(); ENTITY_TYPES.register(modEventBus); }
init
方法用于将之前创建的实体类型注册器ENTITY_TYPES
与模组的事件总线modEventBus
关联起来。FMLJavaModLoadingContext.get().getModEventBus()
获取了模组的事件总线,然后通过ENTITY_TYPES.register(modEventBus)
在模组加载时注册所有通过ENTITY_TYPES
注册的实体类型。总结:
这段代码的主要功能是创建并注册一个名为
ExampleEntity
的自定义实体类型。通过使用DeferredRegister
,确保了实体类型在正确的生命周期阶段被注册。此外,还设置了该实体的基本属性,如大小、跟踪范围和更新频率,并为其实体类型创建了一个ResourceLocation
,以确保它是唯一且可以被Minecraft识别的。
三、EntityRenderersEvent事件
EntityRenderersEvent 是 Forge 模组开发框架中用于处理实体渲染器注册的事件类,它属于 Forge 事件总线系统的一部分。在 Minecraft 模组开发里,当你需要为自定义实体指定渲染器时,就可以借助 EntityRenderersEvent 来达成这一目的。
EntityRenderersEvent 的用途
EntityRenderersEvent 有多个子类,每个子类对应不同的渲染器注册阶段,不过最常用的是 EntityRenderersEvent.RegisterRenderers。这个子类事件允许你在模组初始化期间注册自定义实体的渲染器。
如何使用 EntityRenderersEvent 渲染实体
步骤 1:定义自定义实体
首先,你得定义一个自定义实体类,并且在 EntityRegistry 里注册这个实体。
步骤 2:创建实体渲染器
接着,你需要创建一个渲染器类,这个类要继承自合适的渲染器基类,例如 ThrownItemRen