/// <summary>
        /// Creates map
        /// </summary>
        /// <param name="width">Width of the map</param>
        /// <param name="height">Height of the map</param>
        /// <returns>Array of tiles</returns>
        public static WorldTile[] GenerateMap(int width, int height)
        {
            bool[,] cells = new bool[width, height];

            // Fill map with 1 or 0 randomly
            UH.Loops(width, height, (x, y) => cells[x, y] = x == 0 || y == 0 || x == width - 1 || y == height - 1 || RandomService.GetRandomBool(_generatorWallRoomRation));

            // Simulation
            for (int i = 0; i < _generatorSteps; i++)
            {
                cells = SimulationStep(cells);
            }

            // Set map
            WorldTile[] map = new WorldTile[width * height];
            UH.Loops(width, height, (x, y) => map[y * width + x] = new WorldTile(y * width + x, x, y, cells[x, y], new CollisionType[0]));

            // Set walls' collisions
            UH.Loops(width, height, (x, y) => {
                WorldTile tile = map[y * width + x];
                if (!tile.IsWall)
                {
                    return;
                }

                List <CollisionType> collision = new List <CollisionType>( );

                if (x - 1 < 0 || !map[y * width + x - 1].IsWall)
                {
                    collision.Add(CollisionType.Left);
                }
                if (x + 1 >= width || !map[y * width + x + 1].IsWall)
                {
                    collision.Add(CollisionType.Right);
                }
                if (y - 1 < 0 || !map[(y - 1) * width + x].IsWall)
                {
                    collision.Add(CollisionType.Top);
                }
                if (y + 1 >= height || !map[(y + 1) * width + x].IsWall)
                {
                    collision.Add(CollisionType.Bottom);
                }

                tile.Collisions = collision.ToArray( );
            });

            return(map);
        }
        /// <summary>
        /// Cellular automaton step
        /// </summary>
        /// <param name="original">Original walls map</param>
        /// <returns>Transformed walls map</returns>
        private static bool[,] SimulationStep(bool[,] original)
        {
            int width  = original.GetLength(0);
            int height = original.GetLength(1);

            bool[,] data = new bool[width, height];

            UH.Loops(width, height, (x, y) => {
                int walls = WallCountAround(original, x, y);

                if (walls > 4)
                {
                    data[x, y] = true;
                }
                else if (walls < 4)
                {
                    data[x, y] = false;
                }
            });

            return(data);
        }
        /// <summary>
        /// How many walls are around given point
        /// </summary>
        /// <param name="original">Original walls map</param>
        /// <param name="centerX">Point's X</param>
        /// <param name="centerY">Point's Y</param>
        /// <returns>Amount of walls around given point</returns>
        private static int WallCountAround(bool[,] original, int centerX, int centerY)
        {
            int width  = original.GetLength(0);
            int height = original.GetLength(1);
            int result = 0;

            UH.Loops(3, 3, (x, y) => {
                int targetX = centerX - 1 + x;
                int targetY = centerY - 1 + y;

                if (targetX == centerX && targetY == centerY)
                {
                    return;
                }

                if (targetX < 0 || targetX >= width || targetY < 0 || targetY >= height || original[targetX, targetY])
                {
                    result++;
                }
            });

            return(result);
        }
        /// <summary>
        /// Render state
        /// </summary>
        /// <param name="time"><see cref="GameTime"/></param>
        public override void Render(GameTime time)
        {
            DH.RenderScene(_gameplayScene, _camera, () => {
                foreach (WorldTile tile in _level.Map)
                {
                    if (!tile.IsWall)
                    {
                        float distance   = (float)Math.Sqrt(Math.Pow(tile.DisplayX - _player.X, 2) + Math.Pow(tile.DisplayY - _player.Y, 2));
                        float percentage = 1 - (distance < 350 ? 0 : (distance - 350) / 700);
                        DH.Raw(_content.TEXGround.Texture, tile.DisplayX - 16, tile.DisplayY - 16, color: ColorsManager.Get(percentage));
                    }
                }

                if (_config.DebugMode)
                {
                    foreach (WorldTile tile in _level.Map)
                    {
                        if (tile.Collisions.Contains(CollisionType.Left))
                        {
                            DH.Line(tile.DisplayX, tile.DisplayY, tile.DisplayX, tile.DisplayY + tile.Size, 8, Color.Red);
                        }
                        if (tile.Collisions.Contains(CollisionType.Right))
                        {
                            DH.Line(tile.DisplayX + tile.Size, tile.DisplayY, tile.DisplayX + tile.Size, tile.DisplayY + tile.Size, 8, Color.Red);
                        }
                        if (tile.Collisions.Contains(CollisionType.Top))
                        {
                            DH.Line(tile.DisplayX, tile.DisplayY, tile.DisplayX + tile.Size, tile.DisplayY, 8, Color.Red);
                        }
                        if (tile.Collisions.Contains(CollisionType.Bottom))
                        {
                            DH.Line(tile.DisplayX, tile.DisplayY + tile.Size, tile.DisplayX + tile.Size, tile.DisplayY + tile.Size, 8, Color.Red);
                        }
                    }
                }

                _player.Display(time);
            });

            DH.RenderScene(Scene, () => {
                DH.Scene(_gameplayScene);
                DH.Text(_content.GetFont( ), _player.Name, 15, 15, false);

                // Mini-map
                UH.Loops(_level.Width, _level.Height, (x, y) => {
                    if (!_level.Map[y * _level.Width + x].IsWall)
                    {
                        DH.Raw(_content.Pixel,
                               _config.ViewWidth - 16 - _level.Width * 4 + x * 4,
                               _config.ViewHeight - 16 - _level.Height * 4 + y * 4,
                               4, 4,
                               (_player.OnMapX == x && _player.OnMapY == y ? Color.Red : Color.Gray) * .5f
                               );
                    }
                });

                if (_config.DebugMode)
                {
                    DH.Text(_debugFont, $"{(int)(1 / time.ElapsedGameTime.TotalSeconds)} FPS", _config.WindowWidth - 10, 10, false, ColorsManager.DarkGray, AlignType.RT);
                    DH.Text(_debugFont, $"Mouse ({_input.MouseX}, {_input.MouseY})", _config.WindowWidth - 10, 25, false, ColorsManager.DarkGray, AlignType.RT);
                    DH.Text(_debugFont, $"Player ({_player.X:0.0}, {_player.Y:0.0}) ({_player.OnMapX}, {_player.OnMapY})", _config.WindowWidth - 10, 40, false, ColorsManager.DarkGray, AlignType.RT);
                    DH.Text(_debugFont, $"Camera ({_camera.Target.X:0.0}, {_camera.Target.Y:0.0})", _config.WindowWidth - 10, 55, false, ColorsManager.DarkGray, AlignType.RT);
                    DH.Text(_debugFont, $"Scale {_camera.Scale:0.00}x", _config.WindowWidth - 10, 70, false, ColorsManager.DarkGray, AlignType.RT);

                    DH.Line(0, _config.WindowHeight / 2, _config.WindowWidth, _config.WindowHeight / 2, 1, ColorsManager.DarkestGray * .5f);
                    DH.Line(_config.WindowWidth / 2, 0, _config.WindowWidth / 2, _config.WindowHeight, 1, ColorsManager.DarkestGray * .5f);
                }
            });
        }