/// <summary>
 /// Calculates information for each kingdom, such as its personality
 /// TODO - add kingdom 'types' such as dessert, horse riders, idk what else
 /// </summary>
 public void GenerateKingdoms()
 {
     foreach (Kingdom k in Kingdoms)
     {
         k.SetAggression(GenRan.Random());
     }
 }
    private void GenerateRiver(Vec2i start)
    {
        Vec2i end = null;

        for (int i = 1; i < 100; i++)
        {
            if (end != null)
            {
                break;
            }
            for (int j = 0; j < DIRS.Length; j++)
            {
                Vec2i pos = start + DIRS[j] * i;
                if (GameGenerator2.InBounds(pos))
                {
                    if (GameGen.TerGen.ChunkBases[pos.x, pos.z].Biome == ChunkBiome.ocean)
                    {
                        end = pos;
                        break;
                    }
                }
            }
        }
        if (end == null)
        {
            return;
        }



        LineI li = new LineI(start, end);


        List <Vec2i> basic = li.ConnectPoints();

        float val1 = GenRan.Random(0.1f, 0.001f);
        float val2 = GenRan.Random(0.1f, 0.001f);
        int   val3 = GenRan.RandomInt(8, 32);
        int   val4 = GenRan.RandomInt(8, 32);

        for (int i = 0; i < basic.Count; i++)
        {
            basic[i] += new Vec2i((int)(val3 * Mathf.Sin(i * val1)), (int)(val4 * Mathf.Sin(i * val2)));
        }
        for (int i = 0; i < basic.Count - 1; i++)
        {
            Vec2i v1 = basic[i];
            Vec2i v2 = basic[i + 1];
            LineI i2 = new LineI(v1, v2);
            foreach (Vec2i v in i2.ConnectPoints())
            {
                GameGen.TerGen.ChunkBases[v.x, v.z].SetChunkFeature(new ChunkRiverNode(v));
            }
        }
        return;
    }
Example #3
0
    /// <summary>
    /// We override the create world object function for a tree. This is done as we need to load in multiple
    /// parts of the tree
    /// </summary>
    /// <param name="transform"></param>
    /// <returns></returns>
    public override WorldObject CreateWorldObject(Transform transform = null)
    {
        //Create random with seed unique to tree position - this ensures tree should be same every time.
        GenerationRandom genRan = new GenerationRandom(WorldPosition.x * World.WorldSize * World.ChunkSize + WorldPosition.z);
        int   canopy            = genRan.RandomInt(3, 7);
        float angleOffset       = genRan.Random(0, Mathf.PI);

        float       range    = Mathf.Sqrt(canopy * 0.5f) * 0.8f;
        WorldObject treeBase = WorldObject.CreateWorldObject(this, transform);
        Vec2i       zero     = new Vec2i(0, 0);

        Vector3[] canopyPositions = new Vector3[canopy];

        for (int i = 0; i < canopy; i++)
        {
            //Define the positions of each canopy as roughly circular about the middle of the tree.
            float   angle  = (Mathf.PI * 2 / (canopy)) * i + angleOffset;
            Vector2 delta  = new Vector2(Mathf.Cos(angle), Mathf.Sin(angle)) * range + genRan.RandomVector2(-0.1f, 0.1f);
            float   height = 1.8f + genRan.Random(0, 1f);
            //Store the total position for use later, then generate the canopy itself.
            canopyPositions[i] = new Vector3(delta.x, height, delta.y);
            TreeCanopy tr = new TreeCanopy(zero, canopyPositions[i]);
            tr.SetRandom(genRan);
            tr.CreateWorldObject(treeBase.transform);
        }
        //Generate the trunk

        float      trunkHeight = 1.2f;
        float      trunkScale  = 1.2f;
        TreeBranch trunk       = new TreeBranch(zero);

        trunk.SetCharacteristic(Vector3.zero, new Vector3(0, 0, 0), new Vector3(1, trunkScale, 1));
        WorldObject trunkObj = trunk.CreateWorldObject(treeBase.transform);
        //MeshCollider mc  =trunkObj.gameObject.AddComponent<MeshCollider>();
        //mc.sharedMesh = trunkObj.gameObject.GetComponent<MeshFilter>().mesh;
        Vector3 trunkTop = Vector3.up * trunkHeight * trunkScale; //Scale to correct height

        foreach (Vector3 v in canopyPositions)
        {
            TreeBranch canopyBranch = new TreeBranch(zero);
            //Calculate the Euler angles from the branch base to the canopy
            Vector3 delta_pos = v - trunkTop;
            Quaternion.FromToRotation(Vector3.up, delta_pos);
            //Vector3 rot = Quaternion.FromToRotation(trunkTop, v*5f).eulerAngles;
            Vector3 rot   = Quaternion.FromToRotation(Vector3.up, delta_pos).eulerAngles;
            float   scale = Vector3.Distance(v, trunkTop) / trunkHeight;
            canopyBranch.SetCharacteristic(trunkTop, rot, new Vector3(1 / scale, scale, 1 / scale));
            canopyBranch.CreateWorldObject(treeBase.transform);
        }

        return(treeBase);
    }
