Esempio n. 1
0
        private void WorldMapBox_MouseDown(object sender, MouseEventArgs e)
        {
            int          x     = (worldRenderer.Position.X + e.X) / (20 + zoom);
            int          y     = (worldRenderer.Position.Y + e.Y) / (20 + zoom);
            WeatherPoint wP    = World.Instance.atmosphere[x * World.MaxZ / World.RATIO + y / World.RATIO * World.MaxZ * World.WORLD_SIZE / World.RATIO];
            WorldTile    point = World.Instance.worldMap[x, y];

            pointInformation.Text = $"Co-ords: {x} {y} Temp: {wP.temperature} Pressure: {wP.pressure} Humidity: {wP.humidity} Lon Wind {wP.v} Lat Wind {wP.u} " +
                                    $"Height {point.height} Water: {point.rock.WaterAmount} Average Temp: {point.averageTemp} Landwater {point.landWater}";
            if (e.Button == MouseButtons.Left)
            {
                mouseDownPosition = e.Location;
            }
        }
Esempio n. 2
0
        public void DetermineBiome()
        {
            WorldTileType oldType = type;
            //Determine average averageTemp and water
            double aTemp    = 0;
            double aWater   = 0;
            int    scanSize = 3;

            for (int y = 0; y < scanSize; y++)
            {
                for (int x = 0; x < scanSize; x++)
                {
                    int lX = (position.X - (x - scanSize / 2)).Cut(0, WORLD_SIZE - 1);
                    int lY = (position.Y - (y - scanSize / 2)).Cut(0, WORLD_SIZE - 1);
                    aTemp  += Instance.worldMap[lX, lY].averageTemp;
                    aWater += Instance.worldMap[lX, lY].landWater;
                }
            }
            aTemp  /= scanSize * scanSize;
            aWater /= scanSize * scanSize;

            if (height < 0.42)
            {
                if (aTemp < 0)
                {
                    type = WorldTileType.SeaIce;
                }
                else
                {
                    type = WorldTileType.Ocean;
                }
                Instance.costMap[position.X, position.Y] = 20;
            }
            else if (height > 0.7)
            {
                type = WorldTileType.Alpine;
                Instance.costMap[position.X, position.Y] = 4;
            }
            else if (aTemp < 5)
            {
                type = WorldTileType.Tundra;
                Instance.costMap[position.X, position.Y] = 2;
            }
            else if (aWater > 40 && aTemp > 15)
            {
                type = WorldTileType.Rainforest;
                Instance.costMap[position.X, position.Y] = 4;
            }
            else if (aWater < 15 && aTemp > 20)
            {
                type = WorldTileType.Desert;
                Instance.costMap[position.X, position.Y] = 3;
            }
            else if (aTemp > 18)
            {
                type = WorldTileType.Savanna;
                Instance.costMap[position.X, position.Y] = 2;
            }
            else if (aWater > 20)
            {
                type = WorldTileType.TemperateForest;
                Instance.costMap[position.X, position.Y] = 1;
            }
            else
            {
                type = WorldTileType.TemperateGrassland;
                Instance.costMap[position.X, position.Y] = 1;
            }
            if (type != oldType)
            {
                Instance.lost[oldType]++;
                Instance.gained[type]++;
                WeatherPoint weatherPoint = Instance.GetAtmosphereValue(position.X, position.Y, 0);
                weatherPoint.baseEvaporationRate = GetEvaporationRate(type);
                weatherPoint.albedo              = GetAlebdo(type);
                weatherPoint.groundHeatCapacity  = GetGroundHeatCapacity(type);
                weatherPoint.baseMinimumHumditiy = GetMinimumHumdity(type);
            }
            landWater = 0;
        }
