/// <summary>
 /// Merge cell example. This function will make cell1 marge with a random cell from its neighbours.
 /// </summary>
 void MergeCell(Cell cell1)
 {
     int neighbourCount = cell1.region.neighbours.Count;
     if (neighbourCount==0) return;
     Cell cell2 = (Cell)cell1.region.neighbours[Random.Range(0, neighbourCount)].entity;
     tgs.CellMerge(cell1, cell2);
     tgs.Redraw();
 }
 void CellUpdateBounds(Cell cell)
 {
     cell.polygon = cell.region.polygon;
     List<Vector3> points = cell.polygon.contours[0].GetVector3Points();
     cell.region.points = points;
     // Update bounding rect
     float minx, miny, maxx, maxy;
     minx = miny = float.MaxValue;
     maxx = maxy = float.MinValue;
     for (int p=0;p<points.Count;p++) {
         Vector3 point = points[p];
         if (point.x<minx) minx = point.x;
         if (point.x>maxx) maxx = point.x;
         if (point.y<miny) miny = point.y;
         if (point.y>maxy) maxy = point.y;
     }
     cell.region.rect2D = new Rect(minx, miny, maxx-minx, maxy-miny);
 }
        void SetupIrregularGrid()
        {
            Point[] centers = new Point[_numCells];
            for (int k=0;k<centers.Length;k++) {
                centers[k] = new Point(UnityEngine.Random.Range (-0.49f, 0.49f), UnityEngine.Random.Range (-0.49f, 0.49f));
            }

            VoronoiFortune voronoi = new VoronoiFortune ();
            for (int k=0;k<goodGridRelaxation;k++) {
                voronoi.AssignData (centers);
                voronoi.DoVoronoi ();
                if (k <goodGridRelaxation-1) {
                    for (int j=0;j<_numCells;j++) {
                        Point centroid = voronoi.cells[j].centroid;
                        centers[j] = (centers[j] + centroid)/2;
                    }
                }
            }

            // Make cell regions: we assume cells have only 1 region but that can change in the future
            float curvature = goodGridCurvature;
            for (int k=0; k<voronoi.cells.Length; k++) {
                VoronoiCell voronoiCell = voronoi.cells[k];
                Cell cell = new Cell(k.ToString(), voronoiCell.center.vector3);
                Region cr = new Region (cell);
                if (curvature>0) {
                    cr.polygon = voronoiCell.GetPolygon(3, curvature);
                } else {
                    cr.polygon = voronoiCell.GetPolygon(1, 0);
                }
                if (cr.polygon!=null) {
                    // Add segments
                    for (int i=0;i<voronoiCell.segments.Count;i++) {
                        Segment s = voronoiCell.segments[i];
                        if (!s.deleted) {
                            if (curvature>0) {
                                cr.segments.AddRange(s.subdivisions);
                            } else {
                                cr.segments.Add (s);
                            }
                        }
                    }

                    cell.polygon = cr.polygon.Clone();
                    cell.region = cr;
                    cells.Add (cell);
                }
            }
        }
 /// <summary>
 /// Must be called after changing one cell geometry.
 /// </summary>
 void UpdateCellGeometry(Cell cell, TGS.Geom.Polygon poly)
 {
     // Copy new polygon definition
     cell.region.polygon = poly;
     cell.polygon = cell.region.polygon.Clone();
     // Update segments list
     cell.region.segments.Clear();
     List<Segment>segmentCache = new List<Segment>(cellNeighbourHit.Keys);
     for (int k=0;k<poly.contours[0].points.Count;k++) {
         Segment s = poly.contours[0].GetSegment(k);
         bool found = false;
         // Search this segment in the segment cache
         for (int j=0;j<segmentCache.Count;j++) {
             Segment o = segmentCache[j];
             if ((Point.EqualsBoth(o.start, s.start) && Point.EqualsBoth(o.end, s.end)) || (Point.EqualsBoth(o.end, s.start) && Point.EqualsBoth(o.start, s.end))) {
                 cell.region.segments.Add (o);
                 ((Cell)cellNeighbourHit[o].entity).territoryIndex = cell.territoryIndex; // updates the territory index of this segment in the cache
                 found = true;
                 break;
             }
         }
         if (!found) cell.region.segments.Add (s);
     }
     // Refresh neighbours
     CellsUpdateNeighbours();
     // Refresh rect2D
     CellUpdateBounds(cell);
     // Refresh territories
     FindTerritoryFrontiers();
     UpdateTerritoryBoundaries();
 }
        void SetupBoxGrid(bool strictQuads)
        {
            // Make cell regions: we assume cells have only 1 region but that can change in the future
            int l = _numCells;
            int qx, qy;
            int q = (int)(Math.Sqrt (l));
            if (strictQuads) {
                qx=qy=q;
            } else {
                qx=l;
                qy=1;
                if (q<1) q=1;
                if ( (int)(q*q) != l) { // not squared
                    if (!GetTwoFactors(l, out qx, out qy)) {
                        // if number > 10 and it's prime, reduce by one so we can avoid ugly accordian grids
                        if (l>10) GetTwoFactors(l-1, out qx, out qy);
                    }
                } else {
                    qx = qy = q;
                }
            }
            double stepX = (transform.localScale.y / transform.localScale.x) / qx;
            double stepY = (transform.localScale.x / transform.localScale.y) / qy;

            double halfStepX = stepX*0.5;
            double halfStepY = stepY*0.5;

            Segment [,,] sides = new Segment[qx,qy,4]; // 0 = left, 1 = top, 2 = right, 3 = bottom
            int c = -1;
            int subdivisions = goodGridCurvature > 0 ? 3: 1;
            for (int k=0;k<qx;k++) {
                for (int j=0;j<qy;j++) {
                    Point center = new Point((double)k/qx-0.5+halfStepX,(double)j/qy-0.5+halfStepY);
                    Cell cell = new Cell( (++c).ToString(), new Vector2((float)center.x, (float)center.y));

                    Segment left = k>0 ? sides[k-1, j, 2] : new Segment(center.Offset(-halfStepX, -halfStepY), center.Offset(-halfStepX, halfStepY), true);
                    sides[k, j, 0] = left;

                    Segment top = new Segment(center.Offset(-halfStepX, halfStepY), center.Offset(halfStepX, halfStepY), j==qy-1);
                    sides[k, j, 1] = top;

                    Segment right = new Segment(center.Offset(halfStepX, halfStepY), center.Offset(halfStepX, -halfStepY), k==qx-1);
                    sides[k, j, 2] = right;

                    Segment bottom = j>0 ? sides[k, j-1, 1] : new Segment(center.Offset(halfStepX, -halfStepY), center.Offset(-halfStepX, -halfStepY), true);
                    sides[k, j, 3] = bottom;

                    Region cr = new Region (cell);
                    if (subdivisions>1) {
                        cr.segments.AddRange (top.Subdivide(subdivisions, _gridCurvature));
                        cr.segments.AddRange (right.Subdivide(subdivisions, _gridCurvature));
                        cr.segments.AddRange (bottom.Subdivide(subdivisions, _gridCurvature));
                        cr.segments.AddRange (left.Subdivide(subdivisions, _gridCurvature));
                    } else {
                        cr.segments.Add (top);
                        cr.segments.Add (right);
                        cr.segments.Add (bottom);
                        cr.segments.Add (left);
                    }
                    Connector connector = new Connector();
                    connector.AddRange(cr.segments);
                    cr.polygon = connector.ToPolygon(); // FromLargestLineStrip();
                    if (cr.polygon!=null) {
                        cell.region = cr;
                        cells.Add (cell);
                    }
                }
            }
        }
        void SetupHexagonalGrid()
        {
            // Make cell regions: we assume cells have only 1 region but that can change in the future
            int l = _numCells;
            int qx, qy;
            int q = (int)(Math.Sqrt (l));
            q = q * 12 / 13;
            if (q<1) q= 1;
            qx=qy=q;
            int qx2 = qx * 4 / 3;

            double stepX = (transform.localScale.y / transform.localScale.x) / qx;
            double stepY = (transform.localScale.x / transform.localScale.y) / qy;

            double halfStepX = stepX*0.5;
            double halfStepY = stepY*0.5;

            Segment [,,] sides = new Segment[qx2,qy,6]; // 0 = left-up, 1 = top, 2 = right-up, 3 = right-down, 4 = down, 5 = left-down
            int c = -1;
            int subdivisions = goodGridCurvature > 0 ? 3: 1;
            for (int j=0;j<qy;j++) {
                for (int k=0;k<qx2;k++) {
                    Point center = new Point((double)k/qx-0.5+halfStepX,(double)j/qy-0.5+halfStepY);
                    center.x -= k *  halfStepX/2;
                    Cell cell = new Cell( (++c).ToString(), new Vector2((float)center.x, (float)center.y));

                    double offsetY = (k % 2==0) ? 0: -halfStepY;

                    Segment leftUp =  (k>0 && offsetY<0) ? sides[k-1, j, 3]: new Segment(center.Offset(-halfStepX, offsetY), center.Offset(-halfStepX/2, halfStepY + offsetY), k==0 || (j==qy-1 && offsetY==0));
                    sides[k, j, 0] = leftUp;

                    Segment top = new Segment(center.Offset(-halfStepX/2, halfStepY + offsetY), center.Offset(halfStepX/2, halfStepY + offsetY), j==qy-1);
                    sides[k, j, 1] = top;

                    Segment rightUp = new Segment(center.Offset(halfStepX/2, halfStepY + offsetY), center.Offset(halfStepX, offsetY), k==qx2-1 || (j==qy-1 && offsetY==0));
                    sides[k, j, 2] = rightUp;

                    Segment rightDown = (j > 0 && k<qx2-1 && offsetY<0) ? sides[k+1,j-1,0]: new Segment(center.Offset(halfStepX, offsetY), center.Offset(halfStepX/2, -halfStepY + offsetY), (j==0 && offsetY<0)|| k==qx2-1);
                    sides[k, j, 3] = rightDown;

                    Segment bottom = j>0 ? sides[k, j-1, 1] : new Segment(center.Offset(halfStepX/2, -halfStepY + offsetY), center.Offset(-halfStepX/2, -halfStepY +offsetY), true);
                    sides[k, j, 4] = bottom;

                    Segment leftDown;
                    if (offsetY<0 && j>0) {
                        leftDown = sides[k-1, j-1, 2];
                    } else if (offsetY==0 && k>0) {
                        leftDown = sides[k-1, j, 2];
                    } else {
                        leftDown = new Segment(center.Offset(-halfStepX/2, -halfStepY+offsetY), center.Offset(-halfStepX, offsetY), true);
                    }
                    sides[k, j, 5] = leftDown;

                    if (j==0) {
            //						leftDown.CropBottom();
            //						bottom.CropBottom();
            //						rightDown.CropBottom();
                    }
                    if (k==qx2-1) {
                        top.CropRight();
                        rightUp.CropRight();
                        rightDown.CropRight();
                        bottom.CropRight();
                    }

                    Region cr = new Region (cell);
                    if (subdivisions>1) {
                        if (!top.deleted) cr.segments.AddRange (top.Subdivide(subdivisions, _gridCurvature));
                        if (!rightUp.deleted) cr.segments.AddRange (rightUp.Subdivide(subdivisions, _gridCurvature));
                        if (!rightDown.deleted) cr.segments.AddRange (rightDown.Subdivide(subdivisions, _gridCurvature));
                        if (!bottom.deleted) cr.segments.AddRange (bottom.Subdivide(subdivisions, _gridCurvature));
                        if (!leftDown.deleted) cr.segments.AddRange (leftDown.Subdivide(subdivisions, _gridCurvature));
                        if (!leftUp.deleted) cr.segments.AddRange (leftUp.Subdivide(subdivisions, _gridCurvature));
                    } else {
                        if (!top.deleted) cr.segments.Add (top);
                        if (!rightUp.deleted) cr.segments.Add (rightUp);
                        if (!rightDown.deleted) cr.segments.Add (rightDown);
                        if (!bottom.deleted) cr.segments.Add (bottom);
                        if (!leftDown.deleted) cr.segments.Add (leftDown);
                        if (!leftUp.deleted) cr.segments.Add (leftUp);
                    }
                    Connector connector = new Connector();
                    connector.AddRange(cr.segments);
                    cr.polygon = connector.ToPolygon(); // FromLargestLineStrip();
                    if (cr.polygon!=null) {
                        cell.region = cr;
                        cells.Add (cell);
                    }
                }
            }
        }
        /// <summary>
        /// Highlights the cell region specified. Returns the generated highlight surface gameObject.
        /// Internally used by the Map UI and the Editor component, but you can use it as well to temporarily mark a territory region.
        /// </summary>
        /// <param name="refreshGeometry">Pass true only if you're sure you want to force refresh the geometry of the highlight (for instance, if the frontiers data has changed). If you're unsure, pass false.</param>
        void HighlightCellRegion(int cellIndex, bool refreshGeometry)
        {
            #if HIGHLIGHT_NEIGHBOURS
            DestroySurfaces();
            #endif
            if (highlightedObj!=null) HideCellRegionHighlight();
            if (cellIndex<0 || cellIndex>=cells.Count) return;

            int cacheIndex = GetCacheIndexForCellRegion (cellIndex);
            bool existsInCache = surfaces.ContainsKey (cacheIndex);
            if (refreshGeometry && existsInCache) {
                GameObject obj = surfaces [cacheIndex];
                surfaces.Remove(cacheIndex);
                DestroyImmediate(obj);
                existsInCache = false;
            }
            if (existsInCache) {
                highlightedObj = surfaces [cacheIndex];
                if (highlightedObj!=null) {
                    highlightedObj.SetActive (true);
                    highlightedObj.GetComponent<Renderer> ().sharedMaterial = hudMatCell;
                } else {
                    surfaces.Remove(cacheIndex);
                }
            } else {
                highlightedObj = GenerateCellRegionSurface (cellIndex, hudMatCell);
            }
            _cellHighlighted = cells[cellIndex];
            _cellHighlightedIndex = cellIndex;
            highlightFadeStart = Time.time;

            #if HIGHLIGHT_NEIGHBOURS
            for (int k=0;k<cellRegionHighlighted.neighbours.Count;k++) {
                int  ni = GetCellIndex((Cell)cellRegionHighlighted.neighbours[k].entity);
                GenerateCellRegionSurface(ni, 0, hudMatTerritory);
            }
            #endif
        }
 void HideCellRegionHighlight()
 {
     if (cellHighlighted == null)
         return;
     if (highlightedObj != null) {
         if (cellHighlighted.region.customMaterial!=null) {
             ApplyMaterialToSurface (highlightedObj, cellHighlighted.region.customMaterial);
         } else {
             highlightedObj.SetActive (false);
         }
         highlightedObj = null;
     }
     _cellHighlighted = null;
     _cellHighlightedIndex = -1;
 }
 /// <summary>
 /// Returns the_numCellsrovince in the cells array by its reference.
 /// </summary>
 public int GetCellIndex(Cell cell)
 {
     //			string searchToken = cell.territoryIndex + "|" + cell.name;
     if (cellLookup.ContainsKey(cell))
         return _cellLookup[cell];
     else
         return -1;
 }
 /// <summary>
 /// Merges cell2 into cell1. Cell2 is removed.
 /// Only cells which are neighbours can be merged.
 /// </summary>
 public bool CellMerge(Cell cell1, Cell cell2)
 {
     if (cell1==null || cell2==null) return false;
     if (!cell1.region.neighbours.Contains(cell2.region)) return false;
     cell1.center = (cell2.center + cell1.center)/2.0f;
     // Polygon UNION operation between both regions
     PolygonClipper pc = new PolygonClipper(cell1.polygon, cell2.polygon);
     pc.Compute(PolygonOp.UNION);
     // Remove cell2 from lists
     int territoryIndex = cell2.territoryIndex;
     if (territories[territoryIndex].cells.Contains(cell2)) territories[territoryIndex].cells.Remove(cell2);
     if (cells.Contains(cell2)) cells.Remove(cell2);
     // Updates geometry data on cell1
     UpdateCellGeometry(cell1, pc.subject);
     return true;
 }
