// Create area segments borders private void CreateAreaBlockerLines() { foreach (var edge in VoronoiDiagram.Edges) { if (!edge.Visible()) { continue; } int leftAreaSegmentID = _siteAreaSegmentMap[edge.LeftSite.Coord]; int rightAreaSegmentID = _siteAreaSegmentMap[edge.RightSite.Coord]; AreaSegment leftAreaSegment = AreaSegmentGraph.GetNodeData(leftAreaSegmentID); AreaSegment rightAreaSegment = AreaSegmentGraph.GetNodeData(rightAreaSegmentID); var leftNeighborhood = AreaSegmentGraph.GetNeighbours(leftAreaSegmentID); if (leftAreaSegmentID == rightAreaSegmentID || leftAreaSegment.Type == AreaSegment.EAreaSegmentType.Border || rightAreaSegment.Type == AreaSegment.EAreaSegmentType.Border || !leftNeighborhood.Contains(rightAreaSegmentID) || AreaSegmentGraph.GetEdgeValue(leftAreaSegmentID, rightAreaSegmentID) != (int)AreaSegment.EAreaSegmentEdgeType.NonNavigable) { continue; } var p0 = edge.ClippedEnds[LR.LEFT].ToUnityVector2(); var p1 = edge.ClippedEnds[LR.RIGHT].ToUnityVector2(); var segment = new[] { p0, p1 }; AreaBlockerLines.Add(segment); } }
public void SpawnAreaObject() { GameObject areaObj = currentAreaObj; NetworkServer.Spawn(areaObj); for (int i = 0; i < currentArea.corridors.Count; i++) { AreaCorridor corridor = currentArea.corridors[i]; for (int j = 0; j < corridor.segments.Count; j++) { AreaSegment seg = corridor.segments[j]; Vector3 segmentLocation = new Vector3(seg.x * segmentWidth, -1 * seg.y * segmentHeight, 0); NetworkServer.Spawn(seg.netId.gameObject); RpcSetupAreaSegment(areaObj.GetComponent <NetworkIdentity>(), seg.netId, corridor.index, seg.index, segmentLocation); for (int k = 0; k < 4; k++) { if (seg.walls[k] != null) { AreaSegmentInstallation installation = seg.installations[k]; if (installation != null) { NetworkServer.Spawn(installation.netId.gameObject); RpcSetupAreaInstallation(seg.netId, installation.netId, corridor.index, seg.index, k); } } } } } }
// Sample area texture at given position public KeyValuePair <int, float> SampleTexture(Vector2 position) { Vector2 noisePosition = position + new Vector2(Random.Range(-_alphaNoise, _alphaNoise), Random.Range(-_alphaNoise, _alphaNoise)); AreaSegment areaSegment = GetClosestAreaSegment(noisePosition); int splatID = _splatIDMap[areaSegment.Type == AreaSegment.EAreaSegmentType.Border ? BorderSettings.Splat : BiomeSettings.Splat]; float splatValue = 1; return(new KeyValuePair <int, float>(splatID, splatValue)); }
public int AddNode(AreaSegment segment, AreaSegment correspondence) { int pat = Pattern.AddNode(segment); int rep = Replace.AddNode(correspondence); Correspondences.Add(pat, rep); return(pat); }
[ClientRpc] private void RpcSpawnInstallation(int corridorId, int segmentId, int dir, string type, string name, NetworkIdentity id) { AreaCorridor corridor = currentArea.corridors[corridorId]; AreaSegment segment = corridor.segments[segmentId]; segment.installations[dir] = new AreaSegmentInstallation(dir, segment); segment.installations[dir].type = type; segment.installations[dir].name = name; segment.installations[dir].netId = id; }
// Sample area height at a given position public BiomeHeightParameters SampleHeight(Vector2 position) { AreaSegment areaSegment = GetClosestAreaSegment(position); if (areaSegment.Type == AreaSegment.EAreaSegmentType.Border) { position += new Vector2(Random.Range(-_heightNoise, _heightNoise), Random.Range(-_heightNoise, _heightNoise)); areaSegment = GetClosestAreaSegment(position); } return(areaSegment == null || areaSegment.Type == AreaSegment.EAreaSegmentType.Border ? BorderSettings.HeightParameters : BiomeSettings.HeightParameters); }
public AreaSegment getNeighbor(int directionId) { AreaSegment neighbor = null; Coordinates neighborCoords = new Coordinates(corridor.x + index, corridor.y); neighborCoords = coordinates.getAdjacent(directionId); foreach (AreaCorridor cor in area.corridors) { if (cor.y == neighborCoords.y) { foreach (AreaSegment seg in cor.segments) { if (seg.x == neighborCoords.x) { neighbor = seg; } } } } return(neighbor); }
[ClientRpc] private void RpcSetupAreaSegment(NetworkIdentity areaNetId, NetworkIdentity segNetId, int corridorId, int segmentId, Vector3 segmentLocation) { GameObject areaObj = areaNetId.gameObject; GameObject areaSegment = segNetId.gameObject; AreaSegment seg = currentArea.corridors[corridorId].segments[segmentId]; areaSegment.transform.SetParent(areaObj.transform); areaSegment.transform.localPosition = segmentLocation; for (int i = 0; i < 4; i++) { GameObject wallObj = areaSegment.transform.Find("Wall" + i.ToString()).gameObject; if (seg.walls[i] == null) { GameObject.Destroy(wallObj); } else { currentArea.tileset.setWallSprite(wallObj, seg.walls[i]); } } }
public AreaCorridor spawnCorridor(int x, int y, int len) { AreaCorridor cor = new AreaCorridor(); cor.coordinates = new Coordinates(x, y); cor.area = this; for (int i = 0; i < len; i++) { AreaSegment segment = new AreaSegment(cor); if (i != 0) { segment.walls[2] = null; } if (i != len - 1) { segment.walls[0] = null; } cor.segments.Add(segment); } cor.index = corridors.Count; corridors.Add(cor); return(cor); }
public AreaSegmentInstallation(int dir, AreaSegment seg) { directionId = dir; segment = seg; }
public AreaSegmentWall(int dir, AreaSegment seg) { directionId = dir; segment = seg; }
public static GameObject DrawAreaSegments(TerrainStructure terrainStructure, string name = "AreaSegments") { GameObject result = new GameObject(name); var graph = terrainStructure.AreaSegmentGraph; // Draw all lines GameObject edges = new GameObject("Edges"); edges.transform.parent = result.transform; foreach (var edge in graph.GetAllEdges()) { Vector2 start = terrainStructure.GetAreaSegmentCenter(edge.x); Vector2 end = terrainStructure.GetAreaSegmentCenter(edge.y); Color color; switch ((AreaSegment.EAreaSegmentEdgeType)graph.GetEdgeValue(edge.x, edge.y)) { case AreaSegment.EAreaSegmentEdgeType.NonNavigable: color = Color.black; break; case AreaSegment.EAreaSegmentEdgeType.MainPath: color = Color.green; break; case AreaSegment.EAreaSegmentEdgeType.SidePath: color = Color.cyan; break; case AreaSegment.EAreaSegmentEdgeType.BossInnerPath: color = Color.red; break; case AreaSegment.EAreaSegmentEdgeType.SpecialInnerPath: color = Color.yellow; break; default: color = Color.gray; break; } GameObject line = DrawLine(new Vector3(start.x, 0, start.y), new Vector3(end.x, 0, end.y), 5, color); line.transform.parent = edges.transform; } // Draw all centers GameObject nodes = new GameObject("Nodes"); nodes.transform.parent = result.transform; foreach (var id in graph.GetAllNodeIDs()) { AreaSegment data = graph.GetNodeData(id); Vector2 center = terrainStructure.GetAreaSegmentCenter(id); Color color; switch (data.Type) { case AreaSegment.EAreaSegmentType.Empty: color = Color.white; break; case AreaSegment.EAreaSegmentType.Border: color = Color.black; break; case AreaSegment.EAreaSegmentType.Start: color = Color.blue; break; case AreaSegment.EAreaSegmentType.Boss: color = Color.red; break; case AreaSegment.EAreaSegmentType.Special: color = Color.yellow; break; case AreaSegment.EAreaSegmentType.MainPath: color = Color.green; break; case AreaSegment.EAreaSegmentType.SidePath: color = Color.cyan; break; default: throw new ArgumentOutOfRangeException(); } GameObject node = DrawSphere(new Vector3(center.x, 0, center.y), 20, color); node.name = "Node " + id + " - " + data.Type; node.transform.parent = nodes.transform; } return(result); }
public GameObject GenerateAreaObject() { Area area = currentArea; GameObject areaObj = GameObject.Instantiate <GameObject>(areaObject); if (area.isStarship) { areaObj.transform.Find("Sky").gameObject.GetComponent <SpriteRenderer>().sprite = spaceSkySprites[area.starship.currentSector.skySpriteIndex]; } for (int i = 0; i < area.corridors.Count; i++) { AreaCorridor corridor = area.corridors[i]; for (int j = 0; j < corridor.segments.Count; j++) { AreaSegment seg = corridor.segments[j]; Vector3 segmentLocation = new Vector3(seg.x * segmentWidth, -1 * seg.y * segmentHeight, 0); GameObject areaSegment = GameObject.Instantiate <GameObject>(segmentObject); seg.netId = areaSegment.GetComponent <NetworkIdentity>(); areaSegment.transform.SetParent(areaObj.transform); areaSegment.transform.localPosition = segmentLocation; for (int k = 0; k < 4; k++) { GameObject installationObj; GameObject wallObj = areaSegment.transform.Find("Wall" + k.ToString()).gameObject; if (seg.walls[k] == null) { GameObject.Destroy(wallObj); } else { area.tileset.setWallSprite(wallObj, seg.walls[k]); AreaSegmentInstallation installation = seg.installations[k]; if (installation != null) { installationObj = GameObject.Instantiate(installationPrefabs[k]); installation.netId = installationObj.GetComponent <NetworkIdentity>(); installationObj.transform.SetParent(wallObj.transform); installationObj.transform.localPosition = new Vector3(0, 0, -1); switch (installation.type) { case "door": installationObj.AddComponent <DoorInstallation>(); installationObj.GetComponent <DoorInstallation>().attachedWall = wallObj; installationObj.GetComponent <DoorInstallation>().installationName = installation.name; installationObj.GetComponent <SpriteRenderer>().sprite = area.tileset.doorSprites[k]; installationObj.GetComponent <DoorInstallation>().directionId = k; break; case "interactive": installationObj.AddComponent <InteractiveInstallation>(); installationObj.GetComponent <InteractiveInstallation>().attachedWall = wallObj; installationObj.GetComponent <InteractiveInstallation>().installationName = installation.name; installationObj.GetComponent <InteractiveInstallation>().interfaceOverlayName = installation.overlayName; installationObj.GetComponent <SpriteRenderer>().sprite = area.tileset.getInstallationSprite(installation.name, k); break; } } } } } } return(areaObj); }
// Create border blocker polygon private void CreateBorderBlockerLines(float borderInlandOffset) { var segments = new List <KeyValuePair <Edge, Vector2> >(); foreach (var edge in VoronoiDiagram.Edges) { //Check if this edge is visible before continuing if (!edge.Visible()) { continue; } int leftAreaSegmentID = _siteAreaSegmentMap[edge.RightSite.Coord]; int rightAreaSegmentID = _siteAreaSegmentMap[edge.LeftSite.Coord]; AreaSegment leftAreaSegment = AreaSegmentGraph.GetNodeData(leftAreaSegmentID); AreaSegment rightAreaSegment = AreaSegmentGraph.GetNodeData(rightAreaSegmentID); // Either one or the other must be a border type if (leftAreaSegment.Type != rightAreaSegment.Type && (leftAreaSegment.Type == AreaSegment.EAreaSegmentType.Border || rightAreaSegment.Type == AreaSegment.EAreaSegmentType.Border)) { // Add border edge with the biome center to scale inwards later segments.Add(new KeyValuePair <Edge, Vector2>(edge, leftAreaSegment.Type == AreaSegment.EAreaSegmentType.Border ? edge.LeftSite.Coord.ToUnityVector2() : edge.RightSite.Coord.ToUnityVector2())); } } // Group connected segments var edgeGroups = new List <List <KeyValuePair <Edge, Vector2> > >(); while (segments.Count > 0) { var edges = new List <KeyValuePair <Edge, Vector2> >(); var startEdge = segments[0]; segments.Remove(startEdge); Vertex headPoint = startEdge.Key.RightVertex; Vertex tailPoint = startEdge.Key.LeftVertex; edges.Add(startEdge); // Find a polygon var polygonClosed = false; while (!polygonClosed && segments.Count > 0) { for (int i = 0; i < segments.Count; i++) { var currentElement = segments[i]; Vertex leftPoint = currentElement.Key.LeftVertex; Vertex rightPoint = currentElement.Key.RightVertex; if (leftPoint == headPoint) { edges.Add(currentElement); segments.Remove(currentElement); headPoint = rightPoint; } else if (rightPoint == headPoint) { edges.Add(currentElement); segments.Remove(currentElement); headPoint = leftPoint; } // Polygon has been closed if (headPoint == tailPoint) { polygonClosed = true; break; } } } edgeGroups.Add(edges); } // Iterate over each polygon found previously foreach (var edges in edgeGroups) { var polygon = new List <Vector2>(); var borderLines = edges.Select(pair => pair.Key).ToList().EdgesToSortedLines(); foreach (var line in borderLines) { // Offset borders towards biome center var left = line[0]; var right = line[1]; var center = Vector2.zero; edges.ForEach(e => { var l = e.Key.ClippedEnds[LR.LEFT].ToUnityVector2(); var r = e.Key.ClippedEnds[LR.RIGHT].ToUnityVector2(); if ((l == left || l == right) && (r == left || r == right)) { center = e.Value; } }); left += (center - left).normalized * borderInlandOffset; right += (center - right).normalized * borderInlandOffset; // Offsetting can give duplicated points if (!polygon.Contains(left)) { polygon.Add(left); } if (!polygon.Contains(right)) { polygon.Add(right); } } // Create border blocker lines BorderBlockerLines.AddRange(polygon.ToArray().PolygonToLines()); } }
// Create a graph containing all connected empty areas private void CreateBaseGraph(int lloydIterations) { // Create uniform random point distribution and Voronoi Diagram var centers = new List <Vector2f>(); for (int i = 0; i < _voronoiSamples; i++) { var x = Random.Range(0f, MapSize); var y = Random.Range(0f, MapSize); centers.Add(new Vector2f(x, y)); } VoronoiDiagram = new Voronoi(centers, new Rectf(0, 0, MapSize, MapSize)); // Apply Lloyd Relaxation VoronoiDiagram.LloydRelaxation(lloydIterations); // Assign area segments to initial areas foreach (var site in VoronoiDiagram.SiteCoords()) { bool isOnBorder = false; var segments = VoronoiDiagram.VoronoiBoundaryForSite(site); foreach (var segment in segments) { if (!(segment.p0.x <= VoronoiDiagram.PlotBounds.left) && !(segment.p0.x >= VoronoiDiagram.PlotBounds.right) && !(segment.p0.y <= VoronoiDiagram.PlotBounds.top) && !(segment.p0.y >= VoronoiDiagram.PlotBounds.bottom) && !(segment.p1.x <= VoronoiDiagram.PlotBounds.left) && !(segment.p1.x >= VoronoiDiagram.PlotBounds.right) && !(segment.p1.y <= VoronoiDiagram.PlotBounds.top) && !(segment.p1.y >= VoronoiDiagram.PlotBounds.bottom)) { continue; } isOnBorder = true; break; } // Assign areaSegment to site and corresponding area var areaSegment = new AreaSegment(isOnBorder ? AreaSegment.EAreaSegmentType.Border : AreaSegment.EAreaSegmentType.Empty); var nodeID = AreaSegmentGraph.AddNode(areaSegment); _siteAreaSegmentMap.Add(site, nodeID); _areaSegmentCenterMap.Add(nodeID, site.ToUnityVector2()); } // Create navigation graph - for each area segment that is not a border, add reachable neighbors foreach (var id in _siteAreaSegmentMap) { var areaSegment = AreaSegmentGraph.GetNodeData(id.Value); if (areaSegment.Type == AreaSegment.EAreaSegmentType.Border) { continue; } Vector2 center = _areaSegmentCenterMap[id.Value]; foreach (var neighbor in VoronoiDiagram.NeighborSitesForSite(new Vector2f(center.x, center.y))) { var neighborSegment = AreaSegmentGraph.GetNodeData(_siteAreaSegmentMap[neighbor]); if (neighborSegment.Type != AreaSegment.EAreaSegmentType.Border) { AreaSegmentGraph.AddEdge(_siteAreaSegmentMap[neighbor], id.Value, (int)AreaSegment.EAreaSegmentEdgeType.NonNavigable); } } } }