🇩🇪 Deutsch (German)
🇩🇪 Deutsch (German)
Erscheinungsbild
🇩🇪 Deutsch (German)
🇩🇪 Deutsch (German)
Erscheinungsbild
Diese Seite ist für folgende Version geschrieben:
1.21.4
Diese Seite ist für folgende Version geschrieben:
1.21.4
Manchmal reicht das Nutzen von Minecraft's Modellformat nicht aus. Wenn du dynamisches Rendering zu dessen visuellen Elemten hinzufügen willst, wirst du einen BlockEntityRenderer
nutzen müssen.
Lasst uns als Beispiel den Zählerblock aus dem Artikel zu Block Entitäten die Zahl an Klicks auf der Oberseite anzeigen lassen.
Zuerst müssen wir einen BlockEntityRenderer
für unsere CounterBlockEntity
erstellen.
Beim Erstellen eines BlockEntityRenderer
für die CounterBlockEntity
ist es wichtig, wenn das Projekt geteilte Quellen für den Client und den Server nutzt, die Klasse in das passende Quellenverzeichnis, wie src/client/
, zu platzieren. Der Zugriff auf Rendering-bezogene Klassen direkt im src/main/
Quellenverzeichnis ist nicht sicher, da diese Klassen möglicherweise am Server nicht geladen sind.
public class CounterBlockEntityRenderer implements BlockEntityRenderer<CounterBlockEntity> {
public CounterBlockEntityRenderer(BlockEntityRendererFactory.Context context) {
}
@Override
public void render(CounterBlockEntity entity, float tickDelta, MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light, int overlay) {
}
}
Die neue Klasse hat einen Konstruktor mit einem BlockEntityRendererFactory.Context
als Parameter. Der Context
hat einige nützliche Rendering-Hilfsmittel, wie den ItemRenderer
oder TextRenderer
. Durch die Aufnahme eines derartigen Konstruktors, wird es außerdem möglich den Konstuktor als funktionales Interface der BlockEntityRendererFactory
selbst zu verwenden:
public class FabricDocsBlockEntityRenderer implements ClientModInitializer {
@Override
public void onInitializeClient() {
BlockEntityRendererFactories.register(ModBlockEntities.COUNTER_BLOCK_ENTITY, CounterBlockEntityRenderer::new);
}
}
Du solltest Renderer für Blockentitäten in deiner Klasse ClientModInitializer
registrieren.
BlockEntityRendererFactories
ist eine Registrierung, die jeden BlockEntityType
mit benutzerdefinierten Rendering-Code dem entsprechenden BlockEntityRenderer
zuordnet.
Jetzt, da wir den Renderer haben, können wir zeichnen. Die Methode render
wird bei jedem Frame aufgerufen und ist der Ort, an dem die Magie des Renderns passiert.
Zunächst müssen wir den Text versetzen und drehen, damit er sich auf der oberen Seite des Blocks befindet.
INFO
Wie der Name bereits vermuten lässt ist der MatrixStack
ein Stapel, was bedeutet, dass du Transformationen darauf hinzufügen (push) und davon entfernen (pop) kannst. Eine gute Faustregel ist es, einen neuen Block an den Anfang der render
-Methode hinzuzufügen und ihn am Ende wieder zu entfernen, so dass das Rendern eines Blocks die anderen nicht beeinflusst.
Mehr Informationen zu dem MatrixStack
kann in dem Artikel zu den grundlegenden Konzepten des Rendering gefunden werden.
Zum besseren Verständnis der erforderlichen Verschiebungen und Drehungen sollten wir sie visualisieren. In diesem Bild ist der grüne Block die Position, an der der Text gezeichnet werden würde, standardmäßig am äußersten linken unteren Punkt des Blocks:
Zunächst müssen wir den Text auf der X- und Z-Achse in die Mitte und ihn dann an der Y-Achse an den oberen Rand des Blocks verschieben:
Died wird durch einen einzelnen translate
Aufruf gemacht:
matrices.translate(0.5, 1, 0.5);
Somit ist die Verschiebung erledigt, Drehung und Skalierung bleiben.
Standardmäßig wird der Text auf der XY-Ebene gezeichnet, also müssen wir ihn um 90 Grad um die X-Achse drehen, damit er auf der XZ-Ebene nach oben zeigt:
Der MatrixStack
hat keine rotate
Methode, stattdessen müssen wir multiply
und RotationAxis.POSITIVE_X
verwenden:
matrices.multiply(RotationAxis.POSITIVE_X.rotationDegrees(90));
Jetzt ist der Text an der korrekten Position, aber ist zu groß. Der BlockEntityRenderer
ordnet den ganzen Block zu einem [-0.5, 0.5]
Würfel zu, während der TextRenderer
X-Koordinaten von [0, 9]
verwendet. Somit müssen wir es um den Faktor 18 herunter skalieren:
matrices.scale(1/18f, 1/18f, 1/18f);
Jetzt sieht die ganze Transformation wie folgt aus:
matrices.push();
matrices.translate(0.5, 1, 0.5);
matrices.multiply(RotationAxis.POSITIVE_X.rotationDegrees(90));
matrices.scale(1/18f, 1/18f, 1/18f);
Wie bereits früher erwähnt, hat der an den Konstruktor unseres Renderers übergebene Context
einen TextRenderer
, welchen wir für das Zeichnen von Text einsetzen können. Für dieses Beispiel werden wir ihn in einem Feld speichern.
Der TextRenderer
hat Methoden um Text zu messen (getWidth
), welche für das Zentrieren nützlich ist, und um ihn zu zeichnen (draw
).
String text = entity.getClicks() + "";
float width = textRenderer.getWidth(text);
// draw the text. params:
// text, x, y, color, shadow, matrix, vertexConsumers, layerType, backgroundColor, light
textRenderer.draw(
text,
-width/2, -4f,
0xffffff,
false,
matrices.peek().getPositionMatrix(),
vertexConsumers,
TextRenderer.TextLayerType.SEE_THROUGH,
0,
light
);
Die Methode draw
nimmt einige Paramter, aber die Wichtigsten sind:
Text
(oder String
);x
und y
Koordinaten;color
Wert;Matrix4f
, die beschreibt, wie er transformiert werden soll (um eine aus einem MatrixStack
zu erhalten, können wir .peek().getPositionMatrix()
verwenden, um die Matrix4f
für den obersten Eintrag zu erhalten).Und nach dieser ganzen Arbeit, ist hier das Ergebnis: