Esempio n. 1
0
        /// <summary>
        /// Update tile map based on current samples.
        /// </summary>
        public void UpdateTileMapData()
        {
            // Create tileMap array if not present
            if (TileMap == null)
            {
                TileMap = new Color32[tilemapDimension * tilemapDimension];
            }

            // Also recreate if not sized appropriately
            if (TileMap.Length != tilemapDimension * tilemapDimension)
            {
                TileMap = new Color32[tilemapDimension * tilemapDimension];
            }

            // Assign tile data to tilemap
            Color32 tileColor = new Color32(0, 0, 0, 0);

            for (int y = 0; y < tilemapDimension; y++)
            {
                for (int x = 0; x < tilemapDimension; x++)
                {
                    // Get sample tile data
                    TilemapSample sample = MapData.tilemapSamples[x, y];

                    // Calculate tile index
                    byte record = (byte)(sample.record * 4);
                    if (sample.rotate && !sample.flip)
                    {
                        record += 1;
                    }
                    if (!sample.rotate && sample.flip)
                    {
                        record += 2;
                    }
                    if (sample.rotate && sample.flip)
                    {
                        record += 3;
                    }

                    // Assign to tileMap
                    tileColor.r = record;
                    TileMap[y * tilemapDimension + x] = tileColor;
                }
            }
        }
        // Drops nature flats based on random chance scaled by simple rules
        public static void LayoutNatureBillboards(DaggerfallTerrain dfTerrain, DaggerfallBillboardBatch dfBillboardBatch, float terrainScale)
        {
            const float maxSteepness      = 50f;    // 50
            const float baseChanceOnDirt  = 0.2f;   // 0.2
            const float baseChanceOnGrass = 0.9f;   // 0.4
            const float baseChanceOnStone = 0.05f;  // 0.05

            // Location Rect is expanded slightly to give extra clearance around locations
            const int natureClearance = 4;
            Rect      rect            = dfTerrain.MapData.locationRect;

            if (rect.x > 0 && rect.y > 0)
            {
                rect.xMin -= natureClearance;
                rect.xMax += natureClearance;
                rect.yMin -= natureClearance;
                rect.yMax += natureClearance;
            }
            // Chance scaled based on map pixel height
            // This tends to produce sparser lowlands and denser highlands
            // Adjust or remove clamp range to influence nature generation
            float elevationScale = (dfTerrain.MapData.worldHeight / 128f);

            elevationScale = Mathf.Clamp(elevationScale, 0.4f, 1.0f);

            // Chance scaled by base climate type
            float climateScale = 1.0f;

            DFLocation.ClimateSettings climate = MapsFile.GetWorldClimateSettings(dfTerrain.MapData.worldClimate);
            switch (climate.ClimateType)
            {
            case DFLocation.ClimateBaseType.Desert:             // Just lower desert for now
                climateScale = 0.25f;
                break;
            }
            float chanceOnDirt  = baseChanceOnDirt * elevationScale * climateScale;
            float chanceOnGrass = baseChanceOnGrass * elevationScale * climateScale;
            float chanceOnStone = baseChanceOnStone * elevationScale * climateScale;

            int heightmapDimension = DaggerfallUnity.Instance.TerrainSampler.HeightmapDimension;

            // Get terrain
            Terrain terrain = dfTerrain.gameObject.GetComponent <Terrain>();

            if (!terrain)
            {
                return;
            }

            // Get terrain data
            TerrainData terrainData = terrain.terrainData;

            if (!terrainData)
            {
                return;
            }

            // Remove exiting billboards
            dfBillboardBatch.Clear();
            MeshReplacement.ClearNatureGameObjects(terrain);

            // Seed random with terrain key
            Random.InitState(MakeTerrainKey(dfTerrain.MapPixelX, dfTerrain.MapPixelY));

            // Just layout some random flats spread evenly across entire map pixel area
            // Flats are aligned with tiles, max 16129 billboards per batch
            Vector2 tilePos = Vector2.zero;
            int     dim     = MapsFile.WorldMapTileDim;
            float   scale   = terrainData.heightmapScale.x * (float)heightmapDimension / (float)dim;

            for (int y = 0; y < dim; y++)
            {
                for (int x = 0; x < dim; x++)
                {
                    // Reject based on steepness
                    float steepness = terrainData.GetSteepness((float)x / dim, (float)y / dim);
                    if (steepness > maxSteepness)
                    {
                        continue;
                    }

                    // Reject if inside location rect
                    // Rect is expanded slightly to give extra clearance around locations
                    tilePos.x = x;
                    tilePos.y = y;
                    if (rect.Contains(tilePos))
                    {
                        continue;
                    }

                    // Chance also determined by tile type
                    TilemapSample sample = dfTerrain.MapData.tilemapSamples[x, y];
                    if (sample.record == 1)
                    {
                        // Dirt
                        if (UnityEngine.Random.Range(0f, 1f) > chanceOnDirt)
                        {
                            continue;
                        }
                    }
                    else if (sample.record == 2)
                    {
                        // Grass
                        if (UnityEngine.Random.Range(0f, 1f) > chanceOnGrass)
                        {
                            continue;
                        }
                    }
                    else if (sample.record == 3)
                    {
                        // Stone
                        if (UnityEngine.Random.Range(0f, 1f) > chanceOnStone)
                        {
                            continue;
                        }
                    }
                    else
                    {
                        // Anything else
                        continue;
                    }

                    // Sample height and position billboard
                    Vector3 pos    = new Vector3(x * scale, 0, y * scale);
                    float   height = terrain.SampleHeight(pos + terrain.transform.position);
                    pos.y = height;

                    // Reject if too close to water
                    float beachLine = DaggerfallUnity.Instance.TerrainSampler.BeachElevation * terrainScale;
                    if (height < beachLine)
                    {
                        continue;
                    }

                    // Add to batch
                    int record = UnityEngine.Random.Range(1, 32);
                    if (!MeshReplacement.ImportNatureGameObject(dfBillboardBatch.TextureArchive, record, terrain, x, y))
                    {
                        dfBillboardBatch.AddItem(record, pos);
                    }
                }
            }

            // Apply new batch
            dfBillboardBatch.Apply();
        }