void AddNewBlock(int x, int y) { int2 at = new int2(x, y); GameObject instance = Instantiate(blockObject, new Vector3(x * blockSize, 0f, y * blockSize), Quaternion.identity) as GameObject; instance.name = "City Block (" + x + ", " + y + ")"; CityBlock cb = instance.GetComponent <CityBlock>(); cb.transform.SetParent(this.transform); int2[] neigh = new int2[4] { new int2(0, -1), new int2(-1, 0), new int2(0, 1), new int2(1, 0) }; CityBlock othercb; for (int i = 0; i < 4; i++) { if (cityBlocks.TryGetValue(at + neigh[i], out othercb) == true) { cb.mainConnections[i] = othercb.mainConnections[(i + 2) % 4]; if (Random.Range(0, 100) > deadEndRatio) { cb.secondaryConnections[i] = othercb.secondaryConnections[(i + 2) % 4]; } } } cb.BuildBlock(blockSize); cityBlocks.Add(at, cb); }
void HoverAction() { Ray camRay = Camera.main.ScreenPointToRay(Input.mousePosition); RaycastHit mouseHit; int id = -1; selectable type = selectable.none; CityBlock block = null; Building building = null; Human human = null; if (EventSystem.current.IsPointerOverGameObject() == false && Physics.Raycast(camRay, out mouseHit, 100f, LayerMask.GetMask("Clickable"))) { gridMousePosition.x = Mathf.FloorToInt(mouseHit.point.x); gridMousePosition.y = Mathf.FloorToInt(mouseHit.point.z); human = mouseHit.collider.GetComponent <Human>(); if (human != null) { id = human.id; type = selectable.hero; } else { block = mouseHit.collider.transform.parent.GetComponent <CityBlock> (); building = mouseHit.collider.transform.parent.GetComponent <Building> (); if (block != null) { type = selectable.streetTile; id = block.GetTileId(gridMousePosition % block.width); } else if (building != null) { block = building.GetComponentInParent <CityBlock> (); if (building.ShowingInteriorView() == true) { type = selectable.buildingTile; id = building.GetTileId(gridMousePosition % block.width); } else { type = selectable.building; id = building.id; } } } } if (type != hoveredType || id != hoveredID || block != hoveredBlock || building != hoveredBuilding) { SwitchHovered(false); hoveredType = type; hoveredID = id; hoveredBlock = block; hoveredBuilding = building; SwitchHovered(true); } }
public override IEnumerator PlaceBuildings(CityBlock block, List <BuildingVariant> variants) { this.block = block; this.variants = variants; Placed = new List <Building>(); PickAcceptableRotations(); FilterVariantsBasedOnAllowedHeight(); float occupiedArea = 0; float occupiedAreaMin = block.Area * minAreaFraction; //DB.Log($"block.Area: {block.Area}"); int findPositionFailCounter = 0; int resetCounter = 0; //The algorithm is going to fill the area with buildings so that at least occupiedAreaMin is filled. //However, it might run into situations where it's unlikely that a combination of building size, rotation will be //able to be acommodated, and the alg will fail to find a suitable position many times. If that ever happens, the buildings //that were already placed are erased and the alg resets. If it resets too many times, the occupiedAreaMin will //get smaller to prevent getting stuck. This is only a precaution and isn't likely to happen, unless settings //within building variants are so strict and prohibitive (eg minimal sizes are so large they can't be fit) that //the alg can't find any place to put them. This could be additionaly prevented with some additional checks and balances //in the future. while (occupiedArea < occupiedAreaMin) { Quaternion rot = acceptableRotations.RandomElement(); BuildingVariant pickedVariant = variants.RandomElement(); float wallLengthX = pickedVariant.GetRandomWallLength(); float wallLengthZ = (GS.RChance(squareChance)) ? wallLengthX : pickedVariant.GetRandomWallLength(wallLengthX); Vector3 pos; bool foundPosition = TryFindSuitablePosition(pickedVariant, rot, wallLengthX, wallLengthZ, out pos); if (foundPosition) { PlaceVariant(pickedVariant, pos, rot, wallLengthX, wallLengthZ); occupiedArea += wallLengthX * wallLengthZ; } else { //Debug.DrawRay(pos, Vector3.up * 10f, Color.red, 10f); findPositionFailCounter++; if (findPositionFailCounter >= maxFindPositionFails) { //reset resetCounter++; findPositionFailCounter = 0; occupiedArea = 0; DestroyPlaced(); if (resetCounter >= maxResets) { resetCounter = 0; occupiedAreaMin = (occupiedAreaMin - 1f) * 0.9f; } yield return(null); } } } }
public override IEnumerator Generate(CityBlock block) { if (allowedPlacementMethods.Count == 0) { allowedPlacementMethods.Add(BuildingPlacementMethod.BoxFit); DB.Log("None allowed placement methods, reverting to BoxFit as default."); } BuildingPlacementMethod method = allowedPlacementMethods.RandomElementWithBias(biases); yield return(StartCoroutine(placers[method].PlaceBuildings(block, buildingVariants))); }
bool BlockIsADuplicate(CityBlock block) { //detecting duplicates is done by comparing centers of city blocks //since no matter the order of streets that comprise bounds of a city block, //the center is going to be in the same place every time for (int i = 0; i < Blocks.Count; i++) { if (block.Center3D.Similar(Blocks[i].Center3D)) { return(true); } } return(false); }
public DrawableCityBlock(CityBlock CityBlock) { IsHighlighted = false; this.IsPainted = false; IsBuildable = true; HighLightBuilding = false; this.CityBlock = CityBlock; IsReferenceForBuilding = false; Building = null; //não há estrutura construida nesse bloco RandomizeResouces(); }
public bool FindPath(int heroID, Building destBuilding) { CityBlock destBlock = destBuilding.GetComponentInParent <CityBlock> (); int2 destination = destBlock.GridPos() * blockSize + destBuilding.door.OutsideTile(); if (FindPath(heroID, destination) == false) { return(false); } heroes [heroID].toDoList.Enqueue(new Action(action_type.enter_building, destBuilding.door.gameObject)); heroes [heroID].path.Enqueue(destBlock.GridPos() * blockSize + destBuilding.door.InsideTile()); destBuilding.IncrementHeroCount(); return(true); }
private IEnumerator PlaceCurrentPieceCoroutine() { CityBlock[] pieceBlocks = currentPiece.tetrominoBlocks.ToArray(); Vector3[] piecePositions = currentPiece.tetrominoBlocks.Select(b => b.transform.position).ToArray(); Destroy(currentPiece.gameObject); currentPiece = SpawnPiece(Vector3.zero); for (int i = 0; i < 4; i++) { piecePositions[i].y = piecePlaneHeight; CityBlock block = Instantiate(blockPrefab, piecePositions[i], Quaternion.identity); block.transform.localScale = new Vector3(0.0f, 1.0f, 0.0f); block.transform.DOScale(new Vector3(0.9f, 1.0f, 0.9f), 0.25f); yield return(new WaitForSeconds(0.1f)); } }
void Start() { parent = transform.parent.GetComponent <CityBlock>(); StartCoroutine(Appear()); transform.localRotation = Quaternion.Euler(0, 90 * Random.Range(0, 3), 0); foreach (var rend in GetComponentsInChildren <SkinnedMeshRenderer>()) { if (Game.useShadow) { rend.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.On; rend.receiveShadows = true; } else { rend.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off; rend.receiveShadows = false; } } }
bool FindBestPathAndAdd(CityBlock block, int2 start, int2 end1, int2 end2, int heroID, out int2 bestEnd) { Queue <int2> path1 = new Queue <int2>(); Queue <int2> path2 = new Queue <int2>(); int distance1 = new int(); int distance2 = new int(); bool found1 = false; bool found2 = false; bestEnd = null; found1 = block.FindPath(start, end1, path1, out distance1); found2 = block.FindPath(start, end2, path2, out distance2); if (found1 == false) { return(false); } if (found2 == false || distance1 <= distance2) { bestEnd = end1; while (path1.Count > 0) { heroes[heroID].path.Enqueue(path1.Dequeue()); } } else { bestEnd = end2; while (path2.Count > 0) { heroes[heroID].path.Enqueue(path2.Dequeue()); } } return(true); }
public IEnumerator ExtractCityBlocks(List <Intersection> inters, List <RimStreetLine> linesWithEndOnRim) { DB.Log("EXTRACTING CITY BLOCKS", 1); Blocks = new List <CityBlock>(); //extracting city blocks looks like this: //From every Intersection the algorithm tries to traverse the Streets connected to it //and upon encountering an Intersection on the other end it makes the first clockwise //turn available, unless there is no such turn, then it continues in the same direction. //When it doesn't encounter an Intersection on the end of a Street, but instead a dead end //on the rim of the city circle, it jumps to the next point clockwise along the rim //and continues traversal. This way the alg will eventually reach the same Intersection it started //from and this way it will save all the Streets encountered as the bounds of the city block. //In the case when the traversal gets lost and after a lot of points it still hasn't come back, //it is skipped, but I doubt if getting lost is even mathematically possible, it's just an //extra precaution. for (int i = 0; i < inters.Count; i++) { foreach (Street startStreet in inters[i].Connected) { bool lost = false; bool hasRimSkip = false; Intersection current = startStreet.GetOtherSide(inters[i]); List <StreetTraversal> traversal = new List <StreetTraversal>(); bool startingTraversedFromAToB = (inters[i] == startStreet.InterA); traversal.Add(new StreetTraversal(startStreet, startingTraversedFromAToB)); while (current != inters[i]) { if (current == null) { //current Intersection is null meaning we've reached city rim on its end //need to jump along the rim clockwise hasRimSkip = true; Vector2 pointOnRim = (traversal.Last().FromAToB) ? traversal.Last().Street.B : traversal.Last().Street.A; StreetTraversal traversedAfterSkip = GetTraversalFromSkip(pointOnRim, linesWithEndOnRim); traversal.Add(traversedAfterSkip); current = traversedAfterSkip.FromAToB ? traversedAfterSkip.Street.InterB : traversedAfterSkip.Street.InterA; } else { traversal.Add(PickNextTraversed(current, traversal.Last())); current = traversal.Last().Street.GetOtherSide(current); } if (traversal.Count > 50) { lost = true; DB.Log("traversal got lost."); break; } } if (!lost) { CityBlock block = new CityBlock(traversal, hasRimSkip); if (!BlockIsADuplicate(block)) { Blocks.Add(block); block.DebugDraw(300f); //DB.Log(block.ToString()); //yield return new WaitForSeconds(1f); } } } yield return(null); } DB.Log($"{Blocks.Count} CITY BLOCKS EXTRACTED", 1); }
/// <summary> /// retorna verdadeiro se o primeiro bloco estiver mais a direita do que o segundo /// </summary> /// <param name="?"></param> /// <returns></returns> public static bool RightSideBlock(CityBlock cb1, CityBlock cb2) { return(cb1.MatrixPosition.X >= cb2.MatrixPosition.X && cb1.MatrixPosition.Y <= cb2.MatrixPosition.Y); }
public virtual IEnumerator PlaceBuildings(CityBlock block, List <BuildingVariant> variants) { yield return(null); }
public void AddCityBlock(int x, int y, CityBlock block) { cityBlocks[y * gridSize + x] = block; }
public bool FindPath(int heroID, int2 destination) { if (heroID > heroes.Count) { return(false); } CityBlock endBlock; if (cityBlocks.TryGetValue(destination.DivideAndFloor(blockSize), out endBlock) == false) { return(false); } CityBlock startBlock; int2 start = heroes[heroID].gPos; if (cityBlocks.TryGetValue(start.DivideAndFloor(blockSize), out startBlock) == false) { Debug.Assert(false); } if (endBlock == startBlock) { return(startBlock.FindPath(start % blockSize, destination % blockSize, heroes[heroID].path)); } Queue <int2> path = new Queue <int2>(); CityBlock currentBlock = startBlock; int2 connection1 = new int2(); int2 connection2 = new int2(); heroes[heroID].path.Clear(); start = start % blockSize; while (currentBlock != endBlock) { if (endBlock.GridPos().x > currentBlock.GridPos().x) { connection1.Set(blockSize - 1, currentBlock.mainConnections[3] * 2); if (start.y > connection1.y) { connection1.y += 1; } connection2.Set(blockSize - 1, currentBlock.secondaryConnections[3]); if (FindBestPathAndAdd(currentBlock, start, connection1, connection2, heroID, out connection1) == false) { return(false); } start.Set(0, connection1.y); if (cityBlocks.TryGetValue(currentBlock.GridPos() + new int2(1, 0), out currentBlock) == false) { return(false); } } if (endBlock.GridPos().x < currentBlock.GridPos().x) { connection1.Set(0, currentBlock.mainConnections[1] * 2); if (start.y > connection1.y) { connection1.y += 1; } connection2.Set(0, currentBlock.secondaryConnections[1]); if (FindBestPathAndAdd(currentBlock, start, connection1, connection2, heroID, out connection1) == false) { return(false); } start.Set(blockSize - 1, connection1.y); if (cityBlocks.TryGetValue(currentBlock.GridPos() + new int2(-1, 0), out currentBlock) == false) { return(false); } } if (endBlock.GridPos().y > currentBlock.GridPos().y) { connection1.Set(currentBlock.mainConnections[2] * 2, blockSize - 1); if (start.x > connection1.x) { connection1.x += 1; } connection2.Set(currentBlock.secondaryConnections[2], blockSize - 1); if (FindBestPathAndAdd(currentBlock, start, connection1, connection2, heroID, out connection1) == false) { return(false); } start.Set(connection1.x, 0); if (cityBlocks.TryGetValue(currentBlock.GridPos() + new int2(0, 1), out currentBlock) == false) { return(false); } } if (endBlock.GridPos().y < currentBlock.GridPos().y) { connection1.Set(currentBlock.mainConnections[0] * 2, 0); if (start.x > connection1.x) { connection1.x += 1; } connection2.Set(currentBlock.secondaryConnections[0], 0); if (FindBestPathAndAdd(currentBlock, start, connection1, connection2, heroID, out connection1) == false) { return(false); } start.Set(connection1.x, blockSize - 1); if (cityBlocks.TryGetValue(currentBlock.GridPos() + new int2(0, -1), out currentBlock) == false) { return(false); } } } if (endBlock.FindPath(start, destination % blockSize, path) == false) { return(false); } while (path.Count > 0) { heroes[heroID].path.Enqueue(path.Dequeue()); } return(true); }
public override IEnumerator Generate(CityBlock block) { yield return(null); }
public virtual IEnumerator Generate(CityBlock block) { yield return(null); }
//this function is responsible for identifying all the city blocks between the road network private void FindFaces(List <GameObject> vertices) { //a dictionary to hold the city blocks Dictionary <Vector3, CityBlock> blocks = new Dictionary <Vector3, CityBlock>(); List <GameObject> finished_verts = new List <GameObject>(); foreach (GameObject vertex in vertices) //loop through each road { foreach (GameObject adj in vertex.GetComponent <RoadSegment>().connected_points_all) //for each road look at their connected points { List <GameObject> visit = new List <GameObject>(); //create a new list of visisted roads GameObject point_A = vertex; //the initial vertex we started from GameObject point_B = adj; //the adjecent vertex we are looking at //store the adjacent point visit.Add(point_B); bool found_v = false; bool force_stop = false; //loop as long as we hav not found the starting vertex while (!found_v && !force_stop) { //calculate vector a (the vector between point a and point b Vector2 vector_a = new Vector2(point_B.transform.position.x - point_A.transform.position.x, point_B.transform.position.z - point_A.transform.position.z); //create the list of potential candidate direction List <GameObject> candidates = new List <GameObject>(); foreach (GameObject cand in point_B.GetComponent <RoadSegment>().connected_points_all) { //if the potential road is not where we jsut came form - then don't add it to the list if (cand != point_A) { candidates.Add(cand); } } if (candidates.Count > 0) //if there are potential candidates { GameObject temp = point_B; point_B = BestFaceCandidate(point_A, point_B, candidates, vector_a); //set next point to the best candicate point_A = temp; } else { force_stop = true; } if (point_B == vertex) { found_v = true; visit.Add(point_A); } visit.Add(point_B); } bool ccw = IsCCW(visit); //if has been found and is counter clockwise then create the city block ands store it - ensuring it has not been previously created if (found_v && ccw) { CityBlock block = new CityBlock(); block.AddEncompassingRoads(visit); block.CalcBlocksCentre(); block.CalcMeshPoints(); if (!blocks.ContainsKey(block.centre_point)) { blocks[block.centre_point] = block; } else { block = null; } } finished_verts.Add(vertex); } } city_blocks = blocks.Values.ToList(); }