Example #4
0
    public override WorldObject CreateWorldObject(Transform transform = null)
    {
        GenerationRandom genRan = new GenerationRandom(WorldPosition.GetHashCode() * 13);
        int count = genRan.RandomInt(2, 5);

        WorldObject r1 = null;

        for (int i = 0; i < count; i++)
        {
            Vector3 pos   = genRan.RandomVector3(-MaxSize, MaxSize, (i) * 0.1f, (i) * 0.2f + 0.1f, -MaxSize, MaxSize) / 100f;
            float   rSize = genRan.Random(0.5f, 1.5f);
            Rock    r     = new Rock(WorldPosition, pos, rSize);

            if (i == 0)
            {
                r1 = r.CreateWorldObject(transform);
            }
            else
            {
                WorldObject rn = r.CreateWorldObject(r1.transform);
                rn.transform.localPosition = pos;
            }
        }
        return(r1);
    }
Example #5
0
    /// <summary>
    /// Generates a chunk that has no special land features
    /// </summary>
    /// <param name="x"></param>
    /// <param name="z"></param>
    /// <param name="cb"></param>
    /// <returns></returns>
    private ChunkData GenerateSimpleChunk(int x, int z, ChunkBase2 cb)
    {
        if (cb.Biome == ChunkBiome.ocean)
        {
            return(new ChunkData(x, z, (int[, ])OCEAN.Clone(), false));
        }/*
          * if(cb.Biome == ChunkBiome.dessert)
          * {
          * return new ChunkData(x, z, (int[,])EMPTY_DESERT.Clone(), cb.IsLand, 1, (float[,])OCEAN_HEIGHT.Clone());
          * }if(cb.Biome == ChunkBiome.mountain)
          * {
          * return new ChunkData(x, z, (int[,])MOUNTAIN.Clone(), cb.IsLand, 1, (float[,])OCEAN_HEIGHT.Clone());
          *
          * }*/
        int[,] tiles = (int[, ])(cb.Biome == ChunkBiome.dessert ? EMPTY_DESERT.Clone() : cb.Biome == ChunkBiome.mountain ? MOUNTAIN.Clone() : EMPTY_PLAINS.Clone());

        GenerationRandom genRan = new GenerationRandom(Seed + x << 16 + z);

        //if(genRan.Random() > 0.1f)
        //    return new ChunkData(x, z, tiles, cb.IsLand);

        Dictionary <int, WorldObjectData> obs = new Dictionary <int, WorldObjectData>(256);

        float[,] heights = new float[World.ChunkSize, World.ChunkSize];
        for (int i = 0; i < World.ChunkSize; i++)
        {
            for (int j = 0; j < World.ChunkSize; j++)
            {
                if (genRan.Random() < 0.01f)
                {
                    //obs.Add(WorldObject.ObjectPositionHash(i,j), new Tree(new Vec2i(x * World.ChunkSize + i, z * World.ChunkSize + j)));
                }
                else if (genRan.Random() < 0.3f)
                {
                    //obs.Add(WorldObject.ObjectPositionHash(i, j), new Tree(new Vec2i(x * World.ChunkSize + i, z * World.ChunkSize + j)));
                }
                heights[i, j] = GameGen.TerGen.GetWorldHeightAt(x * World.ChunkSize + i, z * World.ChunkSize + j);
            }
        }
        ChunkData cd = new ChunkData(x, z, tiles, true, cb.Height, heightMap: heights);

        return(cd);
    }
Example #6
0
    /// <summary>
    /// Decides the tile placement in settlement coordinates of all entrances, based on
    /// the entrance direction data <see cref="Shell.LocationData"/>
    /// </summary>
    /// <returns></returns>
    private Vec2i DecideSettlementEntrance()
    {
        List <Vec2i> entrances = new List <Vec2i>();

        for (int i = 0; i < 8; i += 2)
        {
            int ip1 = (i + 1) % 8;

            if (Shell.LocationData.EntranceDirections[i] || Shell.LocationData.EntranceDirections[ip1])
            {
                Vec2i side = Vec2i.QUAD_DIR[i / 2];

                float xAmount = GenerationRandom.Random(0.8f, 0.95f) * side.x;
                float zAmount = GenerationRandom.Random(0.8f, 0.95f) * side.z;
                Vec2i pos     = Middle + new Vec2i((int)(xAmount * TileSize / 2), (int)(zAmount * TileSize / 2));
                entrances.Add(pos);
            }
        }

        return(GenerationRandom.RandomFromList(entrances));
    }
    /// <summary>
    /// Generates a chunk that has no special land features
    /// </summary>
    /// <param name="x"></param>
    /// <param name="z"></param>
    /// <param name="cb"></param>
    /// <returns></returns>
    private ChunkData GenerateSimpleChunk(int x, int z, ChunkBase cb)
    {
        if (!cb.IsLand)
        {
            return(new ChunkData(x, z, (int[, ])OCEAN.Clone(), cb.IsLand));
        }
        if (cb.Biome == ChunkBiome.dessert)
        {
            return(new ChunkData(x, z, (int[, ])EMPTY_DESERT.Clone(), cb.IsLand));
        }
        int[,] tiles = (int[, ])EMPTY_PLAINS.Clone();

        GenerationRandom genRan = new GenerationRandom(Seed + x << 16 + z);

        //if(genRan.Random() > 0.1f)
        //    return new ChunkData(x, z, tiles, cb.IsLand);

        Dictionary <int, WorldObjectData> obs = new Dictionary <int, WorldObjectData>(256);

        for (int i = 0; i < World.ChunkSize; i++)
        {
            for (int j = 0; j < World.ChunkSize; j++)
            {
                if (genRan.Random() < 0.01f)
                {
                    obs.Add(WorldObject.ObjectPositionHash(i, j), new Tree(new Vec2i(x * World.ChunkSize + i, z * World.ChunkSize + j)));
                }
                else if (genRan.Random() < 0.3f)
                {
                    //obs.Add(WorldObject.ObjectPositionHash(i, j), new Tree(new Vec2i(x * World.ChunkSize + i, z * World.ChunkSize + j)));
                }
            }
        }
        ChunkData cd = new ChunkData(x, z, tiles, cb.IsLand, obs);

        return(cd);
    }
