Introduction
Bonjour tout le monde ! Ne vous vous êtes jamais demandé comment, par exemple, les escaliers était codé ? Et non, pas de modèle, simplement un rendu.
Qu’est-ce qu’un rendu ISBRH ?
ISBRH signifie ISimpleBlockRenderingHandler, c’est l’interface que nous allons utiliser pour notre rendu dans l’inventaire et dans le monde
Un rendu simple, comme son nom l’indique, est comme un rendu complexe avec modèle, mais en plus simple (pas de transformation du bloc en entité pour l’avoir). Nous allons voir dans ce tutoriel comment l’utiliser.
Les avantages du ISBRH :
- Il n’utilise pas de TileEntity, il est donc plus léger.
- Il n’est que chargé une fois, il l’est pas mit à jour à chaque tick contrairement au TESR, c’est une autre chose qui le rend plus léger
- Il y a juste la classe de votre rendu, celle de votre bloc, et quelques codes dans le proxy, il est donc aussi plus léger niveau code.
Les désavantages du ISBRH :
- Il ne permet de rendre un modèle techne, si vous le faite ça va crasher (sur le monde uniquement, en main c’est possible).
- Compliqué à utiliser au début, mais on s’y habitue vite, et avec le debug ça va tout seul.
Pre-requis
Appliquer le rendu au bloc
A. Rencontre des fonctions indispensables
Normalement, vous devriez savoir comment faire un bloc simple, donc nous allons directement commencer dans la classe de votre bloc.
Il faudra ajouter ces fonctions :
public boolean renderAsNormalBlock()
{
return false;
}
Retourne faux si le bloc n’est pas normal sachant qu’un bloc normal est un cube.
public boolean isOpaqueCube()
{
return false;
}
Retourne faux si le bloc est transparent sachant que opaque veux dire que le bloc prend toutes la surface et qu’il a une texture non-transparente.
@SideOnly(Side.CLIENT)
public int getRenderType()
{
return TutoClientProxy.renderTableId;
}
Retourne un int associant l’id de notre rendu au bloc.
Vous remarquerez cependant une erreur à la déclaration de “renderTableId”, c’est tout simplement parce que nous l’avons pas encore déclaré
Cette fonction charge seulement côté client car les rendus se font seulement côté client.
@SideOnly(Side.CLIENT)
public boolean shouldSideBeRendered(IBlockAccess blockAccess, int x, int y, int z, int side)
{
return true;
}
Et enfin cette fonction !
Elle sert à… afficher les côtés du rendu !
B. Nouvelle variable
Maintenant, ajoutons un nouvelle variable dans le ClientProxy :
public static int renderTableId;
Cette variable correspondra à notre rendu.
Instancions-là dans la fonction “registerRender” ou comme vous l’avez appelé :
renderTableId = RenderingRegistry.getNextAvailableRenderId();
getNextAvailableRenderId() est une fonction qui retourne le prochain id libre des rendus.
On a plus qu’à enregistrer la classe de notre rendu :
RenderingRegistry.registerBlockHandler(renderTableId, new RenderTable());
renderTableId correspond à la variable créé précédemment et “new RenderTable()” à la classe que nous allons créer tout de suite !
Vous pouvez aussi utiliser :
RenderingRegistry.registerBlockHandler(new RenderTable());
Dans ce cas l’id sera prit dans la fonction getRenderId() de la classe.
#rendu-dans-le-monde(Rendu dans le monde)
Le rendu dans le monde ? C’est le rendu qui se “rend” seulement dans le World et non dans l’inventaire/la main.
Voilà à quoi devrait ressembler votre classe RenderCustomBlocks :
public class RenderTable implements ISimpleBlockRenderingHandler
{
@Override
public void renderInventoryBlock(Block block, int metadata, int modelID, RenderBlocks renderer)
{
}
@Override
public boolean renderWorldBlock(IBlockAccess world, int x, int y, int z, Block block, int modelId, RenderBlocks renderer)
{
return true;
}
@Override
public boolean shouldRender3DInInventory()
{
return false;
}
@Override
public int getRenderId()
{
return 0;
}
}
Remplace le 0 par l’id de votre rendu :
@Override
public int getRenderId()
{
return TutoClientProxy.renderTableId;
}
(très important si vous avez utilisez la deuxième méthode d’enregistrement, sinon ça n’a pas d’importance).
La fonction renderWorldBlock servira à modeler vous bloc en faisant de petits morceaux :
renderer.setRenderBounds(minX, minY, minZ, maxX, maxY, maxZ);
minX : ce float déclare le minimum en X.
minY : celui-ci déclare le minimum en Y.
minZ : celui-là déclare le minimum en Z.
maxX : celui-ci déclare le maximumen X.
maxY : celui-là déclare le maximumen Y.
maxZ : celui-ci déclare le maximum en Z.
Exemple pour faire un cube normal ajoutez dans cette fonction avant le return :
renderer.setRenderBounds(0F, 0F, 0F, 1F, 1F, 1F);
Pour sauvegarder le “morceau”, la sauvegarde ce fera comme ça à chaque déclaration de nouveaux morceaux :
renderer.renderStandardBlock(block, x, y, z);
Voici un petite exemple de table :
renderer.setRenderBounds(0.2F, 0.0F, 0.2F, 0.8F, 0.1F, 0.8F);
renderer.renderStandardBlock(block, x, y, z);
renderer.setRenderBounds(0.45F, 0.1F, 0.45F, 0.55F, 0.8F, 0.55F);
renderer.renderStandardBlock(block, x, y, z);
renderer.setRenderBounds(0.0F, 0.8F, 0.0F, 1F, 0.9F, 1F);
renderer.renderStandardBlock(block, x, y, z);
Voilà !
Il est également possible de mettre tout vos rendus dans la même classe, et d’utiliser des conditions if(modelId == TutoClientProxy.renderTableId) mais je vous conseil de créer une classe par rendu pour une question d’organisation. (surtout quand on a des rendus très complet de plusieurs lignes).
#rendu-dans-l-inventaire(Rendu dans l’inventaire)
Voici la dernière partie de ce tuto, le rendu dans l’inventaire et dans la main (donc le rendu en temps que ItemStack).
Comme vous avez pu le voir dans le screen précédent, le rendu de la table dans l’inventaire n’y est pas.
Nous allons régler ce souci. Le modelage des morceaux se fait de la même façon mais :
renderer.renderStandardBlock(block, x, y, z);
devient :
:::
GL11.glTranslatef(-0.5F, -0.5F, -0.5F);
tessellator.startDrawingQuads();
tessellator.setNormal(0.0F, -1F, 0.0F);
renderer.renderFaceYNeg(block, 0.0D, 0.0D, 0.0D, block.getIcon(0, metadata));
tessellator.draw();
tessellator.startDrawingQuads();
tessellator.setNormal(0.0F, 1.0F, 0.0F);
renderer.renderFaceYPos(block, 0.0D, 0.0D, 0.0D, block.getIcon(1, metadata));
tessellator.draw();
tessellator.startDrawingQuads();
tessellator.setNormal(0.0F, 0.0F, -1F);
renderer.renderFaceZNeg(block, 0.0D, 0.0D, 0.0D, block.getIcon(2, metadata));
tessellator.draw();
tessellator.startDrawingQuads();
tessellator.setNormal(0.0F, 0.0F, 1.0F);
renderer.renderFaceZPos(block, 0.0D, 0.0D, 0.0D, block.getIcon(3, metadata));
tessellator.draw();
tessellator.startDrawingQuads();
tessellator.setNormal(-1F, 0.0F, 0.0F);
renderer.renderFaceXNeg(block, 0.0D, 0.0D, 0.0D, block.getIcon(4, metadata));
tessellator.draw();
tessellator.startDrawingQuads();
tessellator.setNormal(1.0F, 0.0F, 0.0F);
renderer.renderFaceXPos(block, 0.0D, 0.0D, 0.0D, block.getIcon(5, metadata));
tessellator.draw();
GL11.glTranslatef(0.5F, 0.5F, 0.5F);
Vous ne vous attendiez pas à ça non ? xD
:::
Voilà !
Pour ne pas répéter plusieurs fois ce même pavé, je vous conseille de créer une fonction renderInInventory :
private void renderInInventory(Tessellator tessellator, RenderBlocks renderer, Block block, int metadata)
{
GL11.glTranslatef(-0.5F, -0.5F, -0.5F);
tessellator.startDrawingQuads();
tessellator.setNormal(0.0F, -1F, 0.0F);
renderer.renderFaceYNeg(block, 0.0D, 0.0D, 0.0D, block.getIcon(0, metadata));
tessellator.draw();
tessellator.startDrawingQuads();
tessellator.setNormal(0.0F, 1.0F, 0.0F);
renderer.renderFaceYPos(block, 0.0D, 0.0D, 0.0D, block.getIcon(1, metadata));
tessellator.draw();
tessellator.startDrawingQuads();
tessellator.setNormal(0.0F, 0.0F, -1F);
renderer.renderFaceZNeg(block, 0.0D, 0.0D, 0.0D, block.getIcon(2, metadata));
tessellator.draw();
tessellator.startDrawingQuads();
tessellator.setNormal(0.0F, 0.0F, 1.0F);
renderer.renderFaceZPos(block, 0.0D, 0.0D, 0.0D, block.getIcon(3, metadata));
tessellator.draw();
tessellator.startDrawingQuads();
tessellator.setNormal(-1F, 0.0F, 0.0F);
renderer.renderFaceXNeg(block, 0.0D, 0.0D, 0.0D, block.getIcon(4, metadata));
tessellator.draw();
tessellator.startDrawingQuads();
tessellator.setNormal(1.0F, 0.0F, 0.0F);
renderer.renderFaceXPos(block, 0.0D, 0.0D, 0.0D, block.getIcon(5, metadata));
tessellator.draw();
GL11.glTranslatef(0.5F, 0.5F, 0.5F);
}
Ce qui nous donne donc :
@Override
public void renderInventoryBlock(Block block, int metadata, int modelID, RenderBlocks renderer)
{
Tessellator tessellator = Tessellator.instance;
renderer.setRenderBounds(0.2F, 0.0F, 0.2F, 0.8F, 0.1F, 0.8F);
this.renderInInventory(tessellator, renderer, block, metadata);
renderer.setRenderBounds(0.45F, 0.1F, 0.45F, 0.55F, 0.8F, 0.55F);
this.renderInInventory(tessellator, renderer, block, metadata);
renderer.setRenderBounds(0.0F, 0.8F, 0.0F, 1F, 0.9F, 1F);
this.renderInInventory(tessellator, renderer, block, metadata);
}
Une dernière chose, passe en vrai le rendu en 3D dans l’inventaire :
@Override
public boolean shouldRender3DInInventory()
{
return true;
}
Un dernier screen :
Et voilààààààà !!!
Tutoriel terminé !
J’espère qu’il vous aura plus et à bientôt !!!
Questions/Réponses
Rien pour l’instant !