Esempio n. 3
0
        private void CalculateWeather(int startY, int endY)
        {
            //Create a new random instance as the global one is not thread safe
            Random random = new Random(startY + endY);

            //We simply calculate each one from the values around them, so they will have old and new value used
            for (int x = 0; x < WORLD_SIZE / RATIO; x++)
            {
                for (int y = startY / RATIO; y < endY / RATIO; y++)
                {
                    for (int z = 0; z < MaxZ / DZ; z++)
                    {
                        int          position = z + MaxZ * x + y * WORLD_SIZE / RATIO * MaxZ;
                        WeatherPoint point    = atmosphere[position];
                        point.hour += atmosphereTimeStep;

                        // Horizontal wind
                        WeatherPoint right;
                        if (x == WORLD_SIZE / RATIO - 1)
                        {
                            right = atmosphere[z + y * WORLD_SIZE / RATIO * MaxZ];
                        }
                        else
                        {
                            right = atmosphere[z + MaxZ * (x + 1) + y * WORLD_SIZE / RATIO * MaxZ];
                        }
                        WeatherPoint left;
                        if (x == 0)
                        {
                            left = atmosphere[z + MaxZ * (WORLD_SIZE / RATIO - 1) + y * WORLD_SIZE / RATIO * MaxZ];
                        }
                        else
                        {
                            left = atmosphere[z + MaxZ * (x - 1) + y * WORLD_SIZE / RATIO * MaxZ];
                        }
                        float moveU = (point.u * atmosphereTimeStep * 5) / (DX * RATIO);
                        right.u += moveU / 2;
                        left.u  += moveU / 2;
                        point.u -= moveU;
                        //float friction = point.u * 0.05 * atmosphereTimeStep * point.mountain;
                        //Go from high pressure to low pressure
                        float pressureDiff = -(1 - point.Resistance) * WindStrength * 10 * (right.pressure - left.pressure) / (DX * RATIO);
                        float coriolis     = atmosphereTimeStep * point.f;
                        float dU           = coriolis + pressureDiff;// - friction;
                        if (Math.Sign(dU) == Math.Sign(point.u))
                        {
                            dU = Math.Sign(dU) * Math.Max(2 * Math.Abs(dU) - Math.Abs(point.u), 0);
                        }
                        point.u += dU;
                        point.u  = point.u.Cut(-MaxWindStrength, MaxWindStrength);

                        // Vertical wind
                        WeatherPoint bottom;
                        if (y != WORLD_SIZE / RATIO - 1)
                        {
                            bottom = atmosphere[z + MaxZ * x + (y + 1) * WORLD_SIZE / RATIO * MaxZ];
                        }
                        else
                        {
                            bottom = point;
                        }
                        WeatherPoint top;
                        if (y != 0)
                        {
                            top = atmosphere[z + MaxZ * x + (y - 1) * WORLD_SIZE / RATIO * MaxZ];
                        }
                        else
                        {
                            top = point;
                        }
                        float moveV = (point.v * atmosphereTimeStep * 20) / (DY * RATIO);
                        top.v    += moveV / 4 * 3;
                        bottom.v += moveV / 4;
                        point.v  -= moveV;
                        //float friction = point.v * 0.05f * atmosphereTimeStep * point.mountain;
                        float dV = -(1 - point.Resistance) * WindStrength * (top.pressure - bottom.pressure) / (DY * RATIO); // - friction;
                        if (Math.Sign(dV) == Math.Sign(point.v))
                        {
                            dV = Math.Sign(dV) * Math.Max(5 * Math.Abs(dV) - Math.Abs(point.v), 0);
                        }

                        point.v += dV;
                        point.v  = point.v.Cut(-MaxWindStrength, MaxWindStrength);

                        // Pressure
                        float pressure = point.pressure;
                        point.pressure = 1000 + point.temperature * 1.8f + point.dT * 10;// + point.humidity / 10;
                        point.dP       = pressure - point.pressure;

                        // Vertical wind - as long as MaxZ is 1 this is not important
                        // float dW = point.dP * (-dU / DX - dV / DY);
                        // point.w += dW;

                        // Temperature
                        //TODO: Calculate the effect of the wind
                        float        radiation        = point.EnergyBalance * atmosphereTimeStep / (40f * point.groundHeatCapacity);
                        float        latitudinalTemp  = 20 * atmosphereTimeStep * ((left.temperature + right.temperature) / 2 - point.temperature) / (DX * (RATIO / 2).Cut(1, 10));
                        float        longitudinalTemp = 20 * atmosphereTimeStep * ((top.temperature + bottom.temperature) / 2 - point.temperature) / (DY * (RATIO / 2).Cut(1, 10));
                        WeatherPoint below;

                        if (z != 0)
                        {
                            below = atmosphere[(z - 1) + MaxZ * x + y * WORLD_SIZE / RATIO * MaxZ];
                        }
                        else
                        {
                            below = point;
                        }
                        WeatherPoint above;
                        if (z != MaxZ - 1)
                        {
                            above = atmosphere[(z + 1) + MaxZ * x + y * WORLD_SIZE / RATIO * MaxZ];
                        }
                        else
                        {
                            above = point;
                        }
                        float verticalTemp = atmosphereTimeStep * (below.temperature - above.temperature) / (2 * DZ);
                        point.dT = radiation + point.windTemperatureChange + latitudinalTemp + longitudinalTemp + verticalTemp;
                        point.windTemperatureChange = 0;

                        point.temperature += point.dT;
                        point.temperature  = point.temperature.Cut(-100, 100);
                        point.temperature  = (float)FastMath.Round(point.temperature, 3);

                        // Calculate humidity
                        // First add new
                        float dH = point.EvaporationRate * atmosphereTimeStep * (1 - point.CloudCover / 100) / 4;
                        point.humidity += dH;
                        //point.humidity = point.humidity.Cut(0, 100); //Maybe not necessary anymore
                        //Change in humidity also affects temperature
                        float dTfromdH = -dH / 10;
                        point.temperature += dTfromdH;
                        point.dT          += dTfromdH;

                        //Movement due to wind
                        int xMovement = (int)point.u / 10;
                        int yMovement = (int)point.v / 10;
                        int gX        = x + xMovement;
                        while (0 > gX)
                        {
                            gX += WORLD_SIZE / RATIO;
                        }
                        while (gX >= WORLD_SIZE / RATIO)
                        {
                            gX -= WORLD_SIZE / RATIO - 1;
                        }
                        int gY = y + yMovement;
                        while (0 > gY)
                        {
                            gY += WORLD_SIZE / RATIO;
                        }
                        while (gY >= WORLD_SIZE / RATIO)
                        {
                            gY -= WORLD_SIZE / RATIO - 1;
                        }
                        WeatherPoint moveTo = atmosphere[z + gX * MaxZ + gY * MaxZ * WORLD_SIZE / RATIO];

                        //Move humidity
                        float proportion = Math.Min(2, Math.Abs(atmosphereTimeStep * (Math.Abs(point.u) + Math.Abs(point.v)) / (DX * RATIO))) / 2f;
                        float changed    = (float)FastMath.Round((point.humidity - point.movedHumidity - 1).Cut(0, 100) * proportion, 3);
                        point.movedHumidity = 0;
                        if (moveTo.humidity < point.humidity * 2)
                        {
                            point.humidity -= changed;
                            if (point.humidity < 0)
                            {
                                throw new Exception();
                            }
                            moveTo.humidity      += changed;
                            moveTo.movedHumidity += changed;
                        }
                        //Move temperature
                        //TODO: Find way to incorporate wind speed
                        float diff = point.temperature - (moveTo.temperature + moveTo.windTemperatureChange);
                        moveTo.windTemperatureChange += diff * 0.05f;

                        //Now rain
                        point.precipitation = 0;
                        if (point.humidity > point.MinimumHumditiy)
                        {
                            if (random.Next(3) == 0)
                            {
                                point.Raining = true;
                            }
                        }
                        if (point.Raining)
                        {
                            float delta = random.Next(Math.Min(20, (int)point.humidity));
                            if (delta > 5)
                            {
                                point.precipitation += delta;
                                point.humidity      -= delta / 2;
                                if (point.humidity < 0)
                                {
                                    throw new Exception();
                                }

                                for (int X = x * RATIO; X < ((x + 1) * RATIO).Cut(0, WORLD_SIZE - 1); X++)
                                {
                                    for (int Y = y * RATIO; Y < ((y + 1) * RATIO).Cut(0, WORLD_SIZE - 1); Y++)
                                    {
                                        if (IsLand(worldMap[X, Y].type))
                                        {
                                            worldMap[X, Y].rock.WaterAmount += delta * 0.3;
                                        }
                                    }
                                }

                                dTfromdH           = -delta / 10;
                                point.temperature += dTfromdH;
                                point.dT          += dTfromdH;
                            }
                            if (point.humidity < 10)
                            {
                                point.Raining = false;
                            }
                        }

                        var tile = worldMap[x, y];
                        tile.averageTemp = (tile.averageTemp * tile.measurements + point.temperature) / (tile.measurements + 1);
                        tile.measurements++;
                        //totalHumidity += point.humidity;
#if DEBUG
                        if (point.humidity < 0)
                        {
                            throw new Exception();
                        }
                        if (CheckValdidity(point.EnergyBalance))
                        {
                            throw new Exception();
                        }
                        if (CheckValdidity(point.temperature) || new Range(-150, 100).Excludes(point.temperature))
                        {
                            throw new Exception();
                        }
                        if (CheckValdidity(point.dT))
                        {
                            throw new Exception();
                        }
                        if (CheckValdidity(point.pressure))
                        {
                            throw new Exception();
                        }
                        if (CheckValdidity(point.dP))
                        {
                            throw new Exception();
                        }
                        if (CheckValdidity(point.humidity))
                        {
                            throw new Exception();
                        }
                        if (CheckValdidity(point.CloudCover))
                        {
                            throw new Exception();
                        }
                        if (CheckValdidity(point.u))
                        {
                            throw new Exception();
                        }
                        if (CheckValdidity(point.v))
                        {
                            throw new Exception();
                        }
                        if (CheckValdidity(point.w))
                        {
                            throw new Exception();
                        }
#endif
                    }
                }
            }
        }
