コード例 #1
0
        private void growBranch(Random rand, int depth, BlockPos pos, float dx, float dy, float dz, float angleVerStart, float angleHorStart, float curWidth, float dieAt, float trunkWidthLoss, bool wideTrunk)
        {
            if (depth > 30)
            {
                Console.WriteLine("TreeGen.growBranch() aborted, too many branches!"); return;
            }

            TreeGenBranch branch = branchesByDepth[Math.Min(depth, branchesByDepth.Count - 1)];

            short[] outline = forestFloor.GetOutline();

            float widthloss                  = depth == 0 ? trunkWidthLoss : branch.WidthLoss(rand);
            float widthlossCurve             = branch.widthlossCurve;
            float branchspacing              = branch.branchSpacing.nextFloat(1, rand);
            float branchstart                = branch.branchStart.nextFloat(1, rand);
            float branchQuantityStart        = branch.branchQuantity.nextFloat(1, rand);
            float branchWidthMulitplierStart = branch.branchWidthMultiplier.nextFloat(1, rand);

            float reldistance, lastreldistance = 0;
            float totaldistance = curWidth / widthloss;

            int   iteration             = 0;
            float sequencesPerIteration = 1f / (curWidth / widthloss);


            float ddrag, angleVer, angleHor;

            // we want to place around the trunk/branch => offset the coordinates when growing stuff from the base
            float trunkOffsetX, trunkOffsetZ;

            BlockPos currentPos = new BlockPos();

            float branchQuantity, branchWidth;
            float sinAngleVer, cosAnglerHor, sinAngleHor;

            float currentSequence;

            LCGRandom lcgrand = lcgrandTL.Value;

            while (curWidth > 0 && iteration++ < 5000)
            {
                curWidth -= widthloss;
                if (widthlossCurve + curWidth / 20 < 1f)
                {
                    widthloss *= (widthlossCurve + curWidth / 20);
                }

                currentSequence = sequencesPerIteration * (iteration - 1);

                if (curWidth < dieAt)
                {
                    break;
                }

                angleVer = branch.angleVertEvolve.nextFloat(angleVerStart, currentSequence);
                angleHor = branch.angleHoriEvolve.nextFloat(angleHorStart, currentSequence);

                sinAngleVer  = GameMath.FastSin(angleVer);
                cosAnglerHor = GameMath.FastCos(angleHor);
                sinAngleHor  = GameMath.FastSin(angleHor);

                trunkOffsetX = Math.Max(-0.5f, Math.Min(0.5f, 0.7f * sinAngleVer * cosAnglerHor));
                trunkOffsetZ = Math.Max(-0.5f, Math.Min(0.5f, 0.7f * sinAngleVer * sinAngleHor));

                ddrag = branch.gravityDrag * (float)Math.Sqrt(dx * dx + dz * dz);

                dx += sinAngleVer * cosAnglerHor / Math.Max(1, Math.Abs(ddrag));
                dy += Math.Min(1, Math.Max(-1, GameMath.FastCos(angleVer) - ddrag));
                dz += sinAngleVer * sinAngleHor / Math.Max(1, Math.Abs(ddrag));

                int blockId = branch.getBlockId(curWidth, config.treeBlocks, this);
                if (blockId == 0)
                {
                    return;
                }

                currentPos.Set(pos.X + dx, pos.Y + dy, pos.Z + dz);

                PlaceResumeState state = getPlaceResumeState(currentPos, blockId, wideTrunk);

                if (state == PlaceResumeState.CanPlace)
                {
                    api.SetBlock(blockId, currentPos);

                    // Update the canopy outline of the tree for this block position
                    int idz = (int)(dz + 16);
                    int idx = (int)(dx + 16);
                    if (idz > 1 && idz < 31 && idx > 1 && idx < 31)
                    {
                        int canopyIndex = idz * 33 + idx;
                        outline[canopyIndex - 68]++;
                        outline[canopyIndex - 67]++;  //bias canopy shading towards the North (- z direction) for sun effects
                        outline[canopyIndex - 66]++;
                        outline[canopyIndex - 65]++;
                        outline[canopyIndex - 64]++;
                        outline[canopyIndex - 35]++;
                        outline[canopyIndex - 34] += 2;
                        outline[canopyIndex - 33] += 2;
                        outline[canopyIndex - 32] += 2;
                        outline[canopyIndex - 31]++;
                        outline[canopyIndex - 2]++;
                        outline[canopyIndex - 1] += 2;
                        outline[canopyIndex + 0] += 3;
                        outline[canopyIndex + 1] += 2;
                        outline[canopyIndex + 2]++;
                        outline[canopyIndex + 33]++;
                    }

                    if (vineGrowthChance > 0 && rand.NextDouble() < vineGrowthChance && config.treeBlocks.vinesBlock != null)
                    {
                        BlockFacing facing = BlockFacing.HORIZONTALS[rand.Next(4)];

                        BlockPos vinePos = currentPos.AddCopy(facing);
                        float    cnt     = 1 + rand.Next(11) * (vineGrowthChance + 0.2f);

                        while (api.GetBlockId(vinePos) == 0 && cnt-- > 0)
                        {
                            Block block = config.treeBlocks.vinesBlock;

                            if (cnt <= 0 && config.treeBlocks.vinesEndBlock != null)
                            {
                                block = config.treeBlocks.vinesEndBlock;
                            }

                            block.TryPlaceBlockForWorldGen(api, vinePos, facing, lcgrand);
                            vinePos.Down();
                        }
                    }
                }
                else
                {
                    if (state == PlaceResumeState.Stop)
                    {
                        return;
                    }
                }

                reldistance = (float)Math.Sqrt(dx * dx + dy * dy + dz * dz) / totaldistance;


                if (reldistance < branchstart)
                {
                    continue;
                }

                if (reldistance > lastreldistance + branchspacing * (1f - reldistance))
                {
                    branchspacing   = branch.branchSpacing.nextFloat(1, rand);
                    lastreldistance = reldistance;

                    if (branch.branchQuantityEvolve != null)
                    {
                        branchQuantity = branch.branchQuantityEvolve.nextFloat(branchQuantityStart, currentSequence);
                    }
                    else
                    {
                        branchQuantity = branch.branchQuantity.nextFloat(1, rand);
                    }

                    float prevHorAngle = 0f;
                    float horAngle;
                    float minHorangleDist = Math.Min(GameMath.PI / 5, branch.branchHorizontalAngle.var / 5);


                    bool first = true;

                    while (branchQuantity-- > 0)
                    {
                        if (branchQuantity < 1 && rand.NextDouble() < branchQuantity)
                        {
                            break;
                        }

                        curWidth *= branch.branchWidthLossMul;

                        horAngle = angleHor + branch.branchHorizontalAngle.nextFloat(1, rand);

                        int tries = 10;
                        while (!first && Math.Abs(horAngle - prevHorAngle) < minHorangleDist && tries-- > 0)
                        {
                            float newAngle = angleHor + branch.branchHorizontalAngle.nextFloat(1, rand);
                            if (Math.Abs(horAngle - prevHorAngle) < Math.Abs(newAngle - prevHorAngle))
                            {
                                horAngle = newAngle;
                            }
                        }

                        if (branch.branchWidthMultiplierEvolve != null)
                        {
                            branchWidth = curWidth * branch.branchWidthMultiplierEvolve.nextFloat(branchWidthMulitplierStart, currentSequence);
                        }
                        else
                        {
                            branchWidth = branch.branchWidthMultiplier.nextFloat(curWidth, rand);
                        }

                        growBranch(
                            rand,
                            depth + 1,
                            pos, dx + trunkOffsetX, dy, dz + trunkOffsetZ,
                            branch.branchVerticalAngle.nextFloat(1, rand),
                            horAngle,
                            branchWidth,
                            Math.Max(0, branch.dieAt.nextFloat(1, rand)),
                            trunkWidthLoss, false
                            );

                        first        = false;
                        prevHorAngle = angleHor + horAngle;
                    }
                }
            }
        }
