🇬🇧 English
🇬🇧 English
Appearance
🇬🇧 English
🇬🇧 English
Appearance
This page is written for version:
1.21.8
We already briefly touched on rendering things to the HUD in the Basic Rendering Concepts page and Using The Drawing Context, so on this page we'll stick to the Hud API and the RenderTickCounter
parameter.
HudRenderCallback
WARNING
Previously, Fabric provided HudRenderCallback
to render to the HUD. Due to changes to HUD rendering, this event became extremely limited and is deprecated since Fabric API 0.116. Usage is strongly discouraged.
HudElementRegistry
Fabric provides the Hud API to render and layer elements on the HUD.
To start, we need to register a listener to HudElementRegistry
which registers your elements. Each element is an HudElement
. A HudElement
instance is usually a lambda that takes a DrawContext
and a RenderTickCounter
instance as parameters. See HudElementRegistry
and related Javadocs for more details on how to use the API.
The draw context can be used to access the various rendering utilities provided by the game, and access the raw matrix stack. You should check out the Draw Context page to learn more about the draw context.
The RenderTickCounter
class allows you to retrieve the current tickProgress
value. tickProgress
is the "progress" between the last game tick and the next game tick.
For example, if we assume a 200 FPS scenario, the game runs a new tick roughly every 10 frames. Each frame, tickProgress
represents how far we are between the last tick and the next. Over 11 frames, you might see:
Frame | tickProgress |
---|---|
1 | 1 : New tick |
2 | 1/10 = 0.1 |
3 | 2/10 = 0.2 |
4 | 3/10 = 0.3 |
5 | 4/10 = 0.4 |
6 | 5/10 = 0.5 |
7 | 6/10 = 0.6 |
8 | 7/10 = 0.7 |
9 | 8/10 = 0.8 |
10 | 9/10 = 0.9 |
11 | 1 : New tick |
In practice, you should only use tickProgress
when your animations depend on Minecraft's ticks. For time-based animations, use Util.getMeasuringTimeMs()
, which measures real-world time.
You can retrieve tickProgress
by calling renderTickCounter.getTickProgress(false)
, where the boolean parameter is ignoreFreeze
, which essentially just allows you to ignore whenever players use the /tick freeze
command.
In this example, we'll use Util.getMeasuringTimeMs()
to linearly interpolate the color of a square that is being rendered to the HUD.
public class HudRenderingEntrypoint implements ClientModInitializer {
@Override
public void onInitializeClient() {
// Attach our rendering code to before the chat hud layer. Our layer will render right before the chat. The API will take care of z spacing.
HudElementRegistry.attachElementBefore(VanillaHudElements.CHAT, Identifier.of(FabricDocsReference.MOD_ID, "before_chat"), HudRenderingEntrypoint::render);
}
private static void render(DrawContext context, RenderTickCounter tickCounter) {
int color = 0xFFFF0000; // Red
int targetColor = 0xFF00FF00; // Green
// You can use the Util.getMeasuringTimeMs() function to get the current time in milliseconds.
// Divide by 1000 to get seconds.
double currentTime = Util.getMeasuringTimeMs() / 1000.0;
// "lerp" simply means "linear interpolation", which is a fancy way of saying "blend".
float lerpedAmount = MathHelper.abs(MathHelper.sin((float) currentTime));
int lerpedColor = ColorHelper.lerp(lerpedAmount, color, targetColor);
// Draw a square with the lerped color.
// x1, x2, y1, y2, color
context.fill(0, 0, 10, 10, lerpedColor);
}
}
Why don't you try use tickProgress
and see what happens to the animation when you run the /tick freeze
command? You should see the animation freeze in place as tickProgress
becomes constant (assuming you have passed false
as the parameter to RenderTickCounter#getTickProgress
)