Beispiel #11
0
        /// <summary>
        /// Automatically generates territories based on the different colors included in the texture.
        /// </summary>
        /// <param name="neutral">This color won't generate any texture.</param>
        public void CreateTerritories(Texture2D texture, Color neutral, bool hideNeutralCells = false) {

            if (texture == null || cells == null)
                return;

            List<Color> dsColors = new List<Color>();
            Dictionary<Color, int> dsColorDict = new Dictionary<Color, int>();

            int cellCount = cells.Count;
            Color[] colors = null;
            try {
                colors = texture.GetPixels();
            } catch {
                Debug.Log("Texture used to create territories is not readable. Check import settings.");
                return;
            }
            for (int k = 0; k < cellCount; k++) {
                if (!cells[k].visible)
                    continue;
                Vector2 uv = cells[k].center;
                uv.x += 0.5f;
                uv.y += 0.5f;

                int x = (int)(uv.x * texture.width);
                int y = (int)(uv.y * texture.height);
                int pos = y * texture.width + x;
                if (pos < 0 || pos >= colors.Length)
                    continue;
                Color pixelColor = colors[pos];
                int territoryIndex;
                if (!dsColorDict.TryGetValue(pixelColor, out territoryIndex)) {
                    dsColors.Add(pixelColor);
                    territoryIndex = dsColors.Count - 1;
                    dsColorDict[pixelColor] = territoryIndex;
                }
                cells[k].territoryIndex = territoryIndex;
                if (territoryIndex >= MAX_TERRITORIES - 1)
                    break;
            }
            needUpdateTerritories = true;

            if (dsColors.Count > 0) {
                _numTerritories = dsColors.Count;
                _showTerritories = true;

                if (territories == null) {
                    territories = new List<Territory>(_numTerritories);
                } else {
                    territories.Clear();
                }
                for (int c = 0; c < _numTerritories; c++) {
                    Territory territory = new Territory(c.ToString());
                    Color territoryColor = dsColors[c];
                    if (territoryColor.r != neutral.r || territoryColor.g != neutral.g || territoryColor.b != neutral.b) {
                        territory.fillColor = territoryColor;
                    } else {
                        territory.fillColor = new Color(0, 0, 0, 0);
                        territory.visible = false;
                    }
                    // Add cells to territories
                    for (int k = 0; k < cellCount; k++) {
                        Cell cell = cells[k];
                        if (cell.territoryIndex == c) {
                            territory.cells.Add(cell);
                            territory.center += cell.center;
                        }
                    }
                    if (territory.cells.Count > 0) {
                        territory.center /= territory.cells.Count;
                        // Ensure center belongs to territory
                        Cell cellAtCenter = CellGetAtPosition(territory.center);
                        if (cellAtCenter.territoryIndex != c) {
                            territory.center = territory.cells[0].center;
                        }
                    }
                    territories.Add(territory);
                }

                isDirty = true;
                issueRedraw = RedrawType.Full;
                Redraw();
            }
        }