Example #8
0
    /// <summary>
    /// Calculates the total number of cities, towns, and villages this kingdom should have
    /// Number of each is partly random, partly based on total size of kingdom
    /// </summary>
    /// <param name="k"></param>
    /// <returns></returns>
    private KingdomTotalSettlements CalculateSettlementCount(Kingdom k)
    {
        //In the region of 200,000
        int kingdomSize  = k.ClaimedChunks.Count;
        int relSize      = Mathf.CeilToInt(kingdomSize / 80000f);
        int cityCount    = (int)(1 + GenRan.Random(0.5f, 1.5f) * relSize);
        int townCount    = (int)(5 + GenRan.Random(2, 4) * relSize);
        int villageCount = (int)(4 + GenRan.Random(4, 7) * relSize);


        Debug.Log("Kingdom " + k + " has size " + relSize + " -> City: " + cityCount + ", Town: " + townCount + ", Village: " + villageCount);
        KingdomTotalSettlements kts = new KingdomTotalSettlements();

        kts.CityCount    = cityCount;
        kts.TownCount    = townCount;
        kts.VillageCount = villageCount;
        return(kts);
    }
Example #9
0
    /// <summary>
    ///
    /// </summary>
    /// <param name="genRan">The RNG used for this building</param>
    /// <param name="obj">The object to place in the building</param>
    /// <param name="height">The height above the ground the object should sit</param>
    /// <param name="vox">The voxel data of this building. Only required if 'requireWallBacking' is true</param>
    /// <param name="build">The building to place the object in</param>
    /// <param name="distFromWall">The distance from a wall the object should be placed</param>
    /// <param name="wallIndex">Defines the wall we should attempt to place this object on. The 'i'th wall defines the wall
    /// connecting build.BoundingWall[i] -> build.BoundingWall[i+1]. If left as default value (-1), an index will be randomly generated</param>
    /// <param name="requireWallBacking">If true, then we will search for a point on the wall that is backed against a wall.
    /// Used to stop certain objects being placed in front of windows</param>
    /// <param name="forcePlace">If true, then we do not check for intersection with other objects in the building</param>
    /// <param name="attemptsCount">The number of attempts made to place the object on this wall</param>
    /// <returns>True if object is placed sucesfully, false otherwise</returns>
    public static bool PlaceObjectAgainstWall(GenerationRandom genRan, WorldObjectData obj, float height,
                                              BuildingVoxels vox, Building build, float distFromWall = 0, bool requireWallBacking = false, int distToEntr = 2,
                                              bool forcePlace = false, int attemptsCount = 5)
    {
        if (build.InsideWallPoints == null)
        {
            build.InsideWallPoints = FindInsideWallBoundryPoints(vox, build);
        }

        //Check attempts count
        attemptsCount--;
        if (attemptsCount == 0)
        {
            return(false);
        }

        float wallDisp = genRan.Random();
        //Define the position as the start pos + lambda*dir
        //Select a random position from all wall points
        Vec2i pos = genRan.RandomFromArray(build.InsideWallPoints);

        //If too close to entrance, try another placement
        if (build.Entrance != null && pos.QuickDistance(build.Entrance) < distToEntr * distToEntr)
        {
            return(PlaceObjectAgainstWall(genRan, obj, height, vox, build, distFromWall, requireWallBacking, distToEntr, forcePlace, attemptsCount));
        }
        //If the object is too close to any of the corners, try again
        foreach (Vec2i v in build.BoundingWall)
        {
            if (v.QuickDistance(pos) < 2)
            {
                return(PlaceObjectAgainstWall(genRan, obj, height, vox, build, distFromWall, requireWallBacking, distToEntr, forcePlace, attemptsCount));
            }
        }

        Vec2i faceDirection = GetWallPointDirection(build, pos);

        //If we require a backing wall, we check the position
        if (requireWallBacking)
        {
            Vec2i wPos = pos - faceDirection;
            for (int y = 0; y < 4; y++)
            {
                VoxelNode vn = vox.GetVoxelNode(wPos.x, y, wPos.z);
                //If there is no node (nothing set) then this position is not valid
                if (!vn.IsNode)
                {
                    return(PlaceObjectAgainstWall(genRan, obj, height, vox, build, distFromWall, requireWallBacking, distToEntr, forcePlace, attemptsCount));
                }
                if (vn.Voxel == Voxel.glass || vn.Voxel == Voxel.none)
                {
                    return(PlaceObjectAgainstWall(genRan, obj, height, vox, build, distFromWall, requireWallBacking, distToEntr, forcePlace, attemptsCount));
                }
            }
        }
        Vector3 finPos   = pos.AsVector3() + faceDirection.AsVector3() * distFromWall + Vector3.up * height;
        float   rotation = Vec2i.Angle(Vec2i.Forward, faceDirection);

        obj.SetPosition(finPos).SetRotation(rotation);
        if (!forcePlace)
        {
            foreach (WorldObjectData obj_ in build.GetBuildingExternalObjects())
            {
                if (obj.Intersects(obj_))
                {
                    return(PlaceObjectAgainstWall(genRan, obj, height, vox, build, distFromWall, requireWallBacking, distToEntr, forcePlace, attemptsCount));
                }
            }
        }


        //obj.SetPosition(finPos);
        build.AddInternalObject(obj);
        return(true);
    }
