1. Le forum de Minecraft-France va définitivement fermer ses portes. Celui-ci restera en lecture seule mais vous ne pourrez plus y apporter de nouveaux topics. Nous vous invitons à nous rejoindre sur le Discord de Minecraft-France qui permet de présenter vos projets, discuter avec la communauté etc.. Merci à tous d'avoir fait vivre ce forum de nombreuses années. Pour nous rejoindre sur Discord, Cliquez ici

[1.4.7] Une plante

Discussion dans 'Tutoriels' créé par robin4002, 1 Mar 2013.

  1. robin4002

    robin4002 Support Technique
    Staff

    Inscrit:
    17 Août 2012
    Messages:
    5 478
    Points:
    229
    Sexe:
    Homme
    Dans ce tutoriel, nous allons voir comment créer une plante. Grâce à l'api de forge, créer une plante est plus simple, mais cela reste long et complexe.

    Prérequis:
    - Une classe principale
    - Savoir faire un bloc simple
    - Savoir faire un item simple

    1. Dans la classe principale :

    Il faut déjà déclarer le bloc de la plante, l'item de la graine, ainsi que l'item qui va être droppé par la plante :
    Code (java):
          public static Block CropPlanteTuto;
          public static Item SeedTuto;
          public static Item FruitTuto;
    Maintenant dans la parti @Init :
    Code (java):

            //bloc
            CropPlanteTuto = new CropPlanteTuto(2511,16).setBlockName("CropPlanteTuto").setStepSound(Block.soundGrassFootstep);
            //item
            SeedTuto = new SeedTuto(20163).setIconIndex(13).setItemName("SeedTuto");
            FruitTuto = new FruitTuto(20164, 6, 0.8F, false).setIconIndex(14).setItemName("FruitTuto");
            //registry bloc
            GameRegistry.registerBlock(CropPlanteTuto,"Plant Tuto");
            //language
            LanguageRegistry.addName(CropPlanteTuto, "Plante Tuto");
            LanguageRegistry.addName(SeedTuto, "Graine Tuto");
            LanguageRegistry.addName(FruitTuto, "Fruit Tuto");
            //forge plante API
            MinecraftForge.addGrassSeed(new ItemStack(SeedTuto), 10);
     
    Si vous avez suivi les prérequis, la plupart de ce code devrait vous être commun, à part :
    MinecraftForge.addGrassSeed(new ItemStack(SeedTuto), 10);
    Ce code sert à faire en sorte que lorsque vous détruisez une mauvaise herbe, elle droppera votre graine, comme pour le blé. 10 est la valeur du blé, vous pouvez augmenter pour rendre plus fréquent, ou inversement.

    2. La classe du "crop"


    Code (java):
    package modTutoriel.common;
     
    import java.util.ArrayList;
    import java.util.Random;
     
    import cpw.mods.fml.relauncher.Side;
    import cpw.mods.fml.relauncher.SideOnly;
     
    import net.minecraft.block.Block;
    import net.minecraft.block.BlockCrops;
    import net.minecraft.creativetab.CreativeTabs;
    import net.minecraft.entity.player.EntityPlayer;
    import net.minecraft.item.Item;
    import net.minecraft.item.ItemStack;
    import net.minecraft.world.World;
     
    public class CropPlanteTuto extends BlockCrops
    {
        protected CropPlanteTuto(int par1, int par2)
        {
            super(par1, par2);
            this.blockIndexInTexture = par2;
            this.setTickRandomly(true);
            float var3 = 0.5F;
            this.setBlockBounds(0.5F - var3, 0.0F, 0.5F - var3, 0.5F + var3, 0.25F, 0.5F + var3);
            this.setCreativeTab((CreativeTabs)null);
            this.setHardness(0.0F);
            this.disableStats();
            this.setRequiresSelfNotify();
        }
     
        protected boolean canThisPlantGrowOnThisBlockID(int par3)
        {
            return par3 == Block.tilledField.blockID;
        }
     
        public void updateTick(World par1World, int par2, int par3, int par4, Random par5Random)
        {
            super.updateTick(par1World, par2, par3, par4, par5Random);
     
            if (par1World.getBlockLightValue(par2, par3 + 1, par4) >= 9)
            {
                int i = par1World.getBlockMetadata(par2, par3, par4);
     
                if (i < 7) {
                    float f = getGrowthRate(par1World, par2, par3, par4);
     
                    if (par5Random.nextInt((int) (20F / f) + 1) == 0)
                    {
                        i++;
                        par1World.setBlockMetadataWithNotify(par2, par3, par4, i);
                    }
                }
            }
        }
     
        private float getGrowthRate(World par1World, int par2, int par3, int par4)
        {
            float f = 1.0F;
            int i = par1World.getBlockId(par2, par3, par4 - 1);
            int j = par1World.getBlockId(par2, par3, par4 + 1);
            int k = par1World.getBlockId(par2 - 1, par3, par4);
            int l = par1World.getBlockId(par2 + 1, par3, par4);
            int i1 = par1World.getBlockId(par2 - 1, par3, par4 - 1);
            int j1 = par1World.getBlockId(par2 + 1, par3, par4 - 1);
            int k1 = par1World.getBlockId(par2 + 1, par3, par4 + 1);
            int l1 = par1World.getBlockId(par2 - 1, par3, par4 + 1);
            boolean flag = k == blockID || l == blockID;
            boolean flag1 = i == blockID || j == blockID;
            boolean flag2 = i1 == blockID || j1 == blockID || k1 == blockID
                    || l1 == blockID;
     
            for (int i2 = par2 - 1; i2 <= par2 + 1; i2++) {
                for (int j2 = par4 - 1; j2 <= par4 + 1; j2++) {
                    int k2 = par1World.getBlockId(i2, par3 - 1, j2);
                    float f1 = 0.0F;
     
                    if (k2 == Block.tilledField.blockID)
                    {
                        f1 = 1.0F;
     
                        if (par1World.getBlockMetadata(i2, par3 - 1, j2) > 0)
                        {
                            f1 = 3F;
                        }
                    }
     
                    if (i2 != par2 || j2 != par4)
                    {
                        f1 /= 4F;
                    }
     
                    f += f1;
                }
            }
     
            if (flag2 || flag && flag1)
            {
                f /= 2.0F;
            }
     
            return f;
        }
     
        protected int getCropItem()
        {
            return modTutoriel.FruitTuto.itemID;
        }
     
        protected int getSeedItem()
        {
            return modTutoriel.SeedTuto.itemID;
        }
     
        public int getBlockTextureFromSideAndMetadata(int par1, int par2)
        {
            if (par2 < 0)
            {
                par2 = 7;
            }
     
            return this.blockIndexInTexture + par2;
        }
     
        public void dropBlockAsItemWithChance(World par1World, int par2, int par3, int par4, int par5, float par6, int par7)
        {
            super.dropBlockAsItemWithChance(par1World, par2, par3, par4, par5, par6, 0);
        }
     
        @Override
        public ArrayList<ItemStack> getBlockDropped(World world, int x, int y, int z, int metadata, int fortune)
        {
            ArrayList<ItemStack> ret = super.getBlockDropped(world, x, y, z, metadata, fortune);
     
            if (metadata >= 7)
            {
                for (int n = 0; n < 3 + fortune; n++)
                {
                    if (world.rand.nextInt(15) <= metadata)
                    {
                        ret.add(new ItemStack(this.getSeedItem(), 1, 0));
                    }
                }
            }
     
            return ret;
        }
     
        public int idDropped(int par1, Random par2Random, int par3)
        {
            return par1 == 7 ? this.getCropItem() : this.getSeedItem();
        }
     
        public int quantityDropped(Random par1Random)
        {
            return 1;
        }
     
        public boolean onBlockActivated(World par1World, int par2, int par3, int par4, EntityPlayer par5EntityPlayer, int par6, float par7, float par8, float par9)
        {
            ItemStack itemstack = par5EntityPlayer.inventory.getCurrentItem();
            if (!(itemstack == null) && itemstack.itemID == Item.dyePowder.itemID && itemstack.getItemDamage() == 15)
            {
                par1World.setBlockAndMetadataWithNotify(par2, par3, par4, blockID, 7);
     
                if (!par5EntityPlayer.capabilities.isCreativeMode)
                {
                    itemstack.stackSize--;
                }
     
                if (itemstack.stackSize <= 0)
                {
                    par5EntityPlayer.inventory.setInventorySlotContents(par5EntityPlayer.inventory.currentItem, null);
                }
                return true;
            } else {
                return false;
            }
        }
     
        public int idPicked(World par1World, int par2, int par3, int par4)
        {
            return this.getSeedItem();
        }
     
        @SideOnly(Side.CLIENT)
        public String getTextureFile()
        {
                return TutoClientProxy.BlockTexture;
        }
     
    }
    Code (java):
        protected boolean canThisPlantGrowOnThisBlockID(int par3)
        {
            return par3 == Block.tilledField.blockID;
        }
    Cette fonction sert à définir sur quel bloc votre plante pousse. Dans ce cas, il s'agit de la terre labourée, vous pouvez mettre autre chose.

    Code (java):
        private float getGrowthRate(World par1World, int par2, int par3, int par4)
        {
            float f = 1.0F;
            int i = par1World.getBlockId(par2, par3, par4 - 1);
            int j = par1World.getBlockId(par2, par3, par4 + 1);
            int k = par1World.getBlockId(par2 - 1, par3, par4);
            int l = par1World.getBlockId(par2 + 1, par3, par4);
            int i1 = par1World.getBlockId(par2 - 1, par3, par4 - 1);
            int j1 = par1World.getBlockId(par2 + 1, par3, par4 - 1);
            int k1 = par1World.getBlockId(par2 + 1, par3, par4 + 1);
            int l1 = par1World.getBlockId(par2 - 1, par3, par4 + 1);
            boolean flag = k == blockID || l == blockID;
            boolean flag1 = i == blockID || j == blockID;
            boolean flag2 = i1 == blockID || j1 == blockID || k1 == blockID
                    || l1 == blockID;
     
            for (int i2 = par2 - 1; i2 <= par2 + 1; i2++) {
                for (int j2 = par4 - 1; j2 <= par4 + 1; j2++) {
                    int k2 = par1World.getBlockId(i2, par3 - 1, j2);
                    float f1 = 0.0F;
     
                    if (k2 == Block.tilledField.blockID)
                    {
                        f1 = 1.0F;
     
                        if (par1World.getBlockMetadata(i2, par3 - 1, j2) > 0)
                        {
                            f1 = 3F;
                        }
                    }
     
                    if (i2 != par2 || j2 != par4)
                    {
                        f1 /= 4F;
                    }
     
                    f += f1;
                }
            }
     
            if (flag2 || flag && flag1)
            {
                f /= 2.0F;
            }
     
            return f;
        }
    Dans cette fonction vous pouvez à nouveau voir "Block.tilledField.blockID".
    Si vous avez changé dans l'autre fonction, faites-le aussi ici, sinon la plante ne poussera pas.

    Code (java):
        protected int getCropItem()
        {
            return modTutoriel.FruitTuto.itemID;
        }
     
        protected int getSeedItem()
        {
            return modTutoriel.SeedTuto.itemID;
        }
    Ces deux-là servent à définir à quelle graine et quel item est liée votre plante, par exemple dans le cas du blé, c'est l'item de blé et la graine.

    Code (java):
        public int getBlockTextureFromSideAndMetadata(int par1, int par2)
        {
            if (par2 < 0)
            {
                par2 = 7;
            }
     
            return this.blockIndexInTexture + par2;
        }
    Cette fonction sert à définir la texture par rapport au metadata. Il faut savoir que le nombre de metadata (7 ici) influence le nombre d'étapes de votre plante. Dans ce cas la plante a 8 étape, comme le blé (il faut compter le metadata 0). Si vous changez cette valeur, il faudra la changer dans d'autres fonctions, par exemple dans la fonction suivante :

    Code (java):
        @Override
        public ArrayList<ItemStack> getBlockDropped(World world, int x, int y, int z, int metadata, int fortune)
        {
            ArrayList<ItemStack> ret = super.getBlockDropped(world, x, y, z, metadata, fortune);
     
            if (metadata >= 7)
            {
                for (int n = 0; n < 3 + fortune; n++)
                {
                    if (world.rand.nextInt(15) <= metadata)
                    {
                        ret.add(new ItemStack(this.getSeedItem(), 1, 0));
                    }
                }
            }
     
            return ret;
        }
    Il y a aussi 7, pensez à le changer si vous avez pris un autre nombre de metadata maximum.

    Code (java):
        public int idDropped(int par1, Random par2Random, int par3)
        {
            return par1 == 7 ? this.getCropItem() : this.getSeedItem();
        }
    A nouveau un 7, changer-le si besoin sinon votre plante ne dropera jamais le "fruit"

    Code (java):
        @SideOnly(Side.CLIENT)
     
        public String getTextureFile()
     
        {
     
                return TutoClientProxy.BlockTexture;
     
        }
    Pour la texture.
    Les autres fonctions non expliquées ne sont pas à changer.


    3. La classe de la plante :

    Code (java):
    package modTutoriel.common;
     
    import net.minecraft.block.Block;
    import net.minecraft.creativetab.CreativeTabs;
    import net.minecraft.entity.player.EntityPlayer;
    import net.minecraft.item.Item;
    import net.minecraft.item.ItemStack;
    import net.minecraft.world.World;
    import net.minecraftforge.common.EnumPlantType;
    import net.minecraftforge.common.IPlantable;
     
    public class SeedTuto extends Item implements IPlantable
    {
        public SeedTuto(int i)
        {
            super(i);
            maxStackSize = 64;
            this.setCreativeTab(modTutoriel.TutoCreativeTab);
        }
     
        @SideOnly(Side.CLIENT)
        public String getTextureFile()
        {
                return TutoClientProxy.ItemTexture;
        }
     
        @Override
        public EnumPlantType getPlantType(World world, int x, int y, int z)
        {
            return EnumPlantType.Crop;
        }
     
        @Override
        public int getPlantID(World world, int x, int y, int z)
        {
            return modTutoriel.CropPlanteTuto.blockID;
        }
     
        @Override
        public int getPlantMetadata(World world, int x, int y, int z)
        {
            return 0;
        }
     
        public boolean onItemUse(ItemStack par1ItemStack, EntityPlayer par2EntityPlayer, World par3World, int par4, int par5, int par6, int par7, float par8, float par9, float par10) {
            if (par7 != 1)
            {
                return false;
            }
            else if (par2EntityPlayer.canPlayerEdit(par4, par5, par6, par7,par1ItemStack) && par2EntityPlayer.canPlayerEdit(par4, par5 + 1, par6, par7, par1ItemStack)) {
                int var11 = par3World.getBlockId(par4, par5, par6);
                Block soil = Block.blocksList[var11];
     
                if (soil != null && soil.blockID == Block.tilledField.blockID && par3World.isAirBlock(par4, par5 + 1, par6))
                {
                    par3World.setBlockWithNotify(par4, par5 + 1, par6, modTutoriel.CropPlanteTuto.blockID);
                    --par1ItemStack.stackSize;
                    return true;
                } else {
                    return false;
                }
            } else {
                return false;
            }
        }
     
    }
     
    Explication :
    Forge possède un API pour les plantes, il permet de créer des plantes plus facilement.
    Code (java):
    implements IPlantable
        @Override
        public EnumPlantType getPlantType(World world, int x, int y, int z)
        {
            return EnumPlantType.Crop;
        }
     
        @Override
        public int getPlantID(World world, int x, int y, int z)
        {
            return modTutoriel.CropPlanteTuto.blockID;
        }
     
        @Override
        public int getPlantMetadata(World world, int x, int y, int z)
        {
            return 0;
        }
     
    La fonction getPlantID définit quel bloc va être votre plante (le bloc que nous avons créé juste avant).
    La fonction getPlantMetadata définit le metadata par défaut, quand vous plantez la graine. Il faut le mettre à 0 pour avoir l'étape 1 lorsque vous plantez.

    Code (java):
        @SideOnly(Side.CLIENT)
        public String getTextureFile()
        {
                return TutoClientProxy.ItemTexture;
        }
    Texture

    Code (java):
        public boolean onItemUse(ItemStack par1ItemStack, EntityPlayer par2EntityPlayer, World par3World, int par4, int par5, int par6, int par7, float par8, float par9, float par10) {
            if (par7 != 1)
            {
                return false;
            }
            else if (par2EntityPlayer.canPlayerEdit(par4, par5, par6, par7,par1ItemStack) && par2EntityPlayer.canPlayerEdit(par4, par5 + 1, par6, par7, par1ItemStack)) {
                int var11 = par3World.getBlockId(par4, par5, par6);
                Block soil = Block.blocksList[var11];
                if (soil != null && soil.blockID == Block.tilledField.blockID && par3World.isAirBlock(par4, par5 + 1, par6))
                {
                    par3World.setBlockWithNotify(par4, par5 + 1, par6, modTutoriel.CropPlanteTuto.blockID);
                    --par1ItemStack.stackSize;
                    return true;
                } else {
                    return false;
                }
            } else {
                return false;
            }
        }
    A nouveau, si vous avez changé le bloc sur lequel pousse la plante, changez le Block.tilledField.blockID.


    3)La classe du "fruit":


    Dans mon cas, j'ai décidé que l'item droppé sera directement mangeable, contrairement au blé où il faut d'abord faire du pain.
    La plante n'influence pas cette classe, vous pouvez donc faire un item basique.
    Je vais quand même mettre le code de mon aliment, ça permet de montrer comment en faire un en même temps. :)

    Code (java):
    package modTutoriel.common;
     
    import net.minecraft.entity.player.EntityPlayer;
    import net.minecraft.item.EnumAction;
    import net.minecraft.item.ItemFood;
    import net.minecraft.item.ItemStack;
    import net.minecraft.world.World;
     
    public class FruitTuto extends ItemFood
    {
        private final int healAmount;
        private final boolean isWolfsFavoriteMeat;
        private boolean alwaysEdible;
        private final float saturationModifier;
     
        public FruitTuto(int par1, int par2, float par3, boolean par4)
        {
            super(par1, par2, par3, par4);
            healAmount = par2;
            isWolfsFavoriteMeat = par4;
            saturationModifier = par3;
            this.setCreativeTab(modtuto.TutoCreativeTab);
        }
     
        public ItemStack onFoodEaten(ItemStack par1ItemStack, World par2World, EntityPlayer par3EntityPlayer)
        {
            --par1ItemStack.stackSize;
            par3EntityPlayer.getFoodStats().addStats(this);
            par2World.playSoundAtEntity(par3EntityPlayer, "random.burp", 0.5F, par2World.rand.nextFloat() * 0.1F + 0.9F);
            this.func_77849_c(par1ItemStack, par2World, par3EntityPlayer);
            return par1ItemStack;
        }
     
        public int getMaxItemUseDuration(ItemStack par1ItemStack)
        {
            return 32;
        }
     
        public EnumAction getItemUseAction(ItemStack par1ItemStack)
        {
            return EnumAction.eat;
        }
     
        public ItemStack onItemRightClick(ItemStack par1ItemStack, World par2World, EntityPlayer par3EntityPlayer)
        {
            if (par3EntityPlayer.canEat(this.alwaysEdible))
            {
                par3EntityPlayer.setItemInUse(par1ItemStack, this.getMaxItemUseDuration(par1ItemStack));
            }
     
            return par1ItemStack;
        }
     
        public int getHealAmount()
        {
            return this.healAmount;
        }
     
        public float getSaturationModifier()
        {
            return this.saturationModifier;
        }
     
        public FruitTuto setAlwaysEdible()
        {
            this.alwaysEdible = true;
            return this;
        }
     
        @SideOnly(Side.CLIENT)
        public String getTextureFile()
        {
                return TutoClientProxy.ItemTexture;
        }
     
    }
     
    La plupart des choses qui se trouvent dans ce code sont des fonctions pour les ItemFood, il n'y a rien à changer à part :
    Code (java):
        public int getMaxItemUseDuration(ItemStack par1ItemStack)
        {
            return 32;
        }
    Il s'agit du temps en tick que vous allez mettre à manger l'item. Les autres valeurs se changent dans la classe principale, retournons sur ce code :
    Code (java):
    FruitTuto = new FruitTuto(20164, 6, 0.8F, false).setIconIndex(14).setItemName("FruitTuto");
    6 est le nombre de demi points de faim donnés, 0.8F sont les points de saturation et "false" est un boolean pour savoir si la nourriture peut être donné aux chiens (dans ce cas non, il faut mettre true si vous le voulez).
     
  2. Swoonix

    Swoonix Résident de l'End

    Inscrit:
    21 Juil 2012
    Messages:
    6 910
    Points:
    219
    Hâte de voir la suite, ça va me servir !
    Le tuto commence bien.
     
  3. Kanar

    Kanar Ami des Creepers

    Inscrit:
    5 Nov 2012
    Messages:
    11 119
    Points:
    304
    Sexe:
    Homme
    Vite vite, on veut la suite. :B
     
  4. robin4002

    robin4002 Support Technique
    Staff

    Inscrit:
    17 Août 2012
    Messages:
    5 478
    Points:
    229
    Sexe:
    Homme
    Finalement en n'expliquant que le plus important, tout est fini en moins de 30 minutes
     
  5. Swoonix

    Swoonix Résident de l'End

    Inscrit:
    21 Juil 2012
    Messages:
    6 910
    Points:
    219
    Ah génial, ça va être utile Kanar ! Tes tutos sont géniaux.
     
  6. _Tryall_

    _Tryall_ Mineur de Fer

    Inscrit:
    30 Jan 2012
    Messages:
    501
    Points:
    109
    Sexe:
    Homme
    Ouai gros, des plantes gros [​IMG] :k:
     

Partager cette page