示例#1
0
        public static GlobeRegionStorageData Create(GlobeRegion globeRegion, TerrainCell terrainCell)
        {
            var storageData = new GlobeRegionStorageData();

            storageData.Id    = terrainCell.Coords.ToString();
            storageData.Nodes = globeRegion.RegionNodes.Select(x => GlobeRegionNodeStorageData.Create(x)).ToArray();

            return(storageData);
        }
        /// <summary>
        /// Создание
        /// </summary>
        /// <param name="globe">Объект игрового мира, для которого создаётся локация.</param>
        /// <param name="cell">Провинция игрового мира из указанного выше <see cref="Globe" />,
        /// для которого создаётся локация.</param>
        /// <returns>
        /// Возвращает граф локация для провинции.
        /// </returns>
        public Task <GlobeRegion> GenerateRegionAsync(Globe globe, TerrainCell cell)
        {
            var locationSchemeSids = new[] {
                "rat-hole",
                "rat-kingdom",
                "demon-dungeon",
                "demon-lair",
                "crypt",
                "elder-place",
                "genomass-cave"
            };
            var region = new GlobeRegion(LocationBaseSize);

            for (var x = 0; x < LocationBaseSize; x++)
            {
                for (var y = 0; y < LocationBaseSize; y++)
                {
                    //var hasNodeRoll = _dice.Roll(6);
                    //if (hasNodeRoll <= 2)
                    //{
                    //    continue;
                    //}

                    var hasDundeonRoll = _dice.Roll(100);
                    if (hasDundeonRoll > 90)
                    {
                        var locationSidIndex = _dice.Roll(0, locationSchemeSids.Length - 1);
                        var locationSid      = locationSchemeSids[locationSidIndex];
                        var locationScheme   = _schemeService.GetScheme <ILocationScheme>(locationSid);
                        var node             = new GlobeRegionNode(x, y, locationScheme);
                        region.AddNode(node);
                    }
                    else
                    {
                        var hasCityRoll = _dice.Roll(100);

                        if (hasCityRoll > 90)
                        {
                            var locationScheme = _schemeService.GetScheme <ILocationScheme>("city");
                            var node           = new GlobeRegionNode(x, y, locationScheme)
                            {
                                IsTown = true
                            };
                            region.AddNode(node);
                        }
                        else
                        {
                            var locationScheme = _schemeService.GetScheme <ILocationScheme>("forest");
                            var node           = new GlobeRegionNode(x, y, locationScheme);
                            region.AddNode(node);
                        }
                    }
                }
            }

            return(Task.FromResult(region));
        }
        private void AddNodeIfBorder(GlobeRegion region, int x, int y)
        {
            var locationScheme = _schemeService.GetScheme <ILocationScheme>(WILD_SCHEME_SID);
            var borderNode     = new GlobeRegionNode(x, y, locationScheme)
            {
                IsBorder = true
            };

            region.AddNode(borderNode);
        }
 private static void FillRegion(int regionSize, ILocationScheme regionScheme, GlobeRegion currentRegion)
 {
     for (var x = 0; x < regionSize; x++)
     {
         for (var y = 0; y < regionSize; y++)
         {
             currentRegion.AddNode(new GlobeRegionNode(x, y, regionScheme)
             {
                 IsBorder = x == 0 || x == regionSize - 1 || y == 0 || y == regionSize - 1
             });
         }
     }
 }
        public void GetNeighborBorderNodes_TopLeft_ReturnsTopRight()
        {
            // ARRANGE
            const int REGION_SIZE = 20;
            // У нас есть 2 региона, расположенных по соседству.

            var regionSchemeMock = new Mock <ILocationScheme>();
            var regionScheme     = regionSchemeMock.Object;

            var currentRegion = new GlobeRegion(REGION_SIZE);

            FillRegion(REGION_SIZE, regionScheme, currentRegion);

            // Берём правую верхнюю точку для перехода.
            var currentNode = currentRegion.Nodes.OfType <GlobeRegionNode>().Single(node => node.OffsetX == 0 && node.OffsetY == 0);

            var currentTerrainCell = new TerrainCell()
            {
                Coords = new OffsetCoords(1, 0)
            };

            var targetRegion = new GlobeRegion(REGION_SIZE);

            FillRegion(REGION_SIZE, regionScheme, targetRegion);
            var expectedTransitionNodes = new[] {
                targetRegion.Nodes.OfType <GlobeRegionNode>().Single(node => node.OffsetX == REGION_SIZE - 1 && node.OffsetY == 0),
                targetRegion.Nodes.OfType <GlobeRegionNode>().Single(node => node.OffsetX == REGION_SIZE - 1 && node.OffsetY == 1)
            };

            var targetRegionBorders = targetRegion.Nodes.OfType <GlobeRegionNode>().Where(node => node.IsBorder);
            var targetTerrainCell   = new TerrainCell()
            {
                Coords = new OffsetCoords(0, 0)
            };



            // ACT
            var factTransitionNodes = RegionTransitionHelper.GetNeighborBorderNodes(currentNode,
                                                                                    currentTerrainCell,
                                                                                    targetRegionBorders,
                                                                                    targetTerrainCell);



            // ASSERT
            factTransitionNodes.Should().BeEquivalentTo(expectedTransitionNodes);
        }
        /// <summary>
        /// Создание
        /// </summary>
        /// <param name="globe">Объект игрового мира, для которого создаётся локация.</param>
        /// <param name="cell">Провинция игрового мира из указанного выше <see cref="Globe" />,
        /// для которого создаётся локация.</param>
        /// <returns>
        /// Возвращает граф локация для провинции.
        /// </returns>
        public Task <GlobeRegion> GenerateRegionAsync(Globe globe, TerrainCell cell)
        {
            var region = new GlobeRegion(LocationBaseSize);

            // Сейчас допускаем, что паттерны квадратные, меньше размера провинции.
            // Пока не вращаем и не искажаем.
            // Там, где может быть объект, гарантированно создаём один город и два подземелья.
            var regionDraft  = new GlobeRegionDraftValue[LocationBaseSize, LocationBaseSize];
            var startPattern = GlobeRegionPatterns.Start;
            var homePattern  = GlobeRegionPatterns.Home;
            // Расчитываем размер паттернов.
            // Исходим из того, что пока все паттерны квадратные и одинаковые по размеру.
            // Поэтому размер произвольного паттерна будет справедлив для всех остальных.
            // Паттерн старта выбран произвольно.
            var patternSize = startPattern.Values.GetUpperBound(0) - startPattern.Values.GetLowerBound(0) + 1;

            // Вставляем паттерны в указанные области
            ApplyRegionPattern(ref regionDraft, GetDefaultPattrn(), 1, 1);
            ApplyRegionPattern(ref regionDraft, GetDefaultPattrn(), LocationBaseSize - patternSize - 1, 1);
            ApplyRegionPattern(ref regionDraft, GetDefaultPattrn(), 1, LocationBaseSize - patternSize - 1);
            ApplyRegionPattern(ref regionDraft, GetDefaultPattrn(), LocationBaseSize - patternSize - 1, LocationBaseSize - patternSize - 1);
            if (globe.StartProvince == cell)
            {
                ApplyRegionPattern(ref regionDraft, startPattern, (LocationBaseSize - patternSize) / 2, (LocationBaseSize - patternSize) / 2);
            }
            else if (globe.HomeProvince == cell)
            {
                ApplyRegionPattern(ref regionDraft, homePattern, (LocationBaseSize - patternSize) / 2, (LocationBaseSize - patternSize) / 2);
            }
            else
            {
                ApplyRegionPattern(ref regionDraft, GetDefaultPattrn(), (LocationBaseSize - patternSize) / 2, (LocationBaseSize - patternSize) / 2);
            }

            for (var x = regionDraft.GetLowerBound(0); x <= regionDraft.GetUpperBound(0); x++)
            {
                for (var y = regionDraft.GetLowerBound(1); y <= regionDraft.GetUpperBound(1); y++)
                {
                    ValidateRegion(region, regionDraft, x, y);
                }
            }

            return(Task.FromResult(region));
        }