Example #10
0
    private ChunkData GenerateRiverChunk(int x, int z, ChunkBase cb)
    {
        GenerationRandom genRan = new GenerationRandom(new Vec2i(x, z).GetHashCode() + Seed);

        int[,] tiles            = new int[World.ChunkSize, World.ChunkSize];
        WorldObjectData[,] data = new WorldObjectData[World.ChunkSize, World.ChunkSize];

        RiverNode rn        = cb.RiverNode;
        Vec2i     exitDelta = rn.RiverExitDelta;
        Vec2i     entrDelta = rn.RiverEntranceDelta;

        if (exitDelta == null)
        {
            exitDelta = new Vec2i(0, 0);
        }
        if (entrDelta == null)
        {
            entrDelta = new Vec2i(0, 0);
        }

        //Calculatee the tile position of the entrance and exit point of the river
        int entrX = (entrDelta.x == 1) ? 16 : ((entrDelta.x == 0) ? 8 : 0);
        int entrZ = (entrDelta.z == 1) ? 16 : ((entrDelta.z == 0) ? 8 : 0);

        int exitX = (exitDelta.x == 1) ? 16 : ((exitDelta.x == 0) ? 8 : 0);
        int exitZ = (exitDelta.z == 1) ? 16 : ((exitDelta.z == 0) ? 8 : 0);



        float dx = entrX - exitX;
        float dz = entrZ - exitZ;
        //If dx or dz is 0, then
        float a, b, c;
        bool  angle = (dx != 0 && dz != 0);
        float divBy = angle ? 2 : 1;

        if (dx == 0)
        {
            a = 0;
            b = 1;
            c = -entrX;
        }
        else if (dz == 0)
        {
            a = 1;
            b = 0;
            c = -entrZ;
        }
        else
        {
            float m = dz / dx;
            c = -(entrZ - m * entrX);

            a = 1;
            b = -m;
        }

        float dem_sqr = (a * a + b * b);

        for (int tx = 0; tx < World.ChunkSize; tx++)
        {
            for (int tz = 0; tz < World.ChunkSize; tz++)
            {
                float dist_sqr = ((a * tz + b * tx + c) * (a * tz + b * tx + c)) / dem_sqr;
                if (dist_sqr < (cb.RiverNode.EntranceWidth * cb.RiverNode.EntranceWidth) / divBy)
                {
                    Vector2 off = new Vector2(x * World.ChunkSize + tx, z * World.ChunkSize + tz);
                    //Debug.Log("here");
                    tiles[tx, tz] = Tile.WATER.ID;

                    if (!(data[tx, tz] is Water))
                    {
                        data[tx, tz] = new Water(new Vec2i(x * World.ChunkSize + tx, z * World.ChunkSize + tz));
                        (data[tx, tz] as Water).SetUVOffset(off);
                    }

                    if (tx < World.ChunkSize - 1 && !(data[tx + 1, tz] is Water))
                    {
                        data[tx + 1, tz] = new Water(new Vec2i(x * World.ChunkSize + tx + 1, z * World.ChunkSize + tz));
                        (data[tx + 1, tz] as Water).SetUVOffset(off + new Vector2(1, 0));
                    }
                    if (tz < World.ChunkSize - 1 && !(data[tx, tz + 1] is Water))
                    {
                        data[tx, tz + 1] = new Water(new Vec2i(x * World.ChunkSize + tx, z * World.ChunkSize + tz + 1));
                        (data[tx, tz + 1] as Water).SetUVOffset(off + new Vector2(0, 1));
                    }
                    if (tx < World.ChunkSize - 1 && tz < World.ChunkSize - 1 && !(data[tx + 1, tz + 1] is Water))
                    {
                        data[tx + 1, tz + 1] = new Water(new Vec2i(x * World.ChunkSize + tx + 1, z * World.ChunkSize + tz + 1));
                        (data[tx + 1, tz + 1] as Water).SetUVOffset(off + new Vector2(1, 1));
                    }

                    if (tx > 0 && !(data[tx - 1, tz] is Water))
                    {
                        data[tx - 1, tz] = new Water(new Vec2i(x * World.ChunkSize + tx - 1, z * World.ChunkSize + tz));
                        (data[tx - 1, tz] as Water).SetUVOffset(off + new Vector2(-1, 0));
                    }
                    if (tz > 0 && !(data[tx, tz - 1] is Water))
                    {
                        data[tx, tz - 1] = new Water(new Vec2i(x * World.ChunkSize + tx, z * World.ChunkSize + tz - 1));
                        (data[tx, tz - 1] as Water).SetUVOffset(off + new Vector2(0, -1));
                    }
                    if (tx > 0 && tz > 0 && !(data[tx - 1, tz - 1] is Water))
                    {
                        data[tx - 1, tz - 1] = new Water(new Vec2i(x * World.ChunkSize + tx - 1, z * World.ChunkSize + tz - 1));
                        (data[tx - 1, tz - 1] as Water).SetUVOffset(off + new Vector2(-1, -1));
                    }

                    if (tx > 0 && tz < World.ChunkSize - 1 && !(data[tx - 1, tz + 1] is Water))
                    {
                        data[tx - 1, tz + 1] = new Water(new Vec2i(x * World.ChunkSize + tx - 1, z * World.ChunkSize + tz + 1));
                        (data[tx - 1, tz + 1] as Water).SetUVOffset(off + new Vector2(-1, +1));
                    }
                    if (tz > 0 && tx < World.ChunkSize - 1 && !(data[tx + 1, tz - 1] is Water))
                    {
                        data[tx + 1, tz - 1] = new Water(new Vec2i(x * World.ChunkSize + tx + 1, z * World.ChunkSize + tz - 1));
                        (data[tx + 1, tz - 1] as Water).SetUVOffset(off + new Vector2(1, -1));
                    }
                }
                else if (dist_sqr < (cb.RiverNode.EntranceWidth * cb.RiverNode.EntranceWidth) * 2 / divBy)
                {
                    tiles[tx, tz] = Tile.SAND.ID;
                }
                else
                {
                    tiles[tx, tz] = Tile.GRASS.ID;
                    if (genRan.Random() < 0.25f)
                    {
                        data[tx, tz] = new Grass(new Vec2i(x * World.ChunkSize + tx + 1, z * World.ChunkSize + tz - 1));
                    }
                }
            }
        }

        if (cb.RiverNode.Bridge != null)
        {
            GenerateRiverBridge(cb, data);
        }
        data[0, 0] = new Tree(new Vec2i(x * World.ChunkSize, z * World.ChunkSize));

        data[2, 2] = new RockFormation(new Vec2i(x * World.ChunkSize + 2, z * World.ChunkSize + 2));


        Dictionary <int, WorldObjectData> data_ = new Dictionary <int, WorldObjectData>();

        for (int i = 0; i < World.ChunkSize; i++)
        {
            for (int j = 0; j < World.ChunkSize; j++)
            {
                if (data[i, j] != null)
                {
                    data_.Add(WorldObject.ObjectPositionHash(i, j), data[i, j]);
                }
            }
        }

        return(new ChunkData(x, z, tiles, cb.IsLand, data_));
    }
