1 juil. 2014, 14:00

youtubeCe 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 :
    schéma face bloc

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.png

Ensuite 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 avec FMLClientHandler.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 :

Creative Commons
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

retourRetour vers le sommaire des tutoriels