//takes edges and axis. check if edge exist, if exist add closest point to cell public void AddPortal(IEnumerable <EdgeAbstract> edges, Vector3 axis) { Vector2 axisV2 = new Vector2(axis.x, axis.z); Dictionary <Cell, Vector3> cellMountPoints = new Dictionary <Cell, Vector3>(); foreach (var abstractEdge in edges) { CellContentData data = new CellContentData(abstractEdge); Vector3 intersection; SomeMath.ClosestToSegmentTopProjection(data.a, data.b, axisV2, true, out intersection); foreach (var cell in _cells) { if (cell.Contains(data)) { if (cellMountPoints.ContainsKey(cell)) { if (SomeMath.SqrDistance(cellMountPoints[cell], axis) > SomeMath.SqrDistance(intersection, axis)) { cellMountPoints[cell] = intersection; } } else { cellMountPoints.Add(cell, intersection); } } } } Vector2 normalRaw; switch (cellMountPoints.Count) { case 0: return; case 1: normalRaw = ToV2((cellMountPoints.First().Value - axis)).normalized * -1; break; case 2: normalRaw = ( ToV2(cellMountPoints.First().Value - axis).normalized + ToV2(cellMountPoints.Last().Value - axis).normalized).normalized * -1; break; default: normalRaw = Vector2.left; Dictionary <Cell, float> cellAngles = new Dictionary <Cell, float>(); Cell first = cellMountPoints.First().Key; cellAngles.Add(first, 0f); Vector3 firstDirV3 = cellMountPoints.First().Value - axis; Vector2 firstDirV2 = ToV2(firstDirV3); foreach (var pair in cellMountPoints) { if (pair.Key == first) { continue; } Vector2 curDir = new Vector2(pair.Value.x - axis.x, pair.Value.z - axis.z); cellAngles.Add(pair.Key, Vector2.Angle(firstDirV2, curDir) * Mathf.Sign(SomeMath.V2Cross(firstDirV2, curDir))); } normalRaw = ( ToV2(cellMountPoints[cellAngles.Aggregate((l, r) => l.Value > r.Value ? l : r).Key] - axis).normalized + ToV2(cellMountPoints[cellAngles.Aggregate((l, r) => l.Value < r.Value ? l : r).Key] - axis).normalized).normalized * -1; break; } portalBases.Add(new JumpPortalBase(cellMountPoints, axis, new Vector3(normalRaw.x, 0, normalRaw.y))); }
private void DoFunnelIteration(Vector3 startV3, Vector3 endV3, List <CellContentGenericConnection> targetConnections) { List <CellContentData> gd = new List <CellContentData>(); for (int i = 0; i < targetConnections.Count; i++) { gd.Add(targetConnections[i].cellData); } gd.Add(new CellContentData(endV3)); gd.Add(new CellContentData(endV3)); int curCycleEnd = 0, curCycleStart = 0, curIterationGateCount = targetConnections.Count + 1; Vector2 left, right; for (int i = 0; i < maxIterations; i++) { if (curCycleEnd == curIterationGateCount) { break; } Vector2 startV2 = funnelPath.lastV2; for (curCycleStart = curCycleEnd; curCycleStart < curIterationGateCount; curCycleStart++) { if (gd[curCycleStart].leftV2 != startV2 & gd[curCycleStart].rightV2 != startV2) { break; } } left = gd[curCycleStart].leftV2; right = gd[curCycleStart].rightV2; Vector2 lowestLeftDir = left - startV2; Vector2 lowestRightDir = right - startV2; float lowestAngle = Vector2.Angle(lowestLeftDir, lowestRightDir); #region gate iteration int stuckLeft = curCycleStart; int stuckRight = curCycleStart; Vector3?endNode = null; for (int curGate = curCycleStart; curGate < curIterationGateCount; curGate++) { right = gd[curGate].rightV2; left = gd[curGate].leftV2; Vector2 curLeftDir = left - startV2; Vector2 curRightDir = right - startV2; if (SomeMath.V2Cross(lowestLeftDir, curRightDir) >= 0) { float currentAngle = Vector2.Angle(lowestLeftDir, curRightDir); if (currentAngle < lowestAngle) { lowestRightDir = curRightDir; lowestAngle = currentAngle; stuckRight = curGate; } } else { endNode = gd[stuckLeft].leftV3; curCycleEnd = stuckLeft; break; } if (SomeMath.V2Cross(curLeftDir, lowestRightDir) >= 0) { float currentAngle = Vector2.Angle(curLeftDir, lowestRightDir); if (currentAngle < lowestAngle) { lowestLeftDir = curLeftDir; lowestAngle = currentAngle; stuckLeft = curGate; } } else { endNode = gd[stuckRight].rightV3; curCycleEnd = stuckRight; break; } } #endregion //flag to reach next point if (endNode.HasValue) { if (curCycleStart != curCycleEnd) //move inside multiple cells { AddGate(curCycleStart, curCycleEnd, targetConnections, funnelPath.lastV3, endNode.Value); } funnelPath.AddMove(endNode.Value, (MoveState)(int)targetConnections[curCycleEnd].from.passability); } } if (curCycleEnd < gd.Count) { AddGate(curCycleEnd, targetConnections.Count, targetConnections, funnelPath.lastV3, endV3); } }
/// <summary> /// return used edges, /// </summary> private void MakeCell(TriangulatorEdge target, bool aFirst, List <TriangulatorEdge>[] edgesDictionary, TriangulatorNode[] nodes, out List <int> cellNodes, out List <TriangulatorEdge> cellEdges) { cellNodes = new List <int>(); cellEdges = new List <TriangulatorEdge>(); cellEdges.Add(target); int startNode; if (aFirst) //a are origin { startNode = target.a; cellNodes.Add(target.a); cellNodes.Add(target.b); } else { startNode = target.b; cellNodes.Add(target.b); cellNodes.Add(target.a); } int limit = 0; harhar++; while (true) { limit++; if (limit > 50) { #if UNITY_EDITOR if (Debuger_K.doDebug && Debuger_K.debugOnlyNavMesh == false) { for (int i = 0; i < cellNodes.Count - 1; i++) { Vector3 a1 = nodes[cellNodes[i]].positionV3 + (Vector3.up * 0.02f * i); Vector3 a2 = nodes[cellNodes[i + 1]].positionV3 + (Vector3.up * 0.02f * i); Debuger_K.AddTriangulatorDebugLine(pos.x, pos.z, properties, a1, a2, Color.red); //Debuger_K.AddTriangulatorDebugLabel(chunk, properties, SomeMath.MidPoint(a1, a2), i); } } #endif Debug.LogError("error while making cells " + harhar); break; } int nodeMinus = cellNodes[cellNodes.Count - 2]; int nodeCurrent = cellNodes[cellNodes.Count - 1]; int?nodePlus = null; TriangulatorEdge?connectionPlus = null; Vector2 directionToMinus = (nodes[nodeMinus].positionV2 - nodes[nodeCurrent].positionV2).normalized; float lowestAngle = 180f; List <TriangulatorEdge> searchConnections = edgesDictionary[nodeCurrent]; foreach (var connection in searchConnections) { int potentialNodePlus = connection.GetOtherNode(nodeCurrent); if (nodeMinus == potentialNodePlus) { continue; } Vector2 directionToPotentialPlus = (nodes[potentialNodePlus].positionV2 - nodes[nodeCurrent].positionV2).normalized; float cross = SomeMath.V2Cross(directionToMinus, directionToPotentialPlus); float currentAngle = Vector2.Angle(directionToMinus, directionToPotentialPlus); if (cross > 0f & currentAngle != 180) { continue; } if (currentAngle > lowestAngle) { continue; } connectionPlus = connection; nodePlus = potentialNodePlus; lowestAngle = currentAngle; } if (nodePlus == null) { #region error #if UNITY_EDITOR if (Debuger_K.doDebug) { Debuger_K.AddTriangulatorDebugLine(pos.x, pos.z, properties, nodes[cellNodes[0]].positionV3, nodes[cellNodes[0]].positionV3 + SmallV3(0.3f), Color.green); for (int i = 0; i < cellNodes.Count - 1; i++) { Debuger_K.AddTriangulatorDebugLine(pos.x, pos.z, properties, nodes[cellNodes[i]].positionV3 + SmallV3(0.1f), nodes[cellNodes[i + 1]].positionV3 + SmallV3(0.1f), Color.red); } for (int i = 0; i < cellNodes.Count - 1; i++) { Vector3 a1 = nodes[cellNodes[i]].positionV3 + SmallV3(0.02f * i); Vector3 a2 = nodes[cellNodes[i + 1]].positionV3 + SmallV3(0.02f * i); Debuger_K.AddTriangulatorDebugLine(pos.x, pos.z, properties, a1, a2, Color.red); } foreach (var connection in searchConnections) { int potentialNodePlus = connection.GetOtherNode(nodeCurrent); if (nodeMinus == potentialNodePlus) { continue; } Vector2 directionToPotentialPlus = (nodes[potentialNodePlus].positionV2 - nodes[nodeCurrent].positionV2).normalized; float cross = SomeMath.V2Cross(directionToMinus, directionToPotentialPlus); Debuger_K.AddLabel(nodes[potentialNodePlus].positionV3, cross); Debuger_K.AddLabel(nodes[nodeCurrent].positionV3, Vector2.Angle(directionToMinus, directionToPotentialPlus)); //Debuger_K.AddTriangulatorDebugLabel(chunk, properties, nodes[potentialNodePlus].positionV3, cross); //Debuger_K.AddTriangulatorDebugLabel(chunk, properties, nodes[nodeCurrent].positionV3, Vector2.Angle(directionToMinus, directionToPotentialPlus)); } } #endif #endregion Debug.LogError("nodePlus == null"); break; } cellEdges.Add(connectionPlus.Value); if (nodePlus == startNode) { break; } cellNodes.Add(nodePlus.Value); } }
//public GraphTriangulator(GraphGenerator generator, NavMeshTemplateCreation template) { // var volumes = generator.getVolumes; // var nodes = generator.getNodes; // //layer, hash // Dictionary<int, Dictionary<int, List<NodeAbstract>>> dicNodes = new Dictionary<int, Dictionary<int, List<NodeAbstract>>>(); // Dictionary<int, Dictionary<int, List<EdgeAbstract>>> dicEdges = new Dictionary<int, Dictionary<int, List<EdgeAbstract>>>(); // Dictionary<int, Dictionary<int, Dictionary<NodeAbstract, TriangulatorNodeData>>> dicValues = new Dictionary<int, Dictionary<int, Dictionary<NodeAbstract, TriangulatorNodeData>>>(); // foreach (var volume in volumes) { // dicNodes.Add(volume.id, new Dictionary<int, List<NodeAbstract>>()); // dicEdges.Add(volume.id, new Dictionary<int, List<EdgeAbstract>>()); // dicValues.Add(volume.id, new Dictionary<int, Dictionary<NodeAbstract, TriangulatorNodeData>>()); // //some hardcoded stuff // foreach (var a in volume.containsAreas) { // int crouchHash = PathFinder.GetAreaHash(a, Passability.Crouchable); // int walkHash = PathFinder.GetAreaHash(a, Passability.Walkable); // dicNodes[volume.id].Add(crouchHash, new List<NodeAbstract>()); // dicEdges[volume.id].Add(crouchHash, new List<EdgeAbstract>()); // dicValues[volume.id].Add(crouchHash, new Dictionary<NodeAbstract, TriangulatorNodeData>()); // dicNodes[volume.id].Add(walkHash, new List<NodeAbstract>()); // dicEdges[volume.id].Add(walkHash, new List<EdgeAbstract>()); // dicValues[volume.id].Add(walkHash, new Dictionary<NodeAbstract, TriangulatorNodeData>()); // } // } // foreach (var first in nodes) { // foreach (var pair in first.getData) { // int volume = pair.Key.x; // int hash = pair.Key.y; // dicNodes[volume][hash].Add(first); // dicEdges[volume][hash].Add(first[volume, hash]); // NodeTemp middle = first.GetNode(volume, hash); // NodeTemp last = middle.GetNode(volume, hash); // float cross = SomeMath.V2Cross( // last.x - middle.x, last.z - middle.z, // first.x - middle.x, first.z - middle.z); // if (cross < 0) { // Vector2 directionLast = new Vector2(last.x - middle.x, last.z - middle.z).normalized; // Vector2 directionFirst = new Vector2(first.x - middle.x, first.z - middle.z).normalized; // dicValues[volume][hash].Add(middle, new TriangulatorNodeData(cross, Vector2.Angle(directionLast, directionFirst), (directionLast + directionFirst).normalized * -1)); // } // else // dicValues[volume][hash].Add(middle, new TriangulatorNodeData(cross, 0, Vector2.zero)); // } // } // foreach (var volume in volumes) { // foreach (var a in volume.containsAreas) { // int crouchHash = PathFinder.GetAreaHash(a, Passability.Crouchable); // data.Add(new TriangulatorDataSet( // template, // dicNodes[volume.id][crouchHash], // dicEdges[volume.id][crouchHash], // dicValues[volume.id][crouchHash], // volume.id, a, Passability.Crouchable)); // int walkHash = PathFinder.GetAreaHash(a, Passability.Walkable); // data.Add(new TriangulatorDataSet( // template, // dicNodes[volume.id][walkHash], // dicEdges[volume.id][walkHash], // dicValues[volume.id][walkHash], // volume.id, a, Passability.Walkable)); // } // } // //data.RemoveAll(x => x.nodes.Count == 0); //} public GraphTriangulator(GraphGeneratorNew generator, NavMeshTemplateCreation template) { int maxLayers = generator.volumeContainer.layersCount; //var volumes = generator.dataLayers; var nodes = generator.getNodes; //DataLayer[] dataLayers = generator.dataLayers; //int dataLayersLength = dataLayers.Length; profiler = template.profiler; //layer, hash Dictionary <int, List <NodeAbstract> >[] dicNodes = new Dictionary <int, List <NodeAbstract> > [maxLayers]; Dictionary <int, List <EdgeAbstract> >[] dicEdges = new Dictionary <int, List <EdgeAbstract> > [maxLayers]; Dictionary <int, Dictionary <NodeAbstract, TriangulatorNodeData> >[] dicValues = new Dictionary <int, Dictionary <NodeAbstract, TriangulatorNodeData> > [maxLayers]; for (int id = 0; id < maxLayers; id++) { dicNodes[id] = new Dictionary <int, List <NodeAbstract> >(); dicEdges[id] = new Dictionary <int, List <EdgeAbstract> >(); dicValues[id] = new Dictionary <int, Dictionary <NodeAbstract, TriangulatorNodeData> >(); //DataLayer layer = dataLayers[id]; //some hardcoded stuff //foreach (var hash in layer.allAreaHashes) { // dicNodes[id].Add(hash, new List<NodeAbstract>()); // dicEdges[id].Add(hash, new List<EdgeAbstract>()); // dicValues[id].Add(hash, new Dictionary<NodeAbstract, TriangulatorNodeData>()); //} } if (profiler != null) { profiler.AddLog("start preparing data in GraphTriangulator"); } foreach (var first in nodes) { foreach (var pair in first.getData) { int layer = pair.Key.x; int hash = pair.Key.y; var curDicNodes = dicNodes[layer]; var curDicEdges = dicEdges[layer]; var curDicValues = dicValues[layer]; if (curDicNodes.ContainsKey(hash) == false) { curDicNodes.Add(hash, new List <NodeAbstract>()); curDicEdges.Add(hash, new List <EdgeAbstract>()); curDicValues.Add(hash, new Dictionary <NodeAbstract, TriangulatorNodeData>()); } curDicNodes[hash].Add(first); curDicEdges[hash].Add(first[layer, hash]); NodeTemp middle = first.GetNode(layer, hash); NodeTemp last = middle.GetNode(layer, hash); float cross = SomeMath.V2Cross( last.x - middle.x, last.z - middle.z, first.x - middle.x, first.z - middle.z); if (cross < 0) { Vector2 directionLast = new Vector2(last.x - middle.x, last.z - middle.z).normalized; Vector2 directionFirst = new Vector2(first.x - middle.x, first.z - middle.z).normalized; curDicValues[hash].Add(middle, new TriangulatorNodeData(cross, Vector2.Angle(directionLast, directionFirst), (directionLast + directionFirst).normalized * -1)); } else { curDicValues[hash].Add(middle, new TriangulatorNodeData(cross, 0, Vector2.zero)); } } } for (int id = 0; id < maxLayers; id++) { foreach (var hash in dicNodes[id].Keys) { Area area; Passability pass; template.hashData.GetAreaByHash((short)hash, out area, out pass); data.Add(new TriangulatorDataSet( template, dicNodes[id][hash], dicEdges[id][hash], dicValues[id][hash], id, area, pass)); } } if (profiler != null) { profiler.AddLog("end preparing data in GraphTriangulator"); } //data.RemoveAll(x => x.nodes.Count == 0); }
public void MakeConnections(NavMeshTemplateRecast template) { if (nodes.Length == 0) { return; } List <int> nextIterationNodes = new List <int>(); List <T2Helper> helpers = new List <T2Helper>(); //GenerateEdgeMap(10, template); CreateAngleVisibilityField(); for (int curNodeIndex = 0; curNodeIndex < _nodes.Length; curNodeIndex++) { if (data[curNodeIndex].cross >= 0) { continue; } var curVisible = visibilityField[curNodeIndex]; for (int i = 0; i < curVisible.Length; i++) { if (IsVisible(curNodeIndex, curVisible[i])) { AddEdge(curNodeIndex, curVisible[i], 0); goto NEXT; } } nextIterationNodes.Add(curNodeIndex); NEXT : { continue; } } foreach (var nodeIndex in nextIterationNodes) { Vector2 nodePos = _nodes[nodeIndex].positionV2; Vector2 normal = _data[nodeIndex].normal; float validAngle = 180f - (_data[nodeIndex].angle * 0.5f); helpers.Clear(); foreach (var targetNode in Array.FindAll(_nodes, x => Vector2.Angle(normal, x.positionV2 - nodePos) < validAngle)) { if (nodeIndex == targetNode.id) { continue; } Vector2 targetNodeDirection = (targetNode.positionV2 - nodePos).normalized; helpers.Add(new T2Helper(targetNode.id, Vector2.Angle(normal, targetNodeDirection) * Mathf.Sign(SomeMath.V2Cross(normal, targetNodeDirection)))); } helpers.Sort((x, y) => { return((int)Mathf.Sign(Math.Abs(x.angle) - Math.Abs(y.angle))); }); //get first visible node on left for (int i = 0; i < helpers.Count; i++) { if (helpers[i].angle < 0 && IsVisible(nodeIndex, helpers[i].node)) { AddEdge(nodeIndex, helpers[i].node, 0); break; } } //get first visible node on right for (int i = 0; i < helpers.Count; i++) { if (helpers[i].angle > 0 && IsVisible(nodeIndex, helpers[i].node)) { AddEdge(nodeIndex, helpers[i].node, 0); break; } } } }
XZPosInt pos;//for debug public GraphTriangulator(GraphGenerator generator, NavMeshTemplateRecast template) { var volumes = generator.getVolumes; var nodes = generator.getNodes; //layer, hash Dictionary <int, Dictionary <int, List <NodeAbstract> > > dicNodes = new Dictionary <int, Dictionary <int, List <NodeAbstract> > >(); Dictionary <int, Dictionary <int, List <EdgeAbstract> > > dicEdges = new Dictionary <int, Dictionary <int, List <EdgeAbstract> > >(); Dictionary <int, Dictionary <int, Dictionary <NodeAbstract, TriangulatorNodeData> > > dicValues = new Dictionary <int, Dictionary <int, Dictionary <NodeAbstract, TriangulatorNodeData> > >(); foreach (var volume in volumes) { dicNodes.Add(volume.id, new Dictionary <int, List <NodeAbstract> >()); dicEdges.Add(volume.id, new Dictionary <int, List <EdgeAbstract> >()); dicValues.Add(volume.id, new Dictionary <int, Dictionary <NodeAbstract, TriangulatorNodeData> >()); //some hardcoded stuff foreach (var a in volume.containsAreas) { int crouchHash = PathFinder.GetAreaHash(a, Passability.Crouchable); int walkHash = PathFinder.GetAreaHash(a, Passability.Walkable); dicNodes[volume.id].Add(crouchHash, new List <NodeAbstract>()); dicEdges[volume.id].Add(crouchHash, new List <EdgeAbstract>()); dicValues[volume.id].Add(crouchHash, new Dictionary <NodeAbstract, TriangulatorNodeData>()); dicNodes[volume.id].Add(walkHash, new List <NodeAbstract>()); dicEdges[volume.id].Add(walkHash, new List <EdgeAbstract>()); dicValues[volume.id].Add(walkHash, new Dictionary <NodeAbstract, TriangulatorNodeData>()); } } foreach (var first in nodes) { foreach (var pair in first.getData) { int volume = pair.Key.x; int hash = pair.Key.y; dicNodes[volume][hash].Add(first); dicEdges[volume][hash].Add(first[volume, hash]); NodeTemp middle = first.GetNode(volume, hash); NodeTemp last = middle.GetNode(volume, hash); float cross = SomeMath.V2Cross( last.x - middle.x, last.z - middle.z, first.x - middle.x, first.z - middle.z); if (cross < 0) { Vector2 directionLast = new Vector2(last.x - middle.x, last.z - middle.z).normalized; Vector2 directionFirst = new Vector2(first.x - middle.x, first.z - middle.z).normalized; dicValues[volume][hash].Add(middle, new TriangulatorNodeData(cross, Vector2.Angle(directionLast, directionFirst), (directionLast + directionFirst).normalized * -1)); } else { dicValues[volume][hash].Add(middle, new TriangulatorNodeData(cross, 0, Vector2.zero)); } } } foreach (var volume in volumes) { foreach (var a in volume.containsAreas) { int crouchHash = PathFinder.GetAreaHash(a, Passability.Crouchable); data.Add(new TriangulatorDataSet( template, dicNodes[volume.id][crouchHash], dicEdges[volume.id][crouchHash], dicValues[volume.id][crouchHash], volume.id, a, Passability.Crouchable)); int walkHash = PathFinder.GetAreaHash(a, Passability.Walkable); data.Add(new TriangulatorDataSet( template, dicNodes[volume.id][walkHash], dicEdges[volume.id][walkHash], dicValues[volume.id][walkHash], volume.id, a, Passability.Walkable)); } } //data.RemoveAll(x => x.nodes.Count == 0); }