Minecraft的世界生成过程(六)村庄

本文探讨Minecraft村庄的生成过程,包括构造村庄组件数据、生成村庄的具体步骤。通过计算和选择组件,如田地、房屋、铁匠铺,以及生成水井和道路,形成村庄布局。接着,介绍在provideChunk后,populate函数如何添加点缀并生成村庄。村庄生成涉及的类和方法进行了简要说明,揭示了Minecraft建筑硬编码生成的特点。
摘要由CSDN通过智能技术生成

本篇内容是生成村庄,生成其他建筑的过程也差不多就不研究了(代码太多也研究不完)

构造村庄组件数据

它的recursiveGenerate继承自这里,类名net.minecraft.world.gen.structure.MapGenStructure

    // 只是生成结构数据,暂时不操作方块
    protected final void recursiveGenerate(World worldIn, final int chunkX, final int chunkZ, int p_180701_4_, int p_180701_5_, ChunkPrimer chunkPrimerIn)
    {
        // 尝试载入保存的结构数据
        this.func_143027_a(worldIn);

        // 载入失败则生成
        if (!this.structureMap.containsKey(Long.valueOf(ChunkCoordIntPair.chunkXZ2Int(chunkX, chunkZ))))
        {
            this.rand.nextInt();

            try
            {
                // 子类实现判断能否生成
                if (this.canSpawnStructureAtCoords(chunkX, chunkZ))
                {
                    // 子类实现的生成数据
                    StructureStart structurestart = this.getStructureStart(chunkX, chunkZ);
                    this.structureMap.put(Long.valueOf(ChunkCoordIntPair.chunkXZ2Int(chunkX, chunkZ)), structurestart);
                    // 保存数据
                    this.func_143026_a(chunkX, chunkZ, structurestart);
                }
            }
            catch (Throwable throwable)
            {
                // ...
            }
        }
    }

村庄构造流程是这样的:计算村庄里的组件(田、房子、铁匠铺等),构造水井,构造水井周围的道路,沿着道路随机选之前计算好的组件来构造或者构造新的道路

类名net.minecraft.world.gen.structure.MapGenVillage

    protected boolean canSpawnStructureAtCoords(int chunkX, int chunkZ)
    {
        int _chunkX = chunkX;
        int _chunkZ = chunkZ;

        // field_82665_g是村庄平均距离,默认=32
        // field_82666_h是村庄最小距离,默认=8
        // 所以在坐标为n * 32 + 12的区块附近比较可能找到村庄

        // 防止在原点附近生成的村庄可能靠太近

        if (chunkX < 0)
        {
            chunkX -= this.field_82665_g - 1;
        }

        if (chunkZ < 0)
        {
            chunkZ -= this.field_82665_g - 1;
        }

        // 注意这是整数除法
        int keyChunkX = chunkX / this.field_82665_g;
        int keyChunkZ = chunkZ / this.field_82665_g;
        // 设置世界随机种子并返回Random对象
        Random random = this.worldObj.setRandomSeed(keyChunkX, keyChunkZ, 10387312);
        // 附近可以生成村庄的区块坐标
        // keyChunkXZ * field_82665_g后变成了field_82665_g的倍数
        keyChunkX = keyChunkX * this.field_82665_g + random.nextInt(this.field_82665_g - this.field_82666_h);
        keyChunkZ = keyChunkZ * this.field_82665_g + random.nextInt(this.field_82665_g - this.field_82666_h);

        if (_chunkX == keyChunkX && _chunkZ == keyChunkZ)
        {
            // 判断生物群系是否可以生成村庄
            return this.worldObj.getWorldChunkManager().areBiomesViable(_chunkX * 16 + 8, _chunkZ * 16 + 8, 0, villageSpawnBiomes);
        }

        return false;
    }

    protected StructureStart getStructureStart(int chunkX, int chunkZ)
    {
        // terrainType默认为0,超平坦为1,影响村庄各组件数量
        // 读取用的键名为size,所以后面就叫size了
        return new MapGenVillage.Start(this.worldObj, this.rand, chunkX, chunkZ, this.terrainType);
    }

    public static class Start extends StructureStart
        {
   
            /** well ... thats what it does */
            private boolean hasMoreThanTwoComponents;

            public Start()
            {
            }

            public Start(World worldIn, Random rand, int x, int z, int size)
            {
                super(x, z);
                // 计算这个村庄的组件
                List<StructureVillagePieces.PieceWeight> pieces = StructureVillagePieces.getStructureVillageWeightedPieceList(rand, size);
                // 构造水井
                StructureVillagePieces.Start startComponent = new StructureVillagePieces.Start(worldIn.getWorldChunkManager(), 0, rand, x * 16 + 2, z * 16 + 2, pieces, size);
                this.components.add(startComponent);
                // 这里构造了水井周围的道路并加入components和field_74930_j
                startComponent.buildComponent(startComponent, this.components, rand);

                // 构造子组件(一开始只有道路)

                List<StructureComponent> list1 = startComponent.field_74930_j;
                List<StructureComponent> list2 = startComponent.field_74932_i;

                // 优先构造list1的组件(道路),然后构造list2的
                while (!list1.isEmpty() || !list2.isEmpty())
                {
                    if (list1.isEmpty())
                    {
                        // 随机顺序
                        int i = rand.nextInt(list2.size());
                        StructureComponent structurecomponent = (StructureComponent)list2.remove(i);
                        structurecomponent.buildComponent(startComponent, this.components, rand);
                    }
                    else
                    {
                        int j = rand.nextInt(list1.size());
                        StructureComponent structurecomponent2 = (StructureComponent)list1.remove(j);
                        structurecomponent2.buildComponent(startComponent, this.components, rand);
                    }
                }

                // 计算包围盒,使所有组件在包围盒内
                this.updateBoundingBox();

                // 计算除了道路的组件数量

                int componentCount = 0;

                for (StructureComponent component : this.components)
                {
                    if (!(component instanceof StructureVillagePieces.Road))
                    {
                        ++componentCount;
                    }
                }

                this.hasMoreThanTwoComponents = componentCount > 2;
            }

            // ...
        }

类名net.minecraft.world.gen.structure.StructureVillagePieces

    // 计算这个村庄的组件
    public static List<StructureVillagePieces.PieceWeight> getStructureVillageWeightedPieceList(Random random, int size)
    {
        List<StructureVillagePieces.PieceWeight> list = Lists.<StructureVillagePieces.PieceWeight>newArrayList();
        // 后两个参数是权重和数量(villagePiecesLimit)
        list.add(new StructureVillagePieces.PieceWeight(StructureVillagePieces.House4Garden.class, 4, MathHelper.getRandomIntegerInRange(random, 2 + size, 4 + size * 2)));
        list.add(new StructureVillagePieces.PieceWeight(StructureVillagePieces.Church.class, 20, MathHelper.getRandomIntegerInRange(random, 0 + size, 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值