客户端动画 API

按客户端 tick 推进的序列帧动画。全部 @SideOnly(Side.CLIENT),由 ClientTickHandler 统一驱动。

基本信息

属性 值
基类 wanion.lib.client.animation.Animation(abstract)
具体子类 SimpleAnimation、SimpleHalfAnimation(final)、ComplexAnimation、ComplexHalfAnimation(final)
驱动者 wanion.lib.client.ClientTickHandler(final)
帧资源 net.minecraft.util.ResourceLocation[]
挂载事件 TickEvent.ClientTickEvent(注册在 FML 总线 FMLCommonHandler.instance().bus())
步进粒度 简单类 1 tick / 帧,半速类 2 tick / 帧

四个变体对比

属性 SimpleAnimation SimpleHalfAnimation ComplexAnimation ComplexHalfAnimation
修饰 class(可继承) final class class(可继承) final class
父类 Animation SimpleAnimation Animation ComplexAnimation
构造签名 (ResourceLocation[] frames) (ResourceLocation[] frames) (ResourceLocation[] frames, int[] animationStages) (ResourceLocation[] frames, int[] stages)
步进逻辑 if (++currentFrame > lastFrameIndex) currentFrame = 0; if (half ^= true) super.updateAnimation(); if (++currentStage > lastStageIndex) currentStage = 0; 然后 currentFrame = animationStages[currentStage]; if (half ^= true) super.updateAnimation();
每 tick 走几帧 1 0 或 1(隔帧) 1 0 或 1(隔帧)
能否跳帧 否,只能顺序 同左 能,animationStages 显式指定每步的目标帧 能
内部状态 currentFrame currentFrame + private boolean half currentFrame + currentStage + lastStageIndex 同左 + private boolean half
循环 回到帧 0 同左 回到 stage 0 并取 animationStages[0] 同左

half ^= true 的语义:boolean 上 ^= 每次取反,条件为真时才调 super。第一次 updateAnimation() 就会推进(false ^= true → true),之后隔一次才推进 —— 实际 2 tick 一帧。四个类都不在构造时推进,所以注册后的第一个 tick 就会动。

Animation 基类成员

成员 签名 说明
帧数组 private final ResourceLocation[] frames
末帧下标 protected final int lastFrameIndex 构造时 = frames.length
当前帧 protected int currentFrame 初值 0
构造 public Animation(@Nonnull ResourceLocation[] frames) lastFrameIndex - 1 == -1(即空数组)时 throw new RuntimeException("What is an Animation with no frames?")
步进 public abstract void updateAnimation() 抽象
取当前帧 public final ResourceLocation getCurrentFrame() frames[currentFrame]

ClientTickHandler

@SideOnly(Side.CLIENT)
public final class ClientTickHandler implements WanionLib.IDependency {
    private final List<Animation> registeredAnimations = new ArrayList<>();
    private ClientTickHandler() { FMLCommonHandler.instance().bus().register(this); }
    public void registerAnimation(@Nonnull Animation animation) { registeredAnimations.add(animation); }
    @SubscribeEvent
    public void tickEvent(final TickEvent.ClientTickEvent event) { registeredAnimations.forEach(Animation::updateAnimation); }
}
成员 说明
构造私有 单例经 依赖容器 的反射无参构造产出
总线 注册在 FML 总线(FMLCommonHandler.instance().bus()),非 MinecraftForge.EVENT_BUS
registerAnimation(Animation) 无去重,重复注册同一实例会被推进多次
tickEvent(TickEvent.ClientTickEvent) 每个客户端 tick 遍历 registeredAnimations 调 updateAnimation();不区分 phase,故一 tick 内 START/END 两阶段各调一次 → 实际 2 tick 一帧

⚠️ 步进速率由这两层叠加决定:TickEvent.ClientTickEvent 在一个 tick 内触发两次(START 与 END),tickEvent 不做 phase 过滤,所以「1 tick 一帧」实际上是半速。想要真实 1 tick 一帧需消费方自行按 event.phase 去重。

⚠️ registeredAnimations 是 ArrayList,在客户端 tick 回调里遍历时若回调内调 registerAnimation 会抛 ConcurrentModificationException。

取得方式

WanionLib.getClientTickHandler()(@SideOnly(Side.CLIENT))内部走 instance.dependencies.get(ClientTickHandler.class),即由反射无参构造惰性产出并注册到 FML 总线。

⚠️ 见 主类入口与依赖注入 的注意点:WanionLib.loadComplete 把 dependencies 置 null,FMLLoadCompleteEvent 之后不可再调 getClientTickHandler()。

相关条目