Esempio n. 4
0
        //double totalHumidity = 0;

        /// <summary>
        ///
        /// </summary>
        /// <param name="ratio"></param>
        public void InitialiseAtmosphere(int ratio = 1)
        {
            lost   = new Dictionary <WorldTileType, int>();
            gained = new Dictionary <WorldTileType, int>();
            ResetBiomeChangeData();
            DateTime time = DateTime.Now;

            WeatherPoint[] oldAtmosphere = atmosphere;
            if (oldAtmosphere[0] is null)
            {
                atmosphere = new WeatherPoint[WORLD_SIZE / ratio * WORLD_SIZE / ratio * MaxZ / DZ];
                //Create a new atmosphere, x and y are coords in atmosphere not ground coords
                for (int x = 0; x < WORLD_SIZE / ratio; x++)
                {
                    for (int y = 0; y < WORLD_SIZE / ratio; y++)
                    {
                        for (int z = 0; z < MaxZ / DZ; z++)
                        {
                            //TODO: Get a correct temperature decrease with height
                            float evaporationRate    = z == 0 ? (float)worldMap.GetAverage(x * ratio, (x + 1) * ratio, y * ratio, (y + 1) * ratio, t => GetEvaporationRate(t.type)) : 0;
                            float minimumHumdity     = z == 0 ? (float)worldMap.GetAverage(x * ratio, (x + 1) * ratio, y * ratio, (y + 1) * ratio, t => GetMinimumHumdity(t.type)) : 0;
                            float groundHeatCapacity = z == 0 ? (float)worldMap.GetAverage(x * ratio, (x + 1) * ratio, y * ratio, (y + 1) * ratio, t => GetGroundHeatCapacity(t.type)) : 0;
                            float albedo             = (float)worldMap.GetAverage(x * ratio, (x + 1) * ratio, y * ratio, (y + 1) * ratio, t => GetAlebdo(t.type));
                            float height             = (float)heightMap.GetAverage(x * ratio, (x + 1) * ratio, y * ratio, (y + 1) * ratio, h => h < 0.43 ? 0.43 : h);
                            float latitude           = (y * ratio - WORLD_SIZE / 2) / ((float)WORLD_SIZE / 2) * 180;
                            atmosphere[z + x * MaxZ + y * WORLD_SIZE / ratio * MaxZ] = new WeatherPoint(0, 0, 0, (float)temperatureMap[x, y] * 35 - z, z,
                                                                                                        latitude, x * ratio, y * ratio, height, albedo,
                                                                                                        evaporationRate, minimumHumdity, (x * ratio - WORLD_SIZE / 2f) / (WORLD_SIZE / 2f) * 180f, groundHeatCapacity);
                        }
                    }
                }
            }
            else
            {
                //Scale the data from the old one
                if (RATIO > ratio)
                {
                    //The old one was less precise
                    atmosphere = new WeatherPoint[WORLD_SIZE / ratio * WORLD_SIZE / ratio * MaxZ / DZ];
                    for (int x = 0; x < WORLD_SIZE / ratio; x++)
                    {
                        for (int y = 0; y < WORLD_SIZE / ratio; y++)
                        {
                            for (int z = 0; z < MaxZ / DZ; z++)
                            {
                                int          index              = z + x * ratio / RATIO * MaxZ + y * ratio / RATIO * WORLD_SIZE / RATIO * MaxZ;
                                WeatherPoint reference          = oldAtmosphere[index];
                                float        evaporationRate    = reference.baseEvaporationRate;
                                float        minimumHumdity     = reference.baseMinimumHumditiy;
                                float        groundHeatCapacity = reference.groundHeatCapacity;
                                float        albedo             = reference.albedo;
                                float        height             = reference.Height;
                                float        temperature        = reference.temperature;
                                float        pressure           = reference.pressure;
                                float        humidity           = reference.humidity;
                                float        v    = reference.v;
                                float        w    = reference.w;
                                float        u    = reference.u;
                                float        hour = reference.hour;
                                atmosphere[z + x * MaxZ + y * WORLD_SIZE / ratio * MaxZ] = new WeatherPoint(u, v, w, temperature, z,
                                                                                                            (y * ratio - WORLD_SIZE / 2) / ((float)WORLD_SIZE) * 180, x * ratio, y * ratio, height, albedo,
                                                                                                            evaporationRate, minimumHumdity, (x * ratio - WORLD_SIZE / 2f) / (WORLD_SIZE / 2f) * 180f, groundHeatCapacity,
                                                                                                            pressure, humidity, hour);
                            }
                        }
                    }
                }
                else if (ratio > RATIO)
                {
                    //The new one is less precise
                    atmosphere = new WeatherPoint[WORLD_SIZE / ratio * WORLD_SIZE / ratio * MaxZ / DZ];
                    for (int x = 0; x < WORLD_SIZE / ratio; x++)
                    {
                        for (int y = 0; y < WORLD_SIZE / ratio; y++)
                        {
                            for (int z = 0; z < MaxZ / DZ; z++)
                            {
                                //Converts global co-ordinates to zoomed
                                int getIndex(int _x, int _y) => _x / RATIO * MaxZ + _y / RATIO * MaxZ * WORLD_SIZE / RATIO;

                                int   sX = x * ratio; // These values are in global co-ordinates
                                int   eX = Math.Min((x + 1) * ratio, WORLD_SIZE);
                                int   sY = y * ratio;
                                int   eY = Math.Min((y + 1) * ratio, WORLD_SIZE);
                                float evaporationRate    = oldAtmosphere.GetAverage(sX, eX, sY, eY, p => p.baseEvaporationRate, getIndex);
                                float minimumHumdity     = oldAtmosphere.GetAverage(sX, eX, sY, eY, p => p.baseMinimumHumditiy, getIndex);
                                float groundHeatCapacity = oldAtmosphere.GetAverage(sX, eX, sY, eY, p => p.groundHeatCapacity, getIndex);
                                float albedo             = oldAtmosphere.GetAverage(sX, eX, sY, eY, p => p.albedo, getIndex);
                                float height             = oldAtmosphere.GetAverage(sX, eX, sY, eY, p => p.Height, getIndex);
                                float temperature        = oldAtmosphere.GetAverage(sX, eX, sY, eY, p => p.temperature, getIndex);
                                float pressure           = oldAtmosphere.GetAverage(sX, eX, sY, eY, p => p.pressure, getIndex);
                                float humidity           = oldAtmosphere.GetAverage(sX, eX, sY, eY, p => p.humidity, getIndex);
                                float v    = oldAtmosphere.GetAverage(sX, eX, sY, eY, p => p.v, getIndex);
                                float w    = oldAtmosphere.GetAverage(sX, eX, sY, eY, p => p.w, getIndex);
                                float u    = oldAtmosphere.GetAverage(sX, eX, sY, eY, p => p.u, getIndex);
                                float hour = oldAtmosphere.GetAverage(sX, eX, sY, eY, p => p.hour, getIndex);
                                if (float.IsNaN(albedo))
                                {
                                    throw new Exception();
                                }
                                if (float.IsNaN(minimumHumdity) || minimumHumdity == 0)
                                {
                                    throw new Exception();
                                }
                                int index = z + x * MaxZ + y * WORLD_SIZE / ratio * MaxZ;
                                atmosphere[index] = new WeatherPoint(u, v, w, temperature, z,
                                                                     (y * ratio - WORLD_SIZE / 2) / ((float)WORLD_SIZE) * 180, x * ratio, y * ratio, height, albedo,
                                                                     evaporationRate, minimumHumdity, (x * ratio - WORLD_SIZE / 2f) / (WORLD_SIZE / 2f) * 180f, groundHeatCapacity,
                                                                     pressure, humidity, hour);
                            }
                        }
                    }
                }
                else
                {
                    return;
                }
            }
            RATIO = ratio;
            Trace.TraceInformation($"Generated atmosphere in {(DateTime.Now - time).TotalMilliseconds} miliseconds");
        }