Direction de bloc


  • Administrateurs

    Vous êtes actuellement capable de créer des blocs multi-textures, mais vous vous êtes surement rendu compte que ces derniers était toujours dans le même sens et ne se pose pas en rapport de la direction du joueur.

    Nous allons voir dans ce tutoriel comment faire ça.

    Sur un bloc basique

    Pour un bloc basique, nous allons utiliser le même principe que la citrouille. En fonction du sens dans lequel vous allez placer le bloc, le metadata va être différent. Nous allons donc gérer la direction avec les metadata, il est donc impossible d'utiliser cette méthode sur des blocs à metadata !
    Rendez-vous dans la classe du bloc. Pour commencer, je vais ajouter un nouveau icône pour devant :

        private Icon icontop, iconbottom;
    

    devient :

        private Icon icontop, iconbottom, iconfront;
    

    Ensuite l'enregistreur d'icône :

        public void registerIcons(IconRegister iconRegister)
        {
            blockIcon = iconRegister.registerIcon("modtutoriel:BlockTutorial");
            iconfront = iconRegister.registerIcon("modtutoriel:BlockTutorial_Front");
            icontop = iconRegister.registerIcon("modtutoriel:BlockTutorial_Top");
            iconbottom = iconRegister.registerIcon("modtutoriel:BlockTutorial_Bottom");
        }
    

    Ajoutez maintenant cette fonction :

        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);
        }
    

    C'est le même code que pour la citrouille, l'int direction va soit prendre la valeur 0, 1, 2 ou 3 en fonction de la direction de l'entité qui à posé le bloc.
    Ensuite, world.setBlockMetadataWithNotify va poser le ce bloc avec un metadata de la valeur de la direction. (Le dernier 2 est un flag qui gère une action, le 2 sert à ne rien déclencher, car le fait d'ajouter un nouveau bloc cause déjà la mise à jour de l'affichage du client. Les setBlock et leurs flags seront expliqués plus en détail dans un autre tutoriel).

    Maintenant il nous reste plus qu'à changer le getIcon en fonction du metadata du bloc :

        @SideOnly(Side.CLIENT)
        public Icon getIcon(int side, int metadata)
        {
            return side == 1 ? this.icontop : (side == 0 ? this.iconbottom : (metadata == 2 && side == 2 ? this.iconfront : (metadata == 3 && side == 5 ? this.iconfront : (metadata == 0 && side == 3 ? this.iconfront : (metadata == 1 && side == 4 ? this.iconfront : this.blockIcon)))));
        }
    

    C'est juste une longue condition ternaire, rien de méchant 😛 Si vous avez du mal avec, n'hésitez pas à la passer en condition if else, c'est plus simple pour customiser les textures 🙂

    Voir sur github

    Sur un bloc avec metadata

    1. La classe du bloc

    Si vous avez essayé le code juste au dessus sur un bloc avec metadata, vous vous êtes surement rendu compte que vous placez un bloc différent en fonction de votre direction. Et c'est normal, car la première fonction utilise les metadata pour la direction. Comme nous utilisons déjà les metadata pour les différents blocs, il faut utiliser autre chose qui peut stocker des données. Nous allons donc utiliser les TileEntity ! Dans mon cas, je vais uniquement le faire mon pour bloc de metadata 2, mais vous pouvez aussi le faire pour les autres.
    Avant tout, comme j'ajoute un TileEntity en plus, (je ne l'avais que fait pour le metadata 0) :

        @Override
        public TileEntity createTileEntity(World world, int metadata)
        {
            if(metadata == 0)
                return new TileEntityTutorial();
            else if(metadata == 2)
                return new TileEntityTutorial2();
            else
                return null;
        }
    

    Et :

        public boolean hasTileEntity(int metadata)
        {
            if(metadata == 0 || metadata == 2)
                return true;
            else
              return false;
        }
    

    Maintenant la fonction pour le placement du bloc :

        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;
            TileEntity te = world.getBlockTileEntity(x, y, z);
            if(te != null && stack.getItemDamage() == 2 && te instanceof TileEntityTutorial2)
            {
                ((TileEntityTutorial2)te).setDirection((byte)direction);
                world.markBlockForUpdate(x, y, z);
            }
        }
    

    Donc comme avant, le code pour la direction de l'entity, puis j'instancie le TileEntity, ensuite je vérifie si : le TileEntity n'est pas null (donc qu'il est bien existant), que le metadata de l'ItemStack que le joueur a en main est 2 (comme je ne le fais que pour le metadata 2) et que le TileEntity est d'instance TileEntityTutorial2 qui correspond à la classe de mon TileEntity
    Si c'est le cas, je cast TileEntityTutorial2 au tileEntity et je vais la fonction setDirection qui est une fonction que je vais créer dans mon TileEntity. Ensuite je mets à jour l'affichage du client.
    D'ailleurs, j'ai aussi casté (je sais pas si ça ce dit, mais la traduction de "cast" est pas mieux) un byte à mon int direction, pour la simple et bonne raison qu'un byte est largement suffisant pour stocké soit 0, 1, 2 ou 3, utiliser un int serait juste surcharger mon TileEntity.

    2. La classe du TileEntity

    Le principe est exactement que pour le système de visiteur, sauf que la on stock juste un byte :

    package tutoriel.common;
    
    import net.minecraft.nbt.NBTTagCompound;
    import net.minecraft.tileentity.TileEntity;
    
    public class TileEntityTutorial2 extends TileEntity
    {
        public byte direction;
    
        public void readFromNBT(NBTTagCompound nbtTag)
        {
            super.readFromNBT(nbtTag);
            direction = nbtTag.getByte("direction");
        }
    
        public void writeToNBT(NBTTagCompound nbtTag)
        {
            super.writeToNBT(nbtTag);
            nbtTag.setByte("direction", direction);
        }
    
        public void setDirection(byte direct)
        {
            direction = direct;
        }
    
        public byte getDirection()
        {
            return direction;
        }
    
        public Packet getDescriptionPacket()
        {
            NBTTagCompound nbttagcompound = new NBTTagCompound();
            this.writeToNBT(nbttagcompound);
            return new Packet132TileEntityData(this.xCoord, this.yCoord, this.zCoord, 4, nbttagcompound);
        }
    
        public void onDataPacket(INetworkManager net, Packet132TileEntityData pkt)
        {
          this.readFromNBT(pkt.data);
        }
    }
    

    Les deux dernières fonctions gèrent les packets, si vous ne les mettez pas vous allez avoir des problèmes de direction après déco/réco

    3. La classe principale

    N'oubliez pas d'enregistrer votre tileEntity dans la partie Init :

        GameRegistry.registerTileEntity(TileEntityTutorial2.class, "TileEntityTutorial2");
    

    4. Finition

    La direction de votre bloc est bien sauvegardez dans le nbttag, mais elle n'est pas prise en compte. Petit problème, getIcon ne prend pas en compte le tileEntity. Nous allons donc utiliser cette méthode :

        @SideOnly(Side.CLIENT)
        public Icon getBlockTexture(IBlockAccess blockaccess, int x, int y, int z, int side)
        {
            if(blockaccess.getBlockMetadata(x, y, z) == 2)
            {
                TileEntity te = blockaccess.getBlockTileEntity(x, y, z);
                byte direction = ((TileEntityTutorial2)te).getDirection();
                return side == 1 ? Icon3[0] : (side == 0 ? Icon3[1] : (direction == 2 && side == 2 ? Icon3[2] : (direction == 3 && side == 5 ? Icon3[2] : (direction == 0 && side == 3 ? Icon3[2] : (direction == 1 && side == 4 ? Icon3[2] : Icon3[3])))));
            }
            else
            {
                return this.getIcon(side, blockaccess.getBlockMetadata(x, y, z));
            }
        }
    

    Donc si le metadata est 2, j'instancie le TileEntity, je le cast pour récupérer la direction, et ensuite se sont à nouveau des conditions comme juste au dessus. Si le metadata n'est pas 2 (donc mes autres blocs sans direction) il return sur le getIcon(side, metadata)
    /!\ Ne touchez pas à getIcon(side, metadata), laissez-le comme il est, si j'enlève le bloc de metadata 2, l'item en main n'aura plus de texture /!\

    Voir sur github



  • Encore un tuto sur les blocs de la pare de robin, sa fait 5 tuto de robin et 1 de MrCupCakeMonster sur les blocs! la section blocs s'enrichie à vue d'œil !
    Sinon super util comme tuto.(comme presque tout les autres 😛 )



  • Je vais m'en servir de celui la ! 🙂



  • Petit problème : L'item en main n'as pas les textures dans le bon sens 😞
    La face est pas affiché, on voit que les côtés 😞


  • Administrateurs

    Avec les metadata ?
    Il faut changer dans le getIcon, mets ça :

    return side == 0 || side == 1 ? Icon3[side] : side == 3 ? Icon3[2] : Icon3[3];
    

    (j'ai fais ça vite fait, j'ai pas testé mais ça devrait être bon)



  • Erreure pour Icon3[side]

    C'est pas un array 😕


  • Administrateurs

    Bloc avec ou sans metadata ?



  • C'est sans, c'est un block de type four


  • Administrateurs

    Normalement c'est bon avec le code que j'ai donné dans le tutoriel, vérifie que le metadata de l'item que tu as en main est bien 0.



  • hum … en étant en 1.5.2, je remplace le "EntityLivingBase" par quoi si-il vous plais ? x).___
    Problème résolut, c'est tout simplement "EntityLiving".



  • Comment fais-t'on avec un rendu techne svp ?



  • Dans la classe du model il y a une méthode appeler setRotationAngle() ou inspire toi des cranes de squelette, tête de zombie, etc…


  • Administrateurs

    Garde juste la fonction pour le placement, ensuite de le TileEntitySpecialRender tu fais un GL11.glRotatef(90F * metadata, 1.0F, 1.0F, 1.0F);



  • @'robin4002':

    Garde juste la fonction pour le placement, ensuite de le TileEntitySpecialRender tu fais un GL11.glRotatef(90F * metadata, 1.0F, 1.0F, 1.0F);

    Donc il faut que je fasse une metadata pour chaque position, c'est bien sa ?


  • Administrateurs

    Oui, la fonction que je t'ai donné le fait déjà. La direction des citrouilles, les fours, les coffres et de nombreux autres blocs de minecraft sont basé sous les metadatas



  • Je suis dsl mais je ne vois pas ou je dois mettre GL11.glRotatef(90F * metadata, 1.0F, 1.0F, 1.0F);
    Pourriez vous m'indiquer l'endroit exacte stp ?



  • Dans le rendu de tileentity

    renderTileEntityAtTonBlock(TaTileEntity tileentity, double x, double y, double z, float scale)
    

    en dessous de

    GL11.glRotatef(180F, 0.0F, 0.0F, 1.0F);
    

    tu mets:

    GL11.glRotatef(90F * tileentity.getBlockMetadata(), 0.0F, 1.0F, 0.0F);
    

    Si jamais la rotation n'est pas correcte essaie de déplacer le 1.0F sur un des autres 0.0F.



  • Sa marche, merci beaucoup !



  • Bonjour,
    J'ai fait un rendue avec tech, donc avec un TileEntity mais pas moyen de le faire tourner pourtant j'ai bien prit les codes de la deuxièmes parties, je suit sur forge 871 sa change un truc ?
    Merci



  • Dans la classe de ton bloc, tu mets ce code :

    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);
    }
    

    Et ensuite :
    @'kevin_68':

    Dans le rendu de tileentity

    renderTileEntityAtTonBlock(TaTileEntity tileentity, double x, double y, double z, float scale)
    

    en dessous de

    GL11.glRotatef(180F, 0.0F, 0.0F, 1.0F);
    

    tu mets:

    GL11.glRotatef(90F * tileentity.getBlockMetadata(), 0.0F, 1.0F, 0.0F);
    

    Si jamais la rotation n'est pas correcte essaie de déplacer le 1.0F sur un des autres 0.0F.


Log in to reply