Générer une structure



  • Sommaire

    Introduction

    Dans ce tutoriel, nous allons apprendre comment générer une structure. Une structure est un ensemble de blocs générés automatiquement dans le monde qui peuvent avoir plusieurs utilités (Décoration, coffre, etc..). On peut par exemple prendre l'exemple du village PNJ ou encore des mineshafts, donjons, etc...

    Pré-requis

    Code

    La classe principale :

    Tout d'abord, rendez-vous dans votre classe principale.
    à la suite de vos variables de blocs, d'items, etc... ajoutez ceci :

    StructureGenerator structureGenerator = new StructureGenerator();
    

    Vous aurez une erreur sur la déclaration, c'est normal, vous n'avez pas encore créé cette classe !
    Puis, dans la méthode preInit(), ajoutez ceci :

    GameRegistry.registerWorldGenerator(structureGenerator, 0);
    

    Vous aurez encore une erreur sur registerWorldGenerator(), ne vous en faites pas nous allons régler ça !

    Ce sera tout pour la classe principale !

    La classe de génération :

    Créez tout d'abord la classe StructureGenerator dans un nouveau package que j'appellerais gen pour génération.
    Vous devriez avoir ceci :

    public class StructureGenerator
    {
    
    }
    

    Pour pouvoir générer des choses dans notre monde (et plus précisément des structures), il suffit d'ajouter une interface à cette classe : l'interface IWorldGenerator !
    Faites le donc, vous devriez obtenir ceci:

    import cpw.mods.fml.common.IWorldGenerator;
    
    public class StructureGenerator implements IWorldGenerator
    {
    
    }
    

    Vous aurez une erreur sur le nom de la classe, c'est tout à fait normal, passez le curseur dessus et cliquez sur "Add Unimplemented Methods".
    Vous aurez une nouvelle méthode nommée generate() qui va nous permettre de... générer 😛

    public void generate(Random random, int chunkX, int chunkZ, World world, IChunkProvider chunkGenerator, IChunkProvider chunkProvider)
    {
    
    }
    

    Explication des paramètres:

    • Random: pour trouver une valeur de génération au hasard.
    • chunkX, chunkY, chunkZ: les coordonnées du chunk.
    • chunkGenerator, chunkProvider: des classes liées aux chunks que nous n'allons pas utiliser dans ce tutoriel.
      Comme nous voulons que notre classe soit polyvalente et puisse générer des structures dans n'importe quelle dimension, nous allons faire un petit switch sur l'id de la dimension en question:
    switch (world.provider.dimensionId)
    {
    case -1:
        generateNether(world, random, chunkX * 16, chunkZ * 16);
        break;
    case 0:
        generateSurface(world, random, chunkX * 16, chunkZ * 16);
        break;
    case 1:
        generateEnd(world, random, chunkX * 16, chunkZ * 16);
        break;
    }
    

    Votre classe finale devrait ressembler à ceci:

    import java.util.Random;
    
    import net.minecraft.world.World;
    import net.minecraft.world.chunk.IChunkProvider;
    import cpw.mods.fml.common.IWorldGenerator;
    
    public class StructureGenerator implements IWorldGenerator
    {
    
        public void generate(Random random, int chunkX, int chunkZ, World world, IChunkProvider chunkGenerator, IChunkProvider chunkProvider)
        {
            switch (world.provider.dimensionId)
            {
            case -1:
                generateNether(world, random, chunkX * 16, chunkZ * 16);
                break;
            case 0:
                generateSurface(world, random, chunkX * 16, chunkZ * 16);
                break;
            case 1:
                generateEnd(world, random, chunkX * 16, chunkZ * 16);
                break;
            }
    
        }
    
        private void generateSurface(World world, Random random, int i, int j)
        {
    
        }
    
        private void generateNether(World world, Random random, int i, int j)
        {
    
        }
    
        private void generateEnd(World world, Random random, int i, int j)
        {
    
        }
    }
    

    (Merci à agabou pour la structure du switch et les méthodes de générations).

    Ce sera tout pour l'instant, maintenant vous pouvez quitter cette classe.

    La classe de la structure :

    Pour créer notre structure, nous allons créer une nouvelle classe et nous allons faire hériter cette même classe de la classe WorldGenerator, comme ceci :

    import java.util.Random;
    
    import net.minecraft.world.World;
    import net.minecraft.world.chunk.IChunkProvider;
    import net.minecraft.world.gen.feature.WorldGenerator;
    import cpw.mods.fml.common.IWorldGenerator;
    
    public class WorldGenTotem extends WorldGenerator
    {
        public boolean generate(World world, Random rand, int x, int y, int z)
        {
            return false;
        }
    }
    

    Maintenant, tâchons de créer notre première structure ! Elle devrait ressembler à ça :

    0_1529759620143_1404996275-2014-07-10-14-42-21.png

    (Comme vous les voyez, c'est assez inratable).

    Maintenant, pour générer ça, rien de plus simple, ajoutez simplement ceci:

    world.setBlock(x, y, z, Blocks.cobblestone);
    world.setBlock(x, y + 1, z, Blocks.cobblestone);
    world.setBlock(x, y + 2, z, Blocks.sponge);
    

    (N'oubliez pas de changer le return false en return true, sinon votre génération ne marchera pas).

    Et c'est tout pour cette classe ! Pour finaliser le tout, rendez vous dans la classe StructureGeneration précédemment créée, et ajoutez dans la méthode generateSurface():

    int x1 = x + random.nextInt(16);
    int y1 = random.nextInt(128);	
    int z1 = z + random.nextInt(16);	
    (new WorldGenTotem()).generate(world, random, x1, y1, z1);
    

    Et voila !

    Bonus

    Générer au dessus d'un bloc défini :

    Imaginons que vous vouliez que votre structure se génère uniquement au dessus d'un bloc de sable, comment faire ?
    Eh bien c'est assez simple, il suffit de vérifier le bloc en dessous avant de générer !

    public boolean generate(World world, Random rand, int x, int y, int z)
    {
        if (world.getBlock(x, y - 1, z) == Blocks.sand)
        {
            world.setBlock(x, y, z, Blocks.cobblestone);
            world.setBlock(x, y + 1, z, Blocks.cobblestone);
            world.setBlock(x, y + 2, z, Blocks.sponge);
            return true;
        }
        return false;
    }
    

    Simple, mais pas tellement...
    En effet, ce code est fonctionnel, mais il ne convient pas du tout à notre objectif, qui est de générer une structure en surface, puisque les structures peuvent aussi générer sous terre! De plus, si on laissait ce bout de code tel qu'il est, le taux de génération baissera énormément !

    Nous allons donc pallier à ces deux problèmes!

    Pour faire en sorte que les structures génèrent uniquement à l'air libre, il suffit de vérifier que le bloc au dessus est de l'air, et ainsi de suite!

    public boolean generate(World world, Random rand, int x, int y, int z)
    {
        if (world.getBlock(x, y - 1, z) == Blocks.sand && world.isAirBlock(x, y + 1, z)
        {
            world.setBlock(x, y, z, Blocks.cobblestone);
            world.setBlock(x, y + 1, z, Blocks.cobblestone);
            world.setBlock(x, y + 2, z, Blocks.sponge);
            return true;
        }
        return false;
    }
    

    Ceci règle notre premier problème, quand au deuxième, il suffit d'ajouter un boucle for avant de générer la structure dans le StructureGenerator 😉

    private void generateSurface(World world, Random random, int x, int z)
    {
        int x1 = x + random.nextInt(16);
        int y1 = random.nextInt(128);
        int z1 = z + random.nextInt(16);
        for (int i = 0; i < 500; i++) // Il vaut mieux mettre une valeur élevée 
        {
            (new WorldGenTotem()).generate(world, random, x1, y1, z1);
        }
    }
    

    Et voilà ! Vous savez maintenant comment générer une structure au dessus d'un bloc défini!

    Générer dans un biome défini :

    Nous allons apprendre dans cette partie comment générer la structure dans un biome en particulier !

    Il suffit de vérifier le biome et de mettre la boucle for!

    private void generateSurface(World world, Random random, int x, int z)
    {
        int x1 = x + random.nextInt(16);
        int y1 = random.nextInt(128);
        int z1 = z + random.nextInt(16);
        for (int i = 0; i < 500; i++)
        {
            if (world.getBiomeGenForCoords(x1, z1) == BiomeGenBase.desert)
            {
                (new WorldGenTotem()).generate(world, random, x1, y1, z1);
            }
        }
    }
    

    Tadam ! Vous pouvez maintenant générer votre structure dans le biome de votre choix !

    Faire spawner un monstre dans votre structure :

    Pour cet exemple je vais spawner un creeper au dessus du bloc d'éponge.

    Dans la classe WorldGenTotem:

    @Override
    public boolean generate(World world, Random random, int x, int y, int z)
    {
        if (!world.isRemote)
            {
            world.setBlock(x, y, z, Blocks.cobblestone);
            world.setBlock(x, y + 1, z, Blocks.cobblestone);
            world.setBlock(x, y + 2, z, Blocks.sponge);
            EntityCreeper creeper = new EntityCreeper(world);
            creeper.setPosition(x, y + 3, z);
            world.spawnEntityInWorld(creeper);
            return true;
        }
        return false;
    }
    

    Et voila 🙂

    Résultat

    0_1529759545767_1407533222-2014-08-08-23-21-13.png

    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



  • Excellent tuto ! Mais est-il possible de faire en sorte qu'un certain mob spawn dans la structure ?


  • Administrateurs

    Par contre, si il n'y a pas de vidéo, il faudrait retiré la partie vidéo.



  • @Fine: Je pense que c'est possible, je vais essayer 😉
    @Robin: Je vais filmer la vidéo bientôt 🙂


  • Administrateurs

    D'accord, tu veux les accès à la chaine youtube ? Si oui, il me faudrait ton email.



  • MP 🙂



  • Ah, un dernier truc ^^ Comment faire spawner un coffre avec certains items en randomisation dedans ?



  • regarde le code de génération des coffre dans les mineshaft



  • @'isador34':

    regarde le code de génération des coffre dans les mineshaft

    Il passe par une classe annexe, il te faut créer une classe hériter de ChestGenHooks et de recréer se qui faut après regarde dans le donjons (moins complexe que le mineshaft).


  • Administrateurs

    world.isAirBlock(x, y, z) n'est pas la pour rien. (tutoriel modifié).



  • Excellent tutoriel :D, donc si je comprends bien, on peu générer par exemple des plantes sur la grass ? (Ce n'est pas que pour les grosses structures)



  • Merci 😄 Oui en effet, on peux générer de l'herbe avec ça 😉



  • Ah vraiment bien 😄



  • Super tuto et très utile ! Maintenant pour ce qui est de très grande structure existe t-il des logiciels permettant de créer son "donjon" et ensuite de l'exporter en JAVA ?



  • Il me semble avoir vu un logiciel pour convertir ses .schematic en Java, je crois que c'était sur les Minecraft Forums.





  • ça ne marcheras pas, ce logiciel était prévu dans la partie bonus avant de me rendre compte qu'il ne marche pas en 1.7 😞


  • Administrateurs

    Le logiciel fonctionne, il donne juste du code erroné car il n'a pas été mis à jour depuis longtemps.



  • Le code est vraiment érroné où il suffit juste de changer la fonction (les coordonnées et les blocs y sont) ?


  • Administrateurs

    Changer la fonction + ajouter ,3