Example #11
0
    public void GenerateChunkBases()
    {
        ChunkBases = new ChunkBase[World.WorldSize, World.WorldSize];
        LandChunks = new List <Vec2i>();

        Vec2i mid   = new Vec2i(World.WorldSize / 2, World.WorldSize / 2);
        float r_sqr = (World.WorldSize / 3) * (World.WorldSize / 3);

        WorldRad = (World.WorldSize / 2.1f) * (World.WorldSize / 2.1f);

        Texture2D t    = new Texture2D(World.WorldSize, World.WorldSize);
        Texture2D hum  = new Texture2D(World.WorldSize, World.WorldSize);
        Texture2D temp = new Texture2D(World.WorldSize, World.WorldSize);



        float[,] humdity = new float[World.WorldSize, World.WorldSize];
        Vec2i offset = GenRan.RandomVec2i(World.WorldSize / 8, World.WorldSize / 4);

        Vec2i humMid    = mid + offset;
        float humRadSqr = GenRan.Random(World.WorldSize / 4, World.WorldSize / 2);

        humRadSqr *= humRadSqr;


        Vec2i tempMid    = mid - offset;
        float tempRadSqr = GenRan.Random(World.WorldSize / 4, World.WorldSize / 2);

        tempRadSqr          *= tempRadSqr;
        float[,] temperature = new float[World.WorldSize, World.WorldSize];

        for (int x = 0; x < World.WorldSize; x++)
        {
            for (int z = 0; z < World.WorldSize; z++)
            {
                float c = WorldHeightChunk(x, z);



                humdity[x, z]  = 0.4f + 0.6f * Mathf.PerlinNoise(4000 + x * 0.02f, 4000 + z * 0.02f);
                humdity[x, z] /= (((x - humMid.x) * (x - humMid.x) + (z - humMid.z) * (z - humMid.z)) / humRadSqr);
                humdity[x, z]  = Mathf.Clamp(humdity[x, z], 0, 1);

                //temperature[x, z] = Mathf.PerlinNoise(700 + x * 0.02f, 700 + z * 0.02f);
                temperature[x, z]  = 0.4f + 0.6f * Mathf.PerlinNoise(700 + x * 0.02f, 700 + z * 0.02f);
                temperature[x, z] /= (((x - tempMid.x) * (x - tempMid.x) + (z - tempMid.z) * (z - tempMid.z)) / tempRadSqr);
                temperature[x, z]  = Mathf.Clamp(temperature[x, z], 0, 1);
                hum.SetPixel(x, z, new Color(humdity[x, z], humdity[x, z], humdity[x, z]));
                temp.SetPixel(x, z, new Color(temperature[x, z], temperature[x, z], temperature[x, z]));

                //c /= (((x - mid.x) * (x - mid.x) + (z - mid.z) * (z - mid.z)) / r_sqr);

                t.SetPixel(x, z, new Color(c / World.ChunkHeight, c / World.ChunkHeight, c / World.ChunkHeight));
                Vec2i v = new Vec2i(x, z);

                //if ((x - mid.x) * (x - mid.x) + (z - mid.z) * (z - mid.z) < r_sqr)
                if (c > 40 && !(x == 0 || z == 0 || x == World.WorldSize - 1 || z == World.WorldSize - 1))
                { //If point within this radius of middle
                    ChunkBases[x, z] = new ChunkBase(v, Mathf.FloorToInt(c), true);
                    LandChunks.Add(v);

                    if (c > 100)
                    {
                        ChunkBases[x, z].SetBiome(ChunkBiome.mountain);
                    }
                    else if (temperature[x, z] > 0.7f && humdity[x, z] < 0.4f)
                    {
                        ChunkBases[x, z].SetBiome(ChunkBiome.dessert);
                    }
                    else if (humdity[x, z] > 0.4f && temperature[x, z] > 0.5f)
                    {
                        ChunkBases[x, z].SetBiome(ChunkBiome.forrest);
                    }
                    else
                    {
                        ChunkBases[x, z].SetBiome(ChunkBiome.grassland);
                    }

                    /*
                     * if(temperature[x, z] > 0.7f && humdity[x,z] < 0.4f)
                     * {
                     *  ChunkBases[x, z].SetBiome(ChunkBiome.dessert);
                     * }else if(temperature[x, z] < 0.7f && humdity[x, z] > 0.6f)
                     * if (temperature[x, z] < 0.25f)
                     * {
                     *  ChunkBases[x, z].SetBiome(ChunkBiome.forrest);
                     * }
                     * else
                     * {
                     *      ChunkBases[x, z].SetBiome(ChunkBiome.grassland);
                     * }*/
                }
                else
                {
                    ChunkBases[x, z] = new ChunkBase(v, 1, false);
                }
            }
        }
        t.Apply();
        hum.Apply();
        temp.Apply();

        /*
         * GameManager.Game.toDrawTexts[0] = t;
         * GameManager.Game.toDrawTexts[1] = hum;
         * GameManager.Game.toDrawTexts[2] = temp;*/
    }
