Пример #1
0
    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);
    }
Пример #2
0
    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);
        }
    }
Пример #3
0
    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);
                }
            }
        }
    }
Пример #4
0
    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)));
    }
Пример #5
0
 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);
 }
Пример #6
0
        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();
        }
Пример #7
0
    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);
    }
Пример #8
0
    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));
        }
    }
Пример #9
0
 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;
         }
     }
 }
Пример #10
0
    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);
    }
Пример #11
0
    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);
    }
Пример #12
0
 /// <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);
 }
Пример #13
0
 public virtual IEnumerator PlaceBuildings(CityBlock block, List <BuildingVariant> variants)
 {
     yield return(null);
 }
Пример #14
0
 public void AddCityBlock(int x, int y, CityBlock block)
 {
     cityBlocks[y * gridSize + x] = block;
 }
Пример #15
0
    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);
    }
Пример #16
0
 public override IEnumerator Generate(CityBlock block)
 {
     yield return(null);
 }
Пример #17
0
 public virtual IEnumerator Generate(CityBlock block)
 {
     yield return(null);
 }
Пример #18
0
    //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();
    }