🇬🇧 English
🇬🇧 English
Appearance
🇬🇧 English
🇬🇧 English
Appearance
This page is written for version:
1.21.4
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.
HudLayerRegistrationCallback
Fabric provides the Hud API to render and layer elements on the HUD.
To start, we need to register a listener to HudLayerRegistrationCallback
which registers your layers. Each layer is an IdentifiedLayer
, which is a vanilla LayeredDrawer.Layer
with an Identifier
attached. A LayeredDrawer.Layer
instance is usually a lambda that takes a DrawContext
and a RenderTickCounter
instance as parameters. See HudLayerRegistrationCallback
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 tickDelta
value. tickDelta
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, tickDelta
represents how far we are between the last tick and the next. Over 11 frames, you might see:
Frame | tickDelta |
---|---|
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 tickDelta
when your animations depend on Minecraft's ticks. For time-based animations, use Util.getMeasuringTimeMs()
, which measures real-world time.
You can retrieve tickDelta
by calling renderTickCounter.getTickDelta(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 {
private static final Identifier EXAMPLE_LAYER = Identifier.of(FabricDocsReference.MOD_ID, "hud-example-layer");
@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 and automatically add 200 after every layer.
HudLayerRegistrationCallback.EVENT.register(layeredDrawer -> layeredDrawer.attachLayerBefore(IdentifiedLayer.CHAT, EXAMPLE_LAYER, 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, z, color
context.fill(0, 0, 10, 10, 0, lerpedColor);
}
}
Why don't you try use tickDelta
and see what happens to the animation when you run the /tick freeze
command? You should see the animation freeze in place as tickDelta
becomes constant (assuming you have passed false
as the parameter to RenderTickCounter#getTickDelta
)