/**********************************************************************************/ // функция генерирует внутренности блока // // порядок генерации объектов: // - Здания // - Дороги // - Генерируемое окружение /**********************************************************************************/ void GenerateBlockContent(GameObject block, BlockDescriptor descriptor, int x, int y) { // определяемся с ограничениями на соединение дорог RoadManager.GetInstance().SetRoadRulesToBlock(descriptor, x, y); // обновляем карту занятых и свободных клеток descriptor.UpdateFreeSpaceMap(SizeOfBlocks); // определяем тип блока для генерации Base.BLOCK_TYPE blockToGenerate = GetBlockTypeToGenerate(); // олучаем настройки для данного блока из библиотеки блоков BlockSettings settingsForGeneration = BlockLibrary.GetInstance().GetBlockSettings(blockToGenerate); // устанавливаем здания // для это выбираем его(их) из имеющейся коллекции List <GameObject> toInstantiateCollection = GetBuildingToInstance(settingsForGeneration); foreach (GameObject toInstantiate in toInstantiateCollection) { // получаем контроллер у объекта шаблона, он нам потребуется для определения размеров здания BuildingController bcOfPattern = toInstantiate.GetComponent <BuildingController>(); // пробуем установить здание в блок bool success = false; int attempts = 10; while (!success && attempts > 0) { int xBuildingSize = bcOfPattern.XBuildingSize; int yBuildingSize = bcOfPattern.YBuildingSize; int xCorToPlace = Random.Range(0, (descriptor.xSize * SizeOfBlocks) - xBuildingSize + 1); int yCorToPlace = Random.Range(0, (descriptor.ySize * SizeOfBlocks) - yBuildingSize + 1); bool isPossible = true; // проверяем тушку здания for (int xCorToCheck = xCorToPlace; xCorToCheck < xCorToPlace + xBuildingSize; xCorToCheck++) { for (int yCorToCheck = yCorToPlace; yCorToCheck < yCorToPlace + yBuildingSize; yCorToCheck++) { if (descriptor.FreeSpaceMap[xCorToCheck, yCorToCheck] != true) { isPossible = false; } } } // проверяем точку выхода из здания if (isPossible) { Point roadPoint = new Point(xCorToPlace, yCorToPlace) + bcOfPattern.RoadPoint; if (roadPoint.x < 0 || roadPoint.y < 0 || roadPoint.x >= SizeOfBlocks || roadPoint.y >= SizeOfBlocks) { isPossible = false; } else { if (descriptor.FreeSpaceMap[roadPoint.x, roadPoint.y] != true) { isPossible = false; } } } // если получилось подобрать координаты, устанавливаем новое здание в позицию и выходим из цикла if (isPossible) { // правильные координаты будут выставлены несколькими шагами дальше через localPosition GameObject instance = Instantiate(toInstantiate, new Vector3(0.0f, 0.0f, 0.0f), Quaternion.identity) as GameObject; // устанавливаем в родителя instance.transform.SetParent(block.transform); instance.transform.localPosition = new Vector3((float)(xCorToPlace + xBuildingSize / 2) * SizeOfCell, (float)(yCorToPlace + yBuildingSize / 2) * SizeOfCell, 0.0f); // сохраняем ссылку на все сгенерированные здания descriptor.Buildings.Add(instance); // обновляем карту свободных клеток в блоке descriptor.UpdateFreeSpaceMap(SizeOfBlocks); success = true; } // уменьшаем оставшееся кол-во попыток attempts--; } } // достраиваем дороги RoadManager.GetInstance().BuildRoadInBlock(descriptor, x, y, SizeOfBlocks); // генерируем прочие декоротивные и не только объекты GenerateBlockEnviroment(block, descriptor, settingsForGeneration, SizeOfBlocks); }
/**********************************************************************************/ // функция генерирует наполнитель для блока // вызывается после генерации зданий и дорог, когда ограничители по пространству уже определены // /**********************************************************************************/ void GenerateBlockEnviroment(GameObject block, BlockDescriptor descriptor, BlockSettings settings, int SizeOfBlocks) { int numberOfGeneratedObject = settings.NumOfEnvElements; List <GameObject> applicableObjects = new List <GameObject>(); foreach (GeneratedEnvironmentCtr.ENV_TYPE objType in settings.EnvTypes) { // формирование списка применимых для данного блока элементов foreach (GameObject generatedEnvObj in GeneratedEnvCollection) { // получаем контроллер и проверяем его тип GeneratedEnvironmentCtr ctr = generatedEnvObj.GetComponent <GeneratedEnvironmentCtr>(); if (ctr == null) { Debug.LogError("Wrong GeneratedEnvironmentCtr! is Null!"); return; } if (ctr.TYPE == objType) { applicableObjects.Add(generatedEnvObj); } } } if (applicableObjects.Count == 0) { Debug.LogWarning("We have no enviroment items for: " + settings.EnvTypes.ToString() + "; types"); return; } // выбираем рандомные элементы из получившегося набора и используем их для заполнения блока // обновляем карту пространства for (int itemN = 0; itemN < numberOfGeneratedObject; itemN++) { GameObject envItemToInstance = applicableObjects[Random.Range(0, applicableObjects.Count)]; bool generatingSuccess = false; bool weHaveFreeSpace = true; while (!generatingSuccess && weHaveFreeSpace) { // состовляем коллекцию свободных точек List <Point> freeSpacePoints = new List <Point>(); for (int x = 0; x < SizeOfBlocks; x++) { for (int y = 0; y < SizeOfBlocks; y++) { if (descriptor.FreeSpaceMap[x, y] == true) { freeSpacePoints.Add(new Point(x, y)); } } } // проверяем наличие свободного пространства if (freeSpacePoints.Count == 0) { weHaveFreeSpace = false; continue; } // выбираем случайную точку из свободных и устанавливаем туда элемент окружения Point randomFreePosition = freeSpacePoints[Random.Range(0, freeSpacePoints.Count)]; int xPos = randomFreePosition.x; int yPos = randomFreePosition.y; // правильные координаты будут выставлены несколькими шагами дальше через localPosition GameObject instance = Instantiate(envItemToInstance, new Vector3(0.0f, 0.0f, 0.0f), Quaternion.identity) as GameObject; GeneratedEnvironmentCtr gec = instance.GetComponent <GeneratedEnvironmentCtr>(); // устанавливаем в родителя ( TODO: без учёта размера генерируемого элемента) instance.transform.SetParent(block.transform); instance.transform.localPosition = new Vector3(((float)(xPos) + ((float)gec.SIZE) / 2) * SizeOfCell, ((float)(yPos) + ((float)gec.SIZE) / 2) * SizeOfCell, 0.0f); // сохраняем локальные координаты gec.POSITION = new Point(xPos, yPos); // сохраняем ссылку на все сгенерированные элементы окружения descriptor.Enviroment.Add(instance); // обновляем карту свободных клеток в блоке descriptor.UpdateFreeSpaceMap(SizeOfBlocks); generatingSuccess = true; } } }
/**********************************************************************************/ // функция ответсвенная за генерацию блоков // /**********************************************************************************/ void GenerateBlocks(int xSize, int ySize) { // проверяем соответствие размера карты и блоков, они должны быть кратными if (MapSizeX % SizeOfBlocks != 0 || MapSizeY % SizeOfBlocks != 0) { Debug.LogError("MapGenerator::GenerateBlocks size of map or size of blocks is wrong!"); return; } // шанс использования предопределённого блока // вынести в настройки (?) // ! НА ТЕКУЩИЙ МОМЕНТ ФУНКЦИОНАЛ ОТКЛЮЧЁН ! // требуется коллекция предопределённых блоков для использования float chanseOfSpecialBloks = -0.1f; int xMapSizeInBlocks = MapSizeX / SizeOfBlocks; int yMapSizeInBlocks = MapSizeY / SizeOfBlocks; // проходимся по всей карте и заполняем её блоками for (int x = 0; x < xMapSizeInBlocks; x++) { for (int y = 0; y < yMapSizeInBlocks; y++) { // определяем, используем ли мы специальный блок или генерируемый float chanse = Random.Range(0.0f, 1.0f); bool isGenerated = false; GameObject toInstantiate = null; // выбираем блок для "постройки" if (chanse <= chanseOfSpecialBloks) { int attempts = 5; bool succsecc = false; while (attempts > 0 && !succsecc) { toInstantiate = BaseBlockCollection[Random.Range(0, BaseBlockCollection.Length)]; succsecc = RoadManager.GetInstance().IsBlockOk(toInstantiate, x, y); attempts--; } // если не получилось выбрать блок - переключаемся на генерацию if (!succsecc) { toInstantiate = EmptyBlock; isGenerated = true; } } // генерируем блок, для этого используется пустая болванка else { toInstantiate = EmptyBlock; isGenerated = true; } // проверяем возможность установки // если нет - уходим на следующую итерацию BlockDescriptor descriptor = toInstantiate.GetComponent <BlockDescriptor>(); if (!IsPositionFree(x, y, descriptor)) { continue; } // создаём новый экземпляр блока GameObject instance = Instantiate(toInstantiate, new Vector3((float)x * SizeOfCell * SizeOfBlocks, (float)y * SizeOfCell * SizeOfBlocks, 0.0f), Quaternion.identity) as GameObject; // устанавливаем в родителя instance.transform.SetParent(BuildingCollector.transform); // выполняем окончательную установку и настройку блока bool res = PlaceBlockAtPosition(instance, x, y); if (res == false) { Debug.LogError("Somothing is wrong with block place!"); } BlockDescriptor instDescriptor = instance.GetComponent <BlockDescriptor>(); if (isGenerated) { // генерируем внутярнку блока // объекты, дороги GenerateBlockContent(instance, instDescriptor, x, y); } else { instDescriptor.UpdateFreeSpaceMap(SizeOfBlocks); // обновляем правила дорог RoadManager.GetInstance().UpdateRulesForBlock(x, y, instDescriptor.RoadConnections); } PathFinder.GetInstance().ApplyBlockMapData(x, y, instDescriptor); } } }