コード例 #2
0
        private void growBranch(Random rand, int depth, BlockPos pos, float dx, float dy, float dz, float angleVerStart, float angleHorStart, float curWidth, float dieAt)
        {
            if (depth > 30)
            {
                Console.WriteLine("TreeGen.growBranch() aborted, too many branches!"); return;
            }

            TreeGenBranch branch = branchesByDepth[Math.Min(depth, branchesByDepth.Count - 1)];


            float branchspacing              = branch.branchSpacing.nextFloat(1, rand);
            float branchstart                = branch.branchStart.nextFloat(1, rand);
            float branchQuantityStart        = branch.branchQuantity.nextFloat(1, rand);
            float branchWidthMulitplierStart = branch.branchWidthMultiplier.nextFloat(1, rand);

            float reldistance = 0, lastreldistance = 0;
            float totaldistance = curWidth / branch.widthloss;

            int   iteration             = 0;
            float sequencesPerIteration = 1f / (curWidth / branch.widthloss);


            float ddrag = 0, angleVer = 0, angleHor = 0;

            // we want to place around the trunk/branch => offset the coordinates when growing stuff from the base
            float trunkOffsetX = 0, trunkOffsetZ = 0, trunkOffsetY = 0;

            BlockPos currentPos;

            float branchQuantity, branchWidth;
            float sinAngleVer, cosAnglerHor, sinAngleHor;

            float currentSequence;

            LCGRandom lcgrand = lcgrandTL.Value;

            while (curWidth > 0 && iteration++ < 5000)
            {
                curWidth -= branch.widthloss;

                currentSequence = sequencesPerIteration * (iteration - 1);

                if (curWidth < dieAt)
                {
                    break;
                }

                angleVer = branch.angleVertEvolve.nextFloat(angleVerStart, currentSequence);
                angleHor = branch.angleHoriEvolve.nextFloat(angleHorStart, currentSequence);

                sinAngleVer  = GameMath.FastSin(angleVer);
                cosAnglerHor = GameMath.FastCos(angleHor);
                sinAngleHor  = GameMath.FastSin(angleHor);

                trunkOffsetX = Math.Max(-0.5f, Math.Min(0.5f, 0.7f * sinAngleVer * cosAnglerHor));
                trunkOffsetY = Math.Max(-0.5f, Math.Min(0.5f, 0.7f * cosAnglerHor)) + 0.5f;
                trunkOffsetZ = Math.Max(-0.5f, Math.Min(0.5f, 0.7f * sinAngleVer * sinAngleHor));

                ddrag = branch.gravityDrag * (float)Math.Sqrt(dx * dx + dz * dz);

                dx += sinAngleVer * cosAnglerHor / Math.Max(1, Math.Abs(ddrag));
                dy += Math.Min(1, Math.Max(-1, GameMath.FastCos(angleVer) - ddrag));
                dz += sinAngleVer * sinAngleHor / Math.Max(1, Math.Abs(ddrag));

                int blockId = getBlockId(curWidth);
                if (blockId == 0)
                {
                    return;
                }

                currentPos = pos.AddCopy(dx, dy, dz);

                PlaceResumeState state = getPlaceResumeState(currentPos, blockId);

                if (state == PlaceResumeState.CanPlace)
                {
                    api.SetBlock(blockId, currentPos);

                    if (vineGrowthChance > 0 && rand.NextDouble() < vineGrowthChance && config.treeBlocks.vinesBlock != null)
                    {
                        BlockFacing facing = BlockFacing.HORIZONTALS[rand.Next(4)];

                        BlockPos vinePos = currentPos.AddCopy(facing);
                        float    cnt     = 1 + rand.Next(11) * (vineGrowthChance + 0.2f);

                        while (api.GetBlockId(vinePos) == 0 && cnt-- > 0)
                        {
                            Block block = config.treeBlocks.vinesBlock;

                            if (cnt <= 0 && config.treeBlocks.vinesEndBlock != null)
                            {
                                block = config.treeBlocks.vinesEndBlock;
                            }

                            block.TryPlaceBlockForWorldGen(api, vinePos, facing, lcgrand);
                            vinePos.Down();
                        }
                    }
                }
                else
                {
                    if (state == PlaceResumeState.Stop)
                    {
                        return;
                    }
                }

                reldistance = (float)Math.Sqrt(dx * dx + dy * dy + dz * dz) / totaldistance;


                if (reldistance < branchstart)
                {
                    continue;
                }

                if (reldistance > lastreldistance + branchspacing * (1f - reldistance))
                {
                    branchspacing   = branch.branchSpacing.nextFloat(1, rand);
                    lastreldistance = reldistance;

                    if (branch.branchQuantityEvolve != null)
                    {
                        branchQuantity = branch.branchQuantityEvolve.nextFloat(branchQuantityStart, currentSequence);
                    }
                    else
                    {
                        branchQuantity = branch.branchQuantity.nextFloat(1, rand);
                    }

                    float prevHorAngle = 0f;
                    float horAngle;
                    float minHorangleDist = Math.Min(GameMath.PI / 10, branch.branchHorizontalAngle.var / 5);


                    bool first = true;

                    while (branchQuantity-- > 0)
                    {
                        if (branchQuantity < 1 && rand.NextDouble() < branchQuantity)
                        {
                            break;
                        }

                        curWidth *= branch.branchWidthLossMul;

                        horAngle = branch.branchHorizontalAngle.nextFloat(1, rand);

                        int tries = 5;
                        while (!first && Math.Abs(horAngle - prevHorAngle) < minHorangleDist && tries-- > 0)
                        {
                            horAngle = branch.branchHorizontalAngle.nextFloat(1, rand);
                        }

                        if (branch.branchWidthMultiplierEvolve != null)
                        {
                            branchWidth = curWidth * branch.branchWidthMultiplierEvolve.nextFloat(branchWidthMulitplierStart, currentSequence);
                        }
                        else
                        {
                            branchWidth = branch.branchWidthMultiplier.nextFloat(curWidth, rand);
                        }

                        growBranch(
                            rand,
                            depth + 1,
                            pos, dx + trunkOffsetX, dy, dz + trunkOffsetZ,
                            branch.branchVerticalAngle.nextFloat(1, rand),
                            angleHor + branch.branchHorizontalAngle.nextFloat(1, rand),
                            branchWidth,
                            Math.Max(0, branch.dieAt.nextFloat(1, rand))
                            );

                        first        = false;
                        prevHorAngle = horAngle;
                    }
                }
            }
        }