Ajouter plusieurs textures à un bloc (avec ou sans metadata)
-
Ce tutoriel est également disponible en vidéo.
Sommaire
Introduction
Dans ce tutoriel nous allons voir comment créer un bloc avec plusieurs textures, comme la tnt, l’herbe, etc. Les blocs directionnels ne seront pas traités dans ce tutoriel.
La façon dont minecraft gère les faces des blocs est plutôt simple. En fonction de la face, le nombre “side” sera différent.
- 0 pour le bas
- 1 pour le haut
- 2 pour le nord
- 3 pour le sud
- 4 pour l’est
- 5 pour l’ouest
Petit schéma récapitulatif :
Pré-requis
Code
Sur un bloc simple :
La première chose à faire est de supprimer la fonction .setTextureName au niveau de l’initialisation de votre bloc dans la classe principale. Elle ne servira plus.
Maintenant changement de classe, tout le reste se fera dans la classe de votre bloc.Nous allons commencer par déclarer deux objets du type IIcon, dans mon cas je vais les nommer “bottom” et “top” (bas et haut) :
private IIcon top, bottom
(cette ligne se place avant le constructeur).
Ensuite je vais ajouter en-dessous du constructeur la méthode pour enregistrer les icônes :public void registerBlockIcons(IIconRegister iiconRegister) { this.blockIcon = iiconRegister.registerIcon(ModTutoriel.MODID + ":red"); this.top = iiconRegister.registerIcon(ModTutoriel.MODID + ":yellow"); this.bottom = iiconRegister.registerIcon(ModTutoriel.MODID + ":orange"); }
La méthode registerBlockIcons sert donc à enregistrer les icônes. this.blockIcon est l’icône par défaut d’un bloc, il n’a pas besoin d’être déclaré puisqu’il l’est déjà dans la classe mère Block.java.
ModTutoriel.MODID + “:red” correspond à “modtutoriel:red” puis que le String MODID de ma classe principale vaut “modtutoriel”. Ceci :public void registerBlockIcons(IIconRegister iiconRegister) { this.blockIcon = iiconRegister.registerIcon("modtutoriel:red"); this.top = iiconRegister.registerIcon("modtutoriel:yellow"); this.bottom = iiconRegister.registerIcon("modtutoriel:orange"); }
Revient au même.
Le système des textures est le même qu’avec la fonction .setTextureName, il faut mettre modid:nom_de_la_texture et la texture devra être :
<dossier de forge>/src/main/resources/assets/modid/textures/blocks/nom_de_la_texture.pngEnsuite il faut ajouter la fonction getIcon :
public IIcon getIcon(int side, int metadata) { return this.blockIcon; }
Pour l’instant dans tout les cas, il utilisera la texture blockIcon. Nous allons donc ajouter des conditions pour changer ça. Comme dit l’introduction, 0 correspond au dessous, et 1 au dessus. Donc ma fonction doit ressembler à ça :
public IIcon getIcon(int side, int metadata) { if(side == 0) { return this.bottom; } else if(side == 1) { return this.top; } return this.blockIcon; }
Et voila !
Les accolades n’étant pas obligatoire lorsqu’il y a qu’une seule instruction, ceci fonctionne aussi :public IIcon getIcon(int side, int metadata) { if(side == 0) return this.bottom; else if(side == 1) return this.top; return this.blockIcon; }
Sur un bloc avec métadata :
Tout se fera dans la classe du bloc. Allez donc dans cette classe et commencez par retirer tout ce qui concerne les textures (le tableau d’IIcon, le contenu dans la fonction registerBlockIcons et le contenu de la fonction getIcon). Nous allons voir deux méthodes. Dans la première méthode, nous allons appliquer une seule texture à un bloc, deux textures à deux autres blocs et trois textures aux derniers blocs (il y a quatre blocs en metadata dans cette exemple). Dans la deuxième méthode nous allons utiliser des tableaux à deux dimensions pour appliquer trois textures aux quatre blocs.
Première méthode :
Nous allons devoir déclarer chaque icône une par une. Donc plus vous allez avoir de textures différentes, plus la ligne va être longue :
public IIcon block1, block1Top, block2, block3, block3Top, block3Bottom, block4, block4TopBottom;
Dans cette exemple, le premier bloc aura donc deux textures, une en haut, et une autre pour tous les autres côtés, le second bloc n’aura qu’une seule texture, le troisième bloc aura une texture pour le bas, une autre pour le haut, et une dernière pour les quatre côtés, et pour finir le quatrième bloc aura une texture pour en haut et en bas, et une autre pour les quatre côtés.
Maintenant il faut enregistrer toutes ces icônes. Voila à quoi ressemble la fonction registerBlockIcons après modification :
public void registerBlockIcons(IIconRegister iconRegister) { this.block1 = iconRegister.registerIcon(ModTutoriel.MODID + ":block1"); this.block1Top = iconRegister.registerIcon(ModTutoriel.MODID + ":red"); this.block2 = iconRegister.registerIcon(ModTutoriel.MODID + ":yellow"); this.block3 = iconRegister.registerIcon(ModTutoriel.MODID + ":orange"); this.block3Top = iconRegister.registerIcon(ModTutoriel.MODID + ":green"); this.block3Bottom = iconRegister.registerIcon(ModTutoriel.MODID + ":dark_green"); this.block4 = iconRegister.registerIcon(ModTutoriel.MODID + ":dark_blue"); this.block3TopBottom = iconRegister.registerIcon(ModTutoriel.MODID + ":blue"); }
Je ne vais pas réexpliquer la fonction à nouveau, vous devriez la connaître maintenant, si ce n’est pas le cas remontez juste au dessus dans le cas du bloc sans metadata, elle y est expliquée.
Ensuite il faut compléter la fonction getIcon, il faut donc mettre des conditions en fonction du side et du metadata. Il est aussi possible de passer un switch, je vais montrer les deux et expliquer en commentaire :
public IIcon getIcon(int side, int metadata) { switch(metadata) { case 0: // Metadata 0 donc bloc 1. if(side == 1) // Si le côté est 1, donc en haut, { return this.block1Top; // on utilise la texture du haut. } return this.block1; // Dans tous les autres cas, on utilise la texture bloc1. case 1: // Metadata 1, donc bloc 2. return this.block2; // On utilise la texture bloc2 dans tous les cas. case 2: // Metadata 2, donc bloc 3. if(side == 0) // Si le côté est 0, donc en bas { return this.block3Bottom; // on utilise la texture du bas. } else if(side == 1) // Sinon, si le côté est 1, donc en haut { return this.block3Top; // on utilise la texture du haut. } return this.block3; // Sinon pour les 4 autres côtés on utilise la texture bloc3 case 3: // Metadata 3, donc bloc 4. if(side == 0 || side == 1) // Si le côté est 0 ou 1, donc en bas ou en haut, { return this.block4TopBottom; // on utilise la texture bloc4TopBottom pour le haut et le bas. } return this.block4; // Sinon on utilise la texture bloc4. default: // Pour tous les autres metadata, return this.block1; // on met la texture bloc1, mais vous pouvez mettre une autre texture, de toute façon ce cas ne devrait jamais arriver en temps normal. }
Deuxième méthode :
Commencez par déclarer un tableau à deux dimensions :
private IIcon[][] icons = new IIcon[subBlock.length][3];
La première dimension est aussi longue que mon nombre de métadata. La deuxième est aussi longue que le nombre de textures différentes par bloc. Comme dit plus haut, je vais mettre 3 textures différentes (bas, haut, et côtés) dans cet exemple, si vous voulez mettre 2 textures différentes, il faut mettre 2, sinon vous en voulez 4, il faut mettre 4, etc …
Ensuite nous allons enregistrer toutes les icônes du tableau :
public void registerBlockIcons(IIconRegister iconRegister) { for(int i = 0; i < subBlock.length; i++) { for(int j = 0; j < 3; j++) { this.icons[i][j] = iconRegister.registerIcon(ModTutoriel.MODID + ":" + subBlock[i] + "_" + j); } } }
Il faut utiliser deux boucles for. Les icônes vont prendre le nom suivant :
modtutoriel:block1_0 (la texture sera : forge/src/main/resources/assets/modtutoriel/textures/blocks/block1_0.png)
modtutoriel:block1_1 (la texture sera : forge/src/main/resources/assets/modtutoriel/textures/blocks/block1_1.png)
modtutoriel:block1_2 (la texture sera : forge/src/main/resources/assets/modtutoriel/textures/blocks/block1_2.png)
modtutoriel:block2_0 (la texture sera : forge/src/main/resources/assets/modtutoriel/textures/blocks/block2_0.png)
etc …Pour finir, il faut compléter la fonction getIcon :
public IIcon getIcon(int side, int metadata) { if(side > 2) { side = 2; } return metadata >= 0 && metadata < subBlock.length ? this.icons[metadata][side] : this.icons[0][0]; }
Si le side est supérieur à 2, dans ce cas il vaut 2, donc dans le cas où le côté sera 3, 4 ou 5, il prendre la valeur 2, et donc la même texture que le côté 2.
La condition ternaire à la fin sert à éviter un OutOfBoundException, comme dans le tutoriel sur les blocs avec metadata.Dans le cas où on aura voulu appliquer la même texture en haut et en bas, puis une autres textures sur le reste du bloc, la deuxième dimension du tableau n’aurait dû faire que 2, dans la fonction registerBlockIcons il aurait fallut mettre 2 à la place de 3 dans la deuxième boucle for, et la fonction getIcon aurait ressemblé à ça :
public IIcon getIcon(int side, int metadata) { if(side == 0 || side == 1) // le side est égale à 0 ou 1 { return metadata >= 0 && metadata < subBlock.length ? this.icons[metadata][0] /** on utilise l'icône 0 **/ : this.icons[0][0]; } return metadata >= 0 && metadata < subBlock.length ? this.icons[metadata][1] /** sinon on utilise l'icône 1 **/ : this.icons[0][0]; }
Bonus
J’ai vu pas mal de demande pour faire un bloc invisible au joueur en survie mais visible par ceux en créative. Comme cela entre dans les blocs multi-texture, je vais montrer ici comment le faire. Vous avez besoin de deux icônes, une pour la texture visible, et une pour la texture invisible. Pour créer une texture invisible, il suffit d’ajouter une couche alpha à votre texture et de transformer le blanc en alpha (je montre comment le faire avec gimp à 50 minutes et 30 secondes de la vidéo).
Déclarez donc l’icône pour la texture invisible :
private IIcon crea;
Puis enregistrez vos deux icônes :
public void registerBlockIcons(IIconRegister iiconRegister) { this.blockIcon = iiconRegister.registerIcon(ModTutoriel.MODID + ":inv"); this.crea = iiconRegister.registerIcon(ModTutoriel.MODID + ":yellow"); }
Et ensuite, voici la fonction getIcon :
@SideOnly(Side.CLIENT) // Pour être sur que la fonction n'est pas lu en serveur car on fait appelle à FMLClientHandler public IIcon getIcon(int side, int metadata) { if(FMLClientHandler.instance().getClientPlayerEntity().capabilities.isCreativeMode) // Vérifie que le joueur est en créatif { return this.crea; } return this.blockIcon; }
On pourrait très bien passer par
FMLClientHandler.instance().getWorldClient().provider.dimensionId
pour faire changer la texture en fonction de la dimension où même en fonction du joueur avecFMLClientHandler.instance().getClientPlayerEntity().getCommandSenderName()
!Comme une des textures est transparente, ajoutez aussi ces trois fonctions, sinon le bloc va avoir un effet vision des cavernes.
@SideOnly(Side.CLIENT) public int getRenderBlockPass() { return 1; } public boolean renderAsNormalBlock() { return false; } public boolean isOpaqueCube() { return false; }
Et voila ! Pour ceux qui en auraient besoin, voici un aperçu de la classe après modification.
Résultat
Voir le commit sur github
Le commit sur github montre clairement où ont été placés les fichiers, ainsi que ce qui a été ajouté et retiré dans le fichier.En vidéo
https://www.youtube.com/watch?v=ZhFvDHVrFKI
Crédits
Rédaction :
Correction :
Ce tutoriel de Minecraft Forge France est mis à disposition selon les termes de la licence Creative Commons Attribution - Pas d’Utilisation Commerciale - Partage dans les Mêmes Conditions 4.0 International -
j’ai un petit problème avec mes textures quand je lance le jeu, il va chercher le .png dans minecraft:textures/blocks/MISSING_ICON_BLOCK_165_crafter.png! j’ai fait les même code présent dans le tuto pour un block simple! j’ai essayer plusieurs manip mais sa ne veut pas changer
-
Envoie tes codes.
-
code class principal
package fr.dayvrespect.common; import net.minecraft.block.Block; import net.minecraft.block.material.Material; import net.minecraft.creativetab.CreativeTabs; import cpw.mods.fml.common.Mod; import cpw.mods.fml.common.Mod.EventHandler; import cpw.mods.fml.common.Mod.Instance; import cpw.mods.fml.common.SidedProxy; import cpw.mods.fml.common.event.FMLInitializationEvent; import cpw.mods.fml.common.event.FMLPostInitializationEvent; import cpw.mods.fml.common.event.FMLPreInitializationEvent; import cpw.mods.fml.common.registry.GameRegistry; import fr.dayvrespect.proxy.CommonProxy; @Mod(modid = ModCrafter.MODID, name = "Mod Crafter", version = "1.0.0") public class ModCrafter { public static final String MODID = "modcrafter"; @Instance(MODID) public static ModCrafter instance; @SidedProxy(clientSide = "fr.dayvrespect.proxy.ClientProxy", serverSide = "fr.dayvrespect.proxy.CommonProxy") public static CommonProxy proxy; public static Block blockCraft; @EventHandler public void preInit(FMLPreInitializationEvent event) { blockCraft = new BlockCraft().setBlockName("crafter").setCreativeTab(CreativeTabs.tabMaterials); GameRegistry.registerBlock(blockCraft, "block_craft"); } @EventHandler public void init(FMLInitializationEvent event) { proxy.registerRender(); } @EventHandler public void postInit(FMLPostInitializationEvent event) { } }
code class block
package fr.dayvrespect.common; import net.minecraft.block.Block; import net.minecraft.block.material.Material; import net.minecraft.client.renderer.texture.IIconRegister; import net.minecraft.entity.EntityLivingBase; import net.minecraft.item.ItemStack; import net.minecraft.util.IIcon; import net.minecraft.util.MathHelper; import net.minecraft.world.World; public class BlockCraft extends Block { public IIcon top, bottom, front; protected BlockCraft() { super(Material.wood); } private void registerIcon(IIconRegister iiconRegister) { this.blockIcon = iiconRegister.registerIcon(ModCrafter.MODID + ":log"); this.front = iiconRegister.registerIcon(ModCrafter.MODID + ":log_front"); this.top = iiconRegister.registerIcon(ModCrafter.MODID + ":log_top"); this.bottom = iiconRegister.registerIcon(ModCrafter.MODID + ":log_bottom"); } public IIcon getIcon(int side, int metadata) { return side == 1 ? this.top : (side == 0 ? this.bottom : (metadata == 2 && side == 2 ? this.front : (metadata == 3 && side == 5 ? this.front : (metadata == 0 && side == 3 ? this.front : (metadata == 1 && side == 4 ? this.front : this.blockIcon))))); } // ancien get Icon // public IIcon getIcon(int side, int metadata) // { // if(side == 0) // { // return this.bottom; // } // if(side == 1) // { // return this.top; // } // else if(side == 3) // { // return this.front; // } // return this.blockIcon; // } public void onBlockPlacedBy(World world, int x, int y, int z, EntityLivingBase living, ItemStack stack) { int direction = MathHelper.floor_double((double)(living.rotationYaw * 4.0F / 360.0F) + 2.5D) & 3; world.setBlockMetadataWithNotify(x, y, z, direction, 2); } }
-
Dommage, le problème se joue à un s prêt :
private void registerBlockIcon(IIconRegister iiconRegister)
devrait être :
public void registerBlockIcons(IIconRegister iiconRegister)
(je sais pas pourquoi tu as mit private, normalement ça devrait être public). -
merci j’arrête pas de modifier pour savoir se qui déconné sur le code XD pour un S sniff et pour le private il ma semblé l’avoir vu quelque part XD!
serait t’il possible quand tu aura un moment de dispo de m’accorder une discutions sur ts3 ou skype pour des info plus approfondis dans le cadre du mod que je souhaiterais créer et me dire si ce que je pense est possible ou non par rapport a ton expérience !en tous cas tu gere coté code je l’aurais jamais trouver je pense, merci.
-
De rien ^^
Passe sur le ts de mff, j’y suis presque tout le temps. -
Bonjour
je viens de faire le même code du block sur mon nouveaux furance mais il arrête pas de chercher la texture MISSING_ICON_BLOCK_166_furnace.png
j’ai chercher d’ou peux venir l’erreur mais je ne voit pas
Merci de votre aide
-
Ça c’est signe d’un problème avec la fonction
registerBlockIcons
-
@robin4002 voici la classe de mon furnace
import com.mod.Factory.Factory; import com.mod.Factory.Reference; import net.minecraft.block.Block; import net.minecraft.block.BlockContainer; import net.minecraft.block.material.Material; import net.minecraft.client.renderer.texture.IIconRegister; import net.minecraft.util.IIcon; public class Machine_Furnace { private IIcon haut, bas, blockIcon; public Machine_Furnace(Material rock) { } public void registerBlockIcons(IIconRegister iiconRegister) { this.blockIcon = iiconRegister.registerIcon(Reference.MOD_ID + ":machines/Machine_Furnace/furnace_front_off"); this.haut = iiconRegister.registerIcon(Reference.MOD_ID + ":machines/Machine_Furnace/furnace_top"); this.bas = iiconRegister.registerIcon(Reference.MOD_ID + ":machines/Machine_Furnace/furnace_top"); } public IIcon getIcon(int side, int metadata) { if(side == 0) { return this.bas; } else if(side == 1) { return this.haut; } return this.blockIcon; } }
-
Ta classe n’extends pas Block, ce n’est pas normal
-
@robin4002 Super merci c’etait bien sa le probleme, j’ai oublier de le remettre comme j’ai refait la classe j’ai oublier de l’extends
Et autre question qui na rien a voir
est-ce que il a un tuto pour creer un four en 1.7.10 ? -
Il ne me semble pas, le seul tutoriel four du forum c’est pour la 1.8.9 ou plus récent.
-
et vraiment c’est juste 2-3 choses qui changent
1 la tile sur le tuto on n’enumere pas lehasTileEntity
il n’existe pas en 1.8 et plus
2 tout les x y z ont été remplacé par les blocks pos en 1.8 +
le reste j’ai pas regardé -
-
-