这期再来讲讲上一期没讲完的东西,怎么新建一个火球,这个火球和原版的火球不一样,他不会破坏方块,被点燃的实体不会停止燃烧,这就需要新建一个火球类继承原版的火球,冷却时间在下方显示,要绘制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:创建实体渲染器
接着,你需要创建一个渲染器类,这个类要继承自合适的渲染器基类,例如 ThrownItemRenderer 或者 LivingEntityRenderer。
步骤 3:注册实体渲染器
最后,利用 EntityRenderersEvent.RegisterRenderers 事件来注册自定义实体的渲染器。
示例代码
创建实体渲染器:
import net.minecraft.client.renderer.entity.ThrownItemRenderer;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
@OnlyIn(Dist.CLIENT)
public class CustomFireballRenderer extends ThrownItemRenderer<CustomFireball> {
public CustomFireballRenderer(EntityRendererProvider.Context context) {
super(context);
}
}
注册实体渲染器:
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.client.event.EntityRenderersEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod;
@Mod.EventBusSubscriber(bus = Mod.EventBusSubscriber.Bus.MOD, value = Dist.CLIENT)
public class ClientRegistry {
@SubscribeEvent
public static void registerRenderers(EntityRenderersEvent.RegisterRenderers event) {
event.registerEntityRenderer(
EntityRegistry.CUSTOM_FIREBALL.get(),
CustomFireballRenderer::new
);
}
}
代码解释:
EntityRegistry:这个类负责注册自定义实体 CustomFireball。
CustomFireballRenderer:这是自定义实体的渲染器类,继承自 ThrownItemRenderer。
ClientRegistry:该类包含一个静态方法 registerRenderers,用于处理 EntityRenderersEvent.RegisterRenderers 事件。在这个方法里,我们使用 event.registerEntityRenderer 方法来注册自定义实体的渲染器。
通过以上步骤,你就可以使用 EntityRenderersEvent 为自定义实体注册渲染器,进而在 Minecraft 中渲染这些实体了。
四、自定义火球实体
讲这么多,到底怎么新建一个自定义火球呢?可以参考如下代码,代码就不解释了
public class CustomFireball extends Fireball {
// 主构造方法需匹配父类参数
public CustomFireball(EntityType<? extends Fireball> type, Level level) {
super(type, level);
}
// 带实体的构造方法
public CustomFireball(Level level, LivingEntity shooter, double dX, double dY, double dZ) {
super(EntityRegistry.CUSTOM_FIREBALL.get(), shooter, dX, dY, dZ, level);
this.setNoGravity(true);
}
@Override
protected void onHit(@NotNull HitResult result) {
if (!this.level().isClientSide) {
// 创建影响范围
AABB area = this.getBoundingBox().inflate(2.0D);
List<LivingEntity> entities = this.level().getEntitiesOfClass(
LivingEntity.class,
area,
e -> e != this.getOwner()
);
// 对范围内所有生物应用燃烧效果
for (LivingEntity entity : entities) {
entity.setSecondsOnFire(999); // 30秒燃烧
}
// 生成火焰粒子
ServerLevel level = (ServerLevel) this.level();
level.sendParticles(
ParticleTypes.FLAME,
this.getX(),
this.getY(),
this.getZ(),
50,
0.5D, 0.5D, 0.5D,
0.2D
);
this.discard();
}
}
}
五、HUD显示
HUD 是什么
HUD 即 Heads - Up Display,直译为平视显示器,在游戏领域,它指的是游戏界面上显示的信息,如生命值、分数、武器状态等。这些信息通常直接叠加在游戏画面上,让玩家无需转移视线就能获取关键信息。
在 Minecraft Forge 中绘制 HUD 显示信息
步骤
监听渲染事件:借助 RenderGuiOverlayEvent.Post 事件,在游戏界面渲染完成后绘制 HUD。
绘制信息:运用 GuiGraphics 对象来绘制背景和文字。
public class ClientHandler {
@SubscribeEvent
public static void onRenderGui(RenderGuiOverlayEvent.Post event) {
if (event.getOverlay() != VanillaGuiOverlay.HOTBAR.type()) return;
Minecraft mc = Minecraft.getInstance();
Player player = mc.player;
if (player == null) return;
GuiGraphics gui = event.getGuiGraphics();
ItemStack mainHand = player.getMainHandItem();
if (mainHand.getItem() instanceof FlameSwordItem) {
// 获取精确剩余时间
float cooldown = player.getCooldowns().getCooldownPercent(
MyMod.FLAME_SWORD.get(),
mc.getFrameTime()
);
if (cooldown > 0) {
// 计算剩余秒数(保留1位小数)
String text = String.format("冷却: %.1fs", cooldown * 3);
int x = mc.getWindow().getGuiScaledWidth() / 2 - 25;
int y = mc.getWindow().getGuiScaledHeight() - 25;
// 绘制背景
gui.fill(x - 2, y - 2, x + 50, y + 10, 0x80000000);
// 绘制文字
gui.drawString(
mc.font,
text,
x, y,
0xFFAA00, // 橙色文字
false
);
}
}
}
}
这段代码是一个Minecraft模组中的客户端事件处理器,主要功能是在玩家手持特定物品(名为FlameSwordItem
的火焰剑)时,在游戏界面的热键栏下方显示一个冷却倒计时。
让我们逐步分解并详细解释这段代码:
-
类定义:
public class ClientHandler {
这里定义了一个名为
ClientHandler
的公共类。这个类将用于处理客户端事件。 -
事件订阅:
@SubscribeEvent public static void onRenderGui(RenderGuiOverlayEvent.Post event) {
这段代码使用了Forge的
@SubscribeEvent
注解,表示这个方法将订阅RenderGuiOverlayEvent.Post
事件。这意味着每当Minecraft的GUI覆盖层渲染完毕之后,这个方法都会被调用。该事件处理方法名为onRenderGui
,它接收一个RenderGuiOverlayEvent.Post
类型的事件对象。 -
事件类型判断:
if (event.getOverlay() != VanillaGuiOverlay.HOTBAR.type()) return;
这段代码首先检查当前渲染的GUI覆盖层是否是热键栏(
VanillaGuiOverlay.HOTBAR.type()
)。如果不是热键栏,则直接返回,不执行后续的代码逻辑。这一步是为了确保后续的代码仅在热键栏渲染后执行。 -
获取Minecraft实例和玩家对象:
Minecraft mc = Minecraft.getInstance(); Player player = mc.player; if (player == null) return;
这里通过
Minecraft.getInstance()
获取Minecraft的游戏实例,然后从实例中获取当前玩家对象。接着检查玩家对象是否为空,如果为空(例如游戏中没有玩家时),则直接返回,不执行后续逻辑。 -
获取当前渲染的GUI图形对象:
GuiGraphics gui = event.getGuiGraphics();
从事件对象中获取
GuiGraphics
对象,这个对象可以用来在游戏界面绘制图形。 -
获取玩家主手物品:
ItemStack mainHand = player.getMainHandItem();
从玩家对象中获取玩家主手上的物品,并将其存储在
ItemStack
对象mainHand
中。 -
判断主手物品是否为火焰剑:
if (mainHand.getItem() instanceof FlameSwordItem) {
这段代码检查玩家主手上的物品是否是
FlameSwordItem
类型的物品。如果是火焰剑,则执行后续逻辑;如果不是,则直接返回。 -
获取冷却时间百分比:
float cooldown = player.getCooldowns().getCooldownPercent( MyMod.FLAME_SWORD.get(), mc.getFrameTime() );
如果玩家手持的是火焰剑,这里会计算火焰剑的冷却时间百分比。
player.getCooldowns().getCooldownPercent()
方法需要两个参数:要检查的物品和当前帧的时间。MyMod.FLAME_SWORD.get()
返回的是火焰剑物品的实例。 -
冷却时间大于0的判断:
if (cooldown > 0) {
这段代码判断冷却时间的百分比是否大于0,如果大于0,说明火焰剑还在冷却中,则执行后续的冷却时间显示逻辑。
-
计算冷却剩余秒数:
String text = String.format("冷却: %.1fs", cooldown * 3);
这里通过
String.format()
方法将冷却时间的百分比转换为秒数,并格式化为保留一位小数的字符串。注意到这里将百分比乘以3,可能是因为模组中设定火焰剑的冷却时间为3秒。 -
计算文本绘制的位置坐标:
int x = mc.getWindow().getGuiScaledWidth() / 2 - 25; int y = mc.getWindow().getGuiScaledHeight() - 25;
这段代码计算了冷却时间文本在游戏界面中的绘制位置。
x
坐标是窗口宽度的一半再减去25像素,y
坐标是窗口高度减去25像素,这样文本就会出现在屏幕中央下方的位置。 -
绘制背景:
gui.fill(x - 2, y - 2, x + 50, y + 10, 0x80000000);
这段代码使用
GuiGraphics
对象gui
在文本绘制的位置前绘制一个背景矩形。矩形的左上角坐标为(x - 2, y - 2)
,右下角坐标为(x + 50, y + 10)
。矩形颜色为半透明的黑色(0x80000000
),其中前两位十六进制数80
表示透明度。 -
绘制冷却时间文本:
gui.drawString( mc.font, text, x, y, 0xFFAA00, // 橙色文字 false );
这段代码通过
GuiGraphics
对象gui
在计算好的位置绘制冷却时间文本。mc.font
是Minecraft中用于绘制文本的字体对象。文本颜色设置为橙色(0xFFAA00
),并且不使用阴影效果(false
)。
总结:
这段代码的主要功能是在Minecraft客户端渲染热键栏之后,检查玩家主手是否持有火焰剑。如果持有火焰剑且其处于冷却状态,则在屏幕中央下方显示剩余冷却时间。这为玩家提供了一个直观的冷却时间反馈,使得玩家更容易掌握火焰剑的使用时机。
怎么设置技能的冷却时间?(深入了解)
可以参考下面的代码:
player.getCooldowns().addCooldown(MyMod.FLAME_SWORD.get(), 60); // 设置冷却时间为 60 个游戏刻(游戏刻约为 1/20 秒)
为了更好的理解冷却时间,可以研究一下源码
ItemCooldowns
相关方法
protected ItemCooldowns createItemCooldowns() {
return new ItemCooldowns();
}
public ItemCooldowns getCooldowns() {
return this.cooldowns;
}
createItemCooldowns()
创建一个ItemCooldowns
对象,用于管理物品冷却时间。getCooldowns()
返回ItemCooldowns
对象,可以用来获取或设置物品的冷却时间。
技能冷却时间的计算与设置
计算冷却时间:
ItemCooldowns
类提供了方法来管理物品的冷却时间。在上述代码中,Player
类通过 ItemCooldowns
实例来管理冷却时间。
getCooldownPercent(Item item, float frameTime)
方法返回指定物品的冷却时间百分比。item
是要查询冷却状态的物品。frameTime
是当前帧的时间,通常用于动画和时间相关的计算。
- 在
ClientHandler
类中,冷却时间的百分比被获取并乘以 3 来转换为秒数。这个转换可能是因为getCooldownPercent
返回的是一个 0 到 1 的百分比值,而乘以 3 可能是某个特定物品的冷却时间长度(假设总共 3 秒)。
设置冷却时间:
- 冷却时间设置通常在使用物品时调用。例如,当玩家使用某个物品后,可以通过
ItemCooldowns.addCooldown(Item item, int ticks)
来设置冷却时间。item
是要设置冷却时间的物品。ticks
是冷却时间的持续时长(以游戏刻为单位)。
- 在
Player
类中,使用物品后会调用disableShield
方法来设置冷却时间。这个方法中,调用了this.getCooldowns().addCooldown(this.getUseItem().getItem(), 100);
来设置使用物品后的冷却时间为 100 个游戏刻。
总结
这段代码定义了 Player
类,它是 Minecraft 中玩家实体的抽象类。代码中涉及到了玩家的基本属性、物品栏、经验和冷却系统的管理。特别地,ItemCooldowns
类用于管理物品的冷却时间,玩家在使用某些物品后,系统会通过这个类来设置和获取冷却状态。在 ClientHandler
类中,当玩家使用特定物品(如火焰剑)时,代码会获取该物品的冷却时间并将其显示在游戏界面的热巴条上方。
ItemCooldowns类
package net.minecraft.world.item;
import com.google.common.collect.Maps; // 引入用于创建哈希表的Maps类
import java.util.Iterator; // 引入迭代器接口
import java.util.Map; // 引入映射接口
import net.minecraft.util.Mth; // 引入数学工具类
// ItemCooldowns 类用于管理物品的冷却时间
public class ItemCooldowns {
private final Map<Item, CooldownInstance> cooldowns = Maps.newHashMap(); // 存储物品与其冷却实例之间的映射关系
private int tickCount; // 计时器,用于跟踪冷却时间的滴答
// 构造函数
public ItemCooldowns() {
}
// 检查指定的物品是否在冷却中
public boolean isOnCooldown(Item p_41520_) {
return this.getCooldownPercent(p_41520_, 0.0F) > 0.0F; // 如果冷却百分比大于0,表示在冷却中
}
// 获取指定物品的冷却百分比
public float getCooldownPercent(Item p_41522_, float p_41523_) {
CooldownInstance $2 = (CooldownInstance)this.cooldowns.get(p_41522_); // 获取物品的冷却实例
if ($2 != null) { // 如果存在该物品的冷却实例
float $3 = (float)($2.endTime - $2.startTime); // 计算冷却时间间隔
float $4 = (float)$2.endTime - ((float)this.tickCount + p_41523_); // 计算剩余冷却时间
return Mth.clamp($4 / $3, 0.0F, 1.0F); // 将冷却百分比限制在0到1之间
} else {
return 0.0F; // 如果没有冷却实例,则返回0
}
}
// 更新冷却计时器
public void tick() {
++this.tickCount; // 增加计时器
if (!this.cooldowns.isEmpty()) { // 如果冷却列表不为空
Iterator<Map.Entry<Item, CooldownInstance>> $0 = this.cooldowns.entrySet().iterator(); // 获取冷却的迭代器
// 遍历所有冷却实例
while($0.hasNext()) {
Map.Entry<Item, CooldownInstance> $1 = (Map.Entry)$0.next(); // 获取下一个条目
if (((CooldownInstance)$1.getValue()).endTime <= this.tickCount) { // 如果当前时间超过冷却结束时间
$0.remove(); // 从冷却列表中移除
this.onCooldownEnded((Item)$1.getKey()); // 触发冷却结束事件
}
}
}
}
// 为指定的物品添加冷却时间
public void addCooldown(Item p_41525_, int p_41526_) {
this.cooldowns.put(p_41525_, new CooldownInstance(this.tickCount, this.tickCount + p_41526_)); // 添加物品的冷却实例
this.onCooldownStarted(p_41525_, p_41526_); // 触发冷却开始事件
}
// 移除指定物品的冷却时间
public void removeCooldown(Item p_41528_) {
this.cooldowns.remove(p_41528_); // 从冷却列表中移除物品
this.onCooldownEnded(p_41528_); // 触发冷却结束事件
}
// 冷却开始时触发的事件,通常留空供子类重写
protected void onCooldownStarted(Item p_41529_, int p_41530_) {
}
// 冷却结束时触发的事件,通常留空供子类重写
protected void onCooldownEnded(Item p_41531_) {
}
// 内部类用于表示冷却实例
static class CooldownInstance {
final int startTime; // 冷却开始时间
final int endTime; // 冷却结束时间
// 构造函数
CooldownInstance(int p_186358_, int p_186359_) {
this.startTime = p_186358_; // 设置开始时间
this.endTime = p_186359_; // 设置结束时间
}
}
}
代码解释总结:
-
类功能:
ItemCooldowns
是一个用于管理物品冷却时间的类。它追踪每个物品的冷却状态,并提供方法来查询物品是否在冷却中以及其剩余冷却时间。 -
数据结构:使用
Map<Item, CooldownInstance>
来存储物品和其冷却实例的映射。CooldownInstance
内部类用于表示冷却的开始和结束时间。 -
主方法:
isOnCooldown(Item)
:检查指定物品是否在冷却中。getCooldownPercent(Item, float)
:计算物品当前的冷却百分比。tick()
:更新冷却计时器,并移除过期的冷却实例。addCooldown(Item, int)
:为指定物品添加冷却。removeCooldown(Item)
:移除指定物品的冷却。
-
事件处理:定义了
onCooldownStarted
和onCooldownEnded
方法,这些方法在冷却开始或结束时被触发,允许子类自定义行为。
好了,本期就讲到这里,如果对你有帮助,请一定要点赞关注,感谢支持