Example #12
0
    private void FromRiverSource(Vec2i source, Vec2i end, float startHeight = -1, int distSinceFork = 0, bool riverRaySearch = true)
    {
        int i = 0;

        if (startHeight < 0)
        {
            startHeight = ChunkBases[source.x, source.z].Height;
        }

        i = 0;

        Vec2i last    = source;
        Vec2i mainDir = CalcDir(source, end);



        Vec2i current = source + mainDir;
        bool  isDone  = false;

        Vector2 exactCurrent = current.AsVector2();

        List <RiverPoint> river        = new List <RiverPoint>();
        ChunkRiverNode    previousNode = null;

        while (!isDone)
        {
            int distToEnd = end.QuickDistance(current);

            i++;

            /*
             * if(i%16 == 0 && riverRaySearch)
             * {
             *  bool success = false;
             *  //search up to 16 chunks away
             *  for(int j=1; j<16; j++)
             *  {
             *      if (success)
             *          break;
             *      //search all 8 directions
             *      foreach(Vec2i v in Vec2i.OCT_DIRDIR)
             *      {
             *          Vec2i p = current + v * j;
             *
             *          if(ChunkBases[p.x,p.z].Biome == ChunkBiome.ocean || ChunkBases[p.x, p.z].ChunkFeature is ChunkRiverNode)
             *          {
             *              end = p;
             *              success = true;
             *              break;
             *          }
             *      }
             *  }
             * }*/


            // Vector2 currentFlow = FlowField[current.x, current.z];

            float   fx         = PerlinNoise(current.x, current.z, 36) * 2 - 1;
            float   fz         = PerlinNoise(current.x, current.z, 37) * 2 - 1;
            Vector2 noiseFlow  = new Vector2(fx, fz);
            Vector2 flowField  = FlowField[current.x, current.z];
            Vector2 targetFlow = (end - current).AsVector2().normalized;


            float targetFlowMult = distToEnd < 400 ? 4 * Mathf.Exp((400f - distToEnd) / 200f) : 4;

            Vector2 flow = (noiseFlow + targetFlowMult * targetFlow + 3.5f * flowField).normalized;
            exactCurrent += flow;
            current       = Vec2i.FromVector2(exactCurrent);
            int  check   = Mathf.Min(river.Count, 5);
            bool isValid = true;
            for (int j = 0; j < check; j++)
            {
                if (river[river.Count - j - 1].Pos == current)
                {
                    isValid = false;
                }
            }
            if (!isValid)
            {
                current     += mainDir;
                exactCurrent = current.AsVector2();
            }


            if (ChunkBases[current.x, current.z].Biome == ChunkBiome.ocean)
            {
                isDone = true;
            }
            if (ChunkBases[current.x, current.z].ChunkFeature is ChunkRiverNode)
            {
                isDone = true;
                //Shouldn't be null, but lets do a check anyway
                if (previousNode != null)
                {
                    //Get the river node
                    ChunkRiverNode endNode = ChunkBases[current.x, current.z].ChunkFeature as ChunkRiverNode;
                    //Inform river nodes of flow
                    endNode.FlowIn.Add(previousNode);
                    previousNode.FlowOut.Add(endNode);
                    ModifyRiverHeight(endNode);
                }
                if (GenRan.Random() < 0.5f)
                {
                    PlaceLake(current, 8);
                }
            }
            if (current == end)
            {
                isDone = true;
            }
            ChunkRiverNode nextNode = new ChunkRiverNode(current);
            ChunkBases[current.x, current.z].SetChunkFeature(nextNode);
            if (previousNode != null)
            {
                nextNode.FlowIn.Add(previousNode);
                previousNode.FlowOut.Add(nextNode);
            }
            previousNode = nextNode;
            //If this chunk is too high, we modify it and the surrounding area
            if (ChunkBases[current.x, current.z].Height > startHeight)
            {
                ModifyRiverValleyHeight(current, startHeight);
            }
            else if (ChunkBases[current.x, current.z].Height < startHeight)
            {
                startHeight = ChunkBases[current.x, current.z].Height;
            }
            RiverPoint rp = new RiverPoint();
            rp.Pos  = current;
            rp.Flow = flow;

            river.Add(rp);
            if (i > 4096)
            {
                PlaceLake(current, 12);
                return;
            }


            /*
             * distSinceFork++;
             *
             * if(distSinceFork > 256)
             * {
             *
             *  float p = Mathf.Exp(-distSinceFork/200f);
             *  if(p < GenRan.Random())
             *  {
             *
             *      Vec2i delta = GenRan.RandomVec2i(-64, 64);
             *
             *      FromRiverSource(current + delta, current);
             *      distSinceFork = 0;
             *  }
             *
             * }*/
            mainDir = CalcDir(current, end);
        }
        return;

        if (river.Count > 128)
        {
            int forkCount = Mathf.CeilToInt(river.Count / 128f);
            int jump      = (int)(((float)river.Count) / forkCount);
            int index     = GenRan.RandomInt(0, jump);
            for (int j = 0; j < forkCount; j++)
            {
                if (index > river.Count - 30)
                {
                    return;
                }
                RiverPoint rp      = river[index];
                Vec2i      forkEnd = rp.Pos;
                Vec2i      delta   = GenRan.RandomVec2i(-32, 32);

                Vector2 endToForkDir = (forkEnd - end).AsVector2().normalized;

                Vec2i forkStart = Vec2i.FromVector2(forkEnd.AsVector2() + endToForkDir * GenRan.Random(64, 128)) + delta;


                FromRiverSource(forkStart, forkEnd);



                index += jump + GenRan.RandomInt(-32, 32);
            }
        }
    }
    public void GenerateChunkBases()
    {
        ChunkBases = new ChunkBase[World.WorldSize, World.WorldSize];
        LandChunks = new List <Vec2i>();
        GenerationRandom genRan = new GenerationRandom(0);

        Vec2i mid   = new Vec2i(World.WorldSize / 2, World.WorldSize / 2);
        float r_sqr = (World.WorldSize / 3) * (World.WorldSize / 3);

        Texture2D t    = new Texture2D(World.WorldSize, World.WorldSize);
        Texture2D hum  = new Texture2D(World.WorldSize, World.WorldSize);
        Texture2D temp = new Texture2D(World.WorldSize, World.WorldSize);



        float[,] humdity = new float[World.WorldSize, World.WorldSize];
        Vec2i offset = genRan.RandomVec2i(World.WorldSize / 8, World.WorldSize / 4);

        Vec2i humMid    = mid + offset;
        float humRadSqr = genRan.Random(World.WorldSize / 4, World.WorldSize / 2);

        humRadSqr *= humRadSqr;


        Vec2i tempMid    = mid - offset;
        float tempRadSqr = genRan.Random(World.WorldSize / 4, World.WorldSize / 2);

        tempRadSqr          *= tempRadSqr;
        float[,] temperature = new float[World.WorldSize, World.WorldSize];

        for (int x = 0; x < World.WorldSize; x++)
        {
            for (int z = 0; z < World.WorldSize; z++)
            {
                float c = 1 - Mathf.Pow(Mathf.PerlinNoise(x * 0.01f, z * 0.01f), 2);

                humdity[x, z]  = 0.4f + 0.6f * Mathf.PerlinNoise(4000 + x * 0.02f, 4000 + z * 0.02f);
                humdity[x, z] /= (((x - humMid.x) * (x - humMid.x) + (z - humMid.z) * (z - humMid.z)) / humRadSqr);
                humdity[x, z]  = Mathf.Clamp(humdity[x, z], 0, 1);

                //temperature[x, z] = Mathf.PerlinNoise(700 + x * 0.02f, 700 + z * 0.02f);
                temperature[x, z]  = 0.4f + 0.6f * Mathf.PerlinNoise(700 + x * 0.02f, 700 + z * 0.02f);
                temperature[x, z] /= (((x - tempMid.x) * (x - tempMid.x) + (z - tempMid.z) * (z - tempMid.z)) / tempRadSqr);
                temperature[x, z]  = Mathf.Clamp(temperature[x, z], 0, 1);
                hum.SetPixel(x, z, new Color(humdity[x, z], humdity[x, z], humdity[x, z]));
                temp.SetPixel(x, z, new Color(temperature[x, z], temperature[x, z], temperature[x, z]));

                c /= (((x - mid.x) * (x - mid.x) + (z - mid.z) * (z - mid.z)) / r_sqr);

                t.SetPixel(x, z, new Color(c, c, c));
                Vec2i v = new Vec2i(x, z);

                //if ((x - mid.x) * (x - mid.x) + (z - mid.z) * (z - mid.z) < r_sqr)
                if (c > 0.5)
                { //If point within this radius of middle
                    ChunkBases[x, z] = new ChunkBase(v, true);
                    LandChunks.Add(v);


                    //Deserts if its hot and dry
                    if (temperature[x, z] > 0.7f && humdity[x, z] < 0.4f)
                    {
                        ChunkBases[x, z].SetBiome(ChunkBiome.dessert);
                    }
                    else if (humdity[x, z] > 0.4f && temperature[x, z] > 0.5f)
                    {
                        ChunkBases[x, z].SetBiome(ChunkBiome.forrest);
                    }
                    else
                    {
                        ChunkBases[x, z].SetBiome(ChunkBiome.grassland);
                    }

                    /*
                     * if(temperature[x, z] > 0.7f && humdity[x,z] < 0.4f)
                     * {
                     *  ChunkBases[x, z].SetBiome(ChunkBiome.dessert);
                     * }else if(temperature[x, z] < 0.7f && humdity[x, z] > 0.6f)
                     * if (temperature[x, z] < 0.25f)
                     * {
                     *  ChunkBases[x, z].SetBiome(ChunkBiome.forrest);
                     * }
                     * else
                     * {
                     *      ChunkBases[x, z].SetBiome(ChunkBiome.grassland);
                     * }*/
                }
                else
                {
                    ChunkBases[x, z] = new ChunkBase(v, false);
                }
            }
        }
        t.Apply();
        hum.Apply();
        temp.Apply();

        GameManager.Game.toDrawTexts[0] = t;
        GameManager.Game.toDrawTexts[1] = hum;
        GameManager.Game.toDrawTexts[2] = temp;
    }
    private Vec3i ChooseNextPosition(List <Vec3i> tunnel, int radius = 3)
    {
        Vec3i basePoint = tunnel[tunnel.Count - 1];
        int   length    = GenRan.RandomInt(3, 8);
        Vec3i direction = basePoint - tunnel[tunnel.Count - 2];

        if (GenRan.Random() < 0.5f)
        {
            int axis = GenRan.RandomInt(0, 3);
            if (axis == 0)
            {
                direction.x = direction.x == 0 ? GenRan.RandomInt(-1, 2) : 0;
            }
            if (axis == 1)
            {
                direction.y = direction.y == 0 ? (int)Mathf.Clamp(GenRan.GaussianFloat(0, 0.2f), -1, 1) : 0;
            }
            if (axis == 2)
            {
                direction.z = direction.z == 0 ? GenRan.RandomInt(-1, 2) : 0;
            }
        }

        int xEnd = basePoint.x + direction.x * length;
        int yEnd = basePoint.y + direction.y * length;
        int zEnd = basePoint.z + direction.z * length;

        if (xEnd < radius)
        {
            direction.x = GenRan.RandomInt(0, 2);
        }
        else if (xEnd >= TileSize.x - radius)
        {
            direction.x = GenRan.RandomInt(-1, 1);
        }

        if (yEnd < radius)
        {
            direction.y = GenRan.RandomInt(0, 2);
        }
        else if (yEnd >= World.ChunkHeight - radius)
        {
            direction.y = GenRan.RandomInt(-1, 1);
        }

        if (zEnd < radius)
        {
            direction.z = GenRan.RandomInt(0, 2);
        }
        else if (zEnd >= TileSize.z - radius)
        {
            direction.z = GenRan.RandomInt(-1, 1);
        }



        for (int i = 0; i < length; i++)
        {
            tunnel.Add(basePoint + direction * (i + 1));
        }

        return(tunnel[tunnel.Count - 1]);
    }