示例#7
0
        public GlobeRegion Restore(ISchemeService schemeService)
        {
            var globeNode = new GlobeRegion(20);

            foreach (var storedNode in Nodes)
            {
                var scheme = schemeService.GetScheme <ILocationScheme>(storedNode.SchemeSid);
                var node   = new GlobeRegionNode(storedNode.Coords.X, storedNode.Coords.Y, scheme)
                {
                    IsBorder      = storedNode.IsBorder,
                    IsHome        = storedNode.IsHome,
                    IsStart       = storedNode.IsStart,
                    IsTown        = storedNode.IsTown,
                    ObservedState = storedNode.Observed
                };
                globeNode.AddNode(node);
            }

            return(globeNode);
        }
示例#8
0
    public Country(YamlMappingNode YamlObject)
    {
      InitializeComponent();

      foreach( System.Collections.Generic.KeyValuePair<YamlNode, YamlNode> childProperty in YamlObject.Children )
      {
        switch( childProperty.Key.ToString() )
        {
          case "type":
            CountryString = childProperty.Value.ToString();
            break;
          case "fundingBase":
            FundingBaseAmount = Int32.Parse( childProperty.Value.ToString() );
            break;
          case "fundingCap":
            FundingCapAmount = Int32.Parse( childProperty.Value.ToString() );
            break;
          case "labelLon":
            LabelPosition.Longitude = float.Parse( childProperty.Value.ToString() );
            break;
          case "labelLat":
            LabelPosition.Latitude = float.Parse( childProperty.Value.ToString() );
            break;
          case "areas":
            YamlSequenceNode areaList = (YamlSequenceNode)childProperty.Value;

            foreach( YamlNode area in areaList.Children )
            {
              YamlSequenceNode areaSeq = (YamlSequenceNode)area;
              GlobeRegion newRegion = new GlobeRegion();
              newRegion.Minimum.Longitude = float.Parse( areaSeq.Children[0].ToString() );
              newRegion.Maximum.Longitude = float.Parse( areaSeq.Children[1].ToString() );
              newRegion.Minimum.Latitude = float.Parse( areaSeq.Children[2].ToString() );
              newRegion.Maximum.Latitude = float.Parse( areaSeq.Children[3].ToString() );
              Areas.Add( newRegion );
            }

            break;
        }
      }
    }
    private async void Start()
    {
        if (_globeManager.Globe == null)
        {
            _globeManager.Globe = await _globeGenerator.GenerateGlobeAsync();

            var firstLocality = _globeManager.Globe.Localities.First();

            _player.Terrain = firstLocality.Cell;

            var createdRegion = await _globeGenerator.GenerateRegionAsync(_globeManager.Globe, firstLocality.Cell);

            _globeManager.Regions[_player.Terrain] = createdRegion;

            var firstNode = (GlobeRegionNode)createdRegion.Nodes.First();

            _player.GlobeNode = firstNode;
        }

        var currentGlobeCell = _player.Terrain;

        _region = _globeManager.Regions[currentGlobeCell];

        _locationNodeViewModels = new List <MapLocation>(100);
        foreach (GlobeRegionNode globeRegionNode in _region.Nodes)
        {
            var worldCoords = HexHelper.ConvertToWorld(globeRegionNode.OffsetX, globeRegionNode.OffsetY);

            var locationObject = _container.InstantiatePrefab(LocationPrefab, transform);
            locationObject.transform.position = new Vector3(worldCoords[0], worldCoords[1], 0);
            var locationViewModel = locationObject.GetComponent <MapLocation>();
            locationViewModel.Node = globeRegionNode;
            _locationNodeViewModels.Add(locationViewModel);

            locationViewModel.OnSelect += LocationViewModel_OnSelect;
            locationViewModel.OnHover  += LocationViewModel_OnHover;
        }

        var openNodeViewModels = new List <MapLocation>(_locationNodeViewModels);

        while (openNodeViewModels.Any())
        {
            var currentNodeViewModel = openNodeViewModels[0];
            openNodeViewModels.Remove(currentNodeViewModel);

            var neighbors          = _region.GetNext(currentNodeViewModel.Node);
            var neighborViewModels = openNodeViewModels.Where(x => neighbors.Contains(x.Node)).ToArray();
            foreach (var neibourNodeViewModel in neighborViewModels)
            {
                var connectorObject    = _container.InstantiatePrefab(ConnectorPrefab, transform);
                var connectorViewModel = connectorObject.GetComponent <MapLocationConnector>();
                connectorViewModel.gameObject1 = currentNodeViewModel.gameObject;
                connectorViewModel.gameObject2 = neibourNodeViewModel.gameObject;
            }
        }

        var playerGroupNodeViewModel = _locationNodeViewModels.Single(x => x.Node == _player.GlobeNode);
        var groupObject = _container.InstantiatePrefab(HumanGroupPrefab, transform);

        _groupViewModel = groupObject.GetComponent <GroupVM>();
        _groupViewModel.CurrentLocation = playerGroupNodeViewModel;
        groupObject.transform.position  = playerGroupNodeViewModel.transform.position;
        Camera.Target = groupObject;

        _player.GlobeNodeChanged += HumanPlayer_GlobeNodeChanged;
        MoveGroupViewModel(_player.GlobeNode);
    }
示例#10
0
        public void SaveGlobeRegion(GlobeRegion globeRegion, TerrainCell terrainCell)
        {
            var strageDataObject = GlobeRegionStorageData.Create(globeRegion, terrainCell);

            SaveInner(strageDataObject, $"Region{terrainCell}.txt");
        }
示例#11
0
    private async void Start()
    {
        //TODO Разобраться, почему остаются блоки от перемещения при использовании перехода
        _commandBlockerService.DropBlockers();

        if (_globeManager.Globe == null)
        {
            if (!_progressStorageService.LoadGlobe())
            {
                var globeGenerationResult = await _globeGenerator.GenerateGlobeAsync();

                _globeManager.Globe = globeGenerationResult.Globe;
                _globeManager.GlobeGenerationHistory = globeGenerationResult.History;

                var startCell = _globeManager.Globe.StartProvince;

                _player.Terrain = startCell;

                var createdRegion = await CreateRegionAsync(_globeManager.Globe, _player.Terrain, _globeGenerator, _progressStorageService);
                await CreateNeighborRegionsAsync(_player.Terrain.Coords, _globeManager, _globeGenerator, _progressStorageService);

                _globeManager.Regions[_player.Terrain] = createdRegion;


                var startNode = createdRegion.RegionNodes.Single(x => x.IsStart);

                _player.GlobeNode = startNode;

                startNode.ObservedState = GlobeNodeObservedState.Visited;

                _globeModalManager.ShowHistoryBookModal();
            }
            else
            {
                _globeManager.GlobeGenerationHistory = new GlobeGenerationHistory();

                if (!_progressStorageService.LoadPlayer())
                {
                    var startCell = _globeManager.Globe.StartProvince;

                    _player.Terrain = startCell;
                }
            }
        }

        var currentGlobeCell = _player.Terrain;

        if (!_globeManager.Regions.TryGetValue(currentGlobeCell, out var currentRegion))
        {
            var createdRegion = await CreateRegionAsync(_globeManager.Globe, currentGlobeCell, _globeGenerator, _progressStorageService);

            _globeManager.Regions[_player.Terrain] = createdRegion;
        }

        // Создание соседних регионов
        await CreateNeighborRegionsAsync(_player.Terrain.Coords, _globeManager, _globeGenerator, _progressStorageService);

        Debug.Log($"Current: {currentGlobeCell}");
        Debug.Log($"Current: {_globeManager.Globe.HomeProvince}");

        _region = currentRegion;

        // Создание визуализации узлов провинции.
        _locationNodeViewModels = new List <MapLocation>(100);
        foreach (GlobeRegionNode globeRegionNode in _region.Nodes)
        {
            var worldCoords = HexHelper.ConvertToWorld(globeRegionNode.OffsetX + _player.Terrain.Coords.X * 20,
                                                       globeRegionNode.OffsetY + _player.Terrain.Coords.Y * 20);

            var locationObject = _container.InstantiatePrefab(LocationPrefab, transform);
            locationObject.transform.position = new Vector3(worldCoords[0], worldCoords[1], 0);
            var locationViewModel = locationObject.GetComponent <MapLocation>();
            locationViewModel.Node         = globeRegionNode;
            locationViewModel.ParentRegion = _region;
            _locationNodeViewModels.Add(locationViewModel);

            locationViewModel.OnSelect += LocationViewModel_OnSelect;
            locationViewModel.OnHover  += LocationViewModel_OnHover;
        }

        // Создание коннекторов между узлами провинции.
        var openNodeViewModels = new List <MapLocation>(_locationNodeViewModels);

        while (openNodeViewModels.Any())
        {
            var currentNodeViewModel = openNodeViewModels[0];
            openNodeViewModels.Remove(currentNodeViewModel);

            var neighbors          = _region.GetNext(currentNodeViewModel.Node);
            var neighborViewModels = openNodeViewModels.Where(x => neighbors.Contains(x.Node)).ToArray();
            foreach (var neibourNodeViewModel in neighborViewModels)
            {
                CreateConnector(currentNodeViewModel, neibourNodeViewModel);
            }
        }

        // Создание визуализаций соседних провинций
        var currentRegionBorders = _region.RegionNodes.Where(x => x.IsBorder).ToArray();

        // TODO в открытые можно помещать только бордюр для экономии.
        openNodeViewModels = new List <MapLocation>(_locationNodeViewModels);
        var currentBorderNodes = currentRegion.Nodes.OfType <GlobeRegionNode>().Where(x => x.IsBorder).ToArray();

        for (var offsetX = -1; offsetX <= 1; offsetX++)
        {
            for (var offsetY = -1; offsetY <= 1; offsetY++)
            {
                if (offsetX == 0 && offsetY == 0)
                {
                    // Это нулевое смещение от текущего элемента.
                    // Пропускаем, т.к. текущий элемент уже есть.
                    continue;
                }

                var terrainX = _player.Terrain.Coords.X + offsetX;
                var terrainY = _player.Terrain.Coords.Y + offsetY;

                if (_globeManager.Globe.Terrain.GetLowerBound(0) <= terrainX &&
                    terrainX <= _globeManager.Globe.Terrain.GetUpperBound(0) &&
                    _globeManager.Globe.Terrain[0].GetLowerBound(0) <= terrainY &&
                    terrainY <= _globeManager.Globe.Terrain[0].GetUpperBound(0))
                {
                    var terrainCell = _globeManager.Globe.Terrain[terrainX][terrainY];

                    var neighborRegion = _globeManager.Regions[terrainCell];

                    // Ищем узел текущей провинции, являющийся соседним с узлом соседней провинции.
                    var neighborBorderNodes = neighborRegion.Nodes.OfType <GlobeRegionNode>().Where(x => x.IsBorder);

                    foreach (var neighborBorderNode in neighborBorderNodes)
                    {
                        var transitionNodes = RegionTransitionHelper.GetNeighborBorderNodes(neighborBorderNode,
                                                                                            terrainCell,
                                                                                            currentRegionBorders,
                                                                                            _player.Terrain);

                        if (!transitionNodes.Any())
                        {
                            // Этот узел соседней провинции не имеет переходов в текущую.
                            // Соответственно, из текущей провинции никто не будет иметь переходов в этот узел соседней провинции.
                            // Значит его можно вообще не отрисовывать.
                            continue;
                        }

                        var worldCoords = HexHelper.ConvertToWorld(neighborBorderNode.OffsetX + terrainX * 20,
                                                                   neighborBorderNode.OffsetY + terrainY * 20);

                        var locationObject = _container.InstantiatePrefab(LocationPrefab, transform);
                        locationObject.transform.position = new Vector3(worldCoords[0], worldCoords[1], 0);
                        var locationViewModel = locationObject.GetComponent <MapLocation>();
                        locationViewModel.Node         = neighborBorderNode;
                        locationViewModel.ParentRegion = neighborRegion;
                        locationViewModel.OtherRegion  = true;
                        _locationNodeViewModels.Add(locationViewModel);

                        locationViewModel.OnSelect += LocationViewModel_OnSelect;
                        locationViewModel.OnHover  += LocationViewModel_OnHover;

                        // Создаём коннекторы от всех пограничных узлов,
                        // имеющий переходв в текущий узел соседней провинции.
                        var openTransitionNodes = openNodeViewModels.Where(x => transitionNodes.Contains(x.Node));
                        foreach (var openTransitionNode in openTransitionNodes)
                        {
                            CreateConnector(openTransitionNode, locationViewModel);
                        }
                    }
                }
            }
        }

        if (_player.MainPerson == null)
        {
            if (!_progressStorageService.LoadPerson())
            {
                _player.MainPerson = _humanPersonFactory.Create();
            }
        }

        var playerGroupNodeViewModel = _locationNodeViewModels.Single(x => x.Node == _player.GlobeNode);
        var groupObject = _container.InstantiatePrefab(HumanGroupPrefab, transform);

        _groupViewModel = groupObject.GetComponent <GroupVM>();
        _groupViewModel.CurrentLocation = playerGroupNodeViewModel;
        groupObject.transform.position  = playerGroupNodeViewModel.transform.position;
        Camera.Target = groupObject;
        Camera.GetComponent <GlobalFollowCamera>().SetPosition(groupObject.transform);

        var nodes = _locationNodeViewModels.Select(x => x.Node);
        var centerLocationNode          = GlobeHelper.GetCenterLocationNode(nodes);
        var centerLocationNodeViewModel = _locationNodeViewModels
                                          .Single(nodeViewModel => nodeViewModel.Node.OffsetX == centerLocationNode.OffsetX &&
                                                  nodeViewModel.Node.OffsetY == centerLocationNode.OffsetY);

        MapBackground.transform.position = centerLocationNodeViewModel.transform.position;

        _player.GlobeNodeChanged += HumanPlayer_GlobeNodeChanged;
        MoveGroupViewModel(_player.GlobeNode);
    }
示例#12
0
        private void ValidateRegion(GlobeRegion region, GlobeRegionDraftValue[,] regionDraft, int x, int y)
        {
            // Определяем, является ли узел граничным. На граничных узлах ничего не создаём.
            // Потому что это может вызвать трудности при переходах между провинциями.
            // Например, игрок при переходе сразу может попасть в данж или город.
            // Не отлажен механиз перехода, если часть узлов соседней провинции отсутствует.
            var isBorder = x == 0 || x == LocationBaseSize - 1 || y == 0 || y == LocationBaseSize - 1;

            if (isBorder)
            {
                AddNodeIfBorder(region, x, y);
                return;
            }

            var             currentPatternValue = regionDraft[x, y];
            GlobeRegionNode node = null;

            if (currentPatternValue == null || currentPatternValue.Value.HasFlag(GlobeRegionDraftValueType.Wild))
            {
                // Это означает, что сюда не был применен ни один шаблон или
                // Дикий сектор был указан явно одним из шаблонов.
                // Значит генерируем просто дикий сектор.
                var locationScheme = _schemeService.GetScheme <ILocationScheme>(WILD_SCHEME_SID);
                node = new GlobeRegionNode(x, y, locationScheme);
            }
            else if (currentPatternValue.IsStart)
            {
                var locationScheme = _schemeService.GetScheme <ILocationScheme>(WILD_SCHEME_SID);
                node = new GlobeRegionNode(x, y, locationScheme)
                {
                    IsStart = true
                };
            }
            else if (currentPatternValue.IsHome)
            {
                var locationScheme = _schemeService.GetScheme <ILocationScheme>(CITY_SCHEME_SID);
                node = new GlobeRegionNode(x, y, locationScheme)
                {
                    IsTown = true,
                    IsHome = true
                };
            }
            else if (currentPatternValue.Value.HasFlag(GlobeRegionDraftValueType.Town))
            {
                var locationScheme = _schemeService.GetScheme <ILocationScheme>(CITY_SCHEME_SID);
                node = new GlobeRegionNode(x, y, locationScheme)
                {
                    IsTown = true
                };
            }
            else if (currentPatternValue.Value.HasFlag(GlobeRegionDraftValueType.Dungeon))
            {
                var locationSchemeSids = new[]
                {
                    "rat-hole",
                    "rat-kingdom",
                    "demon-dungeon",
                    "demon-lair",
                    "crypt",
                    "elder-place",
                    "genomass-cave"
                };
                var locationSidIndex = _dice.Roll(0, locationSchemeSids.Length - 1);
                var locationSid      = locationSchemeSids[locationSidIndex];
                var locationScheme   = _schemeService.GetScheme <ILocationScheme>(locationSid);
                node = new GlobeRegionNode(x, y, locationScheme);
            }
            else
            {
                Debug.Assert(true, "При генерации провинции должны все исходы быть предусмотрены.");
            }

            if (node != null)
            {
                region.AddNode(node);
            }
        }