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)); }
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); }
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); }
public void SaveGlobeRegion(GlobeRegion globeRegion, TerrainCell terrainCell) { var strageDataObject = GlobeRegionStorageData.Create(globeRegion, terrainCell); SaveInner(strageDataObject, $"Region{terrainCell}.txt"); }
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); }
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); } }