Créer un arbre
-
Sommaire
Introduction
Dans ce tutoriel nous allons créer un arbre et le faire pousser, nous utiliserons des feuilles et du bois de notre mod.
Pré-requis
- Créer un bloc basique
- OpenClassrooms est conseillé si vous n’avez aucune notion de java, les deux premiers chapitres au moins sont à lire.
Code
Bon, passons aux choses sérieuses !
La classe principale:
Pour commencer en dessous de vos autres blocs, items … Déclarez les blocs :
public static Block tutoBois; public static Block tutoFeuilles; public static Block tutoPousse;
Si vous n’avez pas créer d’autres blocs “importer net.minecraft.bloc” (en passant la souris sur “Block” ou avec “ctrl + shift + o”).
Dans la fonction “preInit” ajoutez (pour initialiser les blocs), aussi nous utiliserons pas les metadatas :
@EventHandler public void preInit(FMLPreInitializationEvent event) { tutoBois = new TutoBois().setBlockTextureName("tuto:bois").setBlockName("tuto_bois"); tutoFeuilles = new TutoFeuilles().setBlockTextureName("tuto:feuilles").setBlockName("tuto_feuilles"); tutoPousse = new TutoPouce().setBlockTextureName("tuto:pousse").setBlockName("tuto_pousse"); }
Il ne faut pas oublier d’enregistrer les blocs.
Donc, en-dessous, ajoutez cela :GameRegistry.registerBlock(tutoBois , "tuto_bois"); GameRegistry.registerBlock(tutoFeuilles , "tuto_feuilles"); GameRegistry.registerBlock(tutoPousse, "tuto_pousse");
Bon voilà maintenant vous êtes armés pour coder les classes :).
[ancre=La classe du Bois][size]La classe du Bois :[/ancre]
En premier lieu créez une nouvelle classe avec une extension de la classe “BlockLog”, ce qui devrais donner :public class TutoBois extends BlockLog { //le reste du code se met ICI :) }
pense pas avoir besoin de vous dire à quoi sa correspond ?
Ensuite ajoutez ce bout de code :private IIcon topIcon; @SideOnly(Side.CLIENT) public void registerBlockIcons(IIconRegister iconregister) { blockIcon = iconregister.registerIcon(this.getTextureName()); topIcon = iconregister.registerIcon(this.getTextureName() + "_top"); } // la suite
Donc :
private IIcon topIcon;
On déclare un nouvel icone@SideOnly(Side.CLIENT)
Signifie que la fonction sera que pour le client et pas pour le serveur.
Rappelle tout ce qui est rendu ne touche que le client.
blockIcon
Cela représente la texture de chaque face de notre bloc (Vous pourrez utiliser cette classe pour le rendu de vos autres blocs de bois, enfin si je dit pas de bêtises :p).topIcon
(Le field de dessus). Il nous dit quelle texture il prendra pour les faces du haut et du bas. Donc nous avons le “this.getTextureName()” qui nous permet de reprendre la texture, et le “+ “_top””, donc la texturebois_top
sera dans ledossier blocks de votre assets, ce qui fait que vous aurez deux textures une pour le haut et le bas, et une pour les autres faces.
Bien joli mais si je lance le jeu ça ne fait rien, le bloc ne va pas bien afficher les textures, c’est normal. Juste après la fonction ajoutez :
@Override public IIcon getIcon(int side, int metadata) { int k = metadata & 12; return k == 0 && (side == 1 || side == 0) ? topIcon : (k == 4 && (side == 5 || side == 4) ? topIcon : (k == 8 && (side == 2 || side == 3) ? topIcon : blockIcon)); }
Je vais rapidement l’expliquer :
return k == 0 && (side == 1 || side == 0) ? topIcon
, Cela veut dire que pour les faces du bloc 1 et 0 nous utilisons la texture topIcon, (1 et 0 sont les face dessus et dessous). Normalement vous devriez avoir compris, surtout si vous êtes allé sur OpenClassroom (il y a aussi developpez).Et bien voilà, nous avons fini le bois, il reste que les feuilles et la pousse, courage ;).
La classe des feuilles:
Donc en vitesse, créez la classe de votre feuille avec un extends BlockLeaves. Ajoutez aussi les deux méthodes suivantes.
Ce qui doit vous donner :public class TutoFeuilles extends BlockLeaves { // la suite se met ICI ;) @Override public IIcon getIcon(int var1, int var2) { return null; } @Override public String[] func_150125_e() { return null; } }
Ensuite ajoutez :
protected IIcon fastIcon; @Override public void registerBlockIcons(IIconRegister iconregister) { blockIcon = iconregister.registerIcon(this.getTextureName()); fastIcon = iconregister.registerIcon(this.getTextureName() + "_opaque"); }
- Comme le bois nous avons le “blockIcon”, il ne change pas et exprime la même chose (n’oubliez pas, le getTextureName nous donne la texture).
- Le fastIcon qui comme le bois est une sorte de texture, mais pour le moment elle est inutile, il vous faut changer le getIcon (le fonctionnement est le même il faut ajouter en plus de la texture de base une autre avec en plus “_opaque”).
Donc pour le getIcon changez le comme cela:
@Override public IIcon getIcon(int side, int metadata) { return(isOpaqueCube() ? fastIcon : blockIcon); }
- En premier lieu nous changeons les “int” pour qu’ils soient compréhensibles (du moins significatifs).
- La fonction permet que la texture soit opaque quand les options graphiques sont en fast (faibles).
Nous allons ajouter quelques autres fonctions :
@Override public boolean isOpaqueCube() { return Blocks.leaves.isOpaqueCube(); } @Override public boolean isLeaves(IBlockAccess world, int x, int y, int z) { return true; } @SideOnly(Side.CLIENT) public boolean shouldSideBeRendered(IBlockAccess blockaccess, int x, int y, int z, int side) { return !this.isOpaqueCube() ? true : super.shouldSideBeRendered(blockaccess, x, y, z, side); }
Vous importez tout (Ctrl + Shift + “O”).
- “isOpaqueCube” Cette fonction nous permet de donner l’opacité
- Le seconde nous dit que le bloc est de type feuille.
- Le dernière vous permet de ne pas avoir de problème avec la transparence quand le bloc est posé a coté d’autre bloc (du même type).
Ensuite :
@Override public int getBlockColor() { return -1; } @Override public int getRenderColor(int par1) { return -1; } @Override public int quantityDropped(Random random) { return random.nextInt(20) == 0 ? 1 : 0; } @Override public Item getItemDropped(int metadata, Random random, int par3) { return Item.getItemFromBlock(tutoMain.tutoPouce); }
- Les deux premiers n’ont pas besoin d’explications.
- Le “quantityDropped” nous donne le nombre d’item(s) droppé(s) quand le bloc est cassé.
- Le “getItemDropped” permet de choisir l’item droppé, dans notre cas une pousse d’arbre.
Et enfin :
@Override public void dropBlockAsItemWithChance(World world, int x, int y, int z, int metadata, float par6, int par7) { if(!world.isRemote) { if(world.rand.nextInt(20) == 0) { Item splingid = this.getItemDropped(metadata, world.rand, par7); this.dropBlockAsItem(world, x, y, z, new ItemStack(splingid, 1, this.damageDropped(metadata))); } } }
Cette fonction permet de spécifier les chances de drop des items.
La classe de la pousse
Créez une nouvelle classe pour la pousse de l’arbre, ajoutez l’extension BlockSapling.
Ajoutez ensuite :public TutoPousse() { super(); float f = 0.4F; setBlockBounds(0.5F - f, 0.0F, 0.5F - f, 0.5F + f, f * 2.0F, 0.5F + f); this.setCreativeTab(CreativeTabs.tabBlock); }
- Donc “TutoPousse” correspond au nom de la classe.
- Le “float” et bien si vous ne le savez pas, allez sur un des deux sites recommandé.
- Le “setBlockBounds” est la Hit Box particulière, modifiez les valeurs et la hit box sera différente.
- Le this.setCreativeTabs est donné dans les “Pré-requis”.
Ajoutez par la suite :
@SideOnly(Side.CLIENT) public IIcon getIcon(int side, int metadata) { return blockIcon; } @SideOnly(Side.CLIENT) public void registerBlockIcons(IIconRegister iiconRegister) { this.blockIcon = iiconRegister.registerIcon(this.getTextureName()); }
Les fonctions si dessus permettent de donner la texture.
Un peu de la même manière que pour les deux autres blocs.
Et en fin:@Override public void func_149878_d(World world, int x, int y, int z, Random random) { int l = world.getBlockMetadata(x, y, z) & 3; world.setBlockToAir(x, y, z); Object obj = null; obj = new ClassDeGeneration(true); if(!((WorldGenerator)(obj)).generate(world, random, x, y, z)) { world.setBlock(x, y, z, this, l, 3); } } @Override public void getSubBlocks(Item item, CreativeTabs creativetabs, List list) { list.add(new ItemStack(item, 1, 0)); }
- La première fonction permet de faire pousser notre arbre avec de la poudre d’os (nous allons voir cela juste après).
- La seconde est là au cas où vous utilisez des metadatas.
- Important “WorldGenSavannaTree” est l’arbre généré avec la poudre d’os, il sera à remplacer par votre propre classe.
ASTUCE:
Pour éviter de devoir faire des choses trop dures avec les classes block bush… Je vous conseille d’ajouter cette petite fonction pour placer votre pousse d’arbre sur un autre bloc (il se placera toujours sur la grass et la dirt).protected boolean canPlaceBlockOn(Block block) { return block == Blocks.netherrack || block == Blocks.end_stone; }
Donc vous pouvez mettre la liste de tous les blocs où se placera votre pousse, vous pouvez supprimer ou ajouter autant de blocs que vous le souhaitez.
La classe de la génération:
Pour la classe suivante (le model de notre arbre), il y a plusieurs solutions.
Première méthode :
Utiliser une des classes de base, trouver les blocs à changer et les remplacer par vos blocs.
exemple (classe issue de la génération de chêne) :
:::public class tutoTreeGen extends WorldGenAbstractTree { /** The minimum height of a generated tree. */ //Taille minimum de l'arbre à générer. private final int minTreeHeight; /** True if this tree should grow Vines. */ //Vrai si l'arbre doit faire spawn des vignes. private final boolean vinesGrow; /** The metadata value of the wood to use in tree generation. */ //Le métadata du bois à utiliser pour la génération. private final int metaWood; /** The metadata value of the leaves to use in tree generation. */ //Le métadata des feuilles à utiliser pour la génération. private final int metaLeaves; private static final String __OBFID = "CL_00000438"; public WorldGenTrees(boolean par1) { this(par1, 4, 0, 0, false); } public tutoTreeGen(boolean par1, int par2, int par3, int par4, boolean par5) { super(par1); this.minTreeHeight = par2; this.metaWood = par3; this.metaLeaves = par4; this.vinesGrow = par5; } public boolean generate(World par1World, Random par2Random, int par3, int par4, int par5) { int l = par2Random.nextInt(3) + this.minTreeHeight; boolean flag = true; if (par4 >= 1 && par4 + l + 1 <= 256) { byte b0; int k1; Block block; for (int i1 = par4; i1 <= par4 + 1 + l; ++i1) { b0 = 1; if (i1 == par4) { b0 = 0; } if (i1 >= par4 + 1 + l - 2) { b0 = 2; } for (int j1 = par3 - b0; j1 <= par3 + b0 && flag; ++j1) { for (k1 = par5 - b0; k1 <= par5 + b0 && flag; ++k1) { if (i1 >= 0 && i1 < 256) { block = par1World.getBlock(j1, i1, k1); if (!this.isReplaceable(par1World, j1, i1, k1)) { flag = false; } } else { flag = false; } } } } if (!flag) { return false; } else { Block block2 = par1World.getBlock(par3, par4 - 1, par5); boolean isSoil = block2.canSustainPlant(par1World, par3, par4 - 1, par5, ForgeDirection.UP, (BlockSapling)tutoMain.tutoPousse); if (isSoil && par4 < 256 - l - 1) { block2.onPlantGrow(par1World, par3, par4 - 1, par5, par3, par4, par5); b0 = 3; byte b1 = 0; int l1; int i2; int j2; int i3; for (k1 = par4 - b0 + l; k1 <= par4 + l; ++k1) { i3 = k1 - (par4 + l); l1 = b1 + 1 - i3 / 2; for (i2 = par3 - l1; i2 <= par3 + l1; ++i2) { j2 = i2 - par3; for (int k2 = par5 - l1; k2 <= par5 + l1; ++k2) { int l2 = k2 - par5; if (Math.abs(j2) != l1 || Math.abs(l2) != l1 || par2Random.nextInt(2) != 0 && i3 != 0) { Block block1 = par1World.getBlock(i2, k1, k2); if (block1.isAir(par1World, i2, k1, k2) || tutoMain.tutoFeuille(par1World, i2, k1, k2)) { this.setBlockAndNotifyAdequately(par1World, i2, k1, k2, Blocks.leaves, this.metaLeaves); } } } } } for (k1 = 0; k1 < l; ++k1) { block = par1World.getBlock(par3, par4 + k1, par5); if (block.isAir(par1World, par3, par4 + k1, par5) || block.isLeaves(par1World, par3, par4 + k1, par5)) { this.setBlockAndNotifyAdequately(par1World, par3, par4 + k1, par5, tutoMain.tutoBois, this.metaWood); if (this.vinesGrow && k1 > 0) { if (par2Random.nextInt(3) > 0 && par1World.isAirBlock(par3 - 1, par4 + k1, par5)) { this.setBlockAndNotifyAdequately(par1World, par3 - 1, par4 + k1, par5, Blocks.vine, 8); } if (par2Random.nextInt(3) > 0 && par1World.isAirBlock(par3 + 1, par4 + k1, par5)) { this.setBlockAndNotifyAdequately(par1World, par3 + 1, par4 + k1, par5, Blocks.vine, 2); } if (par2Random.nextInt(3) > 0 && par1World.isAirBlock(par3, par4 + k1, par5 - 1)) { this.setBlockAndNotifyAdequately(par1World, par3, par4 + k1, par5 - 1, Blocks.vine, 1); } if (par2Random.nextInt(3) > 0 && par1World.isAirBlock(par3, par4 + k1, par5 + 1)) { this.setBlockAndNotifyAdequately(par1World, par3, par4 + k1, par5 + 1, Blocks.vine, 4); } } } } if (this.vinesGrow) { for (k1 = par4 - 3 + l; k1 <= par4 + l; ++k1) { i3 = k1 - (par4 + l); l1 = 2 - i3 / 2; for (i2 = par3 - l1; i2 <= par3 + l1; ++i2) { for (j2 = par5 - l1; j2 <= par5 + l1; ++j2) { if (par1World.getBlock(i2, k1, j2).isLeaves(par1World, i2, k1, j2)) { if (par2Random.nextInt(4) == 0 && par1World.getBlock(i2 - 1, k1, j2).isAir(par1World, i2 - 1, k1, j2)) { this.growVines(par1World, i2 - 1, k1, j2, 8); } if (par2Random.nextInt(4) == 0 && par1World.getBlock(i2 + 1, k1, j2).isAir(par1World, i2 + 1, k1, j2)) { this.growVines(par1World, i2 + 1, k1, j2, 2); } if (par2Random.nextInt(4) == 0 && par1World.getBlock(i2, k1, j2 - 1).isAir(par1World, i2, k1, j2 - 1)) { this.growVines(par1World, i2, k1, j2 - 1, 1); } if (par2Random.nextInt(4) == 0 && par1World.getBlock(i2, k1, j2 + 1).isAir(par1World, i2, k1, j2 + 1)) { this.growVines(par1World, i2, k1, j2 + 1, 4); } } } } } if (par2Random.nextInt(5) == 0 && l > 5) { for (k1 = 0; k1 < 2; ++k1) { for (i3 = 0; i3 < 4; ++i3) { if (par2Random.nextInt(4 - k1) == 0) { l1 = par2Random.nextInt(3); this.setBlockAndNotifyAdequately(par1World, par3 + Direction.offsetX[Direction.rotateOpposite[i3]], par4 + l - 5 + k1, par5 + Direction.offsetZ[Direction.rotateOpposite[i3]], Blocks.cocoa, l1 << 2 | i3); } } } } } return true; } else { return false; } } } else { return false; } } /** * Grows vines downward from the given block for a given length. Args: World, x, start_y, z, vine-length */ private void growVines(World par1World, int par2, int par3, int par4, int par5) { this.setBlockAndNotifyAdequately(par1World, par2, par3, par4, Blocks.vine, par5); int i1 = 4; while (true) { --par3; if (par1World.getBlock(par2, par3, par4).isAir(par1World, par2, par3, par4) || i1 <= 0) { return; } this.setBlockAndNotifyAdequately(par1World, par2, par3, par4, Blocks.vine, par5); --i1; } } }
Il faut savoir que la troisième méthode ressemble à celle-ci.
:::Seconde méthode :
C’est ma préférée, car elle est simple est efficace.Mais, il y a des inconvénients :
Elle est très longue à mettre en place, elle est aussi utilisée par les structures (elle supprime un peu le random dans la génération donc si vous voulez un random poussé allez dans la troisième méthode.Donc démarrons notre code :
Créez une classe et ajoutez “extends WorldGenerator”.
Ensuite ajoutez :public tutoTreeGen(boolean par1) { super(par1); } public boolean generate(World world, Random rand, int x, int y, int z) { //où nous ajouterons les blocs à générer return true; }
Je ne vous explique pas la première fonction ?
Mais la deuxième oui, en effet nous allons créer notre “structure”, si je peux le dire ainsi ^^.Pour ajouter un bloc faites :
world.setBlock(x , y , z , tutoMain.tutoBois);
En effet nous utilisons un simple setBlock. Si vous ne l’aviez pas compris le “x, y, z” correspond au bloc de départ
Dans notre cas il remplace la pousse d’arbre par du bois, si je met :world.setBlock(x , y + 1, z , );
Alors le bloc poussera 1 bloc au-dessus.
Vous l’aurez compris en ajoutant + unNombre ou - unNombre après une lettre le bloc sera pas au même endroit. Il utilise les position du F3 (du moins les directions).Un petit exemple:
:::public class tutoTreeGen extends WorldGenerator { public tutoTreeGen(boolean gen) { super(gen); } public boolean generate(World world, Random rand, int x, int y, int z) { //où nous ajoutons les blocs à générer world.setBlock(x , y , z , tutoMain.tutoBois); world.setBlock(x , y + 1 , z , tutoMain.tutoBois); world.setBlock(x , y + 2 , z , tutoMain.tutoBois); world.setBlock(x , y + 3 , z , tutoMain.tutoBois); world.setBlock(x , y + 4 , z , tutoMain.tutoBois); world.setBlock(x , y + 5 , z , tutoMain.tutoBois); world.setBlock(x , y + 6, z , tutoMain.tutoBois); world.setBlock(x , y + 7 , z , tutoMain.tutoBois); world.setBlock(x , y + 8 , z , tutoMain.tutoBois); world.setBlock(x , y + 9 , z , tutoMain.tutoBois); world.setBlock(x , y + 10 , z , tutoMain.tutoFeuilles); world.setBlock(x , y + 11 , z , tutoMain.tutoFeuilles); world.setBlock(x + 1 , y + 5 , z , tutoMain.tutoFeuilles); world.setBlock(x - 1 , y + 5 , z , tutoMain.tutoFeuilles); world.setBlock(x , y + 5 , z + 1 , tutoMain.tutoFeuilles); world.setBlock(x , y + 5 , z - 1 , tutoMain.tutoFeuilles); world.setBlock(x + 1 , y + 9 , z , tutoMain.tutoFeuilles); world.setBlock(x - 1 , y + 9 , z , tutoMain.tutoFeuilles); world.setBlock(x , y + 9 , z + 1 , tutoMain.tutoFeuilles); world.setBlock(x , y + 9 , z - 1 , tutoMain.tutoFeuilles); world.setBlock(x + 2 , y + 9 , z , tutoMain.tutoFeuilles); world.setBlock(x - 2 , y + 9 , z , tutoMain.tutoFeuilles); world.setBlock(x , y + 9 , z + 2 , tutoMain.tutoFeuilles); world.setBlock(x , y + 9 , z - 2 , tutoMain.tutoFeuilles); world.setBlock(x + 1 , y + 9 , z + 1, tutoMain.tutoFeuilles); world.setBlock(x - 1 , y + 9 , z - 1, tutoMain.tutoFeuilles); world.setBlock(x - 1 , y + 9 , z + 1, tutoMain.tutoFeuilles); world.setBlock(x +1 , y + 9 , z - 1 , tutoMain.tutoFeuilles); world.setBlock(x + 1 , y + 10 , z , tutoMain.tutoFeuilles); world.setBlock(x - 1 , y + 10 , z , tutoMain.tutoFeuilles); world.setBlock(x , y + 10 , z + 1 , tutoMain.tutoFeuilles); world.setBlock(x , y + 10 , z - 1 , tutoMain.tutoFeuilles); world.setBlock(x + 1 , y + 11 , z , tutoMain.tutoFeuilles); world.setBlock(x - 1 , y + 11 , z , tutoMain.tutoFeuilles); world.setBlock(x , y + 11 , z + 1 , tutoMain.tutoFeuilles); world.setBlock(x , y + 11 + rand.nextInt(1) , z - 1 , tutoMain.tutoFeuilles); return true; } }
Suite au conseil de Superloup10 Vous pouvez simplifier avec des boucles for.
Exemple:public class tutoTreeGen extends WorldGenerator { public tutoTreeGen(boolean gen) { super(gen); } public boolean generate(World world, Random rand, int x, int y, int z) { //où nous ajoutons les blocs à générer for(int i = 0; i < 10; i++) { world.setBlock(x , y + i, z , tutoMain.tutoBois); } world.setBlock(x , y + 10 , z , tutoMain.tutoFeuilles); world.setBlock(x , y + 11 , z , tutoMain.tutoFeuilles); for(int i = 9; i < 12; i++) { world.setBlock(x + 1 , y + i , z , tutoMain.tutoFeuilles); world.setBlock(x - 1 , y + i , z , tutoMain.tutoFeuilles); world.setBlock(x , y + i , z + 1 , tutoMain.tutoFeuilles); world.setBlock(x , y + i , z - 1 , tutoMain.tutoFeuilles); } world.setBlock(x + 1 , y + 5 , z , tutoMain.tutoFeuilles); world.setBlock(x - 1 , y + 5 , z , tutoMain.tutoFeuilles); world.setBlock(x , y + 5 , z + 1 , tutoMain.tutoFeuilles); world.setBlock(x , y + 5 , z - 1 , tutoMain.tutoFeuilles); world.setBlock(x + 2 , y + 9 , z , tutoMain.tutoFeuilles); world.setBlock(x - 2 , y + 9 , z , tutoMain.tutoFeuilles); world.setBlock(x , y + 9 , z + 2 , tutoMain.tutoFeuilles); world.setBlock(x , y + 9 , z - 2 , tutoMain.tutoFeuilles); world.setBlock(x + 1 , y + 9 , z + 1, tutoMain.tutoFeuilles); world.setBlock(x - 1 , y + 9 , z - 1, tutoMain.tutoFeuilles); world.setBlock(x - 1 , y + 9 , z + 1, tutoMain.tutoFeuilles); world.setBlock(x +1 , y + 9 , z - 1 , tutoMain.tutoFeuilles); return true; } }
Le principe est simple, dans la boucle for nous allons répéter “i” et une fois au maximum nous stoppons. Dans la boucle on pose les blocs à une hauteur y + i, c’est à dire qu’à chacun des tours, on pose les blocs à 1 de plus en hauteur.
:::Troisième méthode :
Pour celle-ci en vue du nombre de choses à faire je le spoiler.
:::Donc pour commencer, il vous faut créez la classe.
Une fois créée, ajoutez une extension de la classe “WorldGenAbstractTree”, importez la mais n’ajoutez pas les constructeurs, faites moi confiance et rien d’autre.
Le premier code que nous ajoutons est :public TutoTreeGen2(boolean par1) . { super(par1); } //le code se mettra ici :)
La fonction est en quelque sorte une fonction où nous pouvons ajouter plein de choses (comme pour les blocs “this.set…”).
Si notre classe était finie là… Tous serait plus simple, mais vous pensez quoi ?
À la suite ajoutez cela :@Override public boolean generate(World world, Random rand, int par3, int par4, int par5) { //Tout le reste de la classe est à mettre ICI et dans aucun cas en dessous du return. return false; //Rien ici. }
Ce seront les deux seules fonctions de notre classe, mais maintenant il faut compléter la fonction “generate”.
Ajoutez :
int l = rand.nextInt(7) + 2; int i1 = rand.nextInt(3); int j1 = l - i1; int k1 = 3 + rand.nextInt(3); boolean flag = true;
Tout le code s’ajoutera à la suite.
:::- le int “l” est la hauteur de l’arbre un petit exemple ici donc ne le faite pas trop élevé, après cela dépend de ce que vous désirez faire.
- pour le “i1” ne le mettez pas trop haut sinon il y a des chances pour q’il n’y ait que du bois.
- le “j1” permet la génération correcte de l’arbre.
- le “int k1” permet la génération correcte des feuilles. Trop élevé votre arbre serait étrange :p.
- le boolean, ne vous en occupez pas :p.
:::
Ha oui le code à partir de maintenant sera très peu expliqué, Merci de le comprendre.
Voilà pour le code explicable, après je vous donne le reste de la classe, vous pourrez le modifier et voir les effets, mais le code n’est pas explicable (enfin je trouve), changez des valeurs et faites de tests . Mais la base de votre arbre est faite (int du début), je regarderais pour faire une chose en rapport avec ça dans les bonus :).
Le reste du code (supprimer le return false avant) :
Voilà le code expliqué au fur et à mesure :p.if (par4 >= 1 && par4 + l + 1 <= 256) { int i2; int l3; for (int l1 = par4; l1 <= par4 + 1 + l && flag ; ++l1) { boolean flag1 = true; if (l1 - par4 < i1) { l3 = 0; } else { l3 = k1; } for (i2 = par3 - l3; i2 <= par3 + l3 && flag; ++i2) { for (int j2 = par5 - l3; j2 <= par5 + l3 && flag; ++j2) { if (l1 >= 0 && l1 < 256) { Block block = world.getBlock(i2, l1, j2); if (!block.isAir(world, i2, l1, j2) && !block.isLeaves(world, i2, l1, j2)) { flag = false; } } else { flag = false; } } } } if (!flag) { return false; } else { Block block1 = world.getBlock(par3, par4 - 1, par5); //Changez (BlockSapling)tutoMain.tutoPousse) par votre bloc de la pousse. boolean isSoil = block1.canSustainPlant(world, par3, par4 - 1, par5, ForgeDirection.UP, (BlockSapling)tutoMain.tutoPousse); if (isSoil && par4 < 256 - l - 1) { block1.onPlantGrow(world, par3, par4 - 1, par5, par3, par4, par5); l3 = rand.nextInt(2); i2 = 1; byte b0 = 0; int k2; int i4; //Le code pour la génération des feuilles, modifiez le à vos souhaits. for (i4 = 0; i4 <= j1; ++i4) { k2 = par4 + l - i4; for (int l2 = par3 - l3; l2 <= par3 + l3; ++l2) { int i3 = l2 - par3; for (int j3 = par5 - l3; j3 <= par5 + l3; ++j3) { int k3 = j3 - par5; if ((Math.abs(i3) != l3 || Math.abs(k3) != l3 || l3 <= 0) && world.getBlock(l2, k2, j3).canBeReplacedByLeaves(world, l2, k2, j3)) { //Changez tutoMain.tutoFeuilles par votre bloc de feuille. this.setBlockAndNotifyAdequately(world, l2, k2, j3, tutoMain.tutoFeuilles, 1); } } } //Changer le code pour avoir du bois qui se génère différemment. if (l3 >= i2) { l3 = b0; b0 = 1; ++i2; if (i2 > k1) { i2 = k1; } } else { ++l3; } } i4 = rand.nextInt(3); for (k2 = 0; k2 < l - i4; ++k2) { Block block2 = world.getBlock(par3, par4 + k2, par5); if (block2.isAir(world, par3, par4 + k2, par5) || block2.isLeaves(world, par3, par4 + k2, par5)) { //Changez tutoMain.tutoBois par votre bloc de bois. this.setBlockAndNotifyAdequately(world, par3, par4 + k2, par5, tutoMain.tutoBois, 1); } } return true; } else { return false; } } } else { return false; }
Quelques exemples :
Je noterai où le code a été modifié.public class TutoGenTree3 extends WorldGenAbstractTree { public TutoGenTree3(boolean par1) { super(par1); } @Override public boolean generate(World world, Random rand, int par3, int par4, int par5) { int l = rand.nextInt(7) + 4; // Le nombre d'étages je vous conseille de le tester pour mieux comprendre. int i1 = rand.nextInt(3) + 2; //Ne le modifiez pas. int j1 = l - i1; //pareille int k1 = 3 + rand.nextInt(7); boolean flag = true; if (par4 >= 1 && par4 + l + 1 <= 256)//Ne vous en préoccupez pas. { int i2; int l3; for (int l1 = par4; l1 <= par4 + 1 + l && flag ; ++l1) { boolean flag1 = true; if (l1 - par4 < i1) { l3 = 0; } else { l3 = k1; } //Ne rien toucher. for (i2 = par3 - l3; i2 <= par3 + l3 && flag; ++i2) { for (int j2 = par5 - l3; j2 <= par5 + l3 && flag; ++j2) { if (l1 >= 0 && l1 < 256) { Block block = world.getBlock(i2, l1, j2); if (!block.isAir(world, i2, l1, j2) && !block.isLeaves(world, i2, l1, j2)) { flag = false; } } else { flag = false; } } } } if (!flag) { return false; } else { Block block1 = world.getBlock(par3, par4 - 1, par5); boolean isSoil = block1.canSustainPlant(world, par3, par4 - 1, par5, ForgeDirection.UP, (BlockSapling)tutoMain.tutoPousse); if (isSoil && par4 < 256 - l - 1) { block1.onPlantGrow(world, par3, par4 - 1, par5, par3, par4, par5); l3 = rand.nextInt(2); i2 = 1; byte b0 = 0; int k2; int i4; //Le code pour la génération des feuilles, modifiez le à vos souhaits for (i4 = 0; i4 <= j1 + 5; ++i4) { k2 = par4 + l - i4; //En ajoutant le +@ (pour moi le nombre juste avant) nous augmentons les feuilles générées (en le faisant il vous faut modifier le var3). for (int l2 = par3 - l3; l2 <= par3 + l3 + 4/* +@*/; ++l2) { int i3 = l2 + par3; //En modifiant les for vous changez votre arbre. for (int j3 = par5 - l3; j3 <= par5 + l3 + rand.nextInt(4) * (-1); ++j3) { int k3 = j3 - par5; if ((Math.abs(i3) != l3 || Math.abs(k3) != l3 || l3 <= 0) && world.getBlock(l2, k2, j3).canBeReplacedByLeaves(world, l2, k2, j3)) { //Changez tutoMain.tutoFeuilles par votre bloc de feuille. this.setBlockAndNotifyAdequately(world, l2 , par4 + k2 -6, j3, tutoMain.tutoFeuilles, 1); //Tout comme les bûches plus bas, si vous enlevez le k2 votre arbre sera assez moche. //Changez tutoMain.tutoFeuilles par votre bloc de feuille. this.setBlockAndNotifyAdequately(world, par3 +5 + 4, par4 + k2 -8, (par5 + 15) + par3 + 4, tutoMain.tutoFeuilles, 1); } } } //Changez le code pour avoir du bois qui se génère différemment. if (l3 >= i2) { l3 = b0; b0 = 1; ++i2; if (i2 > k1) { i2 = k1; } } else { ++l3; } } i4 = rand.nextInt(3); //Changez le 0 en - nombre ou en nombre supérieur si vous voulez un arbre volant. for (k2 = 0; k2 < l - i4; ++k2) { Block block2 = world.getBlock(par3, par4 + k2, par5); if (block2.isAir(world, par3, par4 + k2, par5) || block2.isLeaves(world, par3, par4 + k2, par5)) { //Changez tutoMain.tutoBois) par votre bloc de bois. this.setBlockAndNotifyAdequately(world, par3, par4 + k2, par5, tutoMain.tutoBois, 1); //Cela permet de générer notre arbre en 2x2. this.setBlockAndNotifyAdequately(world, par3, par4 + k2, par5 + 1, tutoMain.tutoBois, 1);//Le k2 correspond a la hauteur de l'arbre. this.setBlockAndNotifyAdequately(world, par3 - 1, par4 + k2, par5 , tutoMain.tutoBois, 1);//Le par3 est la position en x, le par4 en y, et le par5 en z. this.setBlockAndNotifyAdequately(world, par3 - 1, par4 + k2, par5 + 1, tutoMain.tutoBois, 1);//Les 1 permettent de positionner les blocs pour qu'ils soient au bon endroit. //Avec un par4 + (k2 + 1) /rand.nextInt(4) votre arbre ne sera pas droit. } } return true; } else { return false; } } } else { return false; } } }
Un autre exemple:
public class TutoGenTree3 extends WorldGenAbstractTree { public TutoGenTree3(boolean par1) { super(par1); } @Override public boolean generate(World world, Random rand, int par3, int par4, int par5) { int l = rand.nextInt(7) + 3; // Le nombre d'étages. Je vous conseille de le tester pour mieux comprendre. int i1 = rand.nextInt(3); //Ne le modifiez pas int j1 = l - i1; //Idem int k1 = 3 + rand.nextInt(3); boolean flag = true; //Le par4 est la base de l'arbre. Modifiez les fonctions qui le définissent et vous changez votre arbre. Vous pouvez faire de même pour le par3 et par5. if (par4 >= 1 && par4 + l + 1 <= 256) { int i2; int l3; /* Le code a été modifié dans le for, regardez le /4 + 100 */ for (int l1 = par4; l1 <= par4 + 1 + l / 4 + 100 && flag ; ++l1) { boolean flag1 = true; if (l1 - par4 < i1) { l3 = 0; } else { l3 = k1; } for (i2 = par3 - l3; i2 <= par3 + l3 && flag; ++i2) { for (int j2 = par5 - l3; j2 <= par5 + 10 + l3 && flag; ++j2) { if (l1 >= 0 && l1 < 256) { Block block = world.getBlock(i2, l1, j2); if (!block.isAir(world, i2, l1, j2) && !block.isLeaves(world, i2, l1, j2)) { flag = false; } } else { flag = false; } } } } if (!flag) { return false; } else { Block block1 = world.getBlock(par3, par4 - 1, par5); //Changez (BlockSapling)tutoMain.tutoPousse) par votre bloc de pousse. boolean isSoil = block1.canSustainPlant(world, par3, par4 - 1, par5, ForgeDirection.UP, (BlockSapling)tutoMain.tutoPousse); if (isSoil && par4 < 256 - l - 1) { //Le code a été modifié dans le for, regardez le /4 + 100 block1.onPlantGrow(world, par3, par4 - 1 /4 + 100, par5, par3, par4, par5); l3 = rand.nextInt(2); i2 = 1; byte b0 = 0; int k2; int i4; //Le code pour la génération des feuilles, modifiez-le à vos souhaits. for (i4 = 0; i4 <= j1; ++i4) { //Le code a été modifié dessous. k2 = par4 + l - i4 - 1; for (int l2 = par3 - l3; l2 <= par3 + l3; ++l2) { int i3 = l2 - par3; for (int j3 = par5 - l3; j3 <= par5 + l3; ++j3) { int k3 = j3 - par5; if ((Math.abs(i3) != l3 || Math.abs(k3) != l3 || l3 <= 0) && world.getBlock(l2, k2, j3).canBeReplacedByLeaves(world, l2, k2, j3)) { //Changez tutoMain.tutoFeuille par votre bloc de feuille. this.setBlockAndNotifyAdequately(world, l2, k2, j3, tutoMain.tutoFeuilles, 1); } } } //Changez le code pour avoir du bois qui se génère différemment. if (l3 >= i2) { l3 = b0; b0 = 1; ++i2; if (i2 > k1) { i2 = k1; } } else { ++l3; } } i4 = rand.nextInt(3); for (k2 = 0; k2 < l - i4; ++k2) { Block block2 = world.getBlock(par3, par4 + k2, par5); if (block2.isAir(world, par3, par4 + k2, par5) || block2.isLeaves(world, par3, par4 + k2, par5)) { //Changez tutoMain.tutoBois par votre bloc de bois. this.setBlockAndNotifyAdequately(world, par3, par4 + k2, par5, tutoMain.tutoBois, 1); } } return true; } else { return false; } } } else { return false; } } }
Et voilà un dernier exemple :
public class TutoGenTree3 extends WorldGenAbstractTree { public TutoGenTree3(boolean par1) { super(par1); } @Override public boolean generate(World world, Random rand, int par3, int par4, int par5) { int l = rand.nextInt(7) + 3; // Le nombre d'étages. Je vous conseille de le tester pour mieux comprendre. int i1 = rand.nextInt(3); //Ne pas modifier. int j1 = l - i1; //Idem. int k1 = 3 + rand.nextInt(3); boolean flag = true; //Le par4 est la base de l'arbre. Modifiez les fonctions qui le définissent et vous changez votre arbre. Vous pouvez faire de même pour le par3 et par5. if (par4 >= 1 && par4 + l + 1 <= 256) { int i2; int l3; // / 2 + 5 change l'arbre (il doit être égal à celui d'en dessous (le calcul ^^)) for (int l1 = par4; l1 <= par4 + 1 + l / 2 + 35 && flag ; ++l1) { boolean flag1 = true; if (l1 - par4 < i1) { l3 = 0; } else { l3 = k1; } for (i2 = par3 - l3; i2 <= par3 + l3 && flag; ++i2) { for (int j2 = par5 - l3; j2 <= par5 + 10 + l3 && flag; ++j2) { if (l1 >= 0 && l1 < 256) { Block block = world.getBlock(i2, l1, j2); if (!block.isAir(world, i2, l1, j2) && !block.isLeaves(world, i2, l1, j2)) { flag = false; } } else { flag = false; } } } } if (!flag) { return false; } else { Block block1 = world.getBlock(par3, par4 - 1, par5); //Changez (BlockSapling)tutoMain.tutoPousse par votre pousse. boolean isSoil = block1.canSustainPlant(world, par3, par4 - 1, par5, ForgeDirection.UP, (BlockSapling)tutoMain.tutoPousse); if (isSoil && par4 < 256 - l - 1) { // / 2 + 35 change l'arbre. block1.onPlantGrow(world, par3, par4 - 1 / 2 + 35, par5, par3, par4, par5); l3 = rand.nextInt(2); i2 = 1; byte b0 = 0; int k2; int i4; //Le code de la génération des feuilles, modifiez le à vos souhaits. for (i4 = 0; i4 <= j1; ++i4) { //J'ai changé la suite du code. k2 = par4 + l - i4 ; for (int l2 = par3 - l3; l2 <= par3 + l3; ++l2) { int i3 = l2 - par3; for (int j3 = par5 - l3; j3 <= par5 + l3; ++j3) { int k3 = j3 - par5; if ((Math.abs(i3) != l3 || Math.abs(k3) != l3 || l3 <= 0) && world.getBlock(l2, k2, j3).canBeReplacedByLeaves(world, l2, k2, j3)) { //Changez tutoMain.tutoFeuilles par votre bloc de feuilles. this.setBlockAndNotifyAdequately(world, l2, k2, j3, tutoMain.tutoFeuilles, 1); } } } //Changez le code pour avoir du bois qui se génère différemment. if (l3 >= i2) { l3 = b0; b0 = 1; ++i2; if (i2 > k1) { i2 = k1; } } else { ++l3; } } i4 = rand.nextInt(3); for (k2 = 0; k2 < l - i4; ++k2) { Block block2 = world.getBlock(par3, par4 + k2, par5); if (block2.isAir(world, par3, par4 + k2, par5) || block2.isLeaves(world, par3, par4 + k2, par5)) { // Changez tutoMain.tutoBois par votre bloc de bois. this.setBlockAndNotifyAdequately(world, par3, par4 + k2, par5, tutoMain.tutoBois, 1); } } return true; } else { return false; } } } else { return false; } } }
:::
[align][ancre=Bonus]#Bonus(Bonus)[/ancre]
Voilà comment le bonus est organisé :[]Générer l’arbre dans le monde.
[]Faire apparaître un arbre avec des blocs différents.
[*]Générer un arbre ou un autre avec une seule pousse.
[/list]#Générer l’arbre dans le monde(Générer l’arbre dans le monde)Pour générer notre arbre il nous faudra utiliser la classe de génération (déjà créée), plus deux classes, une pour générer notre arbre dans le monde (dimension) et une pour la génération qui ira dans notre classe.
Ajoutez dans la classe principale dans la fonction init :
GameRegistry.registerWorldGenerator(new WorldGeneration/*la classe avec la génération dans la dimension*/(), 0
Donc en premier lieu, il vous faut créer la première classe, il vous faut ajouter extends WorldGenerator Bien sûr il vous faut l’importer.
Avec cela on ne va pas aller bien loin :p.
Donc ajoutez une fonction simple :@Override public boolean generate(World world, Random random, int x, int y, int z) { }
Donc voilà la fonction qui va faire générer notre arbre donc, à partir de là il faudra bien suivre.
Compléter la fonction en ajoutant ceci :
if(world.getBlock(x, y - 1, z) == Blocks.grass && world.isAirBlock(x, y , z)) { } else { return false; }
Cela regarde si le bloc dessous est de l’herbe sinon ça ne fait rien
Donc si vous avez fait une pousse d’arbre pour le nether ou l’end, il vous suffit de changer de bloc.
Pour ajouter d’autres blocs il vous faut faire comme cela :if(world.getBlock(x, y - 1, z) == Blocks.grass || world.getBlock(x, y - 1, z) == Blocks.dirt && world.isAirBlock(x, y , z)) { }
Bon nous avons notre condition il faut juste la compléter.
new package.ClassDeGenerationDeL'Arbre(true).generate(world, random, x, y, z); return true;
Ce qui donne pour moi
new common.fr.diangle.tuto.TutoGenTree3(true).generate(world, random, x, y, z); return true;
Donc cela veut dire que nous générons notre arbre, au dessus des blocs de la condition.
[size]La seconde classe:
Donc créez une classe et faites un “implements IWorldGenerator”
Importez la classe et ajoutez cette fonction.@Override public boolean generate(Random rand, int X, int Z, World world, IChunkProvider chunkGenerator, IChunkProvider chunkProvider) { switch(world.provider.dimensionId) { case -1: this.generateNether(world, X * 16, Z * 16, rand); case 0: this.generateSurface(world, X * 16, Z * 16, rand); case 1: this.generateEnd(world, X * 16, Z * 16, rand); } }
Cette fonction est accompagnée d’un switch.
Le "case numéro " correspond a l’ID de la dimension, si vous avez une dimension avec l’ID 50, il vous faut ajouter un case.
Vous devriez avoir une erreur, donc ajoutez d’autres fonctions :private void generateSurface(World world, int x, int z, Random rand) { } private void generateEnd(World world, int x, int z, Random rand) { } private void generateNether(World world, int x, int z, Random rand) { }
Bon voilà notre classe est finie, il faut juste la compléter.
Dans la fonction de la dimension où vous voulez générer votre arbre, il vous faut ajouter :
for (int i = 0; i < 50; i++) { }
La boucle nous servira pour la rareté de notre arbre, vous avez juste à changer le 50, plus il sera grand plus il se générera, si il est plus petit l’effet contraire se produira.
Bon nous touchons au but, pour que votre arbre se génère il vous faut ajouter 4 simples lignes :
int x1 = x + rand.nextInt(16); int y1 = rand.nextInt(128); int z1 = z + rand.nextInt(16); (new ClasseQuiVientD'êtreCréerJusteAuDessus()).generate(world, rand, x1, y1, z1);
Le x1 correspond au x dans les chunks, tout comme le z1, par contre le y1, c’est la hauteur, changer le 128 en ce que vous voulez.
Voilà il vous reste plus qu’à lancer votre jeu, et voir votre arbre dans votre biome.
En parlant des biomes, si vous voulez générer votre arbre dans un biome particulier. ajoutez cette condition juste avant la boucle for.if(world.getBiomeGenForCoords(x, z).equals(BiomeGenBase.//Votre biome.)) { }
N’oubliez pas d’ajouter votre boucle à l’intérieur sinon ça ne marchera pas.
#Faire apparaître un arbre avec des blocs différents(Faire apparaître un arbre avec des blocs différents)
Pour générer un arbre qui se génère soit dans un blocs ou bien dans l’autre, il faut dans votre classe de la génération ajouter un int après les int de base :int l = rand.nextInt(7) + 3; // Le nombre d'étages. Je vous conseille de le tester pour mieux comprendre. int i1 = rand.nextInt(3); //Ne le modifiez pas. int j1 = l - i1; //Idem int k1 = 3 + rand.nextInt(3); boolean flag = true; //l'int EST à mettre ICI.
et mettre le int :
int blockRand = -3 + rand.nextInt(6); // Il aura une valeur entre -2 et 3.
Ensuite il va falloir aller plus bas et trouver la fonction permettant de générer vos feuilles qui est :
this.setBlockAndNotifyAdequately(world, l2, k2, j3, tutoMain.tutoFeuilles, 1);
Et remplacez là par :
if(blockRand >= 1) { this.setBlockAndNotifyAdequately(world, l2, k2, j3, ClassePrincipale.VotreBloc, 1); } else { this.setBlockAndNotifyAdequately(world, l2, k2, j3, ClassePrincipale.VotreBloc, 1); }
La condition permet de voir si le int blockRand est égal ou supérieur à 1 de faire générer en feuille les blocs choisis en dessous.
Sinon il générera un autre bloc choisi, je vous laisse tester, si vous voulez faire pareil avec un 3ème bloc.
Bon nous allons faire la même chose pour le bois, donc trouver cela :
this.setBlockAndNotifyAdequately(world, par3, par4 + k2, par5, tutoMain.tutoBois, 1);
-
Et remplacez le par :
if(blockRand >= 1) { this.setBlockAndNotifyAdequately(world, par3, par4 + k2, par5, ClassePrincipale.VotreBloc, 1); } else { this.setBlockAndNotifyAdequately(world, par3, par4 + k2, par5, ClassePrincipale.VotreBloc, 1); }
Je ne vous explique pas à quoi ça sert car c’est comme plus haut, mais avec le bloc de bois.
Faire générer un arbre ou un autre avec une seule pousse
Donc pour ce faire il vous faut aller dans la classe de votre pousse, et trouver cette ligne :
obj = new ClasseDeGeneration(true);
Et remplacez la par:
obj = random.nextInt(10) == 0 || random.nextInt(10) == 1 ? new TutoTreeGen3(true) : new TutoTreeGen2(true);
Nous générons notre arbre une fois sur dix.
Résultat
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 -
Pour la fonction dropBlockAsItemWithChance, ça m’a l’air bon.
-
@‘robin4002’:
Pour la fonction dropBlockAsItemWithChance, ça m’a l’air bon.
merci j’ai eux un doute ^^.
-
Pour l’instant, très bon tuto (sauf peut-être au niveau de l’orthographe ^^)
-
@bbcmh3, les correcteurs passeront une fois le tutoriel terminé
-
@bbcmh3 merci ^^
-
@Superloup10 : Je sais qu’ils vont passer après mais bon, n’empêche que ça me fait mal aux yeux de voir beaucoup de fautes et pas des moindres ! ;D
@Diangle : De rien !
-
Ouah les fautes d’orthographe piquent les yeux! Sinon le tuto a l’air sympa mais j’attends de le voir terminé!
-
Du très bon taf, je passerais aussi un coup sur la correction si le tutoriel est terminé et validé
Mais c’est vrai que certaines fautes sont violentes, même robin ne serait pas capable de les reproduire sous le stress
=> " cette partit ", voire même " vous l’aurais compris " ^^ -
J’avoue que même moi j’aurai fait mieux
-
oui je sais je m’en excuse, le tutoriel est pas stopper mais je le continuerai des le 24 juin au soir ^^ (la fin des cours pour moi)
-
" le tutoriel est pas stopper " ?
… Bon d’accord j’arrête
{ Bon courage, continue ^^ } -
Ce monde à besoin de plus de corrections orthographiques et grammaticales! musique épique
-
Vous inquiétez pas je passerai corriger quand ce sera fini ^^.
-
@‘gagoi’:
Vous inquiétez pas je passerai corriger quand ce sera fini ^^.
Tu sais, fait attention a ne pas avoir une bouteille d’alcool et des médocs quand tu corriges ^^.
-
Alors ?! Tu avances dans le tutoriel ?
-
@‘bbcmh3’:
Alors ?! Tu avances dans le tutoriel ?
Oui ^^
-
Ok merci !
-
bon voilà j’ai fait la génération dans le monde, demain je fini ^^, et le tutoriel sera fait, j’ai aussi ajouter un petit truc sur la